]> git.neil.brown.name Git - history.git/commitdiff
2.1.97 - for brave people only. 2.1.97
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:15 +0000 (15:15 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:15 +0000 (15:15 -0500)
I made a 2.1.97 release, in order to synch up with some large patch-sets
I've gotten (non-x86 architecture updates). But due to the new baby this
really hasn't been through my usual exhaustive stress-test ("make bzImage"
+ "boot") so buyer beware.

                Linus

416 files changed:
CREDITS
Documentation/Configure.help
Documentation/pci.txt
Documentation/powerpc/ppc_htab.txt
Documentation/powerpc/smp.txt
Documentation/powerpc/sound.txt
Documentation/sysctl/README
Documentation/sysctl/kernel.txt
Documentation/sysctl/vm.txt
Makefile
arch/i386/kernel/bios32.c
arch/i386/kernel/ldt.c
arch/i386/kernel/process.c
arch/i386/math-emu/fpu_system.h
arch/ppc/8xx_io/Makefile [new file with mode: 0644]
arch/ppc/8xx_io/commproc.c [new file with mode: 0644]
arch/ppc/8xx_io/commproc.h [new file with mode: 0644]
arch/ppc/8xx_io/enet.c [new file with mode: 0644]
arch/ppc/8xx_io/uart.c [new file with mode: 0644]
arch/ppc/Makefile
arch/ppc/boot/Makefile
arch/ppc/boot/head.S
arch/ppc/boot/mbxtty.c [new file with mode: 0644]
arch/ppc/boot/misc.c
arch/ppc/boot/vreset.c
arch/ppc/chrp_defconfig [new file with mode: 0644]
arch/ppc/chrpboot/main.c
arch/ppc/chrpboot/misc.S
arch/ppc/coffboot/main.c
arch/ppc/coffboot/misc.S
arch/ppc/common_defconfig [new file with mode: 0644]
arch/ppc/config.in
arch/ppc/defconfig
arch/ppc/kernel/Makefile
arch/ppc/kernel/align.c
arch/ppc/kernel/chrp_pci.c
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/chrp_time.c
arch/ppc/kernel/head.S
arch/ppc/kernel/idle.c
arch/ppc/kernel/irq.c
arch/ppc/kernel/mbx_pci.c [new file with mode: 0644]
arch/ppc/kernel/mbx_setup.c [new file with mode: 0644]
arch/ppc/kernel/misc.S
arch/ppc/kernel/mk_defs.c
arch/ppc/kernel/pci-bridge.c [deleted file]
arch/ppc/kernel/pci.c
arch/ppc/kernel/pmac_pci.c
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/pmac_support.c
arch/ppc/kernel/pmac_time.c
arch/ppc/kernel/ppc-stub.c [new file with mode: 0644]
arch/ppc/kernel/ppc_htab.c
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/prep_pci.c
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/prep_time.c
arch/ppc/kernel/process.c
arch/ppc/kernel/prom.c
arch/ppc/kernel/ptrace.c
arch/ppc/kernel/residual.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/signal.c
arch/ppc/kernel/smp.c
arch/ppc/kernel/softemu8xx.c [new file with mode: 0644]
arch/ppc/kernel/time.c
arch/ppc/kernel/time.h
arch/ppc/kernel/traps.c
arch/ppc/lib/locks.c
arch/ppc/mbx_defconfig [new file with mode: 0644]
arch/ppc/mm/fault.c
arch/ppc/mm/init.c
arch/ppc/pmac_defconfig
arch/ppc/prep_defconfig
arch/sparc/Makefile
arch/sparc/ap1000/apmmu.c
arch/sparc/boot/Makefile
arch/sparc/boot/btfixupprep.c [new file with mode: 0644]
arch/sparc/config.in
arch/sparc/defconfig
arch/sparc/kernel/Makefile
arch/sparc/kernel/auxio.c
arch/sparc/kernel/cpu.c
arch/sparc/kernel/devices.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/etrap.S
arch/sparc/kernel/head.S
arch/sparc/kernel/init_task.c
arch/sparc/kernel/irq.c
arch/sparc/kernel/process.c
arch/sparc/kernel/rtrap.S
arch/sparc/kernel/sclow.S
arch/sparc/kernel/setup.c
arch/sparc/kernel/signal.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/sparc-stub.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4c_irq.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c [new file with mode: 0644]
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/sun4m_smp.c [new file with mode: 0644]
arch/sparc/kernel/sunos_ioctl.c
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/kernel/systbls.S
arch/sparc/kernel/tadpole.c
arch/sparc/kernel/time.c
arch/sparc/kernel/trampoline.S
arch/sparc/kernel/traps.c
arch/sparc/kernel/wof.S
arch/sparc/kernel/wuf.S
arch/sparc/lib/Makefile
arch/sparc/lib/atomic.S
arch/sparc/lib/blockops.S
arch/sparc/math-emu/Makefile [new file with mode: 0644]
arch/sparc/math-emu/ashldi3.S [new file with mode: 0644]
arch/sparc/math-emu/fabss.c [new file with mode: 0644]
arch/sparc/math-emu/fcmpd.c [new file with mode: 0644]
arch/sparc/math-emu/fcmped.c [new file with mode: 0644]
arch/sparc/math-emu/fcmpeq.c [new file with mode: 0644]
arch/sparc/math-emu/fcmpes.c [new file with mode: 0644]
arch/sparc/math-emu/fcmpq.c [new file with mode: 0644]
arch/sparc/math-emu/fcmps.c [new file with mode: 0644]
arch/sparc/math-emu/fdmulq.c [new file with mode: 0644]
arch/sparc/math-emu/fdtoq.c [new file with mode: 0644]
arch/sparc/math-emu/fdtos.c [new file with mode: 0644]
arch/sparc/math-emu/fmovs.c [new file with mode: 0644]
arch/sparc/math-emu/fnegs.c [new file with mode: 0644]
arch/sparc/math-emu/fqtod.c [new file with mode: 0644]
arch/sparc/math-emu/fqtos.c [new file with mode: 0644]
arch/sparc/math-emu/fsmuld.c [new file with mode: 0644]
arch/sparc/math-emu/fstod.c [new file with mode: 0644]
arch/sparc/math-emu/fstoq.c [new file with mode: 0644]
arch/sparc/math-emu/math.c [new file with mode: 0644]
arch/sparc/math-emu/sfp-machine.h [new file with mode: 0644]
arch/sparc/mm/Makefile
arch/sparc/mm/btfixup.c [new file with mode: 0644]
arch/sparc/mm/fault.c
arch/sparc/mm/hypersparc.S
arch/sparc/mm/init.c
arch/sparc/mm/io-unit.c
arch/sparc/mm/iommu.c
arch/sparc/mm/loadmmu.c
arch/sparc/mm/nosrmmu.c [new file with mode: 0644]
arch/sparc/mm/nosun4c.c [new file with mode: 0644]
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/mm/turbosparc.S
arch/sparc/mm/viking.S
arch/sparc/prom/Makefile
arch/sparc/prom/bootstr.c
arch/sparc/prom/console.c
arch/sparc/prom/devmap.c
arch/sparc/prom/devops.c
arch/sparc/prom/init.c
arch/sparc/prom/memory.c
arch/sparc/prom/misc.c
arch/sparc/prom/mp.c
arch/sparc/prom/ranges.c
arch/sparc/prom/segment.c
arch/sparc/prom/sun4prom.c [new file with mode: 0644]
arch/sparc/prom/tree.c
arch/sparc/vmlinux.lds
arch/sparc64/Makefile
arch/sparc64/config.in
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/binfmt_aout32.c
arch/sparc64/kernel/central.c
arch/sparc64/kernel/cpu.c
arch/sparc64/kernel/devices.c
arch/sparc64/kernel/dtlb_miss.S
arch/sparc64/kernel/dtlb_prot.S
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/head.S
arch/sparc64/kernel/init_task.c
arch/sparc64/kernel/ioctl32.c
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/itlb_miss.S
arch/sparc64/kernel/process.c
arch/sparc64/kernel/psycho.c
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sunos_ioctl32.c
arch/sparc64/kernel/sys32.S
arch/sparc64/kernel/sys_sparc.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/sys_sunos32.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/kernel/trampoline.S
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/ttable.S
arch/sparc64/lib/VIScsumcopy.S
arch/sparc64/math-emu/Makefile
arch/sparc64/math-emu/double.h
arch/sparc64/math-emu/fabsq.c
arch/sparc64/math-emu/fcmpeq.c
arch/sparc64/math-emu/fcmpq.c
arch/sparc64/math-emu/fnegq.c
arch/sparc64/math-emu/math.c
arch/sparc64/math-emu/op-2.h
arch/sparc64/math-emu/op-4.h
arch/sparc64/math-emu/op-common.h
arch/sparc64/math-emu/quad.h
arch/sparc64/math-emu/single.h
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/sparc64/mm/modutil.c
arch/sparc64/prom/bootstr.c
arch/sparc64/prom/init.c
arch/sparc64/prom/ranges.c
arch/sparc64/solaris/Makefile
arch/sparc64/solaris/conv.h
arch/sparc64/solaris/entry64.S
arch/sparc64/solaris/fs.c
arch/sparc64/solaris/ioctl.c
arch/sparc64/solaris/misc.c
arch/sparc64/solaris/socksys.c
arch/sparc64/solaris/socksys.h [new file with mode: 0644]
arch/sparc64/solaris/systbl.S
arch/sparc64/solaris/timod.c [new file with mode: 0644]
arch/sparc64/vmlinux.lds
drivers/block/ide-dma.c
drivers/block/ide-pci.c
drivers/block/ide-proc.c
drivers/char/Config.in
drivers/char/lp.c
drivers/char/mem.c
drivers/char/serial.c
drivers/char/tty_io.c
drivers/char/vt.c
drivers/fc4/fc.c
drivers/fc4/fc_syms.c
drivers/fc4/fcp_scsi.h
drivers/fc4/soc.c
drivers/macintosh/Makefile
drivers/macintosh/adb.c
drivers/macintosh/ati-gx.h
drivers/macintosh/aty.c
drivers/macintosh/chips.c
drivers/macintosh/control.c
drivers/macintosh/imstt.c
drivers/macintosh/imstt.h
drivers/macintosh/mac_keyb.c
drivers/macintosh/macio-adb.c
drivers/macintosh/mackeymap.c [deleted file]
drivers/macintosh/macserial.c
drivers/macintosh/mediabay.c [new file with mode: 0644]
drivers/macintosh/platinum.c
drivers/macintosh/pmac-cons.c
drivers/macintosh/valkyrie.c
drivers/macintosh/via-cuda.c
drivers/macintosh/via-pmu.c [new file with mode: 0644]
drivers/misc/parport_pc.c
drivers/misc/parport_share.c
drivers/net/Config.in
drivers/net/hp100.c
drivers/net/mace.c
drivers/net/mace.h
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/pci/pci.c
drivers/pci/pcisyms.c
drivers/pci/proc.c
drivers/sbus/char/Makefile
drivers/sbus/char/bwtwo.c
drivers/sbus/char/cgfourteen.c
drivers/sbus/char/cgsix.c
drivers/sbus/char/cgthree.c
drivers/sbus/char/creator.c
drivers/sbus/char/envctrl.c [new file with mode: 0644]
drivers/sbus/char/flash.c
drivers/sbus/char/leo.c
drivers/sbus/char/mach64.c
drivers/sbus/char/mach64.h
drivers/sbus/char/pcicons.c
drivers/sbus/char/pcikbd.c
drivers/sbus/char/sab82532.c
drivers/sbus/char/sbuscons.c
drivers/sbus/char/su.c
drivers/sbus/char/suncons.c
drivers/sbus/char/sunkbd.c
drivers/sbus/char/tcx.c
drivers/sbus/char/vfc_dev.c
drivers/sbus/char/weitek.c
drivers/sbus/char/zs.c
drivers/sbus/dvma.c
drivers/sbus/sbus.c
drivers/scsi/53c7,8xx.c
drivers/scsi/BusLogic.c
drivers/scsi/BusLogic.h
drivers/scsi/advansys.c
drivers/scsi/fdomain.c
drivers/scsi/gdth.c
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/pluto.c
drivers/scsi/pluto.h
drivers/scsi/qlogicpti.c
fs/binfmt_aout.c
fs/proc/inode.c
fs/proc/openpromfs.c
fs/proc/proc_devtree.c
fs/proc/root.c
include/asm-alpha/irq.h
include/asm-alpha/serial.h [new file with mode: 0644]
include/asm-i386/irq.h
include/asm-i386/serial.h [new file with mode: 0644]
include/asm-i386/system.h
include/asm-m68k/irq.h
include/asm-ppc/8xx_immap.h [new file with mode: 0644]
include/asm-ppc/adb.h
include/asm-ppc/cache.h
include/asm-ppc/cuda.h
include/asm-ppc/dma.h
include/asm-ppc/elf.h
include/asm-ppc/ide.h
include/asm-ppc/io.h
include/asm-ppc/ioctl.h
include/asm-ppc/irq.h
include/asm-ppc/keyboard.h
include/asm-ppc/kgdb.h [new file with mode: 0644]
include/asm-ppc/mbx.h [new file with mode: 0644]
include/asm-ppc/mediabay.h [new file with mode: 0644]
include/asm-ppc/mmu.h
include/asm-ppc/mmu_context.h
include/asm-ppc/ohare.h [new file with mode: 0644]
include/asm-ppc/page.h
include/asm-ppc/pci-bridge.h
include/asm-ppc/pgtable.h
include/asm-ppc/pmu.h [new file with mode: 0644]
include/asm-ppc/processor.h
include/asm-ppc/prom.h
include/asm-ppc/ptrace.h
include/asm-ppc/smp.h
include/asm-ppc/socket.h
include/asm-ppc/softirq.h
include/asm-ppc/spinlock.h
include/asm-ppc/stat.h
include/asm-ppc/system.h
include/asm-ppc/unistd.h
include/asm-ppc/xstat.h [new file with mode: 0644]
include/asm-sparc/a.out.h
include/asm-sparc/asi.h
include/asm-sparc/asm_offsets.h
include/asm-sparc/asmmacro.h
include/asm-sparc/bitops.h
include/asm-sparc/btfixup.h [new file with mode: 0644]
include/asm-sparc/contregs.h
include/asm-sparc/dma.h
include/asm-sparc/elf.h
include/asm-sparc/head.h
include/asm-sparc/io-unit.h
include/asm-sparc/io.h
include/asm-sparc/irq.h
include/asm-sparc/mmu_context.h
include/asm-sparc/namei.h
include/asm-sparc/obio.h
include/asm-sparc/oplib.h
include/asm-sparc/page.h
include/asm-sparc/pgtable.h
include/asm-sparc/pgtsun4.h
include/asm-sparc/pgtsun4c.h
include/asm-sparc/processor.h
include/asm-sparc/sbi.h
include/asm-sparc/sbus.h
include/asm-sparc/smp.h
include/asm-sparc/softirq.h
include/asm-sparc/stat.h
include/asm-sparc/string.h
include/asm-sparc/sun4paddr.h [new file with mode: 0644]
include/asm-sparc/sun4prom.h [new file with mode: 0644]
include/asm-sparc/system.h
include/asm-sparc/timer.h
include/asm-sparc/traps.h
include/asm-sparc/uaccess.h
include/asm-sparc/unistd.h
include/asm-sparc/user.h
include/asm-sparc/vac-ops.h
include/asm-sparc/winmacro.h
include/asm-sparc/xstat.h [new file with mode: 0644]
include/asm-sparc64/apb.h [new file with mode: 0644]
include/asm-sparc64/asm_offsets.h
include/asm-sparc64/ebus.h
include/asm-sparc64/elf.h
include/asm-sparc64/ide.h
include/asm-sparc64/io.h
include/asm-sparc64/ioctls.h
include/asm-sparc64/irq.h
include/asm-sparc64/namei.h
include/asm-sparc64/openprom.h
include/asm-sparc64/page.h
include/asm-sparc64/pbm.h
include/asm-sparc64/pgtable.h
include/asm-sparc64/processor.h
include/asm-sparc64/psycho.h
include/asm-sparc64/sbus.h
include/asm-sparc64/smp.h
include/asm-sparc64/softirq.h
include/asm-sparc64/stat.h
include/asm-sparc64/system.h
include/asm-sparc64/timer.h
include/asm-sparc64/ttable.h
include/asm-sparc64/unistd.h
include/asm-sparc64/xstat.h [new file with mode: 0644]
include/linux/parport.h
include/linux/pci.h
include/linux/proc_fs.h
include/linux/reboot.h
include/linux/serial.h
kernel/sys.c
net/ipv4/ip_fragment.c

diff --git a/CREDITS b/CREDITS
index a27bb46356ccf3b7c72eb119e39a608f7cb72be7..05d1cb7ef9472f26dc11eba97be457483de52d40 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1433,8 +1433,8 @@ S: 75019 Paris
 S: France
 
 N: Rik van Riel
-E: H.H.vanRiel@fys.ruu.nl
-W: http://www.fys.ruu.nl/~riel/
+E: H.H.vanRiel@phys.uu.nl
+W: http://www.phys.uu.nl/~riel/
 D: Maintainer of the mm-patches page (see www.linuxhq.com)
 D: Documentation/sysctl/*, kswapd fixes, random kernel hacker
 S: Vorenkampsweg 1
index 56f879f9fb430ba9957de27e439aca189c1730dd..649aa42484052f1db28dea9f8f434eed492824d9 100644 (file)
@@ -434,6 +434,15 @@ CONFIG_BLK_DEV_ALI14XX
   I/O speeds to be set as well.  See the Documentation/ide.txt and
   ali14xx.c files for more info.
 
+Apple Macintosh builtin IDE interface support (EXPERIMENTAL)
+CONFIG_BLK_DEV_MAC_IDE
+  This is the IDE driver for the builtin IDE interface on some Apple
+  Macintosh models.  It supports both the Quadra/Performa/LC 630 and
+  the PowerBook 190 IDE interface.
+  Say Y if you have such a Macintosh model and want to use IDE devices
+  (hard disks, CD-ROM drives, etc.) that are connected to the builtin
+  IDE interface.
+
 XT hard disk support
 CONFIG_BLK_DEV_XD
   Very old 8 bit hard disk controllers used in the IBM XT computer. To
@@ -956,6 +965,19 @@ CONFIG_SERIAL_SHARE_IRQ
   serial ports on the same board to share a single IRQ.  To enable
   support for this in the serial driver, say Y here.
 
+Autodetect IRQ on standard ports (unsafe)
+CONFIG_SERIAL_DETECT_IRQ
+  Enable this option if you want the kernel to try to guess which IRQ
+  is configured during the boot sequence and you're too lazy to edit
+  the boot scripts to use the setserial command.  This option can be
+  unsafe and should not be enabled on most machines.  It is far
+  better to dynamically request autoconfiguration during the boot-time
+  scripts using the setserial command.  You can change the IRQ and/or 
+  request automatic IRQ configuration at any time by using the 
+  "setserial" program.  I wouldn't include this config option at all except
+  people keep bellyaching about it.  I guess they are really are too lazy 
+  to edit their boot scripts.  :-)   If unsure, say No.
+
 Support special multiport boards
 CONFIG_SERIAL_MULTIPORT
   Some multiport serial ports have special ports which are used to
@@ -7301,8 +7323,9 @@ CONFIG_ATARI
 
 Macintosh support
 CONFIG_MAC
-  This option would enable support for the Apple Macintosh if there was
-  any for it.  Say N unless you've coded all the necessary support. ;)
+  This option enables support for the Apple Macintosh series of computers
+  (yes, there is experimental support now, at least for part of the series).  
+  Say N unless you're willing to code the remaining necessary support. ;)
 
 # CONFIG_APOLLO, etc. coming soon (?)
 
index b5d8632c184d23392a2943320244752d735f47b8..8dbd3b2725f03428df46bf8a03e3594be61c9f55 100644 (file)
@@ -53,8 +53,13 @@ have been remapped by the kernel.
 
 4. Obsolete functions
 ~~~~~~~~~~~~~~~~~~~~~
-
 <linux/bios32.h> is obsolete and should not be included in new code.
 
 pcibios_find_(device|class) are also obsolete and should be replaced by
 pci_find_(device|class).
+
+5. Bus mastering
+~~~~~~~~~~~~~~~~
+   If you need to setup a bus-mastering card, just call pci_set_master(). It
+should set PCI_COMMAND_MASTER in the command register and adjust the latency
+timer if needed.
index fab9f3aae29b40db5f28c3a9039eea8bd756a9ec..28555686d15eaed9e2c3c051b6e9acc9a6992cca 100644 (file)
@@ -4,6 +4,8 @@
 This document and the related code was written by me (Cort Dougan), please
 email me (cort@cs.nmt.edu) if you have questions, comments or corrections.
 
+Last Change: 2.16.98
+
 This entry in the proc directory is readable by all users but only
 writable by root.
 
index 932170f74788fb16077041c8a48947ce390754cb..d65dfae1964106c4f9091d3bed3b44da160978f9 100644 (file)
@@ -1,8 +1,11 @@
                  Information about Linux/PPC SMP mode
 =====================================================================
 
-This document and the related code was written by me (Cort Dougan), please
-email me (cort@cs.nmt.edu) if you have questions, comments or corrections.
+This document and the related code was written by me
+(Cort Dougan, cort@cs.nmt.edu) please email me if you have questions,
+comments or corrections.
+
+Last Change: 4.1.98
 
 SMP support for Linux/PPC is still in its early stages and likely to
 be buggy for a while.  If you want to help by writing code or testing
@@ -10,11 +13,17 @@ different hardware please email me!
 
 1. State of Supported Hardware
 
-  UMAX s900
+  PowerSurge Architecture - UMAX s900, Apple 9500/9600/8500/8600/7500/7600
     The second processor on this machine boots up just fine and
     enters its idle loop.  Hopefully a completely working SMP kernel
     on this machine will be done shortly.
 
+    The code makes the assumption of only two processors.  The changes
+    necessary to work with any number would not be overly difficult but
+    I don't have any machines with >2 processors so it's not high on my
+    list of priorities.  If anyone else would like do to the work email
+    me and I can point out the places that need changed.
+
   BeBox
     BeBox support hasn't been added to the 2.1.X kernels from 2.0.X
     but work is being done and SMP support for BeBox is in the works.
index c0acf6a7b7c2843048877b5a1466e47b5d212b9e..8f4a440347ad57bf89afd1750fa8a39a486e4c98 100644 (file)
@@ -4,26 +4,31 @@
 Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
 comments or corrections.
 
-This just covers sound on the PReP systems for now, and later will
-contain information on the PowerMac's.
+Last Change: 3.24.98
 
-Sound has been tested and is working with the PowerStack and IBM Power
-Series onboard sound systems which are based on the cs4231(2) chip.
-The sound options when doing the make config are a bit different from the
-default, though.
+This just covers sound on the PReP and CHRP systems for now and later
+will contain information on the PowerMac's.
+
+Sound on PReP has been tested and is working with the PowerStack and IBM
+Power Series onboard sound systems which are based on the cs4231(2) chip.
+The sound options when doing the make config are a bit different from
+the default, though.
 
 The I/O base, irq and dma lines that you enter during the make config
 are ignored and are set when booting according to the machine type.
 This is so that one binary can be used for Motorola and IBM machines
-which use different values and isn't allowed by the driver, so things are
-hacked together in such a way as to allow this information to be set
-automatically on boot.
+which use different values and isn't allowed by the driver, so things
+are hacked together in such a way as to allow this information to be
+set automatically on boot.
+
+1. Motorola PowerStack PReP machines
 
-1. PowerStack
+  Enable support for "Crystal CS4232 based (PnP) cards" and for the
+  Microsoft Sound System.  The MSS isn't used, but some of the routines
+  that the CS4232 driver uses are in it.
 
-  Enable support for "Crystal CS4232 based (PnP) cards".  Although the
-  options you set are ignored and determined automatically on boot these
-  are included for information only:
+  Although the options you set are ignored and determined automatically
+  on boot these are included for information only:
 
   (830) CS4232 audio I/O base 530, 604, E80 or F40
   (10) CS4232 audio IRQ 5, 7, 9, 11, 12 or 15
@@ -33,16 +38,31 @@ automatically on boot.
   This will allow simultaneous record and playback, as 2 different dma
   channels are used.
 
+  The sound will be all left channel and very low volume since the
+  auxiliary input isn't muted by default.  I had the changes necessary
+  for this in the kernel but the sound driver maintainer didn't want
+  to include them since it wasn't common in other machines.  To fix this
+  you need to mute it using a mixer utility of some sort (if you find one
+  please let me know) or by patching the driver yourself and recompiling.
+
+  There is a problem on the PowerStack 2's (PowerStack Pro's) using a
+  different irq/drq than the kernel expects.  Unfortunately, I don't know
+  which irq/drq it is so if anyone knows please email me.
+
   Midi is not supported since the cs4232 driver doesn't support midi yet.
 
-2. IBM machines
+2. IBM PowerPersonal PReP machines and IBM LongTrail CHRP
 
   I've only tested sound on the Power Personal Series of IBM workstations
-  so if you try it on others please let me know the result.
+  so if you try it on others please let me know the result.  I'm especially
+  interested in the 43p's sound system, which I know nothing about.
+
+  Enable support for "Crystal CS4232 based (PnP) cards" and for the
+  Microsoft Sound System.  The MSS isn't used, but some of the routines
+  that the CS4232 driver uses are in it.
 
-  Enable support for "Crystal CS4232 based (PnP) cards".  Although the
-  options you set are ignored and determined automatically on boot these
-  are included for information only:
+  Although the options you set are ignored and determined automatically
+  on boot these are included for information only:
 
   (530) CS4232 audio I/O base 530, 604, E80 or F40
   (5) CS4232 audio IRQ 5, 7, 9, 11, 12 or 15
@@ -54,4 +74,3 @@ automatically on boot.
   This setup does _NOT_ allow for recording yet.
 
   Midi is not supported since the cs4232 driver doesn't support midi yet.
-
index 02100863a1527957d01d19817992515fa1f8d01a..be6a09704d1f680853c13b5625412708eccf8834 100644 (file)
@@ -1,6 +1,6 @@
 
 Documentation for /proc/sys/*/*                version 0.1
-       (c) 1998, Rik van Riel <H.H.vanRiel@fys.ruu.nl>
+       (c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 'Why', I hear you ask, 'would anyone even _want_ documentation
 for them sysctl files? If anybody really needs it, it's all in
@@ -32,7 +32,7 @@ it. Not only to have a great laugh, but also to make sure that
 you're the last RTFMing person to screw up.
 
 In short, e-mail your suggestions, corrections and / or horror
-stories to: <H.H.vanRiel@fys.ruu.nl>
+stories to: <H.H.vanRiel@phys.uu.nl>
 
 Rik van Riel.
 
index baf3f0700d964518250b5c2bd7b7a425a65f1893..c33df7e7bf89e7931b31cb80ecb9366a9600a4a5 100644 (file)
@@ -1,6 +1,6 @@
 
 Documentation for /proc/sys/kernel/*   version 0.1
-       (c) 1998, Rik van Riel <H.H.vanRiel@fys.ruu.nl>
+       (c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 For general info and legal blurb, please look in README.
 
index f2ef26fff7897b59679f466cf059037bc5c380fb..348e002e862a92331f82d8bb3415bb44f1e6436d 100644 (file)
@@ -1,6 +1,6 @@
 
 Documentation for /proc/sys/vm/*       version 0.1
-       (c) 1998, Rik van Riel <H.H.vanRiel@fys.ruu.nl>
+       (c) 1998, Rik van Riel <H.H.vanRiel@phys.uu.nl>
 
 For general info and legal blurb, please look in README.
 
index 7a6f0d296717868b13badb439d789e5b12d5579e..efbf39560a49cb536fc906fed5b57a4f7dffec8c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 96
+SUBLEVEL = 97
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
index 91bbe854d50148511f4d5ac8fbd072e9ca5cb413..f2955918a04ab0526ae45d6fdfd2c7bba62aa4d5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * bios32.c - Low-Level PCI Access
  *
- * $Id: bios32.c,v 1.26 1998/02/18 15:21:09 mj Exp $
+ * $Id: bios32.c,v 1.29 1998/04/17 16:31:15 mj Exp $
  *
  * Sponsored by
  *     iX Multiuser Multitasking Magazine
@@ -73,6 +73,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 
 #include <asm/page.h>
 #include <asm/segment.h>
 
 #include "irq.h"
 
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
 /*
  * Generic PCI access -- indirect calls according to detected HW.
  */
@@ -158,11 +167,13 @@ int pcibios_write_config_dword (unsigned char bus,
        return access_pci->write_config_dword(bus, device_fn, where, value);
 }
 
-static unsigned int pci_probe = ~0;
-
 #define PCI_PROBE_BIOS 1
 #define PCI_PROBE_CONF1 2
 #define PCI_PROBE_CONF2 4
+#define PCI_NO_SORT 0x100
+#define PCI_BIOS_SORT 0x200
+
+static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
 
 /*
  * Direct access to PCI hardware...
@@ -596,8 +607,10 @@ static int pci_bios_find_class (unsigned int class_code, unsigned short index,
        return (int) (ret & 0xff00) >> 8;
 }
 
-static int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
-       unsigned short index, unsigned char *bus, unsigned char *device_fn)
+#endif
+
+__initfunc(static int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
+       unsigned short index, unsigned char *bus, unsigned char *device_fn))
 {
        unsigned short bx;
        unsigned short ret;
@@ -621,8 +634,6 @@ static int pci_bios_find_device (unsigned short vendor, unsigned short device_id
        return (int) (ret & 0xff00) >> 8;
 }
 
-#endif
-
 static int pci_bios_read_config_byte(unsigned char bus,
        unsigned char device_fn, unsigned char where, unsigned char *value)
 {
@@ -803,13 +814,13 @@ __initfunc(static struct pci_access *pci_find_bios(void))
                                check->fields.revision, check);
                        continue;
                }
-               printk ("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
+               DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
                if (check->fields.entry >= 0x100000) {
-                       printk("PCI: BIOS32 entry in high memory, cannot use.\n");
+                       printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
                        return NULL;
                } else {
                        bios32_entry = check->fields.entry;
-                       printk ("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
+                       DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
                        bios32_indirect.address = bios32_entry + PAGE_OFFSET;
                        if (check_pcibios())
                                return &pci_bios_access;
@@ -817,18 +828,104 @@ __initfunc(static struct pci_access *pci_find_bios(void))
                break;  /* Hopefully more than one BIOS32 cannot happen... */
        }
 
-       /*
-        * If we were told to use the PCI BIOS and it's not present, avoid
-        * touching the hardware.
-        */
-       pci_probe = 0;
        return NULL;
 }
 
+/*
+ * Sort the device list according to PCI BIOS.
+ */
+
+__initfunc(void pcibios_sort(void))
+{
+       struct pci_dev *dev = pci_devices;
+       struct pci_dev **last = &pci_devices;
+       struct pci_dev *d, **dd, *e;
+       int idx;
+       unsigned char bus, devfn;
+
+       DBG("PCI: Sorting device list...\n");
+       while ((e = dev)) {
+               idx = 0;
+               while (pci_bios_find_device(e->vendor, e->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
+                       idx++;
+                       for(dd=&dev; (d = *dd); dd = &d->next) {
+                               if (d->bus->number == bus && d->devfn == devfn) {
+                                       *dd = d->next;
+                                       *last = d;
+                                       last = &d->next;
+                                       break;
+                               }
+                       }
+                       if (!d)
+                               printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
+               }
+               if (!idx) {
+                       printk("PCI: Device %02x:%02x not found by BIOS\n",
+                               dev->bus->number, dev->devfn);
+                       d = dev;
+                       dev = dev->next;
+                       *last = d;
+                       last = &d->next;
+               }
+       }
+       *last = NULL;
+}
+
 #endif
 
 /*
- * Arch-dependent fixups.
+ * Several BIOS'es forget to assign addresses to I/O ranges.
+ * We try to fix it here, expecting there are free addresses
+ * starting with 0x5800. Ugly, but until we come with better
+ * resource management, it's the only simple solution.
+ */
+
+static int pci_last_io_addr __initdata = 0x5800;
+
+__initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx))
+{
+       unsigned short cmd;
+       unsigned int reg = PCI_BASE_ADDRESS_0 + 4*idx;
+       unsigned int size, addr, try;
+       unsigned int bus = dev->bus->number;
+       unsigned int devfn = dev->devfn;
+
+       if (!pci_last_io_addr) {
+               printk("PCI: Unassigned I/O space for %02x:%02x\n", bus, devfn);
+               return;
+       }
+       pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+       pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+       pcibios_write_config_dword(bus, devfn, reg, ~0);
+       pcibios_read_config_dword(bus, devfn, reg, &size);
+       size = (~(size & PCI_BASE_ADDRESS_IO_MASK) & 0xffff) + 1;
+       addr = 0;
+       if (!size || size > 0x100)
+               printk("PCI: Unable to handle I/O allocation for %02x:%02x (%04x), tell <mj@ucw.cz>\n", bus, devfn, size);
+       else {
+               do {
+                       addr = (pci_last_io_addr + size - 1) & ~(size-1);
+                       pci_last_io_addr = addr + size;
+               } while (check_region(addr, size));
+               printk("PCI: Assigning I/O space %04x-%04x to device %02x:%02x\n", addr, addr+size-1, bus, devfn);
+               pcibios_write_config_dword(bus, devfn, reg, addr | PCI_BASE_ADDRESS_SPACE_IO);
+               pcibios_read_config_dword(bus, devfn, reg, &try);
+               if ((try & PCI_BASE_ADDRESS_IO_MASK) != addr) {
+                       addr = 0;
+                       printk("PCI: Address setup failed, got %04x\n", try);
+               } else
+                       dev->base_address[idx] = try;
+       }
+       if (!addr) {
+               pcibios_write_config_dword(bus, devfn, reg, 0);
+               dev->base_address[idx] = 0;
+       }
+       pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+}
+
+/*
+ * Arch-dependent fixups. We need to fix here base addresses, I/O
+ * and memory enables and IRQ's as the PCI BIOS'es are buggy as hell.
  */
 
 __initfunc(void pcibios_fixup(void))
@@ -836,7 +933,6 @@ __initfunc(void pcibios_fixup(void))
        struct pci_dev *dev;
        int i, has_io, has_mem;
        unsigned short cmd;
-       unsigned char pin;
 
        for(dev = pci_devices; dev; dev=dev->next) {
                /*
@@ -849,18 +945,15 @@ __initfunc(void pcibios_fixup(void))
                for(i=0; i<6; i++) {
                        unsigned long a = dev->base_address[i];
                        if (a & PCI_BASE_ADDRESS_SPACE_IO) {
-                               has_io |= 1;
+                               has_io = 1;
                                a &= PCI_BASE_ADDRESS_IO_MASK;
-                               if (!a || a == PCI_BASE_ADDRESS_IO_MASK) {
-                                       printk(KERN_WARNING "PCI: BIOS forgot to assign address #%d to device %02x:%02x,"
-                                               " please report to <mj@ucw.cz>\n", i, dev->bus->number, dev->devfn);
-                                       has_io |= 2;
-                               }
+                               if (!a || a == PCI_BASE_ADDRESS_IO_MASK)
+                                       pcibios_fixup_io_addr(dev, i);
                        } else if (a & PCI_BASE_ADDRESS_MEM_MASK)
                                has_mem = 1;
                }
                pci_read_config_word(dev, PCI_COMMAND, &cmd);
-               if (has_io == 1 && !(cmd & PCI_COMMAND_IO)) {
+               if (has_io && !(cmd & PCI_COMMAND_IO)) {
                        printk("PCI: Enabling I/O for device %02x:%02x\n",
                                dev->bus->number, dev->devfn);
                        cmd |= PCI_COMMAND_IO;
@@ -872,14 +965,15 @@ __initfunc(void pcibios_fixup(void))
                        cmd |= PCI_COMMAND_MEMORY;
                        pci_write_config_word(dev, PCI_COMMAND, cmd);
                }
-               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 #ifdef __SMP__
                /*
                 * Recalculate IRQ numbers if we use the I/O APIC
                 */
                {
                int irq;
+               unsigned char pin;
 
+               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
                if (pin) {
                        pin--;          /* interrupt pins are numbered starting from 1 */
                        irq = IO_APIC_get_PCI_irq_vector (dev->bus->number, PCI_SLOT(dev->devfn), pin);
@@ -896,30 +990,38 @@ __initfunc(void pcibios_fixup(void))
                 */
                if (dev->irq >= NR_IRQS)
                        dev->irq = 0;
-               if (pin && !dev->irq)
-                       printk(KERN_WARNING "PCI: Bogus IRQ for device %02x:%02x [pin=%x], please report to <mj@ucw.cz>\n",
-                               dev->bus->number, dev->devfn, pin);
        }
+
+#ifdef CONFIG_PCI_BIOS
+       if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
+               pcibios_sort();
+#endif
 }
 
 /*
- * Initialization. Try all known PCI access methods.
+ * Initialization. Try all known PCI access methods. Note that we support
+ * using both PCI BIOS and direct access: in such cases, we use I/O ports
+ * to access config space, but we still keep BIOS order of cards to be
+ * compatible with 2.0.X. This should go away in 2.3.
  */
 
 __initfunc(void pcibios_init(void))
 {
-       struct pci_access *a = NULL;
+       struct pci_access *bios = NULL;
+       struct pci_access *dir = NULL;
 
 #ifdef CONFIG_PCI_BIOS
-       if (pci_probe & PCI_PROBE_BIOS)
-               a = pci_find_bios();
+       if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios())))
+               pci_probe |= PCI_BIOS_SORT;
 #endif
 #ifdef CONFIG_PCI_DIRECT
-       if (!a && (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)))
-               a = pci_check_direct();
+       if (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2))
+               dir = pci_check_direct();
 #endif
-       if (a)
-               access_pci = a;
+       if (dir)
+               access_pci = dir;
+       else if (bios)
+               access_pci = bios;
 }
 
 #if !defined(CONFIG_PCI_BIOS) && !defined(CONFIG_PCI_DIRECT)
@@ -928,25 +1030,35 @@ __initfunc(void pcibios_init(void))
 
 __initfunc(char *pcibios_setup(char *str))
 {
-       if (!strncmp(str, "off", 3)) {
+       if (!strcmp(str, "off")) {
                pci_probe = 0;
                return NULL;
+       } else if (!strncmp(str, "io=", 3)) {
+               char *p;
+               unsigned int x = simple_strtoul(str+3, &p, 16);
+               if (p && *p)
+                       return str;
+               pci_last_io_addr = x;
+               return NULL;
        }
 #ifdef CONFIG_PCI_BIOS
-       else if (!strncmp(str, "bios", 4)) {
+       else if (!strcmp(str, "bios")) {
                pci_probe = PCI_PROBE_BIOS;
                return NULL;
-       } else if (!strncmp(str, "nobios", 6)) {
+       } else if (!strcmp(str, "nobios")) {
                pci_probe &= ~PCI_PROBE_BIOS;
                return NULL;
+       } else if (!strcmp(str, "nosort")) {
+               pci_probe |= PCI_NO_SORT;
+               return NULL;
        }
 #endif
 #ifdef CONFIG_PCI_DIRECT
-       else if (!strncmp(str, "conf1", 5)) {
+       else if (!strcmp(str, "conf1")) {
                pci_probe = PCI_PROBE_CONF1;
                return NULL;
        }
-       else if (!strncmp(str, "conf2", 5)) {
+       else if (!strcmp(str, "conf2")) {
                pci_probe = PCI_PROBE_CONF2;
                return NULL;
        }
index 046d5cab8423f6e90ffb8035c7b385ea4a2118a0..64d4ab1539418bddbecc563aee8fe345c67dbd1a 100644 (file)
@@ -64,7 +64,7 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
         */
        if (!mm->segments) {
                for (i=1 ; i<NR_TASKS ; i++) {
-                       if (task[i]->mm == mm) {
+                       if (task[i] == current) {
                                if (!(mm->segments = (void *) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
                                        return -ENOMEM;
                                memset(mm->segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
index 3fa241db4fb463f377af350bb1e20ecfc54d4b1b..a06477b9d01cd7a8a96b017f97ae9e46525e97c1 100644 (file)
@@ -488,7 +488,7 @@ void copy_segments(int nr, struct task_struct *p, struct mm_struct *new_mm)
                        memcpy(ldt, old_mm->segments, LDT_ENTRIES*LDT_ENTRY_SIZE);
                }
        }
-       set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY, ldt, LDT_ENTRIES);
+       set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY, ldt, ldt_size);
 }
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
index d98a0aa546029df121b28595062920b607773a2e..1571b2f381745ff742491b806f7bb8d744290121 100644 (file)
@@ -20,7 +20,7 @@
    of the stack frame of math_emulate() */
 #define SETUP_DATA_AREA(arg)   FPU_info = (struct info *) &arg
 
-#define LDT_DESCRIPTOR(s)      (((struct ldt_struct *)current->mm->segments)[(s) >> 3])
+#define LDT_DESCRIPTOR(s)      (((struct desc_struct *)current->mm->segments)[(s) >> 3])
 #define SEG_D_SIZE(x)          ((x).b & (3 << 21))
 #define SEG_G_BIT(x)           ((x).b & (1 << 23))
 #define SEG_GRANULARITY(x)     (((x).b & (1 << 23)) ? 4096 : 1)
diff --git a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile
new file mode 100644 (file)
index 0000000..b33919a
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux MPC8xx ppc-specific parts of comm processor
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := 8xx_io.a
+O_OBJS = commproc.o uart.o enet.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
new file mode 100644 (file)
index 0000000..c1bfd8f
--- /dev/null
@@ -0,0 +1,223 @@
+
+/*
+ * General Purpose functions for the global management of the
+ * Communication Processor Module.
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ * The amount of space available is platform dependent.  On the
+ * MBX, the EPPC software loads additional microcode into the
+ * communication processor, and uses some of the DP ram for this
+ * purpose.  Current, the first 512 bytes and the last 256 bytes of
+ * memory are used.  Right now I am conservative and only use the
+ * memory that can never be used for microcode.  If there are
+ * applications that require more DP ram, we can expand the boundaries
+ * but then we have to be careful of any downloaded microcode.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/mbx.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/8xx_immap.h>
+#include "commproc.h"
+
+static uint    dp_alloc_base;  /* Starting offset in DP ram */
+static uint    dp_alloc_top;   /* Max offset + 1 */
+static uint    host_buffer;    /* One page of host buffer */
+static uint    host_end;       /* end + 1 */
+cpm8xx_t       *cpmp;          /* Pointer to comm processor space */
+
+/* CPM interrupt vector functions.
+*/
+struct cpm_action {
+       void    (*handler)(void *);
+       void    *dev_id;
+};
+static struct  cpm_action cpm_vecs[CPMVEC_NR];
+static void    cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
+static void    cpm_error_interrupt(void *);
+
+void
+mbx_cpm_reset(uint host_page_addr)
+{
+       volatile immap_t         *imp;
+       volatile cpm8xx_t       *commproc;
+       pte_t                   *pte;
+
+       imp = (immap_t *)MBX_IMAP_ADDR;
+       commproc = (cpm8xx_t *)&imp->im_cpm;
+
+#ifdef notdef
+       /* We can't do this.  It seems to blow away the microcode
+        * patch that EPPC-Bug loaded for us.  EPPC-Bug uses SCC1 for
+        * Ethernet, SMC1 for the console, and I2C for serial EEPROM.
+        * Our own drivers quickly reset all of these.
+        */
+
+       /* Perform a reset.
+       */
+       commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
+
+       /* Wait for it.
+       */
+       while (commproc->cp_cpcr & CPM_CR_FLG);
+#endif
+
+       /* Set SDMA Bus Request priority 5.
+       */
+       imp->im_siu_conf.sc_sdcr = 1;
+
+       /* Reclaim the DP memory for our use.
+       */
+       dp_alloc_base = CPM_DATAONLY_BASE;
+       dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
+
+       /* Set the host page for allocation.
+       */
+       host_buffer = host_page_addr;   /* Host virtual page address */
+       host_end = host_page_addr + PAGE_SIZE;
+       pte = va_to_pte(&init_task, host_page_addr);
+       pte_val(*pte) |= _PAGE_NO_CACHE;
+       flush_tlb_page(current->mm->mmap, host_buffer);
+
+       /* Tell everyone where the comm processor resides.
+       */
+       cpmp = (cpm8xx_t *)commproc;
+
+       /* Initialize the CPM interrupt controller.
+       */
+       ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cicr =
+           (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
+               ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
+       ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr = 0;
+
+       /* Set our interrupt handler with the core CPU.
+       */
+       if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0)
+               panic("Could not allocate CPM IRQ!");
+
+       /* Install our own error handler.
+       */
+       cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
+
+       ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
+}
+
+/* CPM interrupt controller interrupt.
+*/
+static void
+cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+       uint    vec;
+
+       /* Get the vector by setting the ACK bit and then reading
+        * the register.
+        */
+       ((volatile immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_civr = 1;
+       vec = ((volatile immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_civr;
+       vec >>= 11;
+
+       if (cpm_vecs[vec].handler != 0)
+               (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id);
+       else
+               ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+
+       /* After servicing the interrupt, we have to remove the status
+        * indicator.
+        */
+       ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
+       
+}
+
+/* The CPM can generate the error interrupt when there is a race condition
+ * between generating and masking interrupts.  All we have to do is ACK it
+ * and return.  This is a no-op function so we don't need any special
+ * tests in the interrupt handler.
+ */
+static void
+cpm_error_interrupt(void *dev)
+{
+}
+
+/* Install a CPM interrupt handler.
+*/
+void
+cpm_install_handler(int vec, void (*handler)(void *), void *dev_id)
+{
+       if (cpm_vecs[vec].handler != 0)
+               printk("CPM interrupt %x replacing %x\n",
+                       (uint)handler, (uint)cpm_vecs[vec].handler);
+       cpm_vecs[vec].handler = handler;
+       cpm_vecs[vec].dev_id = dev_id;
+       ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec);
+}
+
+/* Allocate some memory from the dual ported ram.  We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint
+mbx_cpm_dpalloc(uint size)
+{
+       uint    retloc;
+
+       if ((dp_alloc_base + size) >= dp_alloc_top)
+               return(CPM_DP_NOSPACE);
+
+       retloc = dp_alloc_base;
+       dp_alloc_base += size;
+
+       return(retloc);
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+mbx_cpm_hostalloc(uint size)
+{
+       uint    retloc;
+
+       if ((host_buffer + size) >= host_end)
+               return(0);
+
+       retloc = host_buffer;
+       host_buffer += size;
+
+       return(retloc);
+}
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * four BRGs, any of which can be wired to any channel.
+ * The internal baud rate clock is the system clock divided by 16.
+ * I need to find a way to get this system clock frequency, which is
+ * part of the VPD.......
+ */
+#define BRG_INT_CLK    (40000000/16)
+
+void
+mbx_cpm_setbrg(uint brg, uint rate)
+{
+       volatile uint   *bp;
+
+       /* This is good enough to get SMCs running.....
+       */
+       bp = (uint *)&cpmp->cp_brgc1;
+       bp += brg;
+       *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
+}
diff --git a/arch/ppc/8xx_io/commproc.h b/arch/ppc/8xx_io/commproc.h
new file mode 100644 (file)
index 0000000..38046a3
--- /dev/null
@@ -0,0 +1,464 @@
+
+/*
+ * MPC8xx Communication Processor Module.
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * This file contains structures and information for the communication
+ * processor channels.  Some CPM control and status is available
+ * throught the MPC8xx internal memory map.  See immap.h for details.
+ * This file only contains what I need for the moment, not the total
+ * CPM capabilities.  I (or someone else) will add definitions as they
+ * are needed.  -- Dan
+ *
+ * On the MBX board, EPPC-Bug loads CPM microcode into the first 512
+ * bytes of the DP RAM and relocates the I2C parameter area to the
+ * IDMA1 space.  The remaining DP RAM is available for buffer descriptors
+ * or other use.
+ */
+#ifndef __CPM_8XX__
+#define __CPM_8XX__
+
+#include <asm/8xx_immap.h>
+
+/* CPM Command register.
+*/
+#define CPM_CR_RST     ((ushort)0x8000)
+#define CPM_CR_OPCODE  ((ushort)0x0f00)
+#define CPM_CR_CHAN    ((ushort)0x00f0)
+#define CPM_CR_FLG     ((ushort)0x0001)
+
+/* Some commands (there are more...later)
+*/
+#define CPM_CR_INIT_TRX                ((ushort)0x0000)
+#define CPM_CR_INIT_RX         ((ushort)0x0001)
+#define CPM_CR_INIT_TX         ((ushort)0x0002)
+#define CPM_CR_STOP_TX         ((ushort)0x0004)
+#define CPM_CR_RESTART_TX      ((ushort)0x0006)
+#define CPM_CR_SET_GADDR       ((ushort)0x0008)
+
+/* Channel numbers.
+*/
+#define CPM_CR_CH_SCC1 ((ushort)0x0000)
+#define CPM_CR_CH_I2C  ((ushort)0x0001)        /* I2C and IDMA1 */
+#define CPM_CR_CH_SCC2 ((ushort)0x0004)
+#define CPM_CR_CH_SPI  ((ushort)0x0005)        /* SPI / IDMA2 / Timers */
+#define CPM_CR_CH_SCC3 ((ushort)0x0008)
+#define CPM_CR_CH_SMC1 ((ushort)0x0009)        /* SMC1 / DSP1 */
+#define CPM_CR_CH_SCC4 ((ushort)0x000c)
+#define CPM_CR_CH_SMC2 ((ushort)0x000d)        /* SMC2 / DSP2 */
+
+#define mk_cr_cmd(CH, CMD)     ((CMD << 8) | (CH << 4))
+
+/* The dual ported RAM is multi-functional.  Some areas can be (and are
+ * being) used for microcode.  There is an area that can only be used
+ * as data ram for buffer descriptors, which is all we use right now.
+ * Currently the first 512 and last 256 bytes are used for microcode.
+ */
+#define CPM_DATAONLY_BASE      ((uint)0x0800)
+#define CPM_DATAONLY_SIZE      ((uint)0x0700)
+#define CPM_DP_NOSPACE         ((uint)0x7fffffff)
+
+/* Export the base address of the communication processor registers
+ * and dual port ram.
+ */
+extern cpm8xx_t        *cpmp;          /* Pointer to comm processor */
+uint           mbx_cpm_dpalloc(uint size);
+uint           mbx_cpm_hostalloc(uint size);
+void           mbx_cpm_setbrg(uint brg, uint rate);
+
+/* Buffer descriptors used by many of the CPM protocols.
+*/
+typedef struct cpm_buf_desc {
+       ushort  cbd_sc;         /* Status and Control */
+       ushort  cbd_datlen;     /* Data length in buffer */
+       uint    cbd_bufaddr;    /* Buffer address in host memory */
+} cbd_t;
+
+#define BD_SC_EMPTY    ((ushort)0x8000)        /* Recieve is empty */
+#define BD_SC_READY    ((ushort)0x8000)        /* Transmit is ready */
+#define BD_SC_WRAP     ((ushort)0x2000)        /* Last buffer descriptor */
+#define BD_SC_INTRPT   ((ushort)0x1000)        /* Interrupt on change */
+#define BD_SC_CM       ((ushort)0x0200)        /* Continous mode */
+#define BD_SC_ID       ((ushort)0x0100)        /* Rec'd too many idles */
+#define BD_SC_P                ((ushort)0x0100)        /* xmt preamble */
+#define BD_SC_BR       ((ushort)0x0020)        /* Break received */
+#define BD_SC_FR       ((ushort)0x0010)        /* Framing error */
+#define BD_SC_PR       ((ushort)0x0008)        /* Parity error */
+#define BD_SC_OV       ((ushort)0x0002)        /* Overrun */
+#define BD_SC_CD       ((ushort)0x0001)        /* ?? */
+
+/* Define enough so I can at least use the MBX serial port as a UART.
+ * The MBX uses SMC1 as the host serial port.
+ */
+typedef struct smc_uart {
+       ushort  smc_rbase;      /* Rx Buffer descriptor base address */
+       ushort  smc_tbase;      /* Tx Buffer descriptor base address */
+       u_char  smc_rfcr;       /* Rx function code */
+       u_char  smc_tfcr;       /* Tx function code */
+       ushort  smc_mrblr;      /* Max receive buffer length */
+       uint    smc_rstate;     /* Internal */
+       uint    smc_idp;        /* Internal */
+       ushort  smc_rbptr;      /* Internal */
+       ushort  smc_ibc;        /* Internal */
+       uint    smc_rxtmp;      /* Internal */
+       uint    smc_tstate;     /* Internal */
+       uint    smc_tdp;        /* Internal */
+       ushort  smc_tbptr;      /* Internal */
+       ushort  smc_tbc;        /* Internal */
+       uint    smc_txtmp;      /* Internal */
+       ushort  smc_maxidl;     /* Maximum idle characters */
+       ushort  smc_tmpidl;     /* Temporary idle counter */
+       ushort  smc_brklen;     /* Last received break length */
+       ushort  smc_brkec;      /* rcv'd break condition counter */
+       ushort  smc_brkcr;      /* xmt break count register */
+       ushort  smc_rmask;      /* Temporary bit mask */
+} smc_uart_t;
+
+#define PROFF_SMC1     ((uint)0x0280)  /* Offset in Parameter RAM */
+#define PROFF_SMC2     ((uint)0x0380)
+
+/* Function code bits.
+*/
+#define SMC_EB ((u_char)0x10)  /* Set big endian byte order */
+
+/* SMC uart mode register.
+*/
+#define        SMCMR_REN       ((ushort)0x0001)
+#define SMCMR_TEN      ((ushort)0x0002)
+#define SMCMR_DM       ((ushort)0x000c)
+#define SMCMR_SM_GCI   ((ushort)0x0000)
+#define SMCMR_SM_UART  ((ushort)0x0020)
+#define SMCMR_SM_TRANS ((ushort)0x0030)
+#define SMCMR_SM_MASK  ((ushort)0x0030)
+#define SMCMR_PM_EVEN  ((ushort)0x0100)        /* Even parity, else odd */
+#define SMCMR_PEN      ((ushort)0x0200)        /* Parity enable */
+#define SMCMR_SL       ((ushort)0x0400)        /* Two stops, else one */
+#define SMCR_CLEN_MASK ((ushort)0x7800)        /* Character length */
+#define smcr_mk_clen(C)        (((C) << 11) & SMCR_CLEN_MASK)
+
+/* SMC Event and Mask register.
+*/
+#define        SMCM_TXE        ((unsigned char)0x10)
+#define        SMCM_BSY        ((unsigned char)0x14)
+#define        SMCM_TX         ((unsigned char)0x02)
+#define        SMCM_RX         ((unsigned char)0x01)
+
+/* Baud rate generators.
+*/
+#define CPM_BRG_RST            ((uint)0x00020000)
+#define CPM_BRG_EN             ((uint)0x00010000)
+#define CPM_BRG_EXTC_INT       ((uint)0x00000000)
+#define CPM_BRG_EXTC_CLK2      ((uint)0x00004000)
+#define CPM_BRG_EXTC_CLK6      ((uint)0x00008000)
+#define CPM_BRG_ATB            ((uint)0x00002000)
+#define CPM_BRG_CD_MASK                ((uint)0x00001ffe)
+#define CPM_BRG_DIV16          ((uint)0x00000001)
+
+/* SCCs.
+*/
+#define SCC_GSMRH_IRP          ((uint)0x00040000)
+#define SCC_GSMRH_GDE          ((uint)0x00010000)
+#define SCC_GSMRH_TCRC_CCITT   ((uint)0x00008000)
+#define SCC_GSMRH_TCRC_BISYNC  ((uint)0x00004000)
+#define SCC_GSMRH_TCRC_HDLC    ((uint)0x00000000)
+#define SCC_GSMRH_REVD         ((uint)0x00002000)
+#define SCC_GSMRH_TRX          ((uint)0x00001000)
+#define SCC_GSMRH_TTX          ((uint)0x00000800)
+#define SCC_GSMRH_CDP          ((uint)0x00000400)
+#define SCC_GSMRH_CTSP         ((uint)0x00000200)
+#define SCC_GSMRH_CDS          ((uint)0x00000100)
+#define SCC_GSMRH_CTSS         ((uint)0x00000080)
+#define SCC_GSMRH_TFL          ((uint)0x00000040)
+#define SCC_GSMRH_RFW          ((uint)0x00000020)
+#define SCC_GSMRH_TXSY         ((uint)0x00000010)
+#define SCC_GSMRH_SYNL16       ((uint)0x0000000c)
+#define SCC_GSMRH_SYNL8                ((uint)0x00000008)
+#define SCC_GSMRH_SYNL4                ((uint)0x00000004)
+#define SCC_GSMRH_RTSM         ((uint)0x00000002)
+#define SCC_GSMRH_RSYN         ((uint)0x00000001)
+
+#define SCC_GSMRL_SIR          ((uint)0x80000000)      /* SCC2 only */
+#define SCC_GSMRL_EDGE_NONE    ((uint)0x60000000)
+#define SCC_GSMRL_EDGE_NEG     ((uint)0x40000000)
+#define SCC_GSMRL_EDGE_POS     ((uint)0x20000000)
+#define SCC_GSMRL_EDGE_BOTH    ((uint)0x00000000)
+#define SCC_GSMRL_TCI          ((uint)0x10000000)
+#define SCC_GSMRL_TSNC_3       ((uint)0x0c000000)
+#define SCC_GSMRL_TSNC_4       ((uint)0x08000000)
+#define SCC_GSMRL_TSNC_14      ((uint)0x04000000)
+#define SCC_GSMRL_TSNC_INF     ((uint)0x00000000)
+#define SCC_GSMRL_RINV         ((uint)0x02000000)
+#define SCC_GSMRL_TINV         ((uint)0x01000000)
+#define SCC_GSMRL_TPL_128      ((uint)0x00c00000)
+#define SCC_GSMRL_TPL_64       ((uint)0x00a00000)
+#define SCC_GSMRL_TPL_48       ((uint)0x00800000)
+#define SCC_GSMRL_TPL_32       ((uint)0x00600000)
+#define SCC_GSMRL_TPL_16       ((uint)0x00400000)
+#define SCC_GSMRL_TPL_8                ((uint)0x00200000)
+#define SCC_GSMRL_TPL_NONE     ((uint)0x00000000)
+#define SCC_GSMRL_TPP_ALL1     ((uint)0x00180000)
+#define SCC_GSMRL_TPP_01       ((uint)0x00100000)
+#define SCC_GSMRL_TPP_10       ((uint)0x00080000)
+#define SCC_GSMRL_TPP_ZEROS    ((uint)0x00000000)
+#define SCC_GSMRL_TEND         ((uint)0x00040000)
+#define SCC_GSMRL_TDCR_32      ((uint)0x00030000)
+#define SCC_GSMRL_TDCR_16      ((uint)0x00020000)
+#define SCC_GSMRL_TDCR_8       ((uint)0x00010000)
+#define SCC_GSMRL_TDCR_1       ((uint)0x00000000)
+#define SCC_GSMRL_RDCR_32      ((uint)0x0000c000)
+#define SCC_GSMRL_RDCR_16      ((uint)0x00008000)
+#define SCC_GSMRL_RDCR_8       ((uint)0x00004000)
+#define SCC_GSMRL_RDCR_1       ((uint)0x00000000)
+#define SCC_GSMRL_RENC_DFMAN   ((uint)0x00003000)
+#define SCC_GSMRL_RENC_MANCH   ((uint)0x00002000)
+#define SCC_GSMRL_RENC_FM0     ((uint)0x00001000)
+#define SCC_GSMRL_RENC_NRZI    ((uint)0x00000800)
+#define SCC_GSMRL_RENC_NRZ     ((uint)0x00000000)
+#define SCC_GSMRL_TENC_DFMAN   ((uint)0x00000600)
+#define SCC_GSMRL_TENC_MANCH   ((uint)0x00000400)
+#define SCC_GSMRL_TENC_FM0     ((uint)0x00000200)
+#define SCC_GSMRL_TENC_NRZI    ((uint)0x00000100)
+#define SCC_GSMRL_TENC_NRZ     ((uint)0x00000000)
+#define SCC_GSMRL_DIAG_LE      ((uint)0x000000c0)      /* Loop and echo */
+#define SCC_GSMRL_DIAG_ECHO    ((uint)0x00000080)
+#define SCC_GSMRL_DIAG_LOOP    ((uint)0x00000040)
+#define SCC_GSMRL_DIAG_NORM    ((uint)0x00000000)
+#define SCC_GSMRL_ENR          ((uint)0x00000020)
+#define SCC_GSMRL_ENT          ((uint)0x00000010)
+#define SCC_GSMRL_MODE_ENET    ((uint)0x0000000c)
+#define SCC_GSMRL_MODE_DDCMP   ((uint)0x00000009)
+#define SCC_GSMRL_MODE_BISYNC  ((uint)0x00000008)
+#define SCC_GSMRL_MODE_V14     ((uint)0x00000007)
+#define SCC_GSMRL_MODE_AHDLC   ((uint)0x00000006)
+#define SCC_GSMRL_MODE_PROFIBUS        ((uint)0x00000005)
+#define SCC_GSMRL_MODE_UART    ((uint)0x00000004)
+#define SCC_GSMRL_MODE_SS7     ((uint)0x00000003)
+#define SCC_GSMRL_MODE_ATALK   ((uint)0x00000002)
+#define SCC_GSMRL_MODE_HDLC    ((uint)0x00000000)
+
+#define SCC_TODR_TOD           ((ushort)0x8000)
+
+typedef struct scc_param {
+       ushort  scc_rbase;      /* Rx Buffer descriptor base address */
+       ushort  scc_tbase;      /* Tx Buffer descriptor base address */
+       u_char  scc_rfcr;       /* Rx function code */
+       u_char  scc_tfcr;       /* Tx function code */
+       ushort  scc_mrblr;      /* Max receive buffer length */
+       uint    scc_rstate;     /* Internal */
+       uint    scc_idp;        /* Internal */
+       ushort  scc_rbptr;      /* Internal */
+       ushort  scc_ibc;        /* Internal */
+       uint    scc_rxtmp;      /* Internal */
+       uint    scc_tstate;     /* Internal */
+       uint    scc_tdp;        /* Internal */
+       ushort  scc_tbptr;      /* Internal */
+       ushort  scc_tbc;        /* Internal */
+       uint    scc_txtmp;      /* Internal */
+       uint    scc_rcrc;       /* Internal */
+       uint    scc_tcrc;       /* Internal */
+} sccp_t;
+
+/* Function code bits.
+*/
+#define SCC_EB ((u_char)0x10)  /* Set big endian byte order */
+
+/* CPM Ethernet through SCC1.
+ */
+typedef struct scc_enet {
+       sccp_t  sen_genscc;
+       uint    sen_cpres;      /* Preset CRC */
+       uint    sen_cmask;      /* Constant mask for CRC */
+       uint    sen_crcec;      /* CRC Error counter */
+       uint    sen_alec;       /* alignment error counter */
+       uint    sen_disfc;      /* discard frame counter */
+       ushort  sen_pads;       /* Tx short frame pad character */
+       ushort  sen_retlim;     /* Retry limit threshold */
+       ushort  sen_retcnt;     /* Retry limit counter */
+       ushort  sen_maxflr;     /* maximum frame length register */
+       ushort  sen_minflr;     /* minimum frame length register */
+       ushort  sen_maxd1;      /* maximum DMA1 length */
+       ushort  sen_maxd2;      /* maximum DMA2 length */
+       ushort  sen_maxd;       /* Rx max DMA */
+       ushort  sen_dmacnt;     /* Rx DMA counter */
+       ushort  sen_maxb;       /* Max BD byte count */
+       ushort  sen_gaddr1;     /* Group address filter */
+       ushort  sen_gaddr2;
+       ushort  sen_gaddr3;
+       ushort  sen_gaddr4;
+       uint    sen_tbuf0data0; /* Save area 0 - current frame */
+       uint    sen_tbuf0data1; /* Save area 1 - current frame */
+       uint    sen_tbuf0rba;   /* Internal */
+       uint    sen_tbuf0crc;   /* Internal */
+       ushort  sen_tbuf0bcnt;  /* Internal */
+       ushort  sen_paddrh;     /* physical address (MSB) */
+       ushort  sen_paddrm;
+       ushort  sen_paddrl;     /* physical address (LSB) */
+       ushort  sen_pper;       /* persistence */
+       ushort  sen_rfbdptr;    /* Rx first BD pointer */
+       ushort  sen_tfbdptr;    /* Tx first BD pointer */
+       ushort  sen_tlbdptr;    /* Tx last BD pointer */
+       uint    sen_tbuf1data0; /* Save area 0 - current frame */
+       uint    sen_tbuf1data1; /* Save area 1 - current frame */
+       uint    sen_tbuf1rba;   /* Internal */
+       uint    sen_tbuf1crc;   /* Internal */
+       ushort  sen_tbuf1bcnt;  /* Internal */
+       ushort  sen_txlen;      /* Tx Frame length counter */
+       ushort  sen_iaddr1;     /* Individual address filter */
+       ushort  sen_iaddr2;
+       ushort  sen_iaddr3;
+       ushort  sen_iaddr4;
+       ushort  sen_boffcnt;    /* Backoff counter */
+
+       /* NOTE: Some versions of the manual have the following items
+        * incorrectly documented.  Below is the proper order.
+        */
+       ushort  sen_taddrh;     /* temp address (MSB) */
+       ushort  sen_taddrm;
+       ushort  sen_taddrl;     /* temp address (LSB) */
+} scc_enet_t;
+
+#define PROFF_SCC1     ((uint)0x0000)  /* Offset in Parameter RAM */
+
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.  The TCLK and RCLK seem unique
+ * to the MBX860 board.  Any two of the four available clocks could be
+ * used, and the MPC860 cookbook manual has an example using different
+ * clock pins.
+ */
+#define PA_ENET_RXD    ((ushort)0x0001)
+#define PA_ENET_TXD    ((ushort)0x0002)
+#define PA_ENET_TCLK   ((ushort)0x0200)
+#define PA_ENET_RCLK   ((ushort)0x0800)
+#define PC_ENET_TENA   ((ushort)0x0001)
+#define PC_ENET_CLSN   ((ushort)0x0010)
+#define PC_ENET_RENA   ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1.  Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT        ((uint)0x0000003d)
+
+/* SCC Event register as used by Ethernet.
+*/
+#define SCCE_ENET_GRA  ((ushort)0x0080)        /* Graceful stop complete */
+#define SCCE_ENET_TXE  ((ushort)0x0010)        /* Transmit Error */
+#define SCCE_ENET_RXF  ((ushort)0x0008)        /* Full frame received */
+#define SCCE_ENET_BSY  ((ushort)0x0004)        /* All incoming buffers full */
+#define SCCE_ENET_TXB  ((ushort)0x0002)        /* A buffer was transmitted */
+#define SCCE_ENET_RXB  ((ushort)0x0001)        /* A buffer was received */
+
+/* SCC Mode Register (PMSR) as used by Ethernet.
+*/
+#define SCC_PMSR_HBC   ((ushort)0x8000)        /* Enable heartbeat */
+#define SCC_PMSR_FC    ((ushort)0x4000)        /* Force collision */
+#define SCC_PMSR_RSH   ((ushort)0x2000)        /* Receive short frames */
+#define SCC_PMSR_IAM   ((ushort)0x1000)        /* Check individual hash */
+#define SCC_PMSR_ENCRC ((ushort)0x0800)        /* Ethernet CRC mode */
+#define SCC_PMSR_PRO   ((ushort)0x0200)        /* Promiscuous mode */
+#define SCC_PMSR_BRO   ((ushort)0x0100)        /* Catch broadcast pkts */
+#define SCC_PMSR_SBT   ((ushort)0x0080)        /* Special backoff timer */
+#define SCC_PMSR_LPB   ((ushort)0x0040)        /* Set Loopback mode */
+#define SCC_PMSR_SIP   ((ushort)0x0020)        /* Sample Input Pins */
+#define SCC_PMSR_LCW   ((ushort)0x0010)        /* Late collision window */
+#define SCC_PMSR_NIB22 ((ushort)0x000a)        /* Start frame search */
+#define SCC_PMSR_FDE   ((ushort)0x0001)        /* Full duplex enable */
+
+/* Buffer descriptor control/status used by Ethernet receive.
+*/
+#define BD_ENET_RX_EMPTY       ((ushort)0x8000)
+#define BD_ENET_RX_WRAP                ((ushort)0x2000)
+#define BD_ENET_RX_INTR                ((ushort)0x1000)
+#define BD_ENET_RX_LAST                ((ushort)0x0800)
+#define BD_ENET_RX_FIRST       ((ushort)0x0400)
+#define BD_ENET_RX_MISS                ((ushort)0x0100)
+#define BD_ENET_RX_LG          ((ushort)0x0020)
+#define BD_ENET_RX_NO          ((ushort)0x0010)
+#define BD_ENET_RX_SH          ((ushort)0x0008)
+#define BD_ENET_RX_CR          ((ushort)0x0004)
+#define BD_ENET_RX_OV          ((ushort)0x0002)
+#define BD_ENET_RX_CL          ((ushort)0x0001)
+#define BD_ENET_RX_STATS       ((ushort)0x013f)        /* All status bits */
+
+/* Buffer descriptor control/status used by Ethernet transmit.
+*/
+#define BD_ENET_TX_READY       ((ushort)0x8000)
+#define BD_ENET_TX_PAD         ((ushort)0x4000)
+#define BD_ENET_TX_WRAP                ((ushort)0x2000)
+#define BD_ENET_TX_INTR                ((ushort)0x1000)
+#define BD_ENET_TX_LAST                ((ushort)0x0800)
+#define BD_ENET_TX_TC          ((ushort)0x0400)
+#define BD_ENET_TX_DEF         ((ushort)0x0200)
+#define BD_ENET_TX_HB          ((ushort)0x0100)
+#define BD_ENET_TX_LC          ((ushort)0x0080)
+#define BD_ENET_TX_RL          ((ushort)0x0040)
+#define BD_ENET_TX_RCMASK      ((ushort)0x003c)
+#define BD_ENET_TX_UN          ((ushort)0x0002)
+#define BD_ENET_TX_CSL         ((ushort)0x0001)
+#define BD_ENET_TX_STATS       ((ushort)0x03ff)        /* All status bits */
+
+/* SCC Event and Mask registers when it is used as a UART.
+*/
+#define UART_SCCM_GLR          ((ushort)0x1000)
+#define UART_SCCM_GLT          ((ushort)0x0800)
+#define UART_SCCM_AB           ((ushort)0x0200)
+#define UART_SCCM_IDL          ((ushort)0x0100)
+#define UART_SCCM_GRA          ((ushort)0x0080)
+#define UART_SCCM_BRKE         ((ushort)0x0040)
+#define UART_SCCM_BRKS         ((ushort)0x0020)
+#define UART_SCCM_CCR          ((ushort)0x0008)
+#define UART_SCCM_BSY          ((ushort)0x0004)
+#define UART_SCCM_TX           ((ushort)0x0002)
+#define UART_SCCM_RX           ((ushort)0x0001)
+
+/* CPM interrupts.  There are nearly 32 interrupts generated by CPM
+ * channels or devices.  All of these are presented to the PPC core
+ * as a single interrupt.  The CPM interrupt handler dispatches its
+ * own handlers, in a similar fashion to the PPC core handler.  We
+ * use the table as defined in the manuals (i.e. no special high
+ * priority and SCC1 == SCCa, etc...).
+ */
+#define CPMVEC_NR              32
+#define        CPMVEC_PIO_PC15         ((ushort)0x1f)
+#define        CPMVEC_SCC1             ((ushort)0x1e)
+#define        CPMVEC_SCC2             ((ushort)0x1d)
+#define        CPMVEC_SCC3             ((ushort)0x1c)
+#define        CPMVEC_SCC4             ((ushort)0x1b)
+#define        CPMVEC_PIO_PC14         ((ushort)0x1a)
+#define        CPMVEC_TIMER1           ((ushort)0x19)
+#define        CPMVEC_PIO_PC13         ((ushort)0x18)
+#define        CPMVEC_PIO_PC12         ((ushort)0x17)
+#define        CPMVEC_SDMA_CB_ERR      ((ushort)0x16)
+#define CPMVEC_IDMA1           ((ushort)0x15)
+#define CPMVEC_IDMA2           ((ushort)0x14)
+#define CPMVEC_TIMER2          ((ushort)0x12)
+#define CPMVEC_RISCTIMER       ((ushort)0x11)
+#define CPMVEC_I2C             ((ushort)0x10)
+#define        CPMVEC_PIO_PC11         ((ushort)0x0f)
+#define        CPMVEC_PIO_PC10         ((ushort)0x0e)
+#define CPMVEC_TIMER3          ((ushort)0x0c)
+#define        CPMVEC_PIO_PC9          ((ushort)0x0b)
+#define        CPMVEC_PIO_PC8          ((ushort)0x0a)
+#define        CPMVEC_PIO_PC7          ((ushort)0x09)
+#define CPMVEC_TIMER4          ((ushort)0x07)
+#define        CPMVEC_PIO_PC6          ((ushort)0x06)
+#define        CPMVEC_SPI              ((ushort)0x05)
+#define        CPMVEC_SMC1             ((ushort)0x04)
+#define        CPMVEC_SMC2             ((ushort)0x03)
+#define        CPMVEC_PIO_PC5          ((ushort)0x02)
+#define        CPMVEC_PIO_PC4          ((ushort)0x01)
+#define        CPMVEC_ERROR            ((ushort)0x00)
+
+extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
+
+/* CPM interrupt configuration vector.
+*/
+#define        CICR_SCD_SCC4           ((uint)0x00c00000)      /* SCC4 @ SCCd */
+#define        CICR_SCC_SCC3           ((uint)0x00200000)      /* SCC3 @ SCCc */
+#define        CICR_SCB_SCC2           ((uint)0x00040000)      /* SCC2 @ SCCb */
+#define        CICR_SCA_SCC1           ((uint)0x00000000)      /* SCC1 @ SCCa */
+#define CICR_IRL_MASK          ((uint)0x0000e000)      /* Core interrrupt */
+#define CICR_HP_MASK           ((uint)0x00001f00)      /* Hi-pri int. */
+#define CICR_IEN               ((uint)0x00000080)      /* Int. enable */
+#define CICR_SPS               ((uint)0x00000001)      /* SCC Spread */
+#endif /* __CPM_8XX__ */
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
new file mode 100644 (file)
index 0000000..a732d58
--- /dev/null
@@ -0,0 +1,913 @@
+/*
+ * Ethernet driver for Motorola MPC8xx.
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * I copied the basic skeleton from the lance driver, because I did not
+ * know how to write the Linux driver, but I did know how the LANCE worked.
+ * This version of the driver is specific to the MBX implementation,
+ * since the board contains control registers external to the processor
+ * for the control of the MC68160 SIA/transceiver.  The MPC860 manual
+ * describes connections using the internal parallel port I/O.
+ *
+ * The MBX860 uses the CPM SCC1 serial port for the Ethernet interface.
+ * Buffer descriptors are kept in the CPM dual port RAM, and the frame
+ * buffers are in the host memory.
+ *
+ * Right now, I am very watseful with the buffers.  I allocate memory
+ * pages and then divide them into 2K frame buffers.  This way I know I
+ * have buffers large enough to hold one frame within one buffer descriptor.
+ * Once I get this working, I will use 64 or 128 byte CPM buffers, which
+ * will be much more memory efficient and will easily handle lots of
+ * small packets.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/8xx_immap.h>
+#include <asm/pgtable.h>
+#include <asm/mbx.h>
+#include "commproc.h"
+#include <linux/delay.h>
+
+/*
+ *                             Theory of Operation
+ *
+ * The MPC8xx CPM performs the Ethernet processing on SCC1.  It can use
+ * an aribtrary number of buffers on byte boundaries, but must have at
+ * least two receive buffers to prevent constand overrun conditions.
+ *
+ * The buffer descriptors are allocated from the CPM dual port memory
+ * with the data buffers allocated from host memory, just like all other
+ * serial communication protocols.  The host memory buffers are allocated
+ * from the free page pool, and then divided into smaller receive and
+ * transmit buffers.  The size of the buffers should be a power of two,
+ * since that nicely divides the page.  This creates a ring buffer
+ * structure similar to the LANCE and other controllers.
+ *
+ * Like the LANCE driver:
+ * The driver runs as two independent, single-threaded flows of control.  One
+ * is the send-packet routine, which enforces single-threaded use by the
+ * dev->tbusy flag.  The other thread is the interrupt handler, which is single
+ * threaded by the hardware and other software.
+ *
+ * The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+ * flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+ * queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+ * the 'lp->tx_full' flag.
+ *
+ * The MBX has a control register external to the MPC8xx that has some
+ * control of the Ethernet interface.  Control Register 1 has the
+ * following format:
+ *     bit 0 - Set to enable Ethernet transceiver
+ *     bit 1 - Set to enable Ethernet internal loopback
+ *     bit 2 - Set to auto select AUI or TP port
+ *     bit 3 - if bit 2 is 0, set to select TP port
+ *     bit 4 - Set to disable full duplex (loopback)
+ *     bit 5 - Set to disable XCVR collision test
+ *     bit 6, 7 - Used for RS-232 control.
+ *
+ * EPPC-Bug sets this register to 0x98 for normal Ethernet operation,
+ * so we should not have to touch it.
+ *
+ * The following I/O is used by the MBX implementation of the MPC8xx to
+ * the MC68160 transceiver.  It DOES NOT exactly follow the cookbook
+ * example from the MPC860 manual.
+ *     Port A, 15 - SCC1 Ethernet Rx
+ *     Port A, 14 - SCC1 Ethernet Tx
+ *     Port A, 6 (CLK2) - SCC1 Ethernet Tx Clk
+ *     Port A, 4 (CLK4) - SCC1 Ethernet Rx Clk
+ *     Port C, 15 - SCC1 Ethernet Tx Enable
+ *     Port C, 11 - SCC1 Ethernet Collision
+ *     Port C, 10 - SCC1 Ethernet Rx Enable
+ */
+
+/* The number of Tx and Rx buffers.  These are allocated from the page
+ * pool.  The code may assume these are power of two, so it it best
+ * to keep them that size.
+ * We don't need to allocate pages for the transmitter.  We just use
+ * the skbuffer directly.
+ */
+#define CPM_ENET_RX_PAGES      4
+#define CPM_ENET_RX_FRSIZE     2048
+#define CPM_ENET_RX_FRPPG      (PAGE_SIZE / CPM_ENET_RX_FRSIZE)
+#define RX_RING_SIZE           (CPM_ENET_RX_FRPPG * CPM_ENET_RX_PAGES)
+#define TX_RING_SIZE           8       /* Must be power of two */
+#define TX_RING_MOD_MASK       7       /*   for this to work */
+
+/* The CPM stores dest/src/type, data, and checksum for receive packets.
+ */
+#define PKT_MAXBUF_SIZE                1518
+#define PKT_MINBUF_SIZE                64
+#define PKT_MAXBLR_SIZE                1520
+
+/* The CPM buffer descriptors track the ring buffers.  The rx_bd_base and
+ * tx_bd_base always point to the base of the buffer descriptors.  The
+ * cur_rx and cur_tx point to the currently available buffer.
+ * The dirty_tx tracks the current buffer that is being sent by the
+ * controller.  The cur_tx and dirty_tx are equal under both completely
+ * empty and completely full conditions.  The empty/ready indicator in
+ * the buffer descriptor determines the actual condition.
+ */
+struct cpm_enet_private {
+       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+       struct  sk_buff* tx_skbuff[TX_RING_SIZE];
+       ushort  skb_cur;
+       ushort  skb_dirty;
+
+       /* CPM dual port RAM relative addresses.
+       */
+       cbd_t   *rx_bd_base;            /* Address of Rx and Tx buffers. */
+       cbd_t   *tx_bd_base;
+       cbd_t   *cur_rx, *cur_tx;               /* The next free ring entry */
+       cbd_t   *dirty_tx;      /* The ring entries to be free()ed. */
+       scc_t   *sccp;
+       struct  net_device_stats stats;
+       char    tx_full;
+       unsigned long lock;
+};
+
+static int cpm_enet_open(struct device *dev);
+static int cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev);
+static int cpm_enet_rx(struct device *dev);
+static void cpm_enet_interrupt(void *dev_id);
+static int cpm_enet_close(struct device *dev);
+static struct net_device_stats *cpm_enet_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev);
+
+/* GET THIS FROM THE VPD!!!!
+*/
+static ushort  my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };
+
+/* Initialize the CPM Ethernet on SCC1.  If EPPC-Bug loaded us, or performed
+ * some other network I/O, a whole bunch of this has already been set up.
+ * It is no big deal if we do it again, we just have to disable the
+ * transmit and receive to make sure we don't catch the CPM with some
+ * inconsistent control information.
+ */
+__initfunc(int cpm_enet_init(void))
+{
+       struct device *dev;
+       struct cpm_enet_private *cep;
+       int i, j;
+       unsigned char   *eap;
+       unsigned long   mem_addr;
+       pte_t           *pte;
+       volatile        cbd_t           *bdp;
+       volatile        cpm8xx_t        *cp;
+       volatile        scc_t           *sccp;
+       volatile        scc_enet_t      *ep;
+       volatile        immap_t         *immap;
+
+       cp = cpmp;      /* Get pointer to Communication Processor */
+
+       immap = (immap_t *)MBX_IMAP_ADDR;       /* and to internal registers */
+
+       /* Allocate some private information.
+       */
+       cep = (struct cpm_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+       memset(cep, 0, sizeof(*cep));
+
+       /* Create an Ethernet device instance.
+       */
+       dev = init_etherdev(0, 0);
+
+       /* Get pointer to SCC1 area in parameter RAM.
+       */
+       ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_SCC1]);
+
+       /* And another to the SCC register area.
+       */
+       sccp = (volatile scc_t *)(&cp->cp_scc[0]);
+       cep->sccp = (scc_t *)sccp;              /* Keep the pointer handy */
+
+       /* Disable receive and transmit in case EPPC-Bug started it.
+       */
+       sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       /* Cookbook style from the MPC860 manual.....
+        * Not all of this is necessary if EPPC-Bug has initialized
+        * the network.
+        */
+
+       /* Configure port A pins for Txd and Rxd.
+       */
+       immap->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD);
+       immap->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD);
+       immap->im_ioport.iop_paodr &= ~PA_ENET_TXD;
+
+       /* Configure port C pins to enable CLSN and RENA.
+       */
+       immap->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+       immap->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+       immap->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
+
+       /* Configure port A for TCLK and RCLK.
+       */
+       immap->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK);
+       immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
+
+       /* Configure Serial Interface clock routing.
+        * First, clear all SCC1 bits to zero, then set the ones we want.
+        */
+       cp->cp_sicr &= ~SICR_ENET_MASK;
+       cp->cp_sicr |= SICR_ENET_CLKRT;
+
+       /* Manual says set SDDR, but I can't find anything with that
+        * name.  I think it is a misprint, and should be SDCR.  This
+        * has already been set by the communication processor initialization.
+        */
+
+       /* Allocate space for the buffer descriptors in the DP ram.
+        * These are relative offsets in the DP ram address space.
+        * Initialize base addresses for the buffer descriptors.
+        */
+       i = mbx_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE);
+       ep->sen_genscc.scc_rbase = i;
+       cep->rx_bd_base = (cbd_t *)&cp->cp_dpmem[i];
+
+       i = mbx_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE);
+       ep->sen_genscc.scc_tbase = i;
+       cep->tx_bd_base = (cbd_t *)&cp->cp_dpmem[i];
+
+       cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
+       cep->cur_rx = cep->rx_bd_base;
+
+       /* Issue init Rx BD command for SCC1.
+        * Manual says to perform an Init Rx parameters here.  We have
+        * to perform both Rx and Tx because the SCC may have been
+        * already running.
+        * In addition, we have to do it later because we don't yet have
+        * all of the BD control/status set properly.
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_RX) | CPM_CR_FLG;
+       while (cp->cp_cpcr & CPM_CR_FLG);
+        */
+
+       /* Initialize function code registers for big-endian.
+       */
+       ep->sen_genscc.scc_rfcr = SCC_EB;
+       ep->sen_genscc.scc_tfcr = SCC_EB;
+
+       /* Set maximum bytes per receive buffer.
+        * This appears to be an Ethernet frame size, not the buffer
+        * fragment size.  It must be a multiple of four.
+        */
+       ep->sen_genscc.scc_mrblr = PKT_MAXBLR_SIZE;
+
+       /* Set CRC preset and mask.
+       */
+       ep->sen_cpres = 0xffffffff;
+       ep->sen_cmask = 0xdebb20e3;
+
+       ep->sen_crcec = 0;      /* CRC Error counter */
+       ep->sen_alec = 0;       /* alignment error counter */
+       ep->sen_disfc = 0;      /* discard frame counter */
+
+       ep->sen_pads = 0x8888;  /* Tx short frame pad character */
+       ep->sen_retlim = 15;    /* Retry limit threshold */
+
+       ep->sen_maxflr = PKT_MAXBUF_SIZE;   /* maximum frame length register */
+       ep->sen_minflr = PKT_MINBUF_SIZE;  /* minimum frame length register */
+
+       ep->sen_maxd1 = PKT_MAXBUF_SIZE;        /* maximum DMA1 length */
+       ep->sen_maxd2 = PKT_MAXBUF_SIZE;        /* maximum DMA2 length */
+
+       /* Clear hash tables.
+       */
+       ep->sen_gaddr1 = 0;
+       ep->sen_gaddr2 = 0;
+       ep->sen_gaddr3 = 0;
+       ep->sen_gaddr4 = 0;
+       ep->sen_iaddr1 = 0;
+       ep->sen_iaddr2 = 0;
+       ep->sen_iaddr3 = 0;
+       ep->sen_iaddr4 = 0;
+
+       /* Set Ethernet station address.  This must come from the
+        * Vital Product Data (VPD) EEPROM.....as soon as I get the
+        * I2C interface working.....
+        *
+        * Since we performed a diskless boot, the Ethernet controller
+        * has been initialized and we copy the address out into our
+        * own structure.
+        */
+#ifdef notdef
+       ep->sen_paddrh = my_enet_addr[0];
+       ep->sen_paddrm = my_enet_addr[1];
+       ep->sen_paddrl = my_enet_addr[2];
+#else
+       eap = (unsigned char *)&(ep->sen_paddrh);
+       for (i=5; i>=0; i--)
+               dev->dev_addr[i] = *eap++;
+#endif
+
+       ep->sen_pper = 0;       /* 'cause the book says so */
+       ep->sen_taddrl = 0;     /* temp address (LSB) */
+       ep->sen_taddrm = 0;
+       ep->sen_taddrh = 0;     /* temp address (MSB) */
+
+       /* Now allocate the host memory pages and initialize the
+        * buffer descriptors.
+        */
+       bdp = cep->tx_bd_base;
+       for (i=0; i<TX_RING_SIZE; i++) {
+
+               /* Initialize the BD for every fragment in the page.
+               */
+               bdp->cbd_sc = 0;
+               bdp->cbd_bufaddr = 0;
+               bdp++;
+       }
+
+       /* Set the last buffer to wrap.
+       */
+       bdp--;
+       bdp->cbd_sc |= BD_SC_WRAP;
+
+       bdp = cep->rx_bd_base;
+       for (i=0; i<CPM_ENET_RX_PAGES; i++) {
+
+               /* Allocate a page.
+               */
+               mem_addr = __get_free_page(GFP_KERNEL);
+
+               /* Make it uncached.
+               */
+               pte = va_to_pte(&init_task, mem_addr);
+               pte_val(*pte) |= _PAGE_NO_CACHE;
+               flush_tlb_page(current->mm->mmap, mem_addr);
+
+               /* Initialize the BD for every fragment in the page.
+               */
+               for (j=0; j<CPM_ENET_RX_FRPPG; j++) {
+                       bdp->cbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR;
+                       bdp->cbd_bufaddr = __pa(mem_addr);
+                       mem_addr += CPM_ENET_RX_FRSIZE;
+                       bdp++;
+               }
+       }
+
+       /* Set the last buffer to wrap.
+       */
+       bdp--;
+       bdp->cbd_sc |= BD_SC_WRAP;
+
+       /* Let's re-initialize the channel now.  We have to do it later
+        * than the manual describes because we have just now finished
+        * the BD initialization.
+        */
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+       while (cp->cp_cpcr & CPM_CR_FLG);
+
+       cep->skb_cur = cep->skb_dirty = 0;
+
+       sccp->scc_scce = 0xffff;        /* Clear any pending events */
+
+       /* Enable interrupts for transmit error, complete frame
+        * received, and any transmit buffer we have also set the
+        * interrupt flag.
+        */
+       sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB);
+
+       /* Install our interrupt handler.
+       */
+       cpm_install_handler(CPMVEC_SCC1, cpm_enet_interrupt, dev);
+
+       /* Set GSMR_H to enable all normal operating modes.
+        * Set GSMR_L to enable Ethernet to MC68160.
+        */
+       sccp->scc_gsmrh = 0;
+       sccp->scc_gsmrl = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET);
+
+       /* Set sync/delimiters.
+       */
+       sccp->scc_dsr = 0xd555;
+
+       /* Set processing mode.  Use Ethernet CRC, catch broadcast, and
+        * start frame search 22 bit times after RENA.
+        */
+       sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_BRO | SCC_PMSR_NIB22);
+
+       /* It is now OK to enable the Ethernet transmitter.
+       */
+       immap->im_ioport.iop_pcpar |= PC_ENET_TENA;
+       immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
+
+       dev->base_addr = (unsigned long)ep;
+       dev->priv = cep;
+       dev->name = "CPM_ENET";
+
+       /* The CPM Ethernet specific entries in the device structure. */
+       dev->open = cpm_enet_open;
+       dev->hard_start_xmit = cpm_enet_start_xmit;
+       dev->stop = cpm_enet_close;
+       dev->get_stats = cpm_enet_get_stats;
+       dev->set_multicast_list = set_multicast_list;
+
+       /* And last, enable the transmit and receive processing.
+       */
+       sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+       printk("CPM ENET Version 0.1, ");
+       for (i=0; i<5; i++)
+               printk("%02x:", dev->dev_addr[i]);
+       printk("%02x\n", dev->dev_addr[5]);
+
+       return 0;
+}
+
+static int
+cpm_enet_open(struct device *dev)
+{
+
+       /* I should reset the ring buffers here, but I don't yet know
+        * a simple way to do that.
+        */
+
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+
+       return 0;                                       /* Always succeed */
+}
+
+static int
+cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+       struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv;
+       volatile cbd_t  *bdp;
+       unsigned long flags;
+
+       /* Transmitter timeout, serious problems. */
+       if (dev->tbusy) {
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 20)
+                       return 1;
+               printk("%s: transmit timed out.\n", dev->name);
+               cep->stats.tx_errors++;
+#ifndef final_version
+               {
+                       int     i;
+                       cbd_t   *bdp;
+                       printk(" Ring data dump: cur_tx %x%s cur_rx %x.\n",
+                                  cep->cur_tx, cep->tx_full ? " (full)" : "",
+                                  cep->cur_rx);
+                       bdp = cep->tx_bd_base;
+                       for (i = 0 ; i < TX_RING_SIZE; i++)
+                               printk("%04x %04x %08x\n",
+                                       bdp->cbd_sc,
+                                       bdp->cbd_datlen,
+                                       bdp->cbd_bufaddr);
+                       bdp = cep->rx_bd_base;
+                       for (i = 0 ; i < RX_RING_SIZE; i++)
+                               printk("%04x %04x %08x\n",
+                                       bdp->cbd_sc,
+                                       bdp->cbd_datlen,
+                                       bdp->cbd_bufaddr);
+               }
+#endif
+
+               dev->tbusy=0;
+               dev->trans_start = jiffies;
+
+               return 0;
+       }
+
+       /* Block a timer-based transmit from overlapping.  This could better be
+          done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+       if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+               printk("%s: Transmitter access conflict.\n", dev->name);
+               return 1;
+       }
+
+       if (test_and_set_bit(0, (void*)&cep->lock) != 0) {
+               printk("%s: tx queue lock!.\n", dev->name);
+               /* don't clear dev->tbusy flag. */
+               return 1;
+       }
+
+       /* Fill in a Tx ring entry */
+       bdp = cep->cur_tx;
+
+#ifndef final_version
+       if (bdp->cbd_sc & BD_ENET_TX_READY) {
+               /* Ooops.  All transmit buffers are full.  Bail out.
+                * This should not happen, since dev->tbusy should be set.
+                */
+               printk("%s: tx queue full!.\n", dev->name);
+               cep->lock = 0;
+               return 1;
+       }
+#endif
+
+       /* Clear all of the status flags.
+        */
+       bdp->cbd_sc &= ~BD_ENET_TX_STATS;
+
+       /* If the frame is short, tell CPM to pad it.
+       */
+       if (skb->len <= ETH_ZLEN)
+               bdp->cbd_sc |= BD_ENET_TX_PAD;
+       else
+               bdp->cbd_sc &= ~BD_ENET_TX_PAD;
+
+       /* Set buffer length and buffer pointer.
+       */
+       bdp->cbd_datlen = skb->len;
+       bdp->cbd_bufaddr = __pa(skb->data);
+
+       /* Save skb pointer.
+       */
+       cep->tx_skbuff[cep->skb_cur] = skb;
+
+       cep->stats.tx_bytes += skb->len;
+       cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;
+       
+       /* Push the data cache so the CPM does not get stale memory
+        * data.
+        */
+       /*flush_dcache_range(skb->data, skb->data + skb->len);*/
+
+       /* Send it on its way.  Tell CPM its ready, interrupt when done,
+        * its the last BD of the frame, and to put the CRC on the end.
+        */
+       bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+
+       dev->trans_start = jiffies;
+
+       /* If this was the last BD in the ring, start at the beginning again.
+       */
+       if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+               bdp = cep->tx_bd_base;
+       else
+               bdp++;
+
+       save_flags(flags);
+       cli();
+       cep->lock = 0;
+       if (bdp->cbd_sc & BD_ENET_TX_READY)
+               cep->tx_full = 1;
+       else
+               dev->tbusy=0;
+       restore_flags(flags);
+
+       cep->cur_tx = (cbd_t *)bdp;
+
+       return 0;
+}
+
+/* The interrupt handler.
+ * This is called from the CPM handler, not the MPC core interrupt.
+ */
+static void
+cpm_enet_interrupt(void *dev_id)
+{
+       struct  device *dev = dev_id;
+       struct  cpm_enet_private *cep;
+       volatile cbd_t  *bdp;
+       ushort  int_events;
+       int     must_restart;
+
+       cep = (struct cpm_enet_private *)dev->priv;
+       if (dev->interrupt)
+               printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+       dev->interrupt = 1;
+
+       /* Get the interrupt events that caused us to be here.
+       */
+       int_events = cep->sccp->scc_scce;
+       must_restart = 0;
+
+       /* Handle receive event in its own function.
+       */
+       if (int_events & SCCE_ENET_RXF)
+               cpm_enet_rx(dev_id);
+
+       /* Check for a transmit error.  The manual is a little unclear
+        * about this, so the debug code until I get it figured out.  It
+        * appears that if TXE is set, then TXB is not set.  However,
+        * if carrier sense is lost during frame transmission, the TXE
+        * bit is set, "and continues the buffer transmission normally."
+        * I don't know if "normally" implies TXB is set when the buffer
+        * descriptor is closed.....trial and error :-).
+        */
+       if (int_events & SCCE_ENET_TXE) {
+
+               /* Transmission errors.
+               */
+               bdp = cep->dirty_tx;
+#ifndef final_version
+               printk("CPM ENET xmit error %x\n", bdp->cbd_sc);
+               if (bdp->cbd_sc & BD_ENET_TX_READY)
+                       printk("HEY! Enet xmit interrupt and TX_READY.\n");
+#endif
+               if (bdp->cbd_sc & BD_ENET_TX_HB)        /* No heartbeat */
+                       cep->stats.tx_heartbeat_errors++;
+               if (bdp->cbd_sc & BD_ENET_TX_LC)        /* Late collision */
+                       cep->stats.tx_window_errors++;
+               if (bdp->cbd_sc & BD_ENET_TX_RL)        /* Retrans limit */
+                       cep->stats.tx_aborted_errors++;
+               if (bdp->cbd_sc & BD_ENET_TX_UN)        /* Underrun */
+                       cep->stats.tx_fifo_errors++;
+               if (bdp->cbd_sc & BD_ENET_TX_CSL)       /* Carrier lost */
+                       cep->stats.tx_carrier_errors++;
+
+               cep->stats.tx_errors++;
+
+               /* No heartbeat or Lost carrier are not really bad errors.
+                * The others require a restart transmit command.
+                */
+               if (bdp->cbd_sc &
+                   (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN))
+                       must_restart = 1;
+       }
+
+       /* Transmit OK, or non-fatal error.  Update the buffer descriptors.
+       */
+       if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) {
+               cep->stats.tx_packets++;
+               bdp = cep->dirty_tx;
+#ifndef final_version
+               if (bdp->cbd_sc & BD_ENET_TX_READY)
+                       printk("HEY! Enet xmit interrupt and TX_READY.\n");
+#endif
+               /* Deferred means some collisions occurred during transmit,
+                * but we eventually sent the packet OK.
+                */
+               if (bdp->cbd_sc & BD_ENET_TX_DEF)
+                       cep->stats.collisions++;
+
+               /* Free the sk buffer associated with this last transmit.
+               */
+               dev_kfree_skb(cep->tx_skbuff[cep->skb_dirty]/*, FREE_WRITE*/);
+               cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+               /* Update pointer to next buffer descriptor to be transmitted.
+               */
+               if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+                       bdp = cep->tx_bd_base;
+               else
+                       bdp++;
+
+               /* I don't know if we can be held off from processing these
+                * interrupts for more than one frame time.  I really hope
+                * not.  In such a case, we would now want to check the
+                * currently available BD (cur_tx) and determine if any
+                * buffers between the dirty_tx and cur_tx have also been
+                * sent.  We would want to process anything in between that
+                * does not have BD_ENET_TX_READY set.
+                */
+
+               /* Since we have freed up a buffer, the ring is no longer
+                * full.
+                */
+               if (cep->tx_full && dev->tbusy) {
+                       cep->tx_full = 0;
+                       dev->tbusy = 0;
+                       mark_bh(NET_BH);
+               }
+
+               cep->dirty_tx = (cbd_t *)bdp;
+       }
+
+       if (must_restart) {
+               volatile cpm8xx_t *cp;
+
+               /* Some transmit errors cause the transmitter to shut
+                * down.  We now issue a restart transmit.  Since the
+                * errors close the BD and update the pointers, the restart
+                * _should_ pick up without having to reset any of our
+                * pointers either.
+                */
+               cp = cpmp;
+               cp->cp_cpcr =
+                   mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+               while (cp->cp_cpcr & CPM_CR_FLG);
+       }
+
+       /* Check for receive busy, i.e. packets coming but no place to
+        * put them.  This "can't happen" because the receive interrupt
+        * is tossing previous frames.
+        */
+       if (int_events & SCCE_ENET_BSY) {
+               cep->stats.rx_dropped++;
+               printk("CPM ENET: BSY can't happen.\n");
+       }
+
+       /* Write the SCC event register with the events we have handled
+        * to clear them.  Maybe we should do this sooner?
+        */
+       cep->sccp->scc_scce = int_events;
+
+       dev->interrupt = 0;
+
+       return;
+}
+
+/* During a receive, the cur_rx points to the current incoming buffer.
+ * When we update through the ring, if the next incoming buffer has
+ * not been given to the system, we just set the empty indicator,
+ * effectively tossing the packet.
+ */
+static int
+cpm_enet_rx(struct device *dev)
+{
+       struct  cpm_enet_private *cep;
+       volatile cbd_t  *bdp;
+       struct  sk_buff *skb;
+       ushort  pkt_len;
+
+       cep = (struct cpm_enet_private *)dev->priv;
+
+       /* First, grab all of the stats for the incoming packet.
+        * These get messed up if we get called due to a busy condition.
+        */
+       bdp = cep->cur_rx;
+
+for (;;) {
+       if (bdp->cbd_sc & BD_ENET_RX_EMPTY)
+               break;
+               
+#ifndef final_version
+       /* Since we have allocated space to hold a complete frame, both
+        * the first and last indicators should be set.
+        */
+       if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) !=
+               (BD_ENET_RX_FIRST | BD_ENET_RX_LAST))
+                       printk("CPM ENET: rcv is not first+last\n");
+#endif
+
+       /* Frame too long or too short.
+       */
+       if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))
+               cep->stats.rx_length_errors++;
+       if (bdp->cbd_sc & BD_ENET_RX_NO)        /* Frame alignment */
+               cep->stats.rx_frame_errors++;
+       if (bdp->cbd_sc & BD_ENET_RX_CR)        /* CRC Error */
+               cep->stats.rx_crc_errors++;
+       if (bdp->cbd_sc & BD_ENET_RX_OV)        /* FIFO overrun */
+               cep->stats.rx_crc_errors++;
+
+       /* Report late collisions as a frame error.
+        * On this error, the BD is closed, but we don't know what we
+        * have in the buffer.  So, just drop this frame on the floor.
+        */
+       if (bdp->cbd_sc & BD_ENET_RX_CL) {
+               cep->stats.rx_frame_errors++;
+       }
+       else {
+
+               /* Process the incoming frame.
+               */
+               cep->stats.rx_packets++;
+               pkt_len = bdp->cbd_datlen;
+               cep->stats.rx_bytes += pkt_len;
+
+               /* This does 16 byte alignment, much more than we need.
+               */
+               skb = dev_alloc_skb(pkt_len);
+
+               if (skb == NULL) {
+                       printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+                       cep->stats.rx_dropped++;
+               }
+               else {
+                       skb->dev = dev;
+                       skb_put(skb,pkt_len);   /* Make room */
+                       eth_copy_and_sum(skb,
+                               (unsigned char *)__va(bdp->cbd_bufaddr),
+                               pkt_len, 0);
+                       skb->protocol=eth_type_trans(skb,dev);
+                       netif_rx(skb);
+               }
+       }
+
+       /* Clear the status flags for this buffer.
+       */
+       bdp->cbd_sc &= ~BD_ENET_RX_STATS;
+
+       /* Mark the buffer empty.
+       */
+       bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+
+       /* Update BD pointer to next entry.
+       */
+       if (bdp->cbd_sc & BD_ENET_RX_WRAP)
+               bdp = cep->rx_bd_base;
+       else
+               bdp++;
+
+   }
+       cep->cur_rx = (cbd_t *)bdp;
+
+       return 0;
+}
+
+static int
+cpm_enet_close(struct device *dev)
+{
+       /* Don't know what to do yet.
+       */
+
+       return 0;
+}
+
+static struct net_device_stats *cpm_enet_get_stats(struct device *dev)
+{
+       struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv;
+
+       return &cep->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ * Skeleton taken from sunlance driver.
+ * The CPM Ethernet implementation allows Multicast as well as individual
+ * MAC address filtering.  Some of the drivers check to make sure it is
+ * a group multicast address, and discard those that are not.  I guess I
+ * will do the same for now, but just remove the test if you want
+ * individual filtering as well (do the upper net layers want or support
+ * this kind of feature?).
+ */
+
+static void set_multicast_list(struct device *dev)
+{
+       struct  cpm_enet_private *cep;
+       struct  dev_mc_list *dmi;
+       u_char  *mcptr, *tdptr;
+       volatile scc_enet_t *ep;
+       int     i, j;
+
+       cep = (struct cpm_enet_private *)dev->priv;
+
+       /* Get pointer to SCC1 area in parameter RAM.
+       */
+       ep = (scc_enet_t *)dev->base_addr;
+
+       if (dev->flags&IFF_PROMISC) {
+               /* Log any net taps. */
+               printk("%s: Promiscuous mode enabled.\n", dev->name);
+               cep->sccp->scc_pmsr |= SCC_PMSR_PRO;
+       } else {
+
+               cep->sccp->scc_pmsr &= ~SCC_PMSR_PRO;
+
+               if (dev->flags & IFF_ALLMULTI) {
+                       /* Catch all multicast addresses, so set the
+                        * filter to all 1's.
+                        */
+                       ep->sen_gaddr1 = 0xffff;
+                       ep->sen_gaddr2 = 0xffff;
+                       ep->sen_gaddr3 = 0xffff;
+                       ep->sen_gaddr4 = 0xffff;
+               }
+               else {
+                       /* Clear filter and add the addresses in the list.
+                       */
+                       ep->sen_gaddr1 = 0;
+                       ep->sen_gaddr2 = 0;
+                       ep->sen_gaddr3 = 0;
+                       ep->sen_gaddr4 = 0;
+
+                       dmi = dev->mc_list;
+
+                       for (i=0; i<dev->mc_count; i++) {
+                               
+                               /* Only support group multicast for now.
+                               */
+                               if (!(dmi->dmi_addr[0] & 1))
+                                       continue;
+
+                               /* The address in dmi_addr is LSB first,
+                                * and taddr is MSB first.  We have to
+                                * copy bytes MSB first from dmi_addr.
+                                */
+                               mcptr = (u_char *)dmi->dmi_addr + 5;
+                               tdptr = (u_char *)&ep->sen_taddrh;
+                               for (j=0; j<6; j++)
+                                       *tdptr++ = *mcptr--;
+
+                               /* Ask CPM to run CRC and set bit in
+                                * filter mask.
+                                */
+                               cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_SET_GADDR) | CPM_CR_FLG;
+                               while (cpmp->cp_cpcr & CPM_CR_FLG);
+                       }
+               }
+       }
+}
diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
new file mode 100644 (file)
index 0000000..a60eda6
--- /dev/null
@@ -0,0 +1,2530 @@
+/*
+ *  UART driver for MPC860 CPM SCC or SMC
+ *  Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * I used the serial.c driver as the framework for this driver.
+ * Give credit to those guys.
+ * The original code was written for the MBX860 board.  I tried to make
+ * it generic, but there may be some assumptions in the structures that
+ * have to be fixed later.
+ * To save porting time, I did not bother to change any object names
+ * that are not accessed outside of this file.
+ * It still needs lots of work........When it was easy, I included code
+ * to support the SCCs, but this has never been tested, nor is it complete.
+ * Only the SCCs support modem control, so that is not complete either.
+ *
+ * This module exports the following rs232 io functions:
+ *
+ *     int rs_8xx_init(void);
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#include "commproc.h"
+
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+
+/* this defines the index into rs_table for the port to use
+*/
+#ifndef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT     0
+#endif
+#endif
+
+#define TX_WAKEUP      ASYNC_SHARE_IRQ
+
+static char *serial_name = "CPM UART driver";
+static char *serial_version = "0.01";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/*
+ * Serial driver configuration section.  Here are the various options:
+ */
+#define SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+#define _INLINE_ inline
+  
+#define DBG_CNT(s)
+
+/* We overload some of the items in the data structure to meet our
+ * needs.  For example, the port address is the CPM parameter ram
+ * offset for the SCC or SMC.  The maximum number of ports is 4 SCCs and
+ * 2 SMCs.  The "hub6" field is used to indicate the channel number, with
+ * 0 and 1 indicating the SMCs and 2, 3, 4, and 5 are the SCCs.
+ * Since these ports are so versatile, I don't yet have a strategy for
+ * their management.  For example, SCC1 is used for Ethernet.  Right
+ * now, just don't put them in the table.  Of course, right now I just
+ * want the SMC to work as a uart :-)..
+ * The "type" field is currently set to 0, for PORT_UNKNOWN.  It is
+ * not currently used.  I should probably use it to indicate the port
+ * type of CMS or SCC.
+ * The SMCs do not support any modem control signals.
+ */
+#define smc_scc_num    hub6
+#define SCC_NUM_BASE   2
+
+static struct serial_state rs_table[] = {
+       /* UART CLK   PORT          IRQ      FLAGS  NUM   */
+       { 0,     0, PROFF_SMC1, CPMVEC_SMC1,   0,    0 },    /* SMC1 ttyS0 */
+       { 0,     0, PROFF_SMC2, CPMVEC_SMC2,   0,    1 },    /* SMC1 ttyS0 */
+};
+
+#define NR_PORTS       (sizeof(rs_table)/sizeof(struct serial_state))
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+/* The number of buffer descriptors and their sizes.
+*/
+#define RX_NUM_FIFO    4
+#define RX_BUF_SIZE    32
+#define TX_NUM_FIFO    4
+#define TX_BUF_SIZE    32
+
+#ifndef MIN
+#define MIN(a,b)       ((a) < (b) ? (a) : (b))
+#endif
+
+/* The async_struct in serial.h does not really give us what we
+ * need, so define our own here.
+ */
+typedef struct serial_info {
+       int                     magic;
+       int                     flags;
+       struct serial_state     *state;
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     line;
+       int                     x_char; /* xon/xoff character */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     blocked_open; /* # of blocked opens */
+       long                    session; /* Session of opening process */
+       long                    pgrp; /* pgrp of opening process */
+       struct tq_struct        tqueue;
+       struct tq_struct        tqueue_hangup;
+       struct wait_queue       *open_wait;
+       struct wait_queue       *close_wait;
+
+       /* CPM Buffer Descriptor pointers.
+       */
+       cbd_t                   *rx_bd_base;
+       cbd_t                   *rx_cur;
+       cbd_t                   *tx_bd_base;
+       cbd_t                   *tx_cur;
+} ser_info_t;
+
+static void change_speed(ser_info_t *info);
+static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static inline int serial_paranoia_check(ser_info_t *info,
+                                       kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct (%s) in %s\n";
+       static const char *badinfo =
+               "Warning: null async_struct for (%s) in %s\n";
+
+       if (!info) {
+               printk(badinfo, kdevname(device), routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, kdevname(device), routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts,
+ * indexed by the termio value.  The generic CPM functions are responsible
+ * for setting and assigning baud rate generators for us.
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_stop(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     idx;
+       unsigned long flags;
+       volatile scc_t  *sccp;
+       volatile smc_t  *smcp;
+
+       if (serial_paranoia_check(info, tty->device, "rs_stop"))
+               return;
+       
+       save_flags(flags); cli();
+       if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+               smcp = &cpmp->cp_smc[idx];
+               smcp->smc_smcm &= ~SMCM_TX;
+       }
+       else {
+               sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+               sccp->scc_sccm &= ~UART_SCCM_TX;
+       }
+       restore_flags(flags);
+}
+
+static void rs_8xx_start(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     idx;
+       unsigned long flags;
+       volatile scc_t  *sccp;
+       volatile smc_t  *smcp;
+
+       if (serial_paranoia_check(info, tty->device, "rs_stop"))
+               return;
+       
+       save_flags(flags); cli();
+       if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+               smcp = &cpmp->cp_smc[idx];
+               smcp->smc_smcm |= SMCM_TX;
+       }
+       else {
+               sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+               sccp->scc_sccm |= UART_SCCM_TX;
+       }
+       restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(ser_info_t *info,
+                                 int event)
+{
+       info->event |= 1 << event;
+       queue_task(&info->tqueue, &tq_serial);
+       mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(ser_info_t *info)
+{
+       struct tty_struct *tty = info->tty;
+       unsigned char ch, *cp;
+       int     ignored = 0;
+       int     i;
+       ushort  status;
+       struct  async_icount *icount;
+       volatile cbd_t  *bdp;
+
+       icount = &info->state->icount;
+
+       /* Just loop through the closed BDs and copy the characters into
+        * the buffer.
+        */
+       bdp = info->rx_cur;
+       for (;;) {
+               if (bdp->cbd_sc & BD_SC_EMPTY)  /* If this one is empty */
+                       break;                  /*   we are all done */
+
+               /* The read status mask tell us what we should do with
+                * incoming characters, especially if errors occur.
+                * One special case is the use of BD_SC_EMPTY.  If
+                * this is not set, we are supposed to be ignoring
+                * inputs.  In this case, just mark the buffer empty and
+                * continue.
+               if (!(info->read_status_mask & BD_SC_EMPTY)) {
+                       bdp->cbd_sc |= BD_SC_EMPTY;
+                       bdp->cbd_sc &=
+                               ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+                       if (bdp->cbd_sc & BD_SC_WRAP)
+                               bdp = info->rx_bd_base;
+                       else
+                               bdp++;
+                       continue;
+               }
+                */
+
+               /* Get the number of characters and the buffer pointer.
+               */
+               i = bdp->cbd_datlen;
+               cp = (unsigned char *)__va(bdp->cbd_bufaddr);
+               status = bdp->cbd_sc;
+
+               /* Check to see if there is room in the tty buffer for
+                * the characters in our BD buffer.  If not, we exit
+                * now, leaving the BD with the characters.  We'll pick
+                * them up again on the next receive interrupt (which could
+                * be a timeout).
+                */
+               if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE)
+                       break;
+
+               while (i-- > 0) {
+                       ch = *cp++;
+                       *tty->flip.char_buf_ptr = ch;
+                       icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+                       printk("DR%02x:%02x...", ch, *status);
+#endif
+                       *tty->flip.flag_buf_ptr = 0;
+                       if (status & (BD_SC_BR | BD_SC_FR |
+                                      BD_SC_PR | BD_SC_OV)) {
+                               /*
+                                * For statistics only
+                                */
+                               if (status & BD_SC_BR)
+                                       icount->brk++;
+                               else if (status & BD_SC_PR)
+                                       icount->parity++;
+                               else if (status & BD_SC_FR)
+                                       icount->frame++;
+                               if (status & BD_SC_OV)
+                                       icount->overrun++;
+
+                               /*
+                                * Now check to see if character should be
+                                * ignored, and mask off conditions which
+                                * should be ignored.
+                               if (status & info->ignore_status_mask) {
+                                       if (++ignored > 100)
+                                               break;
+                                       continue;
+                               }
+                                */
+                               status &= info->read_status_mask;
+               
+                               if (status & (BD_SC_BR)) {
+#ifdef SERIAL_DEBUG_INTR
+                                       printk("handling break....");
+#endif
+                                       *tty->flip.flag_buf_ptr = TTY_BREAK;
+                                       if (info->flags & ASYNC_SAK)
+                                               do_SAK(tty);
+                               } else if (status & BD_SC_PR)
+                                       *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               else if (status & BD_SC_FR)
+                                       *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               if (status & BD_SC_OV) {
+                                       /*
+                                        * Overrun is special, since it's
+                                        * reported immediately, and doesn't
+                                        * affect the current character
+                                        */
+                                       if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+                                               tty->flip.count++;
+                                               tty->flip.flag_buf_ptr++;
+                                               tty->flip.char_buf_ptr++;
+                                               *tty->flip.flag_buf_ptr =
+                                                               TTY_OVERRUN;
+                                       }
+                               }
+                       }
+                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                               break;
+
+                       tty->flip.flag_buf_ptr++;
+                       tty->flip.char_buf_ptr++;
+                       tty->flip.count++;
+               }
+
+               /* This BD is ready to be used again.  Clear status.
+                * Get next BD.
+                */
+               bdp->cbd_sc |= BD_SC_EMPTY;
+               bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+               if (bdp->cbd_sc & BD_SC_WRAP)
+                       bdp = info->rx_bd_base;
+               else
+                       bdp++;
+       }
+
+       info->rx_cur = (cbd_t *)bdp;
+
+       queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static _INLINE_ void transmit_chars(ser_info_t *info)
+{
+       
+       if (info->flags & TX_WAKEUP) {
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+       }
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("THRE...");
+#endif
+}
+
+#ifdef notdef
+       /* I need to do this for the SCCs, so it is left as a reminder.
+       */
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+       int     status;
+       struct  async_icount *icount;
+       
+       status = serial_in(info, UART_MSR);
+
+       if (status & UART_MSR_ANY_DELTA) {
+               icount = &info->state->icount;
+               /* update input line counters */
+               if (status & UART_MSR_TERI)
+                       icount->rng++;
+               if (status & UART_MSR_DDSR)
+                       icount->dsr++;
+               if (status & UART_MSR_DDCD) {
+                       icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+                       if ((info->flags & ASYNC_HARDPPS_CD) &&
+                           (status & UART_MSR_DCD))
+                               hardpps();
+#endif
+               }
+               if (status & UART_MSR_DCTS)
+                       icount->cts++;
+               wake_up_interruptible(&info->delta_msr_wait);
+       }
+
+       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+               printk("ttys%d CD now %s...", info->line,
+                      (status & UART_MSR_DCD) ? "on" : "off");
+#endif         
+               if (status & UART_MSR_DCD)
+                       wake_up_interruptible(&info->open_wait);
+               else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                          (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+                       printk("scheduling hangup...");
+#endif
+                       queue_task(&info->tqueue_hangup,
+                                          &tq_scheduler);
+               }
+       }
+       if (info->flags & ASYNC_CTS_FLOW) {
+               if (info->tty->hw_stopped) {
+                       if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx start...");
+#endif
+                               info->tty->hw_stopped = 0;
+                               info->IER |= UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+                               return;
+                       }
+               } else {
+                       if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx stop...");
+#endif
+                               info->tty->hw_stopped = 1;
+                               info->IER &= ~UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                       }
+               }
+       }
+}
+#endif
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+static void rs_8xx_interrupt(void *dev_id)
+{
+       u_char  events;
+       int     idx;
+       ser_info_t *info;
+       volatile smc_t  *smcp;
+       
+       info = (ser_info_t *)dev_id;
+
+       if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+               smcp = &cpmp->cp_smc[idx];
+       }
+       else {
+               panic("SCC UART Interrupt....not ready");
+       }
+       
+       events = smcp->smc_smce;
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt_single(%d, %x)...",
+                                       info->state->smc_scc_num, events);
+#endif
+       if (events & SMCM_RX)
+               receive_chars(info);
+       if (events & SMCM_TX)
+               transmit_chars(info);
+       smcp->smc_smce = events;
+#ifdef modem_control
+       check_modem_status(info);
+#endif
+       info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+       run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+       ser_info_t      *info = (ser_info_t *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                   tty->ldisc.write_wakeup)
+                       (tty->ldisc.write_wakeup)(tty);
+               wake_up_interruptible(&tty->write_wait);
+       }
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ *     serial interrupt routine -> (scheduler tqueue) ->
+ *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+       struct async_struct     *info = (struct async_struct *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       tty_hangup(tty);
+}
+
+static void rs_8xx_timer(void)
+{
+       printk("rs_8xx_timer\n");
+}
+
+
+static int startup(ser_info_t *info)
+{
+       unsigned long flags;
+       int     retval=0;
+       int     idx;
+       struct serial_state *state= info->state;
+       volatile smc_t          *smcp;
+       volatile scc_t          *sccp;
+       volatile smc_uart_t     *up;
+
+
+       save_flags(flags); cli();
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               goto errout;
+       }
+
+#ifdef maybe
+       if (!state->port || !state->type) {
+               if (info->tty)
+                       set_bit(TTY_IO_ERROR, &info->tty->flags);
+               goto errout;
+       }
+#endif
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+
+#ifdef modem_control
+       info->MCR = 0;
+       if (info->tty->termios->c_cflag & CBAUD)
+               info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#endif
+       
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       /*
+        * and set the speed of the serial port
+        */
+       change_speed(info);
+       
+       if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+               smcp = &cpmp->cp_smc[idx];
+
+               /* Enable interrupts and I/O.
+               */
+               smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+               smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+
+               /* We can tune the buffer length and idle characters
+                * to take advantage of the entire incoming buffer size.
+                * If mrblr is something other than 1, maxidl has to be
+                * non-zero or we never get an interrupt.  The maxidl
+                * is the number of character times we wait after reception
+                * of the last character before we decide no more characters
+                * are coming.
+                */
+               up = (smc_uart_t *)&cpmp->cp_dparam[state->port];
+               up->smc_mrblr = 1;      /* receive buffer length */
+               up->smc_maxidl = 0;     /* wait forever for next char */
+               up->smc_brkcr = 1;      /* number of break chars */
+       }
+       else {
+               sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+               sccp->scc_sccm |= UART_SCCM_RX;
+       }
+
+       info->flags |= ASYNC_INITIALIZED;
+       restore_flags(flags);
+       return 0;
+       
+errout:
+       restore_flags(flags);
+       return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(ser_info_t * info)
+{
+       unsigned long   flags;
+       struct serial_state *state;
+       int             idx;
+       volatile smc_t  *smcp;
+       volatile scc_t  *sccp;
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+       state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....", info->line,
+              state->irq);
+#endif
+       
+       save_flags(flags); cli(); /* Disable interrupts */
+
+       if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+               smcp = &cpmp->cp_smc[idx];
+
+               /* Disable interrupts and I/O.
+               */
+               smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+#ifdef CONFIG_SERIAL_CONSOLE
+               /* We can't disable the transmitter if this is the
+                * system console.
+                */
+               if (idx != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+                       smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       }
+       else {
+               sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+               sccp->scc_sccm &= ~UART_SCCM_RX;
+       }
+
+       
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       info->flags &= ~ASYNC_INITIALIZED;
+       restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(ser_info_t *info)
+{
+       int     baud_rate;
+       unsigned cflag, cval, prev_mode;
+       int     i, bits, idx;
+       unsigned long   flags;
+       volatile smc_t  *smcp;
+       volatile scc_t  *sccp;
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       cflag = info->tty->termios->c_cflag;
+
+       /* Character length programmed into the mode register is the
+        * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+        * 1 or 2 stop bits, minus 1.
+        * The value 'bits' counts this for us.
+        */
+       cval = 0;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+             case CS5: bits = 5; break;
+             case CS6: bits = 6; break;
+             case CS7: bits = 7; break;
+             case CS8: bits = 8; break;
+             /* Never happens, but GCC is too dumb to figure it out */
+             default:  bits = 8; break;
+       }
+       if (cflag & CSTOPB) {
+               cval |= SMCMR_SL;       /* Two stops */
+               bits++;
+       }
+       if (cflag & PARENB) {
+               cval |= SMCMR_PEN;
+               bits++;
+       }
+       if (!(cflag & PARODD))
+               cval |= SMCMR_PM_EVEN;
+
+       /* Determine divisor based on baud rate */
+       i = cflag & CBAUD;
+       if (i & CBAUDEX) {
+               i &= ~CBAUDEX;
+               if (i < 1 || i > 4) 
+                       info->tty->termios->c_cflag &= ~CBAUDEX;
+               else
+                       i += 15;
+       }
+
+       baud_rate = baud_table[i];
+
+       info->timeout = (TX_BUF_SIZE*HZ*bits);
+       info->timeout += HZ/50;         /* Add .02 seconds of slop */
+
+#ifdef modem_control
+       /* CTS flow control flag and modem status interrupts */
+       info->IER &= ~UART_IER_MSI;
+       if (info->flags & ASYNC_HARDPPS_CD)
+               info->IER |= UART_IER_MSI;
+       if (cflag & CRTSCTS) {
+               info->flags |= ASYNC_CTS_FLOW;
+               info->IER |= UART_IER_MSI;
+       } else
+               info->flags &= ~ASYNC_CTS_FLOW;
+       if (cflag & CLOCAL)
+               info->flags &= ~ASYNC_CHECK_CD;
+       else {
+               info->flags |= ASYNC_CHECK_CD;
+               info->IER |= UART_IER_MSI;
+       }
+       serial_out(info, UART_IER, info->IER);
+#endif
+
+       /*
+        * Set up parity check flag
+        */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+       info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+       if (I_INPCK(info->tty))
+               info->read_status_mask |= BD_SC_FR | BD_SC_PR;
+       if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+               info->read_status_mask |= BD_SC_BR;
+       
+       /*
+        * Characters to ignore
+        */
+       info->ignore_status_mask = 0;
+       if (I_IGNPAR(info->tty))
+               info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+       if (I_IGNBRK(info->tty)) {
+               info->ignore_status_mask |= BD_SC_BR;
+               /*
+                * If we're ignore parity and break indicators, ignore 
+                * overruns too.  (For real raw support).
+                */
+               if (I_IGNPAR(info->tty))
+                       info->ignore_status_mask |= BD_SC_OV;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               info->read_status_mask &= ~BD_SC_EMPTY;
+       save_flags(flags); cli();
+
+       /* Start bit has not been added (so don't, because we would just
+        * subtract it later), and we need to add one for the number of
+        * stops bits (there is always at least one).
+        */
+       bits++;
+       if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+               smcp = &cpmp->cp_smc[idx];
+
+               /* Set the mode register.  We want to keep a copy of the
+                * enables, because we want to put them back if they were
+                * present.
+                */
+               prev_mode = smcp->smc_smcmr;
+               smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;
+               smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+       }
+       else {
+               sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+               sccp->scc_sccm &= ~UART_SCCM_RX;
+       }
+
+       mbx_cpm_setbrg(info->state->smc_scc_num, baud_rate);
+
+       restore_flags(flags);
+}
+
+static void rs_8xx_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       volatile cbd_t  *bdp;
+
+       if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+               return;
+
+       if (!tty)
+               return;
+
+       bdp = info->tx_cur;
+       while (bdp->cbd_sc & BD_SC_READY);
+
+       *((char *)__va(bdp->cbd_bufaddr)) = ch;
+       bdp->cbd_datlen = 1;
+       bdp->cbd_sc |= BD_SC_READY;
+
+       /* Get next BD.
+       */
+       if (bdp->cbd_sc & BD_SC_WRAP)
+               bdp = info->tx_bd_base;
+       else
+               bdp++;
+
+       info->tx_cur = (cbd_t *)bdp;
+
+}
+
+static int rs_8xx_write(struct tty_struct * tty, int from_user,
+                   const unsigned char *buf, int count)
+{
+       int     c, ret = 0;
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       volatile cbd_t *bdp;
+
+       if (serial_paranoia_check(info, tty->device, "rs_write"))
+               return 0;
+
+       if (!tty) 
+               return 0;
+
+       bdp = info->tx_cur;
+
+       while (1) {
+               c = MIN(count, TX_BUF_SIZE);
+
+               if (c <= 0)
+                       break;
+
+               if (bdp->cbd_sc & BD_SC_READY) {
+                       info->flags |= TX_WAKEUP;
+                       break;
+               }
+
+               if (from_user) {
+                       if (c !=
+                           copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) {
+                               if (!ret)
+                                       ret = -EFAULT;
+                               break;
+                       }
+               } else {
+                       memcpy(__va(bdp->cbd_bufaddr), buf, c);
+               }
+
+               bdp->cbd_datlen = c;
+               bdp->cbd_sc |= BD_SC_READY;
+
+               buf += c;
+               count -= c;
+               ret += c;
+
+               /* Get next BD.
+               */
+               if (bdp->cbd_sc & BD_SC_WRAP)
+                       bdp = info->tx_bd_base;
+               else
+                       bdp++;
+               info->tx_cur = (cbd_t *)bdp;
+       }
+       return ret;
+}
+
+static int rs_8xx_write_room(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int     ret;
+
+       if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+               return 0;
+
+       if ((info->tx_cur->cbd_sc & BD_SC_READY) == 0) {
+               info->flags &= ~TX_WAKEUP;
+               ret = TX_BUF_SIZE;
+       }
+       else {
+               info->flags |= TX_WAKEUP;
+               ret = 0;
+       }
+       return ret;
+}
+
+/* I could track this with transmit counters....maybe later.
+*/
+static int rs_8xx_chars_in_buffer(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+               return 0;
+       return 0;
+}
+
+static void rs_8xx_flush_buffer(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+               return;
+
+       /* There is nothing to "flush", whatever we gave the CPM
+        * is on its way out.
+        */
+       wake_up_interruptible(&tty->write_wait);
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+           tty->ldisc.write_wakeup)
+               (tty->ldisc.write_wakeup)(tty);
+       info->flags &= ~TX_WAKEUP;
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_8xx_send_xchar(struct tty_struct *tty, char ch)
+{
+       volatile cbd_t  *bdp;
+
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+               return;
+
+       bdp = info->tx_cur;
+       while (bdp->cbd_sc & BD_SC_READY);
+
+       *((char *)__va(bdp->cbd_bufaddr)) = ch;
+       bdp->cbd_datlen = 1;
+       bdp->cbd_sc |= BD_SC_READY;
+
+       /* Get next BD.
+       */
+       if (bdp->cbd_sc & BD_SC_WRAP)
+               bdp = info->tx_bd_base;
+       else
+               bdp++;
+
+       info->tx_cur = (cbd_t *)bdp;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_throttle(struct tty_struct * tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("throttle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+               return;
+       
+       if (I_IXOFF(tty))
+               rs_8xx_send_xchar(tty, STOP_CHAR(tty));
+
+#ifdef modem_control
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR &= ~UART_MCR_RTS;
+
+       cli();
+       serial_out(info, UART_MCR, info->MCR);
+       sti();
+#endif
+}
+
+static void rs_8xx_unthrottle(struct tty_struct * tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       rs_8xx_send_xchar(tty, START_CHAR(tty));
+       }
+#ifdef modem_control
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR |= UART_MCR_RTS;
+       cli();
+       serial_out(info, UART_MCR, info->MCR);
+       sti();
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+#ifdef maybe
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+       unsigned char status;
+       unsigned int result;
+
+       cli();
+       status = serial_in(info, UART_LSR);
+       sti();
+       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+       return put_user(result,value);
+}
+#endif
+
+static int get_modem_info(ser_info_t *info, unsigned int *value)
+{
+       unsigned int result = 0;
+#ifdef modem_control
+       unsigned char control, status;
+
+       control = info->MCR;
+       cli();
+       status = serial_in(info, UART_MSR);
+       sti();
+       result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+               | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+               | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+               | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+               | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+               | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+               | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+               | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+#endif
+       return put_user(result,value);
+}
+
+static int set_modem_info(ser_info_t *info, unsigned int cmd,
+                         unsigned int *value)
+{
+       int error;
+       unsigned int arg;
+
+       error = get_user(arg, value);
+       if (error)
+               return error;
+#ifdef modem_control
+       switch (cmd) {
+       case TIOCMBIS: 
+               if (arg & TIOCM_RTS)
+                       info->MCR |= UART_MCR_RTS;
+               if (arg & TIOCM_DTR)
+                       info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+               if (arg & TIOCM_OUT1)
+                       info->MCR |= UART_MCR_OUT1;
+               if (arg & TIOCM_OUT2)
+                       info->MCR |= UART_MCR_OUT2;
+#endif
+               break;
+       case TIOCMBIC:
+               if (arg & TIOCM_RTS)
+                       info->MCR &= ~UART_MCR_RTS;
+               if (arg & TIOCM_DTR)
+                       info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+               if (arg & TIOCM_OUT1)
+                       info->MCR &= ~UART_MCR_OUT1;
+               if (arg & TIOCM_OUT2)
+                       info->MCR &= ~UART_MCR_OUT2;
+#endif
+               break;
+       case TIOCMSET:
+               info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+                                           UART_MCR_OUT1 |
+                                           UART_MCR_OUT2 |
+#endif
+                                           UART_MCR_DTR))
+                            | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+                            | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+                            | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+                            | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+               break;
+       default:
+               return -EINVAL;
+       }
+       cli();
+       serial_out(info, UART_MCR, info->MCR);
+       sti();
+#endif
+       return 0;
+}
+
+/* Sending a break is a two step process on the SMC/SCC.  It is accomplished
+ * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
+ * command.  We take advantage of the begin/end functions to make this
+ * happen.
+ */
+static void begin_break(ser_info_t *info)
+{
+       volatile cpm8xx_t *cp;
+       ushort  chan;
+       ushort  num;
+
+       cp = cpmp;
+
+       if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
+               if (num == 0)
+                       chan = CPM_CR_CH_SMC1;
+               else
+                       chan = CPM_CR_CH_SMC2;
+       }
+       else {
+               num -= SCC_NUM_BASE;
+               switch (num) {
+               case 0: chan = CPM_CR_CH_SCC1; break;
+               case 1: chan = CPM_CR_CH_SCC2; break;
+               case 2: chan = CPM_CR_CH_SCC3; break;
+               case 3: chan = CPM_CR_CH_SCC4; break;
+               default: return;
+               }
+       }
+       cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
+       while (cp->cp_cpcr & CPM_CR_FLG);
+}
+
+static void end_break(ser_info_t *info)
+{
+       volatile cpm8xx_t *cp;
+       ushort  chan;
+       ushort  num;
+
+       cp = cpmp;
+
+       if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
+               if (num == 0)
+                       chan = CPM_CR_CH_SMC1;
+               else
+                       chan = CPM_CR_CH_SMC2;
+       }
+       else {
+               num -= SCC_NUM_BASE;
+               switch (num) {
+               case 0: chan = CPM_CR_CH_SCC1; break;
+               case 1: chan = CPM_CR_CH_SCC2; break;
+               case 2: chan = CPM_CR_CH_SCC3; break;
+               case 3: chan = CPM_CR_CH_SCC4; break;
+               default: return;
+               }
+       }
+       cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+       while (cp->cp_cpcr & CPM_CR_FLG);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(ser_info_t *info, int duration)
+{
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + duration;
+#ifdef SERIAL_DEBUG_SEND_BREAK
+       printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
+#endif
+       begin_break(info);
+       schedule();
+       end_break(info);
+#ifdef SERIAL_DEBUG_SEND_BREAK
+       printk("done jiffies=%lu\n", jiffies);
+#endif
+}
+
+
+static int rs_8xx_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       int error;
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       int retval;
+       struct async_icount cnow;       /* kernel counter temps */
+       struct serial_icounter_struct *p_cuser; /* user space */
+
+       if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+               return -ENODEV;
+
+       if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+       
+       switch (cmd) {
+               case TCSBRK:    /* SVID version: non-zero arg --> no break */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       if (!arg) {
+                               send_break(info, HZ/4); /* 1/4 second */
+                               if (signal_pending(current))
+                                       return -EINTR;
+                       }
+                       return 0;
+               case TCSBRKP:   /* support for POSIX tcsendbreak() */
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
+                       if (signal_pending(current))
+                               return -EINTR;
+                       return 0;
+               case TIOCSBRK:
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       tty_wait_until_sent(tty, 0);
+                       begin_break(info);
+                       return 0;
+               case TIOCCBRK:
+                       retval = tty_check_change(tty);
+                       if (retval)
+                               return retval;
+                       end_break(info);
+                       return 0;
+               case TIOCGSOFTCAR:
+                       return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
+               case TIOCSSOFTCAR:
+                       error = get_user(arg, (unsigned int *) arg);
+                       if (error)
+                               return error;
+                       tty->termios->c_cflag =
+                               ((tty->termios->c_cflag & ~CLOCAL) |
+                                (arg ? CLOCAL : 0));
+                       return 0;
+               case TIOCMGET:
+                       return get_modem_info(info, (unsigned int *) arg);
+               case TIOCMBIS:
+               case TIOCMBIC:
+               case TIOCMSET:
+                       return set_modem_info(info, cmd, (unsigned int *) arg);
+#ifdef maybe
+               case TIOCSERGETLSR: /* Get line status register */
+                       return get_lsr_info(info, (unsigned int *) arg);
+#endif
+               /*
+                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+                * - mask passed in arg for lines of interest
+                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+                * Caller should use TIOCGICOUNT to see which one it was
+                */
+                case TIOCMIWAIT:
+#ifdef modem_control
+                       cli();
+                       /* note the counters on entry */
+                       cprev = info->state->icount;
+                       sti();
+                       while (1) {
+                               interruptible_sleep_on(&info->delta_msr_wait);
+                               /* see if a signal did it */
+                               if (signal_pending(current))
+                                       return -ERESTARTSYS;
+                               cli();
+                               cnow = info->state->icount; /* atomic copy */
+                               sti();
+                               if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+                                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+                                       return -EIO; /* no change => error */
+                               if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+                                    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+                                    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+                                    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+                                       return 0;
+                               }
+                               cprev = cnow;
+                       }
+                       /* NOTREACHED */
+#else
+                       return 0;
+#endif
+
+               /* 
+                * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+                * Return: write counters to the user passed counter struct
+                * NB: both 1->0 and 0->1 transitions are counted except for
+                *     RI where only 0->1 is counted.
+                */
+               case TIOCGICOUNT:
+                       cli();
+                       cnow = info->state->icount;
+                       sti();
+                       p_cuser = (struct serial_icounter_struct *) arg;
+                       error = put_user(cnow.cts, &p_cuser->cts);
+                       if (error) return error;
+                       error = put_user(cnow.dsr, &p_cuser->dsr);
+                       if (error) return error;
+                       error = put_user(cnow.rng, &p_cuser->rng);
+                       if (error) return error;
+                       error = put_user(cnow.dcd, &p_cuser->dcd);
+                       if (error) return error;
+                       return 0;
+
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       return 0;
+}
+
+/* FIX UP modem control here someday......
+*/
+static void rs_8xx_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+       if (   (tty->termios->c_cflag == old_termios->c_cflag)
+           && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+               == RELEVANT_IFLAG(old_termios->c_iflag)))
+         return;
+
+       change_speed(info);
+
+#ifdef modem_control
+       /* Handle transition to B0 status */
+       if ((old_termios->c_cflag & CBAUD) &&
+           !(tty->termios->c_cflag & CBAUD)) {
+               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+               cli();
+               serial_out(info, UART_MCR, info->MCR);
+               sti();
+       }
+       
+       /* Handle transition away from B0 status */
+       if (!(old_termios->c_cflag & CBAUD) &&
+           (tty->termios->c_cflag & CBAUD)) {
+               info->MCR |= UART_MCR_DTR;
+               if (!tty->hw_stopped ||
+                   !(tty->termios->c_cflag & CRTSCTS)) {
+                       info->MCR |= UART_MCR_RTS;
+               }
+               cli();
+               serial_out(info, UART_MCR, info->MCR);
+               sti();
+       }
+       
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_8xx_start(tty);
+       }
+#endif
+
+#if 0
+       /*
+        * No need to wake up processes in open wait, since they
+        * sample the CLOCAL flag once, and don't recheck it.
+        * XXX  It's not clear whether the current behavior is correct
+        * or not.  Hence, this may change.....
+        */
+       if (!(old_termios->c_cflag & CLOCAL) &&
+           (tty->termios->c_cflag & CLOCAL))
+               wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_close(struct tty_struct *tty, struct file * filp)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       struct serial_state *state;
+       unsigned long   flags;
+       int             idx;
+       volatile smc_t  *smcp;
+       volatile scc_t  *sccp;
+
+       if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+               return;
+
+       state = info->state;
+       
+       save_flags(flags); cli();
+       
+       if (tty_hung_up_p(filp)) {
+               DBG_CNT("before DEC-hung");
+               MOD_DEC_USE_COUNT;
+               restore_flags(flags);
+               return;
+       }
+       
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+       if ((tty->count == 1) && (state->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  state->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk("rs_close: bad serial port count; tty->count is 1, "
+                      "state->count is %d\n", state->count);
+               state->count = 1;
+       }
+       if (--state->count < 0) {
+               printk("rs_close: bad serial port count for ttys%d: %d\n",
+                      info->line, state->count);
+               state->count = 0;
+       }
+       if (state->count) {
+               DBG_CNT("before DEC-2");
+               MOD_DEC_USE_COUNT;
+               restore_flags(flags);
+               return;
+       }
+       info->flags |= ASYNC_CLOSING;
+       /*
+        * Save the termios structure, since this port may have
+        * separate termios for callout and dialin.
+        */
+       if (info->flags & ASYNC_NORMAL_ACTIVE)
+               info->state->normal_termios = *tty->termios;
+       if (info->flags & ASYNC_CALLOUT_ACTIVE)
+               info->state->callout_termios = *tty->termios;
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify 
+        * the line discipline to only process XON/XOFF characters.
+        */
+       tty->closing = 1;
+       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the receive line status interrupts, and tell the
+        * interrupt driver to stop checking the data ready bit in the
+        * line status register.
+        */
+       info->read_status_mask &= ~BD_SC_EMPTY;
+       if (info->flags & ASYNC_INITIALIZED) {
+               if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+                       smcp = &cpmp->cp_smc[idx];
+                       smcp->smc_smcm &= ~SMCM_RX;
+                       smcp->smc_smcmr &= ~SMCMR_REN;
+               }
+               else {
+                       sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+                       sccp->scc_sccm &= ~UART_SCCM_RX;
+               }
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important if there is a transmit FIFO!
+                */
+               rs_8xx_wait_until_sent(tty, info->timeout);
+       }
+       shutdown(info);
+       if (tty->driver.flush_buffer)
+               tty->driver.flush_buffer(tty);
+       if (tty->ldisc.flush_buffer)
+               tty->ldisc.flush_buffer(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->tty = 0;
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies + info->close_delay;
+                       schedule();
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+                        ASYNC_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       MOD_DEC_USE_COUNT;
+       restore_flags(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       unsigned long orig_jiffies, char_time;
+       int lsr;
+       volatile cbd_t *bdp;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+               return;
+
+#ifdef maybe
+       if (info->state->type == PORT_UNKNOWN)
+               return;
+#endif
+
+       orig_jiffies = jiffies;
+       /*
+        * Set the check interval to be 1/5 of the estimated time to
+        * send a single character, and make it at least 1.  The check
+        * interval should also be less than the timeout.
+        * 
+        * Note: we have to use pretty tight timings here to satisfy
+        * the NIST-PCTS.
+        */
+       char_time = 1;
+       if (timeout)
+               char_time = MIN(char_time, timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+       printk("jiff=%lu...", jiffies);
+#endif
+
+       /* We go through the loop at least once because we can't tell
+        * exactly when the last character exits the shifter.  There can
+        * be at least two characters waiting to be sent after the buffers
+        * are empty.
+        */
+       do {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+               current->state = TASK_INTERRUPTIBLE;
+/*             current->counter = 0;   /* make us low-priority */
+               current->timeout = jiffies + char_time;
+               schedule();
+               if (signal_pending(current))
+                       break;
+               if (timeout && ((orig_jiffies + timeout) < jiffies))
+                       break;
+               bdp = info->tx_cur;
+       } while (bdp->cbd_sc & BD_SC_READY);
+       current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_8xx_hangup(struct tty_struct *tty)
+{
+       ser_info_t *info = (ser_info_t *)tty->driver_data;
+       struct serial_state *state = info->state;
+       
+       if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+               return;
+
+       state = info->state;
+       
+       rs_8xx_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       state->count = 0;
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+       info->tty = 0;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          ser_info_t *info)
+{
+#ifdef DO_THIS_LATER
+       struct wait_queue wait = { current, NULL };
+#endif
+       struct serial_state *state = info->state;
+       int             retval;
+       int             do_clocal = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If this is a callout device, then just make sure the normal
+        * device isn't being used.
+        */
+       if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+               if (info->flags & ASYNC_NORMAL_ACTIVE)
+                       return -EBUSY;
+               if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   (info->flags & ASYNC_SESSION_LOCKOUT) &&
+                   (info->session != current->session))
+                   return -EBUSY;
+               if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   (info->flags & ASYNC_PGRP_LOCKOUT) &&
+                   (info->pgrp != current->pgrp))
+                   return -EBUSY;
+               info->flags |= ASYNC_CALLOUT_ACTIVE;
+               return 0;
+       }
+       
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        * If this is an SMC port, we don't have modem control to wait
+        * for, so just get out here.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+           (tty->flags & (1 << TTY_IO_ERROR)) ||
+           (info->state->smc_scc_num < SCC_NUM_BASE)) {
+               if (info->flags & ASYNC_CALLOUT_ACTIVE)
+                       return -EBUSY;
+               info->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+               if (state->normal_termios.c_cflag & CLOCAL)
+                       do_clocal = 1;
+       } else {
+               if (tty->termios->c_cflag & CLOCAL)
+                       do_clocal = 1;
+       }
+       
+       /*
+        * Block waiting for the carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, state->count is dropped by one, so that
+        * rs_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+       retval = 0;
+#ifdef DO_THIS_LATER
+       add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttys%d, count = %d\n",
+              state->line, state->count);
+#endif
+       cli();
+       if (!tty_hung_up_p(filp)) 
+               state->count--;
+       sti();
+       info->blocked_open++;
+       while (1) {
+               cli();
+               if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   (tty->termios->c_cflag & CBAUD))
+                       serial_out(info, UART_MCR,
+                                  serial_inp(info, UART_MCR) |
+                                  (UART_MCR_DTR | UART_MCR_RTS));
+               sti();
+               current->state = TASK_INTERRUPTIBLE;
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;  
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   !(info->flags & ASYNC_CLOSING) &&
+                   (do_clocal || (serial_in(info, UART_MSR) &
+                                  UART_MSR_DCD)))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttys%d, count = %d\n",
+                      info->line, state->count);
+#endif
+               schedule();
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&info->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               state->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttys%d, count = %d\n",
+              info->line, state->count);
+#endif
+#endif /* DO_THIS_LATER */
+       if (retval)
+               return retval;
+       info->flags |= ASYNC_NORMAL_ACTIVE;
+       return 0;
+}
+
+static int get_async_struct(int line, ser_info_t **ret_info)
+{
+       struct serial_state *sstate;
+
+       sstate = rs_table + line;
+       if (sstate->info) {
+               sstate->count++;
+               *ret_info = (ser_info_t *)sstate->info;
+               return 0;
+       }
+       else {
+               return -ENOMEM;
+       }
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_8xx_open(struct tty_struct *tty, struct file * filp)
+{
+       ser_info_t      *info;
+       int             retval, line;
+
+       line = MINOR(tty->device) - tty->driver.minor_start;
+       if ((line < 0) || (line >= NR_PORTS))
+               return -ENODEV;
+       retval = get_async_struct(line, &info);
+       if (retval)
+               return retval;
+       if (serial_paranoia_check(info, tty->device, "rs_open"))
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+              info->state->count);
+#endif
+       tty->driver_data = info;
+       info->tty = tty;
+
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       MOD_INC_USE_COUNT;
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               return retval;
+       }
+
+       if ((info->state->count == 1) &&
+           (info->flags & ASYNC_SPLIT_TERMIOS)) {
+               if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+                       *tty->termios = info->state->normal_termios;
+               else 
+                       *tty->termios = info->state->callout_termios;
+               change_speed(info);
+       }
+
+       info->session = current->session;
+       info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open ttys%d successful...", info->line);
+#endif
+       return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static int inline line_info(char *buf, struct serial_state *state)
+{
+#ifdef notdef
+       struct async_struct *info = state->info, scr_info;
+       char    stat_buf[30], control, status;
+#endif
+       int     ret;
+
+       ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+                     state->line,
+                     (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC",
+                     state->port, state->irq);
+
+       if (!state->port || (state->type == PORT_UNKNOWN)) {
+               ret += sprintf(buf+ret, "\n");
+               return ret;
+       }
+
+#ifdef notdef
+       /*
+        * Figure out the current RS-232 lines
+        */
+       if (!info) {
+               info = &scr_info;       /* This is just for serial_{in,out} */
+
+               info->magic = SERIAL_MAGIC;
+               info->port = state->port;
+               info->flags = state->flags;
+               info->quot = 0;
+               info->tty = 0;
+       }
+       cli();
+       status = serial_in(info, UART_MSR);
+       control = info ? info->MCR : serial_in(info, UART_MCR);
+       sti();
+       
+       stat_buf[0] = 0;
+       stat_buf[1] = 0;
+       if (control & UART_MCR_RTS)
+               strcat(stat_buf, "|RTS");
+       if (status & UART_MSR_CTS)
+               strcat(stat_buf, "|CTS");
+       if (control & UART_MCR_DTR)
+               strcat(stat_buf, "|DTR");
+       if (status & UART_MSR_DSR)
+               strcat(stat_buf, "|DSR");
+       if (status & UART_MSR_DCD)
+               strcat(stat_buf, "|CD");
+       if (status & UART_MSR_RI)
+               strcat(stat_buf, "|RI");
+
+       if (info->quot) {
+               ret += sprintf(buf+ret, " baud:%d",
+                              state->baud_base / info->quot);
+       }
+
+       ret += sprintf(buf+ret, " tx:%d rx:%d",
+                     state->icount.tx, state->icount.rx);
+
+       if (state->icount.frame)
+               ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+       
+       if (state->icount.parity)
+               ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+       
+       if (state->icount.brk)
+               ret += sprintf(buf+ret, " brk:%d", state->icount.brk);  
+
+       if (state->icount.overrun)
+               ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines
+        */
+       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+#endif
+       return ret;
+}
+
+int rs_8xx_read_proc(char *page, char **start, off_t off, int count,
+                int *eof, void *data)
+{
+       int i, len = 0;
+       off_t   begin = 0;
+
+       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+       for (i = 0; i < NR_PORTS && len < 4000; i++) {
+               len += line_info(page + len, &rs_table[i]);
+               if (len+begin > off+count)
+                       goto done;
+               if (len+begin < off) {
+                       begin += len;
+                       len = 0;
+               }
+       }
+       *eof = 1;
+done:
+       if (off >= len+begin)
+               return 0;
+       *start = page + (begin-off);
+       return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+       printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+}
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+__initfunc(int rs_8xx_init(void))
+{
+       struct serial_state * state;
+       ser_info_t      *info;
+       uint            mem_addr, dp_addr;
+       int             i, j;
+       ushort          chan;
+       volatile        cbd_t           *bdp;
+       volatile        cpm8xx_t        *cp;
+       volatile        smc_t           *sp;
+       volatile        smc_uart_t      *up;
+       
+       init_bh(SERIAL_BH, do_serial_bh);
+#if 0
+       timer_table[RS_TIMER].fn = rs_8xx_timer;
+       timer_table[RS_TIMER].expires = 0;
+#endif
+
+       show_serial_version();
+
+       /* Initialize the tty_driver structure */
+       
+       memset(&serial_driver, 0, sizeof(struct tty_driver));
+       serial_driver.magic = TTY_DRIVER_MAGIC;
+       serial_driver.driver_name = "serial";
+       serial_driver.name = "ttyS";
+       serial_driver.major = TTY_MAJOR;
+       serial_driver.minor_start = 64;
+       serial_driver.num = NR_PORTS;
+       serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver.subtype = SERIAL_TYPE_NORMAL;
+       serial_driver.init_termios = tty_std_termios;
+       serial_driver.init_termios.c_cflag =
+               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver.flags = TTY_DRIVER_REAL_RAW;
+       serial_driver.refcount = &serial_refcount;
+       serial_driver.table = serial_table;
+       serial_driver.termios = serial_termios;
+       serial_driver.termios_locked = serial_termios_locked;
+
+       serial_driver.open = rs_8xx_open;
+       serial_driver.close = rs_8xx_close;
+       serial_driver.write = rs_8xx_write;
+       serial_driver.put_char = rs_8xx_put_char;
+       serial_driver.write_room = rs_8xx_write_room;
+       serial_driver.chars_in_buffer = rs_8xx_chars_in_buffer;
+       serial_driver.flush_buffer = rs_8xx_flush_buffer;
+       serial_driver.ioctl = rs_8xx_ioctl;
+       serial_driver.throttle = rs_8xx_throttle;
+       serial_driver.unthrottle = rs_8xx_unthrottle;
+       serial_driver.send_xchar = rs_8xx_send_xchar;
+       serial_driver.set_termios = rs_8xx_set_termios;
+       serial_driver.stop = rs_8xx_stop;
+       serial_driver.start = rs_8xx_start;
+       serial_driver.hangup = rs_8xx_hangup;
+       serial_driver.wait_until_sent = rs_8xx_wait_until_sent;
+       serial_driver.read_proc = rs_8xx_read_proc;
+       
+       /*
+        * The callout device is just like normal device except for
+        * major number and the subtype code.
+        */
+       callout_driver = serial_driver;
+       callout_driver.name = "cua";
+       callout_driver.major = TTYAUX_MAJOR;
+       callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+       callout_driver.read_proc = 0;
+       callout_driver.proc_entry = 0;
+
+       if (tty_register_driver(&serial_driver))
+               panic("Couldn't register serial driver\n");
+       if (tty_register_driver(&callout_driver))
+               panic("Couldn't register callout driver\n");
+       
+       cp = cpmp;      /* Get pointer to Communication Processor */
+
+       /* Configure SMCs Tx/Rx instead of port B parallel I/O.
+       */
+       cp->cp_pbpar |= 0x00000cc0;
+       cp->cp_pbdir &= ~0x00000cc0;
+       cp->cp_pbodr &= ~0x00000cc0;
+
+       /* Wire BRG1 to SMC1 and BRG2 to SMC2.
+       */
+       cp->cp_simode = 0x10000000;
+
+       for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+               state->magic = SSTATE_MAGIC;
+               state->line = i;
+               state->type = PORT_UNKNOWN;
+               state->custom_divisor = 0;
+               state->close_delay = 5*HZ/10;
+               state->closing_wait = 30*HZ;
+               state->callout_termios = callout_driver.init_termios;
+               state->normal_termios = serial_driver.init_termios;
+               state->icount.cts = state->icount.dsr = 
+                       state->icount.rng = state->icount.dcd = 0;
+               state->icount.rx = state->icount.tx = 0;
+               state->icount.frame = state->icount.parity = 0;
+               state->icount.overrun = state->icount.brk = 0;
+               printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n",
+                      i, state->port,
+                      (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC");
+#ifdef CONFIG_SERIAL_CONSOLE
+               /* If we just printed the message on the console port, and
+                * we are about to initialize it for general use, we have
+                * to wait a couple of character times for the CR/NL to
+                * make it out of the transmit buffer.
+                */
+               if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                       udelay(2000);
+#endif
+               info = kmalloc(sizeof(ser_info_t), GFP_KERNEL);
+               if (info) {
+                       memset(info, 0, sizeof(ser_info_t));
+                       info->magic = SERIAL_MAGIC;
+                       info->flags = state->flags;
+                       info->tqueue.routine = do_softint;
+                       info->tqueue.data = info;
+                       info->tqueue_hangup.routine = do_serial_hangup;
+                       info->tqueue_hangup.data = info;
+                       info->line = i;
+                       info->state = state;
+                       state->info = (struct async_struct *)info;
+
+                       /* Right now, assume we are using SMCs.
+                       */
+                       sp = &cp->cp_smc[state->smc_scc_num];
+
+                       up = (smc_uart_t *)&cp->cp_dparam[state->port];
+
+                       /* We need to allocate a transmit and receive buffer
+                        * descriptors from dual port ram, and a character
+                        * buffer area from host mem.
+                        */
+                       dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO);
+
+                       /* Allocate space for FIFOs in the host memory.
+                       */
+                       mem_addr = mbx_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE);
+
+                       /* Set the physical address of the host memory
+                        * buffers in the buffer descriptors, and the
+                        * virtual address for us to work with.
+                        */
+                       bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
+                       up->smc_rbase = dp_addr;
+                       info->rx_cur = info->rx_bd_base = (cbd_t *)bdp;
+
+                       for (j=0; j<(RX_NUM_FIFO-1); j++) {
+                               bdp->cbd_bufaddr = __pa(mem_addr);
+                               bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
+                               mem_addr += RX_BUF_SIZE;
+                               bdp++;
+                       }
+                       bdp->cbd_bufaddr = __pa(mem_addr);
+                       bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+
+                       dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO);
+
+                       /* Allocate space for FIFOs in the host memory.
+                       */
+                       mem_addr = mbx_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE);
+
+                       /* Set the physical address of the host memory
+                        * buffers in the buffer descriptors, and the
+                        * virtual address for us to work with.
+                        */
+                       bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
+                       up->smc_tbase = dp_addr;
+                       info->tx_cur = info->tx_bd_base = (cbd_t *)bdp;
+
+                       for (j=0; j<(TX_NUM_FIFO-1); j++) {
+                               bdp->cbd_bufaddr = __pa(mem_addr);
+                               bdp->cbd_sc = BD_SC_INTRPT;
+                               mem_addr += TX_BUF_SIZE;
+                               bdp++;
+                       }
+                       bdp->cbd_bufaddr = __pa(mem_addr);
+                       bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
+
+                       /* Set up the uart parameters in the parameter ram.
+                       */
+                       up->smc_rfcr = SMC_EB;
+                       up->smc_tfcr = SMC_EB;
+
+                       /* Set this to 1 for now, so we get single character
+                        * interrupts.  Using idle charater time requires
+                        * some additional tuning.
+                        */
+                       up->smc_mrblr = 1;      /* receive buffer length */
+                       up->smc_maxidl = 0;     /* wait forever for next char */
+                       up->smc_brkcr = 1;      /* number of break chars */
+
+                       /* Send the CPM an initialize command.
+                       */
+                       if (state->smc_scc_num == 0)
+                               chan = CPM_CR_CH_SMC1;
+                       else
+                               chan = CPM_CR_CH_SMC2;
+                       cp->cp_cpcr = mk_cr_cmd(chan,
+                                               CPM_CR_INIT_TRX) | CPM_CR_FLG;
+                       while (cp->cp_cpcr & CPM_CR_FLG);
+
+                       /* Set UART mode, 8 bit, no parity, one stop.
+                        * Enable receive and transmit.
+                        */
+                       sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+                       /* Disable all interrupts and clear all pending
+                        * events.
+                        */
+                       sp->smc_smcm = 0;
+                       sp->smc_smce = 0xff;
+
+                       /* Install interrupt handler.
+                       */
+                       cpm_install_handler(state->irq, rs_8xx_interrupt, info);
+
+                       /* Set up the baud rate generator.
+                       */
+                       mbx_cpm_setbrg(state->smc_scc_num, 9600);
+
+                       /* If the port is the console, enable Rx and Tx.
+                       */
+#ifdef CONFIG_SERIAL_CONSOLE
+                       if (i == CONFIG_SERIAL_CONSOLE_PORT)
+                               sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+#endif
+               }
+       }
+       return 0;
+}
+
+/*
+ * The serial console driver used during boot.  Note that these names
+ * clash with those found in "serial.c", so we currently can't support
+ * the 16xxx uarts and these at the same time.  I will fix this to become
+ * an indirect function call from tty_io.c (or something).
+ */
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/*
+ * Print a string to the serial port trying not to disturb any possible
+ * real use of the port...
+ */
+static void serial_console_write(struct console *c, const char *s,
+                               unsigned count)
+{
+       struct          serial_state    *ser;
+       ser_info_t                      *info;
+       unsigned                        i;
+       volatile        cbd_t           *bdp, *bdbase;
+       volatile        smc_uart_t      *up;
+       volatile        u_char          *cp;
+
+       ser = rs_table + c->index;
+
+       /* If the port has been initialized for general use, we have
+        * to use the buffer descriptors allocated there.  Otherwise,
+        * we simply use the single buffer allocated.
+        */
+       if ((info = (ser_info_t *)ser->info) != NULL) {
+               bdp = info->tx_cur;
+               bdbase = info->tx_bd_base;
+       }
+       else {
+               /* Pointer to UART in parameter ram.
+               */
+               up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
+
+               /* Get the address of the host memory buffer.
+                */
+               bdp = bdbase = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
+       }
+
+       /*
+        * We need to gracefully shut down the transmitter, disable
+        * interrupts, then send our bytes out.
+        */
+
+       /*
+        * Now, do each character.  This is not as bad as it looks
+        * since this is a holding FIFO and not a transmitting FIFO.
+        * We could add the complexity of filling the entire transmit
+        * buffer, but we would just wait longer between accesses......
+        */
+       for (i = 0; i < count; i++, s++) {
+
+               /* Wait for transmitter fifo to empty.
+                * Ready indicates output is ready, and xmt is doing
+                * that, not that it is ready for us to send.
+                */
+               while (bdp->cbd_sc & BD_SC_READY);
+
+               /* Send the character out. */
+               cp = __va(bdp->cbd_bufaddr);
+               *cp = *s;
+               bdp->cbd_datlen = 1;
+               bdp->cbd_sc |= BD_SC_READY;
+
+               if (bdp->cbd_sc & BD_SC_WRAP)
+                       bdp = bdbase;
+               else
+                       bdp++;
+
+               /* if a LF, also do CR... */
+               if (*s == 10) {
+                       while (bdp->cbd_sc & BD_SC_READY);
+                       cp = __va(bdp->cbd_bufaddr);
+                       *cp = 13;
+                       bdp->cbd_datlen = 1;
+                       bdp->cbd_sc |= BD_SC_READY;
+
+                       if (bdp->cbd_sc & BD_SC_WRAP) {
+                               bdp = bdbase;
+                       }
+                       else {
+                               bdp++;
+                       }
+               }
+       }
+
+       /*
+        * Finally, Wait for transmitter & holding register to empty
+        *  and restore the IER
+        */
+       while (bdp->cbd_sc & BD_SC_READY);
+
+       if (info)
+               info->tx_cur = (cbd_t *)bdp;
+}
+
+/*
+ * Receive character from the serial port.  This only works well
+ * before the port is initialize for real use.
+ */
+static int serial_console_wait_key(struct console *co)
+{
+       struct serial_state             *ser;
+       u_char                          c, *cp;
+       ser_info_t                      *info;
+       volatile        cbd_t           *bdp;
+       volatile        smc_uart_t      *up;
+
+       ser = rs_table + co->index;
+
+       /* Pointer to UART in parameter ram.
+       */
+       up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
+
+       /* Get the address of the host memory buffer.
+        * If the port has been initialized for general use, we must
+        * use information from the port structure.
+        */
+       if ((info = ser->info))
+               bdp = info->rx_cur;
+       else
+               bdp = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+       /*
+        * We need to gracefully shut down the receiver, disable
+        * interrupts, then read the input.
+        */
+       while (bdp->cbd_sc & BD_SC_EMPTY);      /* Wait for a character */
+       cp = __va(bdp->cbd_bufaddr);
+
+       if (info) {
+               if (bdp->cbd_sc & BD_SC_WRAP) {
+                       bdp = info->rx_bd_base;
+               }
+               else {
+                       bdp++;
+               }
+               info->rx_cur = (cbd_t *)bdp;
+       }
+
+       c = *cp;
+       return((int)c);
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+       return MKDEV(TTYAUX_MAJOR, 64 + c->index);
+}
+
+/* This must always be called before the rs_8xx_init() function, otherwise
+ * it blows away the port control information.
+*/
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+       struct          serial_state *ser;
+       uint            mem_addr, dp_addr;
+       volatile        cbd_t           *bdp;
+       volatile        cpm8xx_t        *cp;
+       volatile        smc_t           *sp;
+       volatile        smc_uart_t      *up;
+
+       co->cflag = CREAD|CLOCAL|B9600|CS8;
+
+       ser = rs_table + co->index;
+
+       cp = cpmp;      /* Get pointer to Communication Processor */
+
+       /* Right now, assume we are using SMCs.
+       */
+       sp = &cp->cp_smc[ser->smc_scc_num];
+
+       /* When we get here, the CPM has been reset, so we need
+        * to configure the port.
+        * We need to allocate a transmit and receive buffer descriptor
+        * from dual port ram, and a character buffer area from host mem.
+        */
+       up = (smc_uart_t *)&cp->cp_dparam[ser->port];
+       cp->cp_pbpar = 0x00c0;  /* Enable SMC1 instead of Port B I/O */
+
+       /* Allocate space for two buffer descriptors in the DP ram.
+       */
+       dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * 2);
+
+       /* Allocate space for two 2 byte FIFOs in the host memory.
+       */
+       mem_addr = mbx_cpm_hostalloc(4);
+
+       /* Set the physical address of the host memory buffers in
+        * the buffer descriptors.
+        */
+       bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
+       bdp->cbd_bufaddr = __pa(mem_addr);
+       (bdp+1)->cbd_bufaddr = __pa(mem_addr+2);
+
+       /* For the receive, set empty and wrap.
+        * For transmit, set wrap.
+        */
+       bdp->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+       (bdp+1)->cbd_sc = BD_SC_WRAP;
+
+       /* Set up the uart parameters in the parameter ram.
+       */
+       up->smc_rbase = dp_addr;        /* Base of receive buffer desc. */
+       up->smc_tbase = dp_addr+sizeof(cbd_t);  /* Base of xmt buffer desc. */
+       up->smc_rfcr = SMC_EB;
+       up->smc_tfcr = SMC_EB;
+
+       /* Set this to 1 for now, so we get single character interrupts.
+       */
+       up->smc_mrblr = 1;              /* receive buffer length */
+       up->smc_maxidl = 0;             /* wait forever for next char */
+
+       /* Send the CPM an initialize command.
+       */
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+       while (cp->cp_cpcr & CPM_CR_FLG);
+
+       /* Set UART mode, 8 bit, no parity, one stop.
+        * Enable receive and transmit.
+        */
+       sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+       /* Set up the baud rate generator.
+       */
+       mbx_cpm_setbrg(ser->smc_scc_num, 9600);
+       /* And finally, enable Rx and Tx.
+       */
+       sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+       return 0;
+}
+
+static struct console sercons = {
+       "ttyS",
+       serial_console_write,
+       NULL,
+       serial_console_device,
+       serial_console_wait_key,
+       NULL,
+       serial_console_setup,
+       CON_PRINTBUFFER,
+       CONFIG_SERIAL_CONSOLE_PORT,
+       0,
+       NULL
+};
+
+/*
+ *     Register console.
+ */
+__initfunc (long console_8xx_init(long kmem_start, long kmem_end))
+{
+       register_console(&sercons);
+       return kmem_start;
+}
+
+#endif
index 832513c8dfd7b79a0da0f738c72f142626448099..cd81e45a4f7c26575d179e56988039321a38b8e4 100644 (file)
 # Rewritten by Cort Dougan and Paul Mackerras
 #
 
-ifdef CONFIG_CHRP
-# XXX for now
-KERNELBASE     =0x90000000
-KERNELLOAD     =0x90010000
-else
-KERNELBASE     =0xc0000000 
-KERNELLOAD     =0xc0000000 
-endif
+KERNELLOAD     =0xc0000000
 
 # PowerPC (cross) tools
 ifneq ($(shell uname -m),ppc)
@@ -32,21 +25,13 @@ ASFLAGS             =
 LINKFLAGS      = -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
 CFLAGSINC      = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
 CFLAGS         := $(CFLAGS) -D__powerpc__ -fsigned-char -msoft-float -pipe \
-               -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring \
-               -DKERNELBASE=$(KERNELBASE)
+               -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring
 CPP            = $(CC) -E $(CFLAGS)
 
-ifdef CONFIG_601
-CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
+ifdef CONFIG_8xx
+CFLAGS := $(CFLAGS) -mcpu=860
 endif
 
-ifdef CONFIG_603
-CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
-endif
-
-ifdef CONFIG_604
-CFLAGS := $(CFLAGS) -mcpu=604 -DCPU=604
-endif
 
 HEAD := arch/ppc/kernel/head.o
 
@@ -64,6 +49,11 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 MAKECOFFBOOT = $(MAKE) -C arch/$(ARCH)/coffboot
 MAKECHRPBOOT = $(MAKE) -C arch/$(ARCH)/chrpboot
 
+ifdef CONFIG_8xx
+SUBDIRS += arch/ppc/8xx_io
+DRIVERS += arch/ppc/8xx_io/8xx_io.a drivers/net/net.a
+endif
+
 checks:
        @$(MAKE) -C arch/$(ARCH)/kernel checks
 
@@ -83,6 +73,19 @@ prep_config:
        rm -f .config arch/ppc/defconfig
        ln -s prep_defconfig arch/ppc/defconfig
 
+chrp_config:
+       rm -f .config arch/ppc/defconfig
+       ln -s chrp_defconfig arch/ppc/defconfig
+
+common_config:
+       rm -f .config arch/ppc/common_defconfig
+       ln -s common_defconfig arch/ppc/defconfig
+
+mbx_config:
+       rm -f .config arch/ppc/defconfig
+       ln -s mbx_defconfig arch/ppc/defconfig
+
+
 tags:
        etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
 
index 02f95f577a7c3c1ee7dc5b5bf394c8d929708aa6..84be805b2edd3d2a7d286d6939949a072f36502b 100644 (file)
@@ -25,31 +25,70 @@ ZOFF = 0
 ZSZ = 0
 IOFF = 0
 ISZ = 0
+ifeq ($(CONFIG_MBX),y)
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
+else
 #ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
 ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00600000
+endif
 GZIP_FLAGS = -v9
 
-OBJECTS := head.o misc.o vreset.o kbd.o ../coffboot/zlib.o # inflate.o unzip.o
-#OBJECTS := crt0.o start.o vreset.o
+OBJECTS := head.o misc.o ../coffboot/zlib.o # inflate.o unzip.o
 CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
 
+ifeq ($(CONFIG_MBX),y)
+OBJECTS += mbxtty.o
+CFLAGS += -DCONFIG_MBX
+else
+OBJECTS += vreset.o kbd.o
+endif
+
 all:   zImage
 
+ifeq ($(CONFIG_ALL_PPC),y)
+CONFIG_PREP = y
+endif
 
 ifeq ($(CONFIG_PREP),y)
-mkprep : mkprep.c
-       $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c
+zvmlinux.initrd: zvmlinux
+       $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section=initrd=ramdisk.image.gz \
+               --add-section=image=../coffboot/vmlinux.gz \
+               zvmlinux.initrd.tmp zvmlinux.initrd
+       $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset zvmlinux.initrd initrd` \
+               -DINITRD_SIZE=`sh size zvmlinux.initrd initrd` \
+               -DZIMAGE_OFFSET=`sh offset zvmlinux.initrd image` \
+               -DZIMAGE_SIZE=`sh size zvmlinux.initrd image` \
+               -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
+       $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
+       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section=initrd=ramdisk.image.gz \
+               --add-section=image=../coffboot/vmlinux.gz \
+               zvmlinux.initrd.tmp $@
+       rm zvmlinux.initrd.tmp
 
-floppy: $(TOPDIR)/vmlinux zImage
-       dd if=zImage of=/dev/fd0H1440 bs=64b
+else
+zvmlinux.initrd:
+endif
 
-znetboot : zImage
-       cp zImage /tftpboot/zImage.prep
+zImage: zvmlinux mkprep
+ifeq ($(CONFIG_PREP),y)
+       ./mkprep -pbp zvmlinux zImage
+endif
+ifeq ($(CONFIG_MBX),y)
+       ln -sf zvmlinux zImage
+endif
 
-znetboot.initrd : zImage.initrd
-       cp zImage.initrd /tftpboot/zImage.prep
+zImage.initrd: zvmlinux.initrd mkprep
+ifeq ($(CONFIG_PREP),y)
+       ./mkprep -pbp zvmlinux.initrd zImage.initrd
+endif
+ifeq ($(CONFIG_MBX),y)
+       ln -sf zvmlinux.initrd zImage.initrd
+endif
 
 zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
 #
@@ -63,61 +102,39 @@ zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
 # then with the offset rebuild the bootloader so we know where the kernel is
 #
        $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
-               -DZIMAGE_OFFSET=`./offset zvmlinux image` \
-               -DZIMAGE_SIZE=`./size zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
+               -DZIMAGE_OFFSET=`sh offset zvmlinux image` \
+               -DZIMAGE_SIZE=`sh size zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
                -c -o misc.o misc.c
        $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
        $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
                zvmlinux.tmp $@
        rm zvmlinux.tmp
 
-zvmlinux.initrd: zvmlinux
-       $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
-       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section=initrd=ramdisk.image.gz \
-               --add-section=image=../coffboot/vmlinux.gz \
-               zvmlinux.initrd.tmp zvmlinux.initrd
-       $(CC) $(CFLAGS) -DINITRD_OFFSET=`./offset zvmlinux.initrd initrd` \
-               -DINITRD_SIZE=`./size zvmlinux.initrd initrd` \
-               -DZIMAGE_OFFSET=`./offset zvmlinux.initrd image` \
-               -DZIMAGE_SIZE=`./size zvmlinux.initrd image` \
-               -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
-       $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
-       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section=initrd=ramdisk.image.gz \
-               --add-section=image=../coffboot/vmlinux.gz \
-               zvmlinux.initrd.tmp $@
-       rm zvmlinux.initrd.tmp
-
-zImage: zvmlinux mkprep
-       ./mkprep -pbp zvmlinux zImage
-
-zImage.initrd: zvmlinux.initrd mkprep
-       ./mkprep -pbp zvmlinux.initrd zImage.initrd
-else
-mkprep:
-
-floppy:
-
-znetboot:
-
-znetboot.initrd:
-
-zvmlinux:
-
-zvmlinux.initrd:
-
-zImage:
-
-zImage.initrd:
+floppy: $(TOPDIR)/vmlinux zImage
+ifeq ($(CONFIG_PREP),y)
+       dd if=zImage of=/dev/fd0H1440 bs=64b
 endif
 
+mkprep : mkprep.c
+ifeq ($(CONFIG_PREP),y)
+       $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c
+endif
 
+znetboot : zImage
+ifeq ($(CONFIG_PREP),y)
+       cp zImage /tftpboot/zImage.prep
+endif
+ifeq ($(CONFIG_MBX),y)
+       cp zImage /tftpboot/zImage.mbx
+endif
 
-# just here to match coffboot/Makefile
-vmlinux.coff:
-
-vmlinux.coff.initrd:
+znetboot.initrd : zImage.initrd
+ifeq ($(CONFIG_PREP),y)
+       cp zImage.initrd /tftpboot/zImage.prep
+endif
+ifeq ($(CONFIG_MBX),y)
+       cp zImage.initrd /tftpboot/zImage.mbx
+endif
 
 clean:
        rm -f vmlinux* zvmlinux* mkprep zImage*
@@ -128,3 +145,7 @@ fastdep:
 dep:
        $(CPP) -M *.S *.c > .depend
 
+# just here to match coffboot/Makefile
+vmlinux.coff:
+
+vmlinux.coff.initrd:
index ff003015441acc9aa2529a93087372815267f898..e66f9445ae150e1df78433bc2631e8c90c858aca 100644 (file)
@@ -1,19 +1,42 @@
 #include "../kernel/ppc_defs.h"
 #include "../kernel/ppc_asm.tmpl"
 #include <asm/processor.h>
+#include <asm/cache.h>
 
        .text
 
 /*
  * This code is loaded by the ROM loader at some arbitrary location.
  * Move it to high memory so that it can load the kernel at 0x0000.
+ *
+ * The MBX EPPC-Bug understands ELF, so it loads us into the location
+ * specified in the header.  This is a two step process.  First, EPPC-Bug
+ * loads the file into the intermediate buffer memory location specified
+ * by the environment parameters.  When it discovers this is an ELF
+ * binary, it relocates to the link address for us.  Unfortunately, the
+ * header does not move with the file, so we have to find the
+ * intermediate load location and read the header from there.  From
+ * information provided by Motorola (thank you), we know this intermediate
+ * location can be found from the NVRAM environment.
+ * All of these addresses must be somewhat carefully chosen to make sure
+ * we don't overlap the regions.  I chose to load the kernel at 0, the
+ * compressed image loads at 0x00100000, and the MBX intermediate buffer
+ * was set to 0x00200000.  Provided the loaded kernel image never grows
+ * over one megabyte (which I am going to ensure never happens :-), these
+ * will work fine.  When we get called from EPPC-Bug, registers are:
+ *              R1 - Stack pointer at a high memory address.
+ *              R3 - Pointer to Board Information Block.
+ *              R4 - Pointer to argument string.
+ *              Interrupts masked, cache and MMU disabled.
  */
 
        .globl  start
 start:
        bl      start_
 start_:
-       mr      r11,r3          /* Save pointer to residual data */
+       mr      r11,r3          /* Save pointer to residual/board data */
+       
+#ifndef CONFIG_MBX
        mfmsr   r3              /* Turn off interrupts */
        li      r4,0
        ori     r4,r4,MSR_EE
@@ -33,7 +56,6 @@ start_:
        bne     00b
        mflr    r21
        mfctr   r22
-       bl      flush_instruction_cache
        mtlr    r21
        mtctr   r22
        bctr                    /* Jump to code */
@@ -70,6 +92,8 @@ relocate:
        mtlr    r3                      /* Easiest way to do an absolute jump */
        blr
 start_ldr:     
+#endif /* ndef CONFIG_MBX */
+       
 /* Clear all of BSS */
        lis     r3,edata@h
        ori     r3,r3,edata@l
@@ -89,12 +113,21 @@ start_ldr:
        li      r2,0x000F               /* Mask pointer to 16-byte boundary */
        andc    r1,r1,r2
 /* Run loader */
+#ifdef CONFIG_MBX
+        bl      serial_init             /* Init MBX serial port */
+#define ILAP_ADDRESS    0xfa000020
+        lis     r8, ILAP_ADDRESS@h
+        lwz     r8, ILAP_ADDRESS@l(r8)
+       li      r9,end@h
+       ori     r9,r9,end@l
+       sub     r7,r8,r9
+        addis   r8, r8, 1               /* Add 64K */
+#endif 
        mr      r3,r8                   /* Load point */
        mr      r4,r7                   /* Program length */
        mr      r5,r6                   /* Checksum */
        mr      r6,r11                  /* Residual data */
        bl      decompress_kernel
-       
        /* changed to use r3 (as firmware does) for kernel
           as ptr to residual -- Cort*/
        lis     r6,cmd_line@h
@@ -111,45 +144,25 @@ start_ldr:
        lis     r2,initrd_end@h
        ori     r2,r2,initrd_end@l
        lwz     r5,0(r2)
-               
-       li      r9,0x00c                /* Kernel code starts here */
+       
+       /* tell kernel we're prep */
+       /* 
+        * get start address of kernel code which is stored as a coff
+        * entry.  see boot/head.S -- Cort 
+        */
+       li      r9,0x0
+       lwz     r9,0(r9)
        mtlr    r9
+#ifndef CONFIG_MBX
+       li      r9,0
+       lis     r10,0xdeadc0de@h
+       ori     r10,r10,0xdeadc0de@l
+       stw     r10,0(r9)
+#endif
        blr     
 hang:
        b       hang    
 
-       .globl  _get_SP
-_get_SP:
-       mr      r3,r1
-       blr
-
-       .globl  _get_PVR
-_get_PVR:
-       mfspr   r3,PVR
-       blr
-
-       .globl  _get_MSR
-_get_MSR:
-       mfmsr   r3
-       blr
-
-       .globl  _put_MSR
-_put_MSR:
-       sync
-       mtmsr   r3
-       blr
-
-       .globl  _get_HID0
-_get_HID0:
-       mfspr   r3,HID0
-       blr
-       
-       .globl  _put_HID0
-_put_HID0:
-       sync
-       mtspr   HID0,r3
-       blr
-
 /*
  * Delay for a number of microseconds
  * -- Use the BUS timer (assumes 66MHz)
@@ -189,98 +202,4 @@ udelay:
        blt     2b
 3:     blr             
        
-/*
- * 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.
- */
-#define NUM_CACHE_LINES 128*8
-#define CACHE_LINE_SIZE 32 
-#if 0
-cache_flush_buffer:
-       .space  NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
-#else
-#define cache_flush_buffer 0x1000
-#endif
-
-
-/*
- * Flush instruction cache
- * *** I'm really paranoid here!
- */
-_GLOBAL(flush_instruction_cache)
-       mflr    r5
-       bl      flush_data_cache
-       mfspr   r3,HID0 /* Caches are controlled by this register */
-       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
-
-/*
- * Flush data cache
- * *** I'm really paranoid here!
- */
-_GLOBAL(flush_data_cache)
-       lis     r3,cache_flush_buffer@h
-       ori     r3,r3,cache_flush_buffer@l
-       li      r4,NUM_CACHE_LINES
-       mtctr   r4
-#if 0
-00:    dcbz    0,r3                    /* Flush cache line with minimal BUS traffic */
-#else
-00:    lwz     r4,0(r3)
-#endif
-       addi    r3,r3,CACHE_LINE_SIZE   /* Next line, please */
-       bdnz    00b     
-10:    blr
-
-/*
- * 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)
- */
-_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
-       blr
-
-/*
- * Execute a [foreign] function
- *
- * run(p1, p2, cp, ep, entry)
- *
- */
-       .globl  run
-run:
-       mtctr   r7                      /* Entry point */
-#define IS_PreP 0x50726550             /* 'PreP' */    
-       lis     r30,IS_PreP>>16
-       ori     r30,r30,IS_PreP&0xFFFF
-       mr      11,r5
-       mr      12,r6
-       mr      r28,r5
-       mr      r29,r6
-       mr      11,r5
-       mr      12,r6
-       bctr
-
        .comm   .stack,4096*2,4
diff --git a/arch/ppc/boot/mbxtty.c b/arch/ppc/boot/mbxtty.c
new file mode 100644 (file)
index 0000000..ee6c59c
--- /dev/null
@@ -0,0 +1,118 @@
+
+
+/* Minimal serial functions needed to send messages out the serial
+ * port on the MBX console.
+ *
+ * The MBX uxes SMC1 for the serial port.  We reset the port and use
+ * only the first BD that EPPC-Bug set up as a character FIFO.
+ *
+ * It's a big hack, but I don't have time right now....I want a kernel
+ * that boots.
+ */
+#include <linux/types.h>
+#include <asm/mbx.h>
+#include "../8xx_io/commproc.h"
+
+#define CPM_CPCR       ((volatile ushort *)0xfa2009c0)
+#define SMC1_MODE      ((volatile ushort *)0xfa200a82)
+#define SMC1_TBDF      ((volatile bd_t *)0xfa202c90)
+#define SMC1_RBDF      ((volatile bd_t *)0xfa202c10)
+
+static cpm8xx_t        *cpmp = (cpm8xx_t *)&(((immap_t *)MBX_IMAP_ADDR)->im_cpm);
+
+void
+serial_init(void)
+{
+       volatile smc_t          *sp;
+       volatile smc_uart_t     *up;
+       volatile cbd_t  *tbdf, *rbdf;
+       volatile cpm8xx_t       *cp;
+
+       cp = cpmp;
+       sp = (smc_t*)&(cp->cp_smc[0]);
+       up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
+
+       /* Disable transmitter/receiver.
+       */
+       sp->smc_smcm &= ~(SMCMR_REN | SMCMR_TEN);
+
+       tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase];
+       rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase];
+
+       /* Issue a stop transmit, and wait for it.
+       */
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_STOP_TX) | CPM_CR_FLG;
+       while (cp->cp_cpcr & CPM_CR_FLG);
+
+       /* Make the first buffer the only buffer.
+       */
+       tbdf->cbd_sc |= BD_SC_WRAP;
+       rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+       /* Single character receive.
+       */
+       up->smc_mrblr = 1;
+       up->smc_maxidl = 0;
+
+       /* Initialize Tx/Rx parameters.
+       */
+       cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+       while (cp->cp_cpcr & CPM_CR_FLG);
+
+       /* Enable transmitter/receiver.
+       */
+       sp->smc_smcm |= SMCMR_REN | SMCMR_TEN;
+}
+
+void
+serial_putchar(const char c)
+{
+       volatile cbd_t          *tbdf;
+       volatile char           *buf;
+       volatile smc_uart_t     *up;
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+       tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
+
+       /* Wait for last character to go.
+       */
+       buf = (char *)tbdf->cbd_bufaddr;
+       while (tbdf->cbd_sc & BD_SC_READY);
+
+       *buf = c;
+       tbdf->cbd_datlen = 1;
+       tbdf->cbd_sc |= BD_SC_READY;
+}
+
+char
+serial_getc()
+{
+       volatile cbd_t          *rbdf;
+       volatile char           *buf;
+       volatile smc_uart_t     *up;
+       char                    c;
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+       /* Wait for character to show up.
+       */
+       buf = (char *)rbdf->cbd_bufaddr;
+       while (rbdf->cbd_sc & BD_SC_EMPTY);
+       c = *buf;
+       rbdf->cbd_sc |= BD_SC_EMPTY;
+
+       return(c);
+}
+
+int
+serial_tstc()
+{
+       volatile cbd_t          *rbdf;
+       volatile smc_uart_t     *up;
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+       return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
index bc6aa088f283edd35bd6db57d8c2f5aab487ac93..33c7c3e0da718272213a41d225d48e8c5efe6635 100644 (file)
@@ -4,25 +4,35 @@
  * Adapted for PowerPC by Gary Thomas
  *
  * Rewritten by Cort Dougan (cort@cs.nmt.edu)
- * Soon to be replaced by a single bootloader for chrp/prep/pmac. -- Cort
+ * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort
  */
 
 #include "../coffboot/zlib.h"
 #include "asm/residual.h"
 #include <elf.h>
+#include <linux/config.h>
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+bd_t   hold_board_info;
+#endif
 
 /* this is where the INITRD gets moved to for safe keeping */
-#define INITRD_DESTINATION /*0x00f00000*/ 0x01f00000
+#define INITRD_DESTINATION /*0x00f00000*/ 0x01800000
+#ifdef CONFIG_8xx
+char *avail_ram = (char *) 0x00200000;
+char *end_avail = (char *) 0x00400000;
+#else /* CONFIG_8xx */
 /* this will do for now - Cort */
 char *avail_ram = (char *) 0x00800000; /* start with 8M */
 /* assume 15M max since this is where we copy the initrd to -- Cort */
 char *end_avail = (char *) INITRD_DESTINATION; 
+#endif /* CONFIG_8xx */
 
+char cmd_line[256];
 RESIDUAL hold_residual;
 unsigned long initrd_start = 0, initrd_end = 0;
 char *zimage_start;
 int zimage_size;
-char cmd_line[256];
 
 char *vidmem = (char *)0xC00B8000;
 int lines, cols;
@@ -47,6 +57,7 @@ void exit()
        while(1); 
 }
 
+#ifndef CONFIG_MBX
 static void clear_screen()
 {
        int i, j;
@@ -144,6 +155,39 @@ void puts(const char *s)
        orig_x = x;
        orig_y = y;
 }
+#else
+/* The MBX is just the serial port.
+*/
+tstc(void)
+{
+        return (serial_tstc());
+}
+
+getc(void)
+{
+        while (1) {
+                if (serial_tstc()) return (serial_getc());
+        }
+}
+
+void 
+putc(const char c)
+{
+        serial_putchar(c);
+}
+
+void puts(const char *s)
+{
+        char c;
+
+        while ( ( c = *s++ ) != '\0' ) {
+                serial_putchar(c);
+                if ( c == '\n' )
+                        serial_putchar('\r');
+        }
+}
+
+#endif /* CONFIG_MBX */
 
 void * memcpy(void * __dest, __const void * __src,
                            int __n)
@@ -253,6 +297,8 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
        inflateEnd(&s);
 }
 
+unsigned char sanity[0x2000];
+
 unsigned long
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
 {
@@ -260,31 +306,60 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
        extern unsigned long start;
        char *cp, ch;
        unsigned long i;
-       
-       
+
        lines = 25;
        cols = 80;
        orig_x = 0;
        orig_y = 24;
        
        
-       /* Turn off MMU.  Since we are mapped 1-1, this is OK. */
-       flush_instruction_cache();
-       _put_HID0(_get_HID0() & ~0x0000C000);
-       _put_MSR(_get_MSR() & ~0x0030);
-
+#ifndef CONFIG_8xx
        vga_init(0xC0000000);
-       /*clear_screen();*/
+       /* copy the residual data */
+       if (residual)
+               memcpy(&hold_residual,residual,sizeof(RESIDUAL));
+#endif /* CONFIG_8xx */
+#ifdef CONFIG_MBX      
+       /* copy board data */
+       if (residual)
+               _bcopy((char *)residual, (char *)&hold_board_info,
+                      sizeof(hold_board_info));
+#endif /* CONFIG_8xx */
+       
 
-       puts("loaded at:    "); puthex(load_addr);
+       puts("loaded at:     "); puthex(load_addr);
        puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
-       
-       puts("relocated to: "); puthex((unsigned long)&start);
+       puts("relocated to:  "); puthex((unsigned long)&start);
        puts(" "); puthex((unsigned long)((unsigned long)&start + (4*num_words))); puts("\n");
-       
+
+       if ( residual )
+       {
+               puts("board data at: "); puthex((unsigned long)residual);
+               puts(" ");
+#ifdef CONFIG_MBX      
+               puthex((unsigned long)((unsigned long)residual + sizeof(bd_t)));
+#else
+               puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL)));
+#endif 
+               puts("\n");
+               puts("relocated to:  ");
+#ifdef CONFIG_MBX
+               puthex((unsigned long)&hold_board_info);
+#else
+               puthex((unsigned long)&hold_residual);
+#endif
+               puts(" ");
+#ifdef CONFIG_MBX
+               puthex((unsigned long)((unsigned long)&hold_board_info + sizeof(bd_t)));
+#else
+               puthex((unsigned long)((unsigned long)&hold_residual + sizeof(RESIDUAL)));
+#endif 
+               puts("\n");
+       }
+
        zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
        zimage_size = ZIMAGE_SIZE;
-       puts("zimage at:    "); puthex((unsigned long)zimage_start);
+       puts("zimage at:     "); puthex((unsigned long)zimage_start);
        puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
 
        if ( INITRD_OFFSET )
@@ -296,18 +371,19 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
        /* relocate initrd */
        if ( initrd_start )
        {
-               puts("initrd at:    "); puthex(initrd_start);
+               puts("initrd at:     "); puthex(initrd_start);
                puts(" "); puthex(initrd_end); puts("\n");
                
                memcpy ((void *)INITRD_DESTINATION,(void *)initrd_start,
                        INITRD_SIZE );
                initrd_end = INITRD_DESTINATION + INITRD_SIZE;
                initrd_start = INITRD_DESTINATION;
-               puts("Moved initrd to: "); puthex(initrd_start);
+               puts("Moved initrd to:  "); puthex(initrd_start);
                puts(" "); puthex(initrd_end); puts("\n");
        }
-       
+#ifndef CONFIG_MBX
        CRT_tstc();  /* Forces keyboard to be initialized */
+#endif 
        puts("\nLinux/PPC load: ");
        timer = 0;
        cp = cmd_line;
@@ -339,9 +415,12 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
        if ( initrd_start > (16<<20))
                puts("initrd_start located > 16M\n");
        
-  
        puts("Uncompressing Linux...");
-       gunzip(0, 0x400000, zimage_start, &zimage_size);  
+
+       /* these _bcopy() calls are here so I can add breakpoints to the boot for mbx -- Cort */
+       /*_bcopy( (char *)0x100,(char *)&sanity, 0x2000-0x100);*/
+       gunzip(0, 0x400000, zimage_start, &zimage_size);
+       /*_bcopy( (char *)&sanity,(char *)0x100,0x2000-0x100);*/
        puts("done.\n");
        puts("Now booting the kernel\n");
        return (unsigned long)&hold_residual;
index 3bc3936c6e7b9df459c80d608efc4e1b26319804..6086372a0ae2ae9a9f9eb97301d6659dc49ff150 100644 (file)
@@ -434,16 +434,15 @@ vga_init(unsigned char *ISA_mem)
 {
        int slot;
        struct VgaRegs *VgaTextRegs;
-
+#if 0
        if ((_get_PVR()>>16) == PPC_601) {
                return(old_vga_init(ISA_mem));
        }
-
-#if 1
+#endif
+       
        /* 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...
         */
@@ -522,11 +521,6 @@ vga_init(unsigned char *ISA_mem)
        return (1);  /* 'CRT' I/O supported */
 }
 
-static int
-NOP(int x)
-{
-}
-
 /*
  * Write to VGA Attribute registers.  
  */
@@ -852,166 +846,5 @@ void printslots(void)
                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] = {
-    0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 
-    0x00, 0x4F, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x00, /*0x07, 0x80, */
-    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};
-
-#if 0
-static const unsigned char color_LUT[] =
-   {
-       0x00, 0x00, 0x00, /* 0 - black */
-       0x00, 0x00, 0x2A, /* 1 - blue */
-       0x00, 0x2A, 0x00, /* 2 - green */
-       0x00, 0x2A, 0x2A, /* 3 - cyan */
-       0x2A, 0x00, 0x00, /* 4 - red */
-       0x2A, 0x00, 0x2A, /* 5 - magenta */
-       0x2A, 0x2A, 0x00, /* 6 - brown */
-       0x2A, 0x2A, 0x2A, /* 7 - white */
-       0x00, 0x00, 0x15, /* 8 - gray */
-       0x00, 0x00, 0x3F, /* 9 - light blue */
-       0x00, 0x2A, 0x15, /* 10 - light green */
-       0x00, 0x2A, 0x3F, /* 11 - light cyan */
-       0x2A, 0x00, 0x15, /* 12 - light red */
-       0x2A, 0x00, 0x3F, /* 13 - light magenta */
-       0x2A, 0x2A, 0x15, /* 14 - yellow */
-       0x2A, 0x2A, 0x3F, /* 15 - bright white */
-   };
-#endif
-old_vga_init(unsigned char *ISA_mem)
-{
-       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;
-    
-       /* 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);
-
-#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/chrp_defconfig b/arch/ppc/chrp_defconfig
new file mode 100644 (file)
index 0000000..ccbc0f9
--- /dev/null
@@ -0,0 +1,321 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_6xx=y
+# CONFIG_8xx is not set
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+CONFIG_CHRP=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_MBX is not set
+CONFIG_MACH_SPECIFIC=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_PCI_OLD_PROC=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+# CONFIG_ABSTRACT_CONSOLE is not set
+CONFIG_PMAC_CONSOLE=y
+CONFIG_MAC_KEYBOARD=y
+# CONFIG_MAC_FLOPPY is not set
+CONFIG_MACMOUSE=y
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_XMON is not set
+CONFIG_CONTROL_VIDEO=y
+CONFIG_PLATINUM_VIDEO=y
+CONFIG_VALKYRIE_VIDEO=y
+CONFIG_ATY_VIDEO=y
+CONFIG_IMSTT_VIDEO=y
+CONFIG_CHIPS_VIDEO=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# NEW devices (io_request, all ALPHA and dangerous)
+#
+# CONFIG_IO_REQUEST is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+CONFIG_NET_ALIAS=y
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_RARP=y
+CONFIG_IP_NOSR=y
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+CONFIG_SCSI_AIC7XXX=m
+# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set
+# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_PAGE_ENABLE is not set
+CONFIG_AIC7XXX_PROC_STATS=y
+CONFIG_AIC7XXX_RESET_DELAY=15
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=10
+CONFIG_SCSI_MAC53C94=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_UFS_FS is not set
+# CONFIG_ADFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SOFTCURSOR is not set
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_MOUSE is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_VIDEO_DEV is not set
+CONFIG_NVRAM=y
+# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
index 629256eaa31d2c9556d08c65931d460e90ba93b2..05a2f85d3013b7b7cf9586d9571a548513d4b8ad 100644 (file)
@@ -16,11 +16,11 @@ void gunzip(void *, int, unsigned char *, int *);
 #define get_16be(x)    (*(unsigned short *)(x))
 #define get_32be(x)    (*(unsigned *)(x))
 
-#define RAM_START      0x90000000
-#define RAM_END                0x90800000      /* only 8M mapped with BATs */
+#define RAM_START      0x00000000
+#define RAM_END                0x00800000      /* only 8M mapped with BATs */
 
-#define RAM_FREE       0x90540000      /* after image of chrpboot */
-#define PROG_START     0x90010000
+#define RAM_FREE       0x00540000      /* after image of chrpboot */
+#define PROG_START     0x00010000
 
 char *avail_ram;
 char *end_avail;
@@ -40,7 +40,7 @@ chrpboot(int a1, int a2, void *prom)
     unsigned initrd_start, initrd_size;
     
     printf("chrpboot starting\n\r");
-    setup_bats();
+    /* setup_bats(); */
 
     if (initrd_len) {
        initrd_size = initrd_len;
index 11a612af1a391baf104155fd59ed35b6beda7f3f..b2094b9d3df4a2eac6607225ff6d7bb5184eb0a0 100644 (file)
@@ -23,10 +23,10 @@ setup_bats:
        b       5f
 4:     ori     4,4,0xff                /* set up BAT registers for 604 */
        li      5,2
-       mtdbatu 0,4
-       mtdbatl 0,5
-5:     mtibatu 0,4
-       mtibatl 0,5
+       mtdbatu 3,4
+       mtdbatl 3,5
+5:     mtibatu 3,4
+       mtibatl 3,5
        isync
        blr
 
index ab0ee6c4a5e802232cae92b64f2a309ca5eecef6..e70844b62c209f6c640e7eeb09ee44018a030d65 100644 (file)
@@ -18,9 +18,10 @@ void gunzip(void *, int, unsigned char *, int *);
 #define get_32be(x)    (*(unsigned *)(x))
 
 #define RAM_START      0xc0000000
-#define RAM_END                0xc0800000      /* only 8M mapped with BATs */
+#define PROG_START     RAM_START
+#define RAM_END                (RAM_START + 0x800000)  /* only 8M mapped with BATs */
 
-#define RAM_FREE       0xc0540000      /* after image of coffboot */
+#define RAM_FREE       (RAM_START + 0x540000)  /* after image of coffboot */
 
 char *avail_ram;
 char *end_avail;
@@ -47,7 +48,7 @@ coffboot(int a1, int a2, void *prom)
        printf("error getting load-base\n");
        exit();
     }
-    setup_bats();
+    setup_bats(RAM_START);
 
     eh = (struct external_filehdr *) loadbase;
     ns = get_16be(eh->f_nscns);
@@ -82,7 +83,7 @@ coffboot(int a1, int a2, void *prom)
        
     im = (unsigned char *)(loadbase + get_32be(isect->s_scnptr));
     len = get_32be(isect->s_size);
-    dst = (void *) RAM_START;
+    dst = (void *) PROG_START;
 
     if (im[0] == 0x1f && im[1] == 0x8b) {
        void *cp = (void *) RAM_FREE;
@@ -98,7 +99,7 @@ coffboot(int a1, int a2, void *prom)
 
     flush_cache(dst, len);
 
-    sa = *(unsigned *)dst + RAM_START;
+    sa = *(unsigned *)dst + PROG_START;
     printf("start address = 0x%x\n", sa);
 
 #if 0
index ae08ee2faebcb6cb6190eb8466f8438e593071e5..1a9f07129eb0f2500e07a74925c0bd3f7bfd6301 100644 (file)
@@ -9,24 +9,25 @@
        .text
 
 /*
- * Use the BAT0 registers to map the 1st 8MB of RAM to 0xc0000000.
+ * Use the BAT0 registers to map the 1st 8MB of RAM to
+ * the address given as the 1st argument.
  */
        .globl  setup_bats
 setup_bats:
+       mr      4,3
        mfpvr   3
        rlwinm  3,3,16,16,31            /* r3 = 1 for 601, 4 for 604 */
        cmpi    0,3,1
-       lis     4,0xc000
        bne     4f
        ori     4,4,4                   /* set up BAT registers for 601 */
        li      5,0x7f
        b       5f
 4:     ori     4,4,0xff                /* set up BAT registers for 604 */
        li      5,2
-       mtdbatu 0,4
-       mtdbatl 0,5
-5:     mtibatu 0,4
-       mtibatl 0,5
+       mtdbatu 3,4
+       mtdbatl 3,5
+5:     mtibatu 3,4
+       mtibatl 3,5
        isync
        blr
 
diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig
new file mode 100644 (file)
index 0000000..4f99831
--- /dev/null
@@ -0,0 +1,331 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_6xx=y
+# CONFIG_8xx is not set
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+# CONFIG_CHRP is not set
+CONFIG_ALL_PPC=y
+# CONFIG_MBX is not set
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_PCI_OLD_PROC=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+CONFIG_ABSTRACT_CONSOLE=y
+CONFIG_FB=y
+CONFIG_VGA_CONSOLE=y
+CONFIG_FB_COMPAT_XPMAC=y
+CONFIG_MAC_KEYBOARD=y
+CONFIG_MAC_FLOPPY=y
+CONFIG_MACMOUSE=y
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_XMON is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# NEW devices (io_request, all ALPHA and dangerous)
+#
+# CONFIG_IO_REQUEST is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_IP_ACCT=y
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_RARP=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
+CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
+CONFIG_SCSI_NCR53C8XX_SYNC=5
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MAC53C94=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+CONFIG_PPP=y
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_ADFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Frame buffer devices
+#
+CONFIG_FB_OPEN_FIRMWARE=y
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_MFB=y
+CONFIG_FBCON_CFB8=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SOFTCURSOR is not set
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
index c6ab44e7c937d264a0c432c55715f0e5f2e3b476..47bdd99871064842068f35d7e5aa3c60aa22401a 100644 (file)
@@ -1,30 +1,37 @@
-# $Id: config.in,v 1.36 1997/12/29 21:36:52 geert Exp $
+# $Id: config.in,v 1.47 1998/04/10 10:19:04 geert Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
 mainmenu_name "Linux/PowerPC Kernel Configuration"
 
+
+
 mainmenu_option next_comment
 comment 'Platform support'
 define_bool CONFIG_PPC y
-if [ "`uname`" != "Linux" -o "`uname -m`" != "ppc" ]; then
-  define_bool CONFIG_CROSSCOMPILE y
-else
-  define_bool CONFIG_NATIVE y
-fi
-
-define_bool CONFIG_MACH_SPECIFIC y
-bool 'Build PowerMac Kernel (not PReP or CHRP)?' CONFIG_PMAC
-bool 'Build PReP Kernel (not PowerMac or CHRP)?' CONFIG_PREP
-bool 'Build CHRP Kernel (not PReP or PowerMac)?' CONFIG_CHRP
+#if [ "`uname`" != "Linux" -o "`uname -m`" != "ppc" ]; then
+#  define_bool CONFIG_CROSSCOMPILE y
+#else
+#  define_bool CONFIG_NATIVE y
+#fi
 
 choice 'Processor type' \
-       "Common         CONFIG_COMMON \
-        601            CONFIG_601      \
-        603            CONFIG_603      \
-        604            CONFIG_604" Common
+       "6xx/7xx        CONFIG_6xx \
+        860/821        CONFIG_8xx" 6xx/7xx
+
+choice 'Machine Type' \
+       "PowerMac       CONFIG_PMAC \
+        PReP           CONFIG_PREP \
+        CHRP           CONFIG_CHRP \
+        PowerMac/PReP/CHRP     CONFIG_ALL_PPC \
+        APUS           CONFIG_APUS \
+        MBX            CONFIG_MBX" PReP
 endmenu
 
+if [ "$CONFIG_ALL_PPC" != "y" ]; then
+  define_bool CONFIG_MACH_SPECIFIC y
+fi
+
 mainmenu_option next_comment
 comment 'General setup'
 
@@ -35,7 +42,11 @@ if [ "$CONFIG_MODULES" = "y" ]; then
   bool 'Kernel module loader' CONFIG_KMOD
 fi
 
-define_bool CONFIG_PCI y
+if [ "$CONFIG_APUS" = "y" ]; then
+  define_bool CONFIG_PCI n
+else
+  define_bool CONFIG_PCI y
+fi
 if [ "$CONFIG_PREP" = "y" ]; then
   bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE
 fi
@@ -51,6 +62,14 @@ define_bool CONFIG_KERNEL_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 
+tristate 'Parallel port support' CONFIG_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+    bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
+  fi
+fi
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'New unified console driver (EXPERIMENTAL)' CONFIG_ABSTRACT_CONSOLE
 fi
@@ -68,6 +87,7 @@ else
 # if compiling specifically for prep or chrp, or supporting all arch's
   if [ "$CONFIG_ABSTRACT_CONSOLE" = "y" ]; then
     bool 'Support for frame buffer devices' CONFIG_FB
+    bool 'Support for VGA devices' CONFIG_VGA_CONSOLE
     bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
   else
     bool 'Support for PowerMac console' CONFIG_PMAC_CONSOLE
@@ -79,13 +99,10 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'Support for PowerMac mouse (EXPERIMENTAL)' CONFIG_MACMOUSE
 fi
 bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+bool 'Include kgdb kernel debugger' CONFIG_KGDB
 bool 'Include xmon kernel debugger' CONFIG_XMON
 
-if [ "$CONFIG_ABSTRACT_CONSOLE" = "y" ]; then
-  if [ "$CONFIG_FB" != "y" ]; then
-    define_bool CONFIG_VGA_CONSOLE y
-  fi
-else
+if [ "$CONFIG_ABSTRACT_CONSOLE" != "y" ]; then
   if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then
     bool 'Support for Apple "control" display' CONFIG_CONTROL_VIDEO
     bool 'Support for Apple "platinum" display' CONFIG_PLATINUM_VIDEO
index 7e5caa71dfa0e88c02a09730b71b46022378d7a3..e498b52494508c7f9bce4220dce3b15b3d5baa64 100644 (file)
@@ -6,22 +6,21 @@
 # Platform support
 #
 CONFIG_PPC=y
-CONFIG_NATIVE=y
-CONFIG_MACH_SPECIFIC=y
+# CONFIG_6xx is not set
+CONFIG_8xx=y
 # CONFIG_PMAC is not set
-CONFIG_PREP=y
+# CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_COMMON=y
+# CONFIG_ALL_PPC is not set
+CONFIG_MBX=y
+CONFIG_MACH_SPECIFIC=y
 
 #
 # General setup
 #
-CONFIG_EXPERIMENTAL=y
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_MODULES is not set
 CONFIG_PCI=y
-# CONFIG_PCI_OPTIMIZE is not set
 CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
 # CONFIG_SYSCTL is not set
@@ -31,6 +30,7 @@ CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
 # CONFIG_PMAC_CONSOLE is not set
 # CONFIG_MAC_KEYBOARD is not set
 # CONFIG_MAC_FLOPPY is not set
@@ -46,25 +46,17 @@ CONFIG_VGA_CONSOLE=y
 #
 # Floppy, IDE, and other block devices
 #
-CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_TRITON is not set
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_BLK_DEV_HD_ONLY is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_EZ is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -79,83 +71,30 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
 # CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
 # CONFIG_IP_ACCT is not set
-# CONFIG_IP_MASQUERADE is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
-CONFIG_INET_RARP=y
-# CONFIG_IP_NOSR is not set
-CONFIG_SKB_LARGE=y
-# CONFIG_IPV6 is not set
+# CONFIG_INET_RARP is not set
+CONFIG_IP_NOSR=y
+# CONFIG_SKB_LARGE is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_LLC is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_CPU_IS_SLOW is not set
-# CONFIG_NET_SCHED is not set
 
 #
 # SCSI support
 #
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
-# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
-CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
-CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
-CONFIG_SCSI_NCR53C8XX_SYNC=5
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT 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
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
-# CONFIG_SCSI_MESH is not set
-# CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_SCSI is not set
 
 #
 # Network device support
@@ -164,34 +103,28 @@ CONFIG_NETDEVICES=y
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_ETHERTAP is not set
 CONFIG_NET_ETHERNET=y
 # CONFIG_NET_VENDOR_3COM is not set
-CONFIG_LANCE=y
+# CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-CONFIG_DE4X5=y
-# CONFIG_DEC_ELCP is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
-# CONFIG_TLAN is not set
-# CONFIG_ES3210 is not set
-# CONFIG_ZNET is not set
+# CONFIG_NET_EISA is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=m
-# CONFIG_NET_RADIO is not set
+# CONFIG_PPP is not set
 # CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
-# CONFIG_SHAPER is not set
+# CONFIG_WAN_DRIVERS is not set
+# CONFIG_LAPBETHER is not set
+# CONFIG_X25_ASY is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
 
 #
 # ISDN subsystem
@@ -202,6 +135,7 @@ CONFIG_PPP=m
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
 #
 # CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_CDROM is not set
 
 #
 # Filesystems
@@ -209,63 +143,52 @@ CONFIG_PPP=m
 # CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+# CONFIG_ISO9660_FS is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
-CONFIG_PROC_FS=y
+# CONFIG_PROC_FS is not set
 CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
 # CONFIG_NFSD is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_MAC_PARTITION is not set
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
 
 #
 # Character devices
 #
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SOFTCURSOR is not set
+# CONFIG_VT is not set
 CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
 CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_PRINTER is not set
-CONFIG_MOUSE=y
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-# CONFIG_UMISC is not set
+# CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
-# CONFIG_VIDEO_BT848 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
 
 #
 # Sound
index 37776109d3c1bc6a8314dec6ff730e46dd99baa8..3561fd26afd4af5f4ac403639433b569a979c1e2 100644 (file)
        $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o
 
 O_TARGET := kernel.o
-O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
-         align.o ptrace.o irq.o openpic.o bitops.o ppc_htab.o idle.o \
-         time.o prep_time.o pmac_time.o chrp_time.o \
-         setup.o prep_setup.o pmac_setup.o pmac_support.o chrp_setup.o \
-         pci.o prep_pci.o pmac_pci.o chrp_pci.o \
-         residual.o prom.o
 OX_OBJS := ppc_ksyms.o
 
+
+O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \
+         bitops.o ppc_htab.o setup.o ptrace.o align.o
+
+ifdef CONFIG_PCI
+O_OBJS += pci.o
+endif
+ifdef CONFIG_KGDB
+O_OBJS += ppc-stub.o
+endif
+
+ifeq ($(CONFIG_MBX),y)
+O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o
+else
+ifeq ($(CONFIG_APUS),y)
+O_OBJS += prom.o openpic.o
+else
+O_OBJS += prep_time.o pmac_time.o chrp_time.o \
+         prep_setup.o pmac_setup.o pmac_support.o chrp_setup.o \
+         prep_pci.o pmac_pci.o chrp_pci.o \
+         residual.o prom.o openpic.o
+endif
+endif
+
 ifdef SMP
 O_OBJS += smp.o
 endif
@@ -38,10 +56,10 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
        rm mk_defs.s
 
 find_name : find_name.c
-       $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o find_name find_name.c
+       $(HOSTCC) -o find_name find_name.c
 
 checks: checks.c
-       $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
+       $(HOSTCC) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
        ./checks
 
 include $(TOPDIR)/Rules.make
index 39cb04f77152021515e20db37a1ff7e314e316ba..70284674bfc437a5cf4be7fb3af6e1c6e6b94c73 100644 (file)
@@ -194,9 +194,13 @@ fix_alignment(struct pt_regs *regs)
                        return -EFAULT; /* bad address */
        }
 
+#ifdef __SMP__
+       if ((flags & F) && (regs->msr & MSR_FP) )
+               smp_giveup_fpu(current);
+#else  
        if ((flags & F) && last_task_used_math == current)
                giveup_fpu();
-
+#endif
        if (flags & M)
                return 0;               /* too hard for now */
 
@@ -255,12 +259,22 @@ fix_alignment(struct pt_regs *regs)
         * the kernel with -msoft-float so it doesn't use the
         * fp regs for copying 8-byte objects. */
        case LD+F+S:
+#ifdef __SMP__
+               if (regs->msr & MSR_FP )
+                       smp_giveup_fpu(current);
+#else  
                giveup_fpu();
+#endif         
                cvt_fd(&data.f, &current->tss.fpr[reg]);
                /* current->tss.fpr[reg] = data.f; */
                break;
        case ST+F+S:
+#ifdef __SMP__
+               if (regs->msr & MSR_FP )
+                       smp_giveup_fpu(current);
+#else  
                giveup_fpu();
+#endif         
                cvt_df(&current->tss.fpr[reg], &data.f);
                /* data.f = current->tss.fpr[reg]; */
                break;
index 16b379254e10734d0821109497096ce35f6bf332..6036efc2864a9081dde2e4cf347812f618a3e514 100644 (file)
@@ -4,13 +4,13 @@
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/openpic.h>
 
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/hydra.h>
 #include <asm/prom.h>
 
 volatile struct Hydra *Hydra = NULL;
 
-
 #if 1
+/*
+ * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
+ * limit the bus number to 3 bits
+ */
+
 int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
                                  unsigned char offset, unsigned char *val)
 {
@@ -32,11 +36,6 @@ int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
        return PCIBIOS_DEVICE_NOT_FOUND;
     }
     *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
-    if (offset == PCI_INTERRUPT_LINE) {
-       /* PCI interrupts are controlled by the OpenPIC */
-       if (*val)
-           *val = openpic_to_irq(*val);
-    }
     return PCIBIOS_SUCCESSFUL;
 }
 
@@ -228,10 +227,11 @@ __initfunc(int w83c553f_init(void))
     unsigned char t8;
     unsigned short t16;
     unsigned int t32;
-    if (pcibios_find_device(PCI_VENDOR_ID_WINBOND,
-                           PCI_DEVICE_ID_WINBOND_83C553, 0, &bus, &dev)
-       == PCIBIOS_SUCCESSFUL) {
-       dev++;
+    struct pci_dev *pdev;
+    if ((pdev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                               PCI_DEVICE_ID_WINBOND_83C553, NULL))) {
+       bus = pdev->bus->number;
+       dev = pdev->devfn + 1;
        chrp_pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
        if (t32 == (PCI_DEVICE_ID_WINBOND_82C105<<16) + PCI_VENDOR_ID_WINBOND) {
 #if 0
index 6c5d2afa565fc9cbf704be04821400e9129f0318..91ca5d595aa6634d2c71cdd559eda8203784d3cb 100644 (file)
@@ -60,21 +60,6 @@ extern int rd_prompt;                /* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_image_start;     /* starting block # of image */
 #endif
 
-
-int chrp_ide_irq = 0;
-
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
-{
-       ide_ioreg_t port = base;
-       int i = 8;
-
-       while (i--)
-               *p++ = port++;
-       *p++ = base + 0x206;
-       if (irq != NULL)
-               *irq = chrp_ide_irq;
-}
-
 static const char *gg2_memtypes[4] = {
     "FPM", "SDRAM", "EDO", "BEDO"
 };
@@ -89,6 +74,34 @@ static const char *gg2_cachemodes[4] = {
     "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
 };
 
+#if 0
+#ifdef CONFIG_BLK_DEV_IDE
+int chrp_ide_ports_known;
+ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
+ide_ioreg_t chrp_idedma_regbase; /* one for both channels */
+unsigned int chrp_ide_irq;
+
+void chrp_ide_probe(void)
+{
+}
+
+void chrp_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+       int i;
+
+       *p = 0;
+       if (base == 0)
+               return;
+       for (i = 0; i < 8; ++i)
+               *p++ = base + i * 0x10;
+       *p = base + 0x160;
+       if (irq != NULL) {
+               *irq = chrp_ide_irq;
+       }
+}
+#endif /* CONFIG_BLK_DEV_IDE */
+#endif
+
 int
 chrp_get_cpuinfo(char *buffer)
 {
@@ -139,12 +152,63 @@ chrp_get_cpuinfo(char *buffer)
        }
        /* L2 cache */
        t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
-       len += sprintf(buffer+len, "l2\t\t: %s %s (%s)\n",
+       len += sprintf(buffer+len, "board l2\t: %s %s (%s)\n",
                       gg2_cachesizes[(t>>7) & 3], gg2_cachetypes[(t>>2) & 3],
                       gg2_cachemodes[t & 3]);
        return len;
 }
 
+    /*
+     *  Fixes for the National Semiconductor PC78308VUL SuperI/O
+     *
+     *  Some versions of Open Firmware incorrectly initialize the IRQ settings
+     *  for keyboard and mouse
+     */
+
+__initfunc(static inline void sio_write(u8 val, u8 index))
+{
+    outb(index, 0x15c);
+    outb(val, 0x15d);
+}
+
+__initfunc(static inline u8 sio_read(u8 index))
+{
+    outb(index, 0x15c);
+    return inb(0x15d);
+}
+
+__initfunc(static void sio_init(void))
+{
+    u8 irq, type;
+
+    /* select logical device 0 (KBC/Keyboard) */
+    sio_write(0, 0x07);
+    irq = sio_read(0x70);
+    type = sio_read(0x71);
+    printk("sio: Keyboard irq %d, type %d: ", irq, type);
+    if (irq == 1 && type == 3)
+       printk("OK\n");
+    else {
+       printk("remapping to irq 1, type 3\n");
+       sio_write(1, 0x70);
+       sio_write(3, 0x71);
+    }
+
+    /* select logical device 1 (KBC/Mouse) */
+    sio_write(1, 0x07);
+    irq = sio_read(0x70);
+    type = sio_read(0x71);
+    printk("sio: Mouse irq %d, type %d: ", irq, type);
+    if (irq == 12 && type == 3)
+       printk("OK\n");
+    else {
+       printk("remapping to irq 12, type 3\n");
+       sio_write(12, 0x70);
+       sio_write(3, 0x71);
+    }
+}
+
+
 __initfunc(void
 chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
@@ -191,7 +255,12 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
        hydra_init();           /* Mac I/O */
        w83c553f_init();        /* PCI-ISA bridge and IDE */
 
-#ifdef CONFIG_ABSTRACT_CONSOLE
+       /*
+        *  Fix the Super I/O configuration
+        */
+       sio_init();
+
+#ifdef CONFIG_FB
        /* Frame buffer device based console */
        conswitchp = &fb_con;
 #endif
index 73dcf9844c9fd5f0eec1b173443c0a5f9ca680f8..7109c0e5dc2797bc9be5c4a1c0a71358b2bc04af 100644 (file)
@@ -38,7 +38,7 @@ void chrp_time_init(void)
        rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
        if (rtcs == NULL || rtcs->addrs == NULL)
                return;
-       base = ((int *)rtcs->addrs)[2];
+       base = rtcs->addrs[0].address;
        nvram_as1 = 0;
        nvram_as0 = base;
        nvram_data = base + 1;
@@ -69,7 +69,7 @@ int chrp_set_rtc_time(unsigned long nowtime)
        unsigned char save_control, save_freq_select;
        struct rtc_time tm;
 
-       to_tm(nowtime + 10*60*60, &tm); /* XXX for now */
+       to_tm(nowtime, &tm);
 
        save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
 
@@ -146,7 +146,7 @@ unsigned long chrp_get_rtc_time(void)
          }
        if ((year += 1900) < 1970)
                year += 100;
-       return mktime(year, mon, day, hour, min, sec) - 10*60*60 /* XXX for now */;
+       return mktime(year, mon, day, hour, min, sec);
 }
 
 
@@ -155,6 +155,9 @@ void chrp_calibrate_decr(void)
        struct device_node *cpu;
        int freq, *fp, divisor;
 
+       if (via_calibrate_decr())
+               return;
+
        /*
         * The cpu node should have a timebase-frequency property
         * to tell us the rate at which the decrementer counts.
index 2924febc5ea1d76f1acdccd6f3d84ae939c6f6c1..d8540e68ddbc56247352851e344eb16e85ecc882 100644 (file)
@@ -9,6 +9,8 @@
  *  Low-level exception handlers and MMU support
  *  rewritten by Paul Mackerras.
  *    Copyright (C) 1996 Paul Mackerras.
+ *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
  *
  *  This file contains the low-level support and setup for the
  *  PowerPC platform, including trap and interrupt dispatch.
 #include <linux/sys.h>
 #include <linux/errno.h>
 #include <linux/config.h>
+#ifdef CONFIG_8xx
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+#endif
 
 #ifdef CONFIG_APUS
-/* At CYBERBASEp we'll find the following sum:
- * -KERNELBASE+CyberStormMemoryBase
- */
-#define CYBERBASEp (0xfff00000)
+#include <asm/amigappc.h>
 #endif
 
 /* optimization for 603 to load the tlb directly from the linux table */
@@ -77,6 +81,8 @@ LG_CACHE_LINE_SIZE = 5
        sync; \
        isync
 
+/* This instruction is not implemented on the PPC 603 or 601 */
+#ifndef CONFIG_8xx
 /* This instruction is not implemented on the PPC 603 or 601 */
 #define tlbia \
        li      r4,128; \
@@ -85,6 +91,7 @@ LG_CACHE_LINE_SIZE = 5
 0:     tlbie   r4; \
        addi    r4,r4,0x1000; \
        bdnz    0b
+#endif
 
 #define LOAD_BAT(n, offset, reg, RA, RB) \
        lwz     RA,offset+0(reg); \
@@ -96,6 +103,20 @@ LG_CACHE_LINE_SIZE = 5
        mtspr   DBAT##n##U,RA;  \
        mtspr   DBAT##n##L,RB
 
+#ifndef CONFIG_APUS
+#define tophys(rd,rs,rt)       addis   rd,rs,-KERNELBASE@h
+#define tovirt(rd,rs,rt)       addis   rd,rs,KERNELBASE@h
+#else
+#define tophys(rd,rs,rt)        \
+       lis     rt,CYBERBASEp@h; \
+       lwz     rt,0(rt);        \
+       add     rd,rs,rt
+#define tovirt(rd,rs,rt)        \
+       lis     rt,CYBERBASEp@h; \
+       lwz     rt,0(rt);        \
+       sub     rd,rs,rt
+#endif
+       
        .text
        .globl  _stext
 _stext:
@@ -130,12 +151,44 @@ _start:
  *
  * This just gets a minimal mmu environment setup so we can call
  * start_here() to do the real work.
- * -- Cort     
+ * -- Cort
+ *
+ * MPC8xx
+ * This port was done on an MBX board with an 860.  Right now I only
+ * support an ELF compressed (zImage) boot from EPPC-Bug because the
+ * code there loads up some registers before calling us:
+ *   r3: ptr to board info data
+ *   r4: initrd_start or if no initrd then 0
+ *   r5: initrd_end - unused if r4 is 0
+ *   r6: Start of command line string
+ *   r7: End of command line string
+ *
+ * I decided to use conditional compilation instead of checking PVR and
+ * adding more processor specific branches around code I don't need.
+ * Since this is an embedded processor, I also appreciate any memory
+ * savings I can get.
+ *
+ * The MPC8xx does not have any BATs, but it supports large page sizes.
+ * We first initialize the MMU to support 8M byte pages, then load one
+ * entry into each of the instruction and data TLBs to map the first
+ * 8M 1:1.  I also mapped an additional I/O space 1:1 so we can get to
+ * the "internal" processor registers before MMU_init is called.
+ *
+ * The TLB code currently contains a major hack.  Since I use the condition
+ * code register, I have to save and restore it.  I am out of registers, so
+ * I just store it in memory location 0 (the TLB handlers are not reentrant).
+ * To avoid making any decisions, I need to use the "segment" valid bit
+ * in the first level table, but that would require many changes to the
+ * Linux page directory/table functions that I don't want to do right now.
+ *
+ * I used to use SPRG2 for a temporary register in the TLB handler, but it
+ * has since been put to other uses.  I now use a hack to save a register
+ * and the CCR at memory location 0.....Someday I'll fix this.....
+ *     -- Dan
  */
        
        .globl  __start
 __start:
-
 /*
  * We have to do any OF calls before we map ourselves to KERNELBASE,
  * because OF may have I/O devices mapped in in that area
@@ -145,12 +198,16 @@ __start:
        mr      r30,r4
        mr      r29,r5
        mr      r28,r6
-       mr      r29,r7
+       mr      r27,r7
+#ifndef CONFIG_8xx
+#ifndef CONFIG_APUS
        bl      prom_init
+#endif
 
 /*
  * Use the first pair of BAT registers to map the 1st 16MB
- * of RAM to KERNELBASE.
+ * of RAM to KERNELBASE.  From this point on we can't safely
+ * call OF any more.
  */
        mfspr   r9,PVR
        rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
@@ -173,17 +230,134 @@ __start:
        addis   r8,r8,KERNELBASE@h
        addi    r8,r8,2
 #endif
-       mtspr   DBAT0U,r11
+5:     mtspr   DBAT0U,r11
        mtspr   DBAT0L,r8
-5:     mtspr   IBAT0U,r11
+       mtspr   IBAT0U,r11
        mtspr   IBAT0L,r8
        isync
+
+/*
+ * We need to run with _start at physical address 0.
+ * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
+ * the exception vectors at 0 (and therefore this copy
+ * overwrites OF's exception vectors with our own).
+ * If the MMU is already turned on, we copy stuff to KERNELBASE,
+ * otherwise we copy it to 0.
+ */
+       bl      reloc_offset
+       mr      r26,r3
+       addis   r4,r3,KERNELBASE@h      /* current address of _start */
+       cmpwi   0,r4,0                  /* are we already running at 0? */
+       beq     2f                      /* assume it's OK if so */
+       li      r3,0
+       mfmsr   r0
+       andi.   r0,r0,MSR_DR            /* MMU enabled? */
+       beq     7f
+       lis     r3,KERNELBASE@h         /* if so, are we */
+       cmpw    0,r4,r3                 /* already running at KERNELBASE? */
+       beq     2f
+       rlwinm  r4,r4,0,8,31            /* translate source address */
+       add     r4,r4,r3                /* to region mapped with BATs */
+7:     addis   r9,r26,klimit@ha        /* fetch klimit */
+       lwz     r25,klimit@l(r9)
+       addis   r25,r25,-KERNELBASE@h
+       li      r6,0                    /* Destination */
+#ifdef CONFIG_APUS
+       lis     r9,0x6170
+       ori     r9,r9,0x7573
+       cmpw    0,r9,r31
+       bne     8f
+       lis     r6,0xfff0               /* Copy to 0xfff00000 on APUS */
+8:
+#endif
+       li      r5,0x4000               /* # bytes of memory to copy */
+       bl      copy_and_flush          /* copy the first 0x4000 bytes */
+#ifdef CONFIG_APUS
+       cmpw    0,r9,r31                /* That's all we need on APUS. */
+       beq     2f
+#endif
+       addi    r0,r3,4f@l              /* jump to the address of 4f */
+       mtctr   r0                      /* in copy and do the rest. */
+       bctr                            /* jump to the copy */
+4:     mr      r5,r25
+       bl      copy_and_flush          /* copy the rest */
+2:
 /*
  * we now have the 1st 16M of ram mapped with the bats.
  * prep needs the mmu to be turned on here, but pmac already has it on.
  * this shouldn't bother the pmac since it just gets turned on again
  * as we jump to our code at KERNELBASE. -- Cort
  */
+       
+#else /* CONFIG_8xx */
+       tlbia                   /* Invalidate all TLB entries */
+       li      r8, 0
+       mtspr   MI_CTR, r8      /* Set instruction control to zero */
+       lis     r8, MD_RESETVAL@h
+       mtspr   MD_CTR, r8      /* Set data TLB control */
+
+       /* Now map the lower 8 Meg into the TLBs.  For this quick hack,
+        * we can load the instruction and data TLB registers with the
+        * same values.
+        */
+       lis     r8, KERNELBASE@h        /* Create vaddr for TLB */
+       ori     r8, r8, MI_EVALID       /* Mark it valid */
+       mtspr   MI_EPN, r8
+       mtspr   MD_EPN, r8
+       li      r8, MI_PS8MEG           /* Set 8M byte page */
+       ori     r8, r8, MI_SVALID       /* Make it valid */
+       mtspr   MI_TWC, r8
+       mtspr   MD_TWC, r8
+       li      r8, MI_BOOTINIT         /* Create RPN for address 0 */
+       mtspr   MI_RPN, r8              /* Store TLB entry */
+       mtspr   MD_RPN, r8
+       lis     r8, MI_Kp@h             /* Set the protection mode */
+       mtspr   MI_AP, r8
+       mtspr   MD_AP, r8
+#ifdef CONFIG_MBX
+       /* Map another 8 MByte at 0xfa000000 to get the processor
+        * internal registers (among other things).
+        */
+       lis     r8, 0xfa000000@h        /* Create vaddr for TLB */
+       ori     r8, r8, MD_EVALID       /* Mark it valid */
+       mtspr   MD_EPN, r8
+       li      r8, MD_PS8MEG           /* Set 8M byte page */
+       ori     r8, r8, MD_SVALID       /* Make it valid */
+       mtspr   MD_TWC, r8
+       lis     r8, 0xfa000000@h        /* Create paddr for TLB */
+       ori     r8, r8, MI_BOOTINIT
+       mtspr   MD_RPN, r8
+#endif
+
+       /* Since the cache is enabled according to the information we
+        * just loaded into the TLB, invalidate and enable the caches here.
+        * We should probably check/set other modes....later.
+        */
+       lis     r8, IDC_INVALL@h
+       mtspr   IC_CST, r8
+       mtspr   DC_CST, r8
+       lis     r8, IDC_ENABLE@h
+       mtspr   IC_CST, r8
+#ifdef notdef
+       mtspr   DC_CST, r8
+#else
+       /* I still have a bug somewhere because the Ethernet driver
+        * does not want to work with copyback enabled.  For now,
+        * at least enable write through.
+        */
+#if 0  
+       lis     r8, DC_SFWT@h
+       mtspr   DC_CST, r8
+       lis     r8, IDC_ENABLE@h
+       mtspr   DC_CST, r8
+#endif 
+#endif
+
+/* We now have the lower 8 Meg mapped into TLB entries, and the caches
+ * ready to work.
+ */
+#endif /* CONFIG_8xx */
+
        mfmsr   r0
        ori     r0,r0,MSR_DR|MSR_IR
        mtspr   SRR1,r0
@@ -201,48 +375,6 @@ __start:
  */
 #define STACK_UNDERHEAD        64
        
-/*
- * 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)
-
-#ifndef CONFIG_APUS
-#define tophys(rd,rs,rt)       addis   rd,rs,-KERNELBASE@h
-#define tovirt(rd,rs,rt)       addis   rd,rs,KERNELBASE@h
-#else
-#define tophys(rd,rs,rt)        \
-       lis     rt,CYBERBASEp@h; \
-       lwz     rt,0(rt);        \
-       add     rd,rs,rt
-#define tovirt(rd,rs,rt)        \
-       lis     rt,CYBERBASEp@h; \
-       lwz     rt,0(rt);        \
-       sub     rd,rs,rt
-#endif
-       
 /*
  * Exception entry code.  This code runs with address translation
  * turned off, i.e. using physical addresses.
@@ -303,11 +435,15 @@ label:                                            \
 /* Machine check */
        STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
 
-/* Data access exception */
+/* Data access exception.
+ * This is "never generated" by the MPC8xx.  We jump to it for other
+ * translation errors.
+ */
        . = 0x300
 DataAccess:
        EXCEPTION_PROLOG
        mfspr   r20,DSISR
+#ifndef CONFIG_8xx
        andis.  r0,r20,0xa470           /* weird error? */
        bne     1f                      /* if not, try to put a PTE */
        mfspr   r3,DAR                  /* into the hash table */
@@ -315,6 +451,7 @@ DataAccess:
        rlwimi  r4,r20,32-23,29,29      /* DSISR_STORE -> _PAGE_RW */
        mfspr   r5,SPRG3                /* phys addr of TSS */
        bl      hash_page
+#endif
 1:     stw     r20,_DSISR(r21)
        mr      r5,r20
        mfspr   r4,DAR
@@ -326,10 +463,14 @@ DataAccess:
        .long   do_page_fault
        .long   int_return
 
-/* Instruction access exception */
+/* Instruction access exception.
+ * This is "never generated" by the MPC8xx.  We jump to it for other
+ * translation errors.
+ */
        . = 0x400
 InstructionAccess:
        EXCEPTION_PROLOG
+#ifndef CONFIG_8xx
        andis.  r0,r23,0x4000           /* no pte found? */
        beq     1f                      /* if so, try to put a PTE */
        mr      r3,r22                  /* into the hash table */
@@ -337,6 +478,7 @@ InstructionAccess:
        mr      r20,r23                 /* SRR1 has reason bits */
        mfspr   r5,SPRG3                /* phys addr of TSS */
        bl      hash_page
+#endif
 1:     addi    r3,r1,STACK_FRAME_OVERHEAD
        mr      r4,r22
        mr      r5,r23
@@ -347,7 +489,38 @@ InstructionAccess:
        .long   int_return
 
 /* External interrupt */
-       STD_EXCEPTION(0x500, HardwareInterrupt, do_IRQ)
+       . = 0x500;
+HardwareInterrupt:
+       EXCEPTION_PROLOG;
+#ifdef CONFIG_APUS
+       mfmsr   20
+       xori    r20,r20,MSR_DR
+       sync
+       mtmsr   r20
+       sync
+
+       lis     r3,APUS_IPL_EMU@h
+
+       li      r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT)
+       stb     r20,APUS_IPL_EMU@l(r3)
+       sync
+
+       lbz     r3,APUS_IPL_EMU@l(r3)
+
+       mfmsr   r20
+       xori    r20,r20,MSR_DR
+       sync
+       mtmsr   r20
+       sync
+
+       stw     r3,(_CCR+4)(r21);
+#endif
+       addi    r3,r1,STACK_FRAME_OVERHEAD;
+       li      r20,MSR_KERNEL;
+       bl      transfer_to_handler;
+       .long   do_IRQ;
+       .long   int_return
+       
 
 /* Alignment exception */
        . = 0x600
@@ -375,6 +548,7 @@ ProgramCheck:
        .long   ProgramCheckException
        .long   int_return
 
+#ifndef CONFIG_8xx
 /* Floating-point unavailable */
        . = 0x800
 FPUnavailable:
@@ -384,6 +558,11 @@ FPUnavailable:
        bl      transfer_to_handler     /* if from kernel, take a trap */
        .long   KernelFP
        .long   int_return
+#else
+/* No FPU on MPC8xx.  This exception is not supposed to happen.
+*/
+       STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+#endif
 
        STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
        STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
@@ -406,6 +585,7 @@ SystemCall:
        STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
        STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
 
+#ifndef CONFIG_8xx
 /*
  * Handle TLB miss for instruction on 603/603e.
  * Note: we get an alternate set of r0 - r3 to use automatically.
@@ -502,7 +682,14 @@ InstructionAddressInvalid:
        sync                    /* Some chip revs have problems here... */
        mtmsr   r0
        b       InstructionAccess
+#else
+/* On the MPC8xx, this is a software emulation interrupt.  It occurs
+ * for all unimplemented and illegal instructions.
+ */
+       STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation)
+#endif
 
+#ifndef CONFIG_8xx
 /*
  * Handle TLB miss for DATA Load operation on 603/603e
  */
@@ -598,12 +785,78 @@ DataAddressInvalid:
        sync                    /* Some chip revs have problems here... */
        mtmsr   r0
        b       DataAccess
+#else
+/*
+ * For the MPC8xx, this is a software tablewalk to load the instruction
+ * TLB.  It is modelled after the example in the Motorola manual.  The task
+ * switch loads the M_TWB register with the pointer to the first level table.
+ * If we discover there is no second level table (the value is zero), the
+ * plan was to load that into the TLB, which causes another fault into the
+ * TLB Error interrupt where we can handle such problems.  However, that did
+ * not work, so if we discover there is no second level table, we restore
+ * registers and branch to the error exception.  We have to use the MD_xxx
+ * registers for the tablewalk because the equivalent MI_xxx registers
+ * only perform the attribute functions.
+ */
+InstructionTLBMiss:
+       mtspr   M_TW, r20       /* Save a couple of working registers */
+       mfcr    r20
+       stw     r20, 0(r0)
+       stw     r21, 4(r0)
+       mfspr   r20, SRR0       /* Get effective address of fault */
+       mtspr   MD_EPN, r20     /* Have to use MD_EPN for walk, MI_EPN can't */
+       mfspr   r20, M_TWB      /* Get level 1 table entry address */
+       lwz     r21, 0(r20)     /* Get the level 1 entry */
+       rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */
+       beq     2f              /* If zero, don't try to find a pte */
+
+       /* We have a pte table, so load the MI_TWC with the attributes
+        * for this page, which has only bit 31 set.
+        */
+       tophys(r21,r21,0)
+       ori     r21,r21,1               /* Set valid bit */
+       mtspr   MI_TWC, r21     /* Set page attributes */
+       mtspr   MD_TWC, r21     /* Load pte table base address */
+       mfspr   r21, MD_TWC     /* ....and get the pte address */
+       lwz     r21, 0(r21)     /* Get the pte */
+
+       /* Set four subpage valid bits (24, 25, 26, and 27).
+        * Since we currently run MI_CTR.PPCS = 0, the manual says,
+        *      "If the page size is larger than 4k byte, then all the
+        *       4 bits should have the same value."
+        * I don't really know what to do if the page size is 4k Bytes,
+        * but I know setting them all to 0 does not work, and setting them
+        * all to 1 does, so that is the way it is right now.
+        * BTW, these four bits map to the software only bits in the
+        * linux page table.  I used to turn them all of, but now just
+        * set them all for the hardware.
+       li      r20, 0x00f0
+       andc    r20, r21, r20
+       ori     r20, r20, 0x0080
+        */
+       ori     r20, r21, 0x00f0
 
+       mtspr   MI_RPN, r20     /* Update TLB entry */
+
+       mfspr   r20, M_TW       /* Restore registers */
+       lwz     r21, 0(r0)
+       mtcr    r21
+       lwz     r21, 4(r0)
+       rfi
+
+2:     mfspr   r20, M_TW       /* Restore registers */
+       lwz     r21, 0(r0)
+       mtcr    r21
+       lwz     r21, 4(r0)
+       b       InstructionAccess
+#endif /* CONFIG_8xx */
+       
 /*
  * Handle TLB miss for DATA Store on 603/603e
  */
        . = 0x1200
 DataStoreTLBMiss:
+#ifndef CONFIG_8xx
 #ifdef NO_RELOAD_HTAB
 /*
  * r0: stored ctr
@@ -671,27 +924,164 @@ DataStoreTLBMiss:
        ori     r3,r3,0x40      /* Set secondary hash */
        b       00b                     /* Try lookup again */
 #endif /* NO_RELOAD_HTAB */
-       
+#else /* CONFIG_8xx */ 
+       mtspr   M_TW, r20       /* Save a couple of working registers */
+       mfcr    r20
+       stw     r20, 0(r0)
+       stw     r21, 4(r0)
+       mfspr   r20, M_TWB      /* Get level 1 table entry address */
+       lwz     r21, 0(r20)     /* Get the level 1 entry */
+       rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */
+       beq     2f              /* If zero, don't try to find a pte */
+
+       /* We have a pte table, so load fetch the pte from the table.
+        */
+       tophys(r21, r21, 0)
+       ori     r21, r21, 1     /* Set valid bit in physical L2 page */
+       mtspr   MD_TWC, r21     /* Load pte table base address */
+       mfspr   r21, MD_TWC     /* ....and get the pte address */
+       lwz     r21, 0(r21)     /* Get the pte */
+
+       /* Set four subpage valid bits (24, 25, 26, and 27).
+        * Since we currently run MD_CTR.PPCS = 0, the manual says,
+        *      "If the page size is larger than 4k byte, then all the
+        *       4 bits should have the same value."
+        * I don't really know what to do if the page size is 4k Bytes,
+        * but I know setting them all to 0 does not work, and setting them
+        * all to 1 does, so that is the way it is right now.
+        * BTW, these four bits map to the software only bits in the
+        * linux page table.  I used to turn them all of, but now just
+        * set them all for the hardware.
+       li      r20, 0x00f0
+       andc    r20, r21, r20
+       ori     r20, r20, 0x0080
+        */
+       ori     r20, r21, 0x00f0
 
+       mtspr   MD_RPN, r20     /* Update TLB entry */
+
+       mfspr   r20, M_TW       /* Restore registers */
+       lwz     r21, 0(r0)
+       mtcr    r21
+       lwz     r21, 4(r0)
+       rfi
+
+2:     mfspr   r20, M_TW       /* Restore registers */
+       lwz     r21, 0(r0)
+       mtcr    r21
+       lwz     r21, 4(r0)
+       b       DataAccess
+#endif /* CONFIG_8xx */
+
+#ifndef CONFIG_8xx
 /* Instruction address breakpoint exception (on 603/604) */
        STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
+#else
+
+/* This is an instruction TLB error on the MPC8xx.  This could be due
+ * to many reasons, such as executing guarded memory or illegal instruction
+ * addresses.  There is nothing to do but handle a big time error fault.
+ */
+       . = 0x1300
+InstructionTLBError:
+       b       InstructionAccess
+#endif
 
 /* System management exception (603?) */
+#ifndef CONFIG_8xx
        STD_EXCEPTION(0x1400, Trap_14, UnknownException)
+#else
+
+/* This is the data TLB error on the MPC8xx.  This could be due to
+ * many reasons, including a dirty update to a pte.  We can catch that
+ * one here, but anything else is an error.  First, we track down the
+ * Linux pte.  If it is valid, write access is allowed, but the
+ * page dirty bit is not set, we will set it and reload the TLB.  For
+ * any other case, we bail out to a higher level function that can
+ * handle it.
+ */
+       . = 0x1400
+DataTLBError:
+       mtspr   M_TW, r20       /* Save a couple of working registers */
+       mfcr    r20
+       stw     r20, 0(r0)
+       stw     r21, 4(r0)
+
+       /* First, make sure this was a store operation.
+       */
+       mfspr   r20, DSISR
+       andis.  r21, r20, 0x0200        /* If set, indicates store op */
+       beq     2f
+
+       mfspr   r20, M_TWB      /* Get level 1 table entry address */
+       lwz     r21, 0(r20)     /* Get the level 1 entry */
+       rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */
+       beq     2f              /* If zero, bail */
+
+       /* We have a pte table, so fetch the pte from the table.
+        */
+       tophys(r21, r21, 0)
+       ori     r21, r21, 1             /* Set valid bit in physical L2 page */
+       mtspr   MD_TWC, r21             /* Load pte table base address */
+       mfspr   r21, MD_TWC             /* ....and get the pte address */
+       lwz     r21, 0(r21)             /* Get the pte */
+
+       andi.   r20, r21, _PAGE_RW      /* Is it writeable? */
+       beq     2f                      /* Bail out if not */
+
+       ori     r21, r21, _PAGE_DIRTY   /* Update changed bit */
+       mfspr   r20, MD_TWC             /* Get pte address again */
+       stw     r21, 0(r20)             /* and update pte in table */
+
+       /* Set four subpage valid bits (24, 25, 26, and 27).
+        * Since we currently run MD_CTR.PPCS = 0, the manual says,
+        *      "If the page size is larger than 4k byte, then all the
+        *       4 bits should have the same value."
+        * I don't really know what to do if the page size is 4k Bytes,
+        * but I know setting them all to 0 does not work, and setting them
+        * all to 1 does, so that is the way it is right now.
+        * BTW, these four bits map to the software only bits in the
+        * linux page table.  I used to turn them all of, but now just
+        * set them all for the hardware.
+       li      r20, 0x00f0
+       andc    r20, r21, r20
+       ori     r20, r20, 0x0080
+        */
+       ori     r20, r21, 0x00f0
+
+       mtspr   MD_RPN, r20     /* Update TLB entry */
+
+       mfspr   r20, M_TW       /* Restore registers */
+       lwz     r21, 0(r0)
+       mtcr    r21
+       lwz     r21, 4(r0)
+       rfi
+2:
+       mfspr   r20, M_TW       /* Restore registers */
+       lwz     r21, 0(r0)
+       mtcr    r21
+       lwz     r21, 4(r0)
+       b       DataAccess
+#endif /* CONFIG_8xx */
 
        STD_EXCEPTION(0x1500, Trap_15, UnknownException)
        STD_EXCEPTION(0x1600, Trap_16, UnknownException)
-       STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+       STD_EXCEPTION(0x1700, Trap_17, TAUException)
        STD_EXCEPTION(0x1800, Trap_18, UnknownException)
        STD_EXCEPTION(0x1900, Trap_19, UnknownException)
        STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
        STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+/* On the MPC8xx, these next four traps are used for development
+ * support of breakpoints and such.  Someday I will get around to
+ * using them.
+ */
        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 */
+#ifndef CONFIG_8xx
+       /* Run mode exception */
        STD_EXCEPTION(0x2000, RunMode, RunModeException)
 
        STD_EXCEPTION(0x2100, Trap_21, UnknownException)
@@ -711,6 +1101,9 @@ DataStoreTLBMiss:
        STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
 
        . = 0x3000
+#else
+       . = 0x2000
+#endif
 
 /*
  * This code finishes saving the registers to the exception frame
@@ -720,6 +1113,8 @@ DataStoreTLBMiss:
        .globl  transfer_to_handler
 transfer_to_handler:
        stw     r22,_NIP(r21)
+       lis     r22,MSR_POW@h
+       andc    r23,r23,r22
        stw     r23,_MSR(r21)
        SAVE_GPR(7, r21)
        SAVE_4GPRS(8, r21)
@@ -768,6 +1163,7 @@ stack_ovf:
        SYNC
        rfi
 
+#ifndef CONFIG_8xx
 /*
  * Continuation of the floating-point unavailable handler.
  */
@@ -790,9 +1186,18 @@ load_up_fpu:
        ori     r5,r5,MSR_FP
        SYNC
        mtmsr   r5                      /* enable use of fpu now */
+#ifndef __SMP__
        SYNC
        cmpi    0,r4,0
        beq     1f
+#else
+/*
+ * All the saving of last_task_used_math is handled
+ * by a switch_to() call to smp_giveup_fpu() in SMP so 
+ * last_task_used_math is not used. -- Cort
+ */
+       b       1f
+#endif 
        add     r4,r4,r6
        addi    r4,r4,TSS               /* want TSS of last_task_used_math */
        SAVE_32FPRS(0, r4)
@@ -810,9 +1215,11 @@ load_up_fpu:
        lfd     fr0,TSS_FPSCR-4(r5)
        mtfsf   0xff,fr0
        REST_32FPRS(0, r5)
+#ifndef __SMP__        
        subi    r4,r5,TSS
        sub     r4,r4,r6
        stw     r4,last_task_used_math@l(r3)
+#endif /* __SMP__ */   
        /* restore registers and return */
        lwz     r3,_CCR(r21)
        lwz     r4,_LINK(r21)
@@ -859,16 +1266,6 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
 
        .globl  hash_page
 hash_page:
-#ifdef __SMP__
-       lis     r6,hash_table_lock@h
-       ori     r6,r6,hash_table_lock@l
-       tophys(r6,r6,r2)
-1011:  lwarx   r0,0,r6
-       stwcx.  r6,0,r6
-       bne-    1011b
-       cmpi    0,r0,0
-       bne     1011b
-#endif /* __SMP__ */   
        /* Get PTE (linux-style) and check access */
        lwz     r5,PG_TABLES(r5)                
        tophys(r5,r5,r2)                /* convert to phys addr */
@@ -1018,7 +1415,6 @@ found_slot:
        lwz     r3,0(r2)
        addi    r3,r3,1
        stw     r3,0(r2)
-       SYNC
 
        /* Return from the exception */
        lwz     r3,_CCR(r21)
@@ -1027,19 +1423,14 @@ found_slot:
        mtcrf   0xff,r3
        mtlr    r4
        mtctr   r5
-#ifdef __SMP__
-       lis     r5,hash_table_lock@h
-       ori     r5,r5,hash_table_lock@l
-       tophys(r5,r5,r6)
-       li      r6,0
-       stw     r6,0(r5)
-#endif /* __SMP__ */   
        REST_GPR(0, r21)
        REST_2GPRS(1, r21)
        REST_4GPRS(3, r21)
        /* we haven't used xer */
+       SYNC
        mtspr   SRR1,r23
        mtspr   SRR0,r22
+       SYNC
        REST_GPR(20, r21)
        REST_2GPRS(22, r21)
        lwz     r21,GPR21(r21)
@@ -1047,16 +1438,37 @@ found_slot:
        rfi
        
 hash_page_out:
-#ifdef __SMP__
-       lis     r5,hash_table_lock@h
-       ori     r5,r5,hash_table_lock@l
-       tophys(r5,r5,r6)
-       li      r6,0
-       stw     r6,0(r5)
-#endif /* __SMP__ */   
        blr
 next_slot:
        .long   0
+#endif /* CONFIG_8xx */
+       
+#ifndef CONFIG_APUS
+/*
+ * Copy routine used to copy the kernel to start at physical address 0
+ * and flush and invalidate the caches as needed.
+ * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
+ * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
+ */
+copy_and_flush:
+       addi    r5,r5,-4
+       addi    r6,r6,-4
+4:     li      r0,8
+       mtctr   r0
+3:     addi    r6,r6,4                 /* copy a cache line */
+       lwzx    r0,r6,r4
+       stwx    r0,r6,r3
+       bdnz    3b
+       dcbst   r6,r3                   /* write it to memory */
+       sync
+       icbi    r6,r3                   /* flush the icache line */
+       cmplw   0,r6,r5
+       blt     4b
+       isync
+       addi    r5,r5,4
+       addi    r6,r6,4
+       blr
+#endif
 
 #ifdef CONFIG_APUS
        /* On APUS the first 0x4000 bytes of the kernel will be mapped
@@ -1072,6 +1484,7 @@ next_slot:
  */
 
 start_here:
+#ifndef CONFIG_8xx
        /*
         * Enable caches and 604-specific features if necessary.
         */
@@ -1108,6 +1521,7 @@ start_here:
        ori     r11,r11,HID0_BTCD
 5:     mtspr   HID0,r11                /* superscalar exec & br history tbl */
 4:
+#endif /* CONFIG_8xx */
        /* ptr to current */
        lis     r2,init_task_union@h
        ori     r2,r2,init_task_union@l
@@ -1140,6 +1554,9 @@ start_here:
        mr      r6,r28
        mr      r7,r27
        bl      identify_machine
+#ifdef CONFIG_MBX
+       bl      set_mbx_memory
+#endif
        bl      MMU_init
 
 /*
@@ -1147,8 +1564,19 @@ start_here:
  * for SDR1 (hash table pointer) and the segment registers
  * and change to using our exception vectors.
  */
+#ifndef CONFIG_8xx
        lis     r6,_SDR1@ha
        lwz     r6,_SDR1@l(r6)
+#else
+       /* The right way to do this would be to track it down through
+        * init's TSS like the context switch code does, but this is
+        * easier......until someone changes init's static structures.
+        */
+       lis     r6, swapper_pg_dir@h
+       tophys(r6,r6,0)
+       ori     r6, r6, swapper_pg_dir@l
+       mtspr   M_TWB, r6
+#endif
        lis     r4,2f@h
        ori     r4,r4,2f@l
        tophys(r4,r4,r3)
@@ -1158,8 +1586,10 @@ start_here:
        rfi
 /* Load up the kernel context */
 2:
+
        SYNC                    /* Force all PTE updates to finish */
        tlbia                   /* Clear all TLB entries */
+#ifndef CONFIG_8xx
        mtspr   SDR1,r6
        li      r0,16           /* load up segment register values */
        mtctr   r0              /* for context 0 */
@@ -1179,7 +1609,8 @@ start_here:
        LOAD_BAT(1,16,r3,r4,r5)
        LOAD_BAT(2,32,r3,r4,r5)
        LOAD_BAT(3,48,r3,r4,r5)
-
+#endif /* CONFIG_8xx */
+       
 /* Set up for using our exception vectors */
        /* ptr to phys current tss */
        tophys(r4,r2,r4)
@@ -1188,36 +1619,6 @@ start_here:
        li      r3,0
        mtspr   SPRG2,r3        /* 0 => r1 has kernel sp */
 
-/* On CHRP copy exception vectors down to 0 */
-       lis     r5,_stext@ha
-       addi    r5,r5,_stext@l
-       addis   r5,r5,-KERNELBASE@h
-       cmpwi   0,r5,0
-       beq     77f             /* vectors are already at 0 */
-       li      r3,0x1000
-       mtctr   r3
-       li      r4,-4
-       addi    r5,r5,-4
-74:    lwzu    r0,4(r5)
-       stwu    r0,4(r4)
-       bdnz    74b
-       /* need to flush/invalidate caches too */
-       li      r3,0x4000/CACHE_LINE_SIZE
-       li      r4,0
-       mtctr   r3
-73:    dcbst   0,r4
-       addi    r4,r4,CACHE_LINE_SIZE
-       bdnz    73b
-       sync
-       li      r4,0
-       mtctr   r3
-72:    icbi    0,r4
-       addi    r4,r4,CACHE_LINE_SIZE
-       bdnz    72b
-       sync
-       isync
-77:
-
 /* Now turn on the MMU for real! */
        li      r4,MSR_KERNEL
        lis     r3,start_kernel@h
@@ -1227,29 +1628,6 @@ start_here:
        rfi                     /* enable MMU and jump to start_kernel */
 
 
-       .globl reset_SDR1
-reset_SDR1:
-       lis     r6,_SDR1@ha
-       lwz     r6,_SDR1@l(r6)
-       mfmsr   r5
-       li      r4,0
-       ori     r4,r4,MSR_EE|MSR_IR|MSR_DR
-       andc    r3,r5,r4
-       lis     r4,2f@h
-       ori     r4,r4,2f@l
-       tophys(r4,r4,r5)
-       mtspr   SRR0,r4
-       mtspr   SRR1,r3
-       rfi
-2:     /* load new SDR1 */
-       tlbia
-       mtspr   SDR1,r6
-       /* turn the mmu back on */
-       mflr    r3
-       mtspr   SRR0,r3
-       mtspr   SRR1,r5
-       rfi
-
 /*
  * FP unavailable trap from kernel - print a message, but let
  * the task use FP in the kernel until it returns to user mode.
@@ -1272,10 +1650,19 @@ KernelFP:
  * and save its floating-point registers in its thread_struct.
  * Enables the FPU for use in the kernel on return.
  */
+/* smp_giveup_fpu() takes an arg to tell it where to save the fpu
+ * regs since last_task_used_math can't be trusted (many many race
+ * conditions). -- Cort
+ */
+       .globl  smp_giveup_fpu
+smp_giveup_fpu:        
+       mr      r4,r3
+       b       12f
        .globl  giveup_fpu
 giveup_fpu:
        lis     r3,last_task_used_math@ha
        lwz     r4,last_task_used_math@l(r3)
+12:            
        mfmsr   r5
        ori     r5,r5,MSR_FP
        SYNC
@@ -1284,8 +1671,10 @@ giveup_fpu:
        cmpi    0,r4,0
        beqlr-                          /* if no previous owner, done */
        addi    r4,r4,TSS               /* want TSS of last_task_used_math */
+#ifndef __SMP__
        li      r5,0
        stw     r5,last_task_used_math@l(r3)
+#endif /* __SMP__ */   
        SAVE_32FPRS(0, r4)
        mffs    fr0
        stfd    fr0,TSS_FPSCR-4(r4)
@@ -1445,6 +1834,18 @@ syscall_ret_2:
  *
  * The code which creates the new task context is in 'copy_thread'
  * in arch/ppc/kernel/process.c
+ *
+ * The MPC8xx has something that currently happens "automagically."
+ * Unshared user space address translations are subject to ASID (context)
+ * match.  During each task switch, the ASID is incremented.  We can
+ * guarantee (I hope :-) that no entries currently match this ASID
+ * because every task will cause at least a TLB entry to be loaded for
+ * the first instruction and data access, plus the kernel running will
+ * have displaced several more TLBs.  The MMU contains 32 entries for
+ * each TLB, and there are 16 contexts, so we just need to make sure
+ * two pages get replaced for every context switch, which currently
+ * happens.  There are other TLB management techniques that I will
+ * eventually implement, but this is the easiest for now.  -- Dan
  */    
 _GLOBAL(_switch)
        stwu    r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
@@ -1476,6 +1877,7 @@ _GLOBAL(_switch)
        SYNC
        lwz     r1,KSP(r4)      /* Load new stack pointer */
        addi    r2,r4,-TSS      /* Update current */
+#ifndef CONFIG_8xx
        /* Set up segment registers for new task */
        rlwinm  r5,r5,4,8,27    /* VSID = context << 4 */
        addis   r5,r5,0x6000    /* Set Ks, Ku bits */
@@ -1486,9 +1888,32 @@ _GLOBAL(_switch)
        addi    r5,r5,1         /* next VSID */
        addis   r3,r3,0x1000    /* address of next segment */
        bdnz    3b
+#else
+/* On the MPC8xx, we place the physical address of the new task
+ * page directory loaded into the MMU base register, and set the
+ * ASID compare register with the new "context".
+ */
+       mtspr   M_CASID, r5             /* Update context */
+       lwz     r5,MM-TSS(r4)           /* Get virtual address of mm */
+       lwz     r5,PGD(r5)              /* get new->mm->pgd */  
+       tophys(r5, r5, 0)               /* convert to phys addr */
+       mtspr   M_TWB, r5               /* Update MMU base address */
+#endif
        SYNC
 
 /* FALL THROUGH into int_return */
+#ifdef __SMP__
+       /* drop scheduler_lock since we weren't called by schedule() */
+       lwz     r5,TSS_SMP_FORK_RET(r4)
+       cmpi    0,r5,0
+       beq+    int_return
+       li      r3,0
+       lis     r5,scheduler_lock@ha
+       stw     r3,TSS_SMP_FORK_RET(r4)
+       stw     r3,scheduler_lock@l+4(r5)       /* owner_pc */
+       stw     r3,scheduler_lock@l+8(r5)       /* owner_cpu */
+       stw     r3,scheduler_lock@l(r5)         /* lock */
+#endif /* __SMP__ */
 
 /*
  * Trap exit.
@@ -1566,6 +1991,18 @@ int_return:
        SYNC
        rfi
 
+#if 0/*def __SMP__*/
+       .globl  ret_from_smpfork
+ret_from_smpfork:
+       /* drop scheduler_lock since schedule() called us */
+       lis     r4,scheduler_lock@ha
+       li      r5,0
+       stw     r5,scheduler_lock@l+4(r4)       /* owner_pc */
+       stw     r5,scheduler_lock@l+8(r4)       /* owner_cpu */
+       stw     r5,scheduler_lock@l(r4)         /* lock */
+       b       int_return
+#endif /* __SMP__ */
+       
 /*
  * Fake an interrupt from kernel mode.
  * This is used when enable_irq loses an interrupt.
@@ -1686,6 +2123,7 @@ _GLOBAL(flush_page_to_ram)
  * Flush entries from the hash table with VSIDs in the range
  * given.
  */
+#ifndef CONFIG_8xx     
 _GLOBAL(flush_hash_segments)
 #ifdef NO_RELOAD_HTAB
 /*
@@ -1700,15 +2138,6 @@ _GLOBAL(flush_hash_segments)
        rlwnm.  r0,r9,r0,0,0
        bne     99f
 #endif /* NO_RELOAD_HTAB */
-#ifdef __SMP__
-       lis     r6,hash_table_lock@h
-       ori     r6,r6,hash_table_lock@l
-1011:  lwarx   r0,0,r6
-       stwcx.  r6,0,r6
-       bne-    1011b
-       cmpi    0,r0,0
-       bne     1011b
-#endif /* __SMP__ */   
        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 */
@@ -1730,12 +2159,6 @@ _GLOBAL(flush_hash_segments)
        stw     r0,0(r5)                /* invalidate entry */
 2:     bdnz    1b                      /* continue with loop */
        sync
-#ifdef __SMP__
-       lis     r5,hash_table_lock@h
-       ori     r5,r5,hash_table_lock@l
-       li      r6,0
-       stw     r6,0(r5)
-#endif /* __SMP__ */   
 99:    tlbia
        isync
        blr
@@ -1753,15 +2176,6 @@ _GLOBAL(flush_hash_page)
        rlwnm.  r0,r9,r0,0,0
        bne     99f
 #endif /* NO_RELOAD_HTAB */            
-#ifdef __SMP__
-       lis     r6,hash_table_lock@h
-       ori     r6,r6,hash_table_lock@l
-1011:  lwarx   r0,0,r6
-       stwcx.  r6,0,r6
-       bne-    1011b
-       cmpi    0,r0,0
-       bne     1011b
-#endif /* __SMP__ */   
        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 */
@@ -1794,22 +2208,17 @@ _GLOBAL(flush_hash_page)
 3:     li      r0,0
        stw     r0,0(r7)                /* invalidate entry */
 4:     sync
-#ifdef __SMP__
-       lis     r5,hash_table_lock@h
-       ori     r5,r5,hash_table_lock@l
-       li      r6,0
-       stw     r6,0(r5)
-#endif /* __SMP__ */   
 99:    tlbie   r4                      /* in hw tlb too */
        isync
        blr
-
+#endif /* CONFIG_8xx */
 /*
  * This routine is just here to keep GCC happy - sigh...
  */    
 _GLOBAL(__main)
        blr
 
+#ifndef CONFIG_8xx             
 /*
  * On CHRP, the Run-Time Abstraction Services (RTAS) have to be
  * called with the MMU off.
@@ -1819,9 +2228,9 @@ enter_rtas:
        stwu    r1,-16(r1)
        mflr    r0
        stw     r0,20(r1)
-       addis   r3,r3,-KERNELBASE@h
        lis     r4,rtas_data@ha
        lwz     r4,rtas_data@l(r4)
+       addis   r4,r4,-KERNELBASE@h
        lis     r6,1f@ha        /* physical return address for rtas */
        addi    r6,r6,1f@l
        addis   r6,r6,-KERNELBASE@h
@@ -1829,14 +2238,15 @@ enter_rtas:
        addis   r7,r7,-KERNELBASE@h
        lis     r8,rtas_entry@ha
        lwz     r8,rtas_entry@l(r8)
+       addis   r5,r8,-KERNELBASE@h
        mfmsr   r9
        stw     r9,8(r1)
-       li      r0,0
        ori     r0,r0,MSR_EE|MSR_SE|MSR_BE
        andc    r0,r9,r0
        andi.   r9,r9,MSR_ME|MSR_RI
        sync                    /* disable interrupts so SRR0/1 */
        mtmsr   r0              /* don't get trashed */
+       li      r6,0    
        mtlr    r6
        mtspr   SPRG2,r7
        mtspr   SRR0,r8
@@ -1850,23 +2260,26 @@ enter_rtas:
        mtspr   SRR0,r8
        mtspr   SRR1,r9
        rfi                     /* return to caller */
+#endif /* CONFIG_8xx */
 
+#ifdef CONFIG_8xx
+/* This is called during an exec when new page tables are created.
+ * It maps to the SET_PAGE_DIR macro.  I guess I should make it an
+ * inline function.
+ */
+_GLOBAL(set_page_dir)
+       addis   r3,r3,-KERNELBASE@h     /* convert to phys addr */
+       mtspr   M_TWB, r3               /* Update MMU base address */
+       blr
+#endif
        
-       .globl amhere
-amhere:        .long 0
-       
+               
 #ifdef __SMP__
 /*
  * Secondary processor begins executing here.
  */
        .globl  secondary_entry
 secondary_entry:
-       lis     r0,amhere@h
-       ori     r0,r0,amhere@l
-       addis   r0,r0,-KERNELBASE@h
-       stw     r0,0(r0)
-       sync
-       isync   
        /* just like __start() with a few changes -- Cort */
        mfspr   r9,PVR
        rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
@@ -1938,16 +2351,6 @@ secondary_entry:
        ori     r11,r11,HID0_BTCD
 5:     mtspr   HID0,r11                /* superscalar exec & br history tbl */
 4:
-       /* get ptr to current */
-       lis     r2,current_set@h
-       ori     r2,r2,current_set@l
-       /* assume we're second processor for now */
-       lwz     r2,4(r2)
-       /* stack */
-       addi    r1,r2,TASK_UNION_SIZE
-       li      r0,0
-       stwu    r0,-STACK_FRAME_OVERHEAD(r1)
-               
 /*
  * init_MMU on the first processor has setup the variables
  * for us - all we need to do is load them -- Cort 
@@ -1969,6 +2372,18 @@ secondary_entry:
        rfi
 /* Load up the kernel context */
 2:
+       /* get ptr to current */
+       lis     r2,current_set@h
+       ori     r2,r2,current_set@l
+       /* assume we're second processor for now */
+       tophys(r2,r2,r10)
+       lwz     r2,4(r2)
+       /* stack */
+       addi    r1,r2,TASK_UNION_SIZE
+       li      r0,0
+       tophys(r3,r1,r10)
+       stwu    r0,-STACK_FRAME_OVERHEAD(r3)
+       
        SYNC                    /* Force all PTE updates to finish */
        tlbia                   /* Clear all TLB entries */
        mtspr   SDR1,r6
@@ -2025,6 +2440,31 @@ secondary_entry:
 /* should never return */
        .long 0
 #endif /* __SMP__ */
+
+#ifdef CONFIG_MBX
+/* Jump into the system reset for the MBX rom.
+ * We first disable the MMU, and then jump to the ROM reset address.
+ *
+ * This does not work, don't bother trying.  There is no place in
+ * the ROM we can jump to cause a reset.  We will have to program
+ * a watchdog of some type that we don't service to cause a processor
+ * reset.
+ */
+       .globl  MBX_gorom
+MBX_gorom:
+       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
+2:
+       lis     r4, 0xfe000000@h
+       addi    r4, r4, 0xfe000000@l
+       mtlr    r4
+       blr
+#endif
        
 /*
  * We put a few things here that have to be page-aligned.
index f47d6f3d6df4e7a8a91b34f93abf0e3105e20e21..e93d0a6e0bad28b64ea8cb3d528211b9e17f8558 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.13 1998/01/06 06:44:55 cort Exp $
+ * $Id: idle.c,v 1.35 1998/04/07 20:24:23 cort Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
 #include <asm/smp_lock.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
+#include <asm/cache.h>
+#ifdef CONFIG_PMAC
+#include <asm/mediabay.h>
+#endif
 
-int zero_paged(void *unused);
-void inline power_save(void);
+void zero_paged(void);
+void power_save(void);
 void inline htab_reclaim(void);
 
+unsigned long htab_reclaim_on = 0;
+unsigned long zero_paged_on = 0;
+
 int idled(void *unused)
 {
        int ret = -EPERM;
 
-       /*
-        * 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); */
-
-#ifdef __SMP__ 
-printk("SMP %d: in idle.  current = %s/%d\n",
-       current->processor,current->comm,current->pid);
-#endif /* __SMP__ */
        for (;;)
        {
+               __sti();
+               
                /* endless loop with no priority at all */
                current->priority = -100;
                current->counter = -100;
+               
+               check_pgt_cache();
 
-               /* endless idle loop with no priority at all */
-               /* htab_reclaim(); */
-               schedule();
+               if ( !need_resched && zero_paged_on ) zero_paged();
+               if ( !need_resched && htab_reclaim_on ) htab_reclaim();
+
+               /*
+                * Only processor 1 may sleep now since processor 2 would
+                * never wake up.  Need to add timer code for processor 2
+                * then it can sleep. -- Cort
+                */
 #ifndef __SMP__
-               /* can't do this on smp since second processor
-                  will never wake up -- Cort */
-               /* power_save(); */
-#endif /* __SMP__  */
+               if ( !need_resched ) power_save();
+#endif /* __SMP__ */
+               schedule();
        }
        ret = 0;
        return ret;
@@ -76,13 +79,16 @@ printk("SMP %d: in idle.  current = %s/%d\n",
  * Mark 'zombie' pte's in the hash table as invalid.
  * This improves performance for the hash table reload code
  * a bit since we don't consider unused pages as valid.
- * I haven't done any rigorous performance analysis yet
- * so it's still experimental and turned off here.
  *  -- Cort
  */
+PTE *reclaim_ptr = 0;
 void inline htab_reclaim(void)
 {
+#ifndef CONFIG_8xx             
+#if 0  
        PTE *ptr, *start;
+       static int dir = 1;
+#endif 
        struct task_struct *p;
        unsigned long valid = 0;
        extern PTE *Hash, *Hash_end;
@@ -91,28 +97,33 @@ void inline htab_reclaim(void)
        /* if we don't have a htab */
        if ( Hash_size == 0 )
                return;
-       /*lock_dcache();*/
-       
+       lock_dcache(1);
+
+#if 0  
        /* find a random place in the htab to start each time */
-       start = &Hash[jiffies%(Hash_size/sizeof(ptr))];
-       for ( ptr = start; ptr < Hash_end ; ptr++)
+       start = &Hash[jiffies%(Hash_size/sizeof(PTE))];
+       /* go a different direction each time */
+       dir *= -1;
+        for ( ptr = start;
+             !need_resched && (ptr != Hash_end) && (ptr != Hash);
+             ptr += dir)
        {
-               if ( ptr == start )
-                       return;
-               if ( ptr == Hash_end )
-                       ptr = Hash;
-               valid = 0;
-               if (!ptr->v)
+#else
+       if ( !reclaim_ptr ) reclaim_ptr = Hash;
+       while ( !need_resched )
+       {
+               reclaim_ptr++;
+               if ( reclaim_ptr == Hash_end ) reclaim_ptr = Hash;
+#endif   
+               if (!reclaim_ptr->v)
                        continue;
+               valid = 0;
                for_each_task(p)
                {
                        if ( need_resched )
-                       {
-                               /*unlock_dcache();*/
-                               return;
-                       }
+                               goto out;
                        /* if this vsid/context is in use */
-                       if ( (ptr->vsid >> 4) == p->mm->context )
+                       if ( (reclaim_ptr->vsid >> 4) == p->mm->context )
                        {
                                valid = 1;
                                break;
@@ -121,19 +132,28 @@ void inline htab_reclaim(void)
                if ( valid )
                        continue;
                /* this pte isn't used */
-               ptr->v = 0;
+               reclaim_ptr->v = 0;
        }
-       /*unlock_dcache();*/
+out:
+       if ( need_resched ) printk("need_resched: %x\n", need_resched);
+       unlock_dcache();
+#endif /* CONFIG_8xx */
 }
-
+       
 /*
  * Syscall entry into the idle task. -- Cort
  */
 asmlinkage int sys_idle(void)
 {
+       extern int media_bay_task(void *);
        if(current->pid != 0)
                return -EPERM;
 
+#ifdef CONFIG_PMAC
+       if (media_bay_present)
+               kernel_thread(media_bay_task, NULL, 0);
+#endif
+
        idled(NULL);
        return 0; /* should never execute this but it makes gcc happy -- Cort */
 }
@@ -157,10 +177,8 @@ 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 */
 unsigned long zeropage_calls = 0;/* # zero'd pages request that've been made */
-static struct wait_queue * page_zerod_wait = NULL;
 #define PAGE_THRESHOLD 96       /* how many pages to keep pre-zero'd */
 
 /*
@@ -189,7 +207,6 @@ unsigned long get_prezerod_page(void)
                 */
                atomic_inc((atomic_t *)&zeropage_hits);
                atomic_dec((atomic_t *)&zerocount);
-               wake_up(&page_zerod_wait);
                need_resched = 1;
                
                /* zero out the pointer to next in the page */
@@ -201,35 +218,18 @@ unsigned long get_prezerod_page(void)
 
 /*
  * 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.
+ * to speed up get_free_pages(). Zero's out pages until
+ * we've reached the limit of zero'd pages.  We handle
+ * reschedule()'s in here so when we return we know we've
+ * zero'd all we need to for now.
  */
-int zero_paged(void *unused)
+void zero_paged(void)
 {
-       extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
-       pgd_t *dir;
-       pmd_t *pmd;
+       unsigned long pageptr = 0;      /* current page being zero'd */
        pte_t *pte;
-
-       sprintf(current->comm, "zero_paged (idle)");
-       /* current->blocked = ~0UL; */
        
-#ifdef __SMP__
-       printk("Started zero_paged (cpu %d)\n", hard_smp_processor_id());
-#else
-       printk("Started zero_paged\n");
-#endif /* __SMP__ */
-       
-       __sti();
-       while ( 1 )
+       while ( zerocount <= PAGE_THRESHOLD )
        {
-               /* don't want to be pre-empted by swapper or power_save */
-               current->priority = -98;
-               current->counter = -98;
-               /* we don't want to run until we have something to do */
-               while ( zerocount >= PAGE_THRESHOLD )
-                       sleep_on(&page_zerod_wait);
                /*
                 * Mark a page as reserved so we can mess with it
                 * If we're interrupted we keep this page and our place in it
@@ -237,7 +237,7 @@ int zero_paged(void *unused)
                 */
                pageptr = __get_free_pages(GFP_ATOMIC, 0);
                if ( !pageptr )
-                       goto retry;
+                       return;
                
                if ( need_resched )
                        schedule();
@@ -245,20 +245,15 @@ int zero_paged(void *unused)
                /*
                 * Make the page no cache so we don't blow our cache with 0's
                 */
-               dir = pgd_offset( init_task.mm, pageptr );
-               if (dir)
+               pte = find_pte(init_task.mm, pageptr);
+               if ( !pte )
                {
-                       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);
-                               }
-                       }
+                       printk("pte NULL in zero_paged()\n");
+                       return;
                }
+               
+               pte_uncache(*pte);
+               flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
        
                /*
                 * Important here to not take time away from real processes.
@@ -308,35 +303,34 @@ int zero_paged(void *unused)
                 */
                atomic_inc((atomic_t *)&zerocount);
                atomic_inc((atomic_t *)&zerototal);
-retry: 
-               schedule();
        }
 }
 
-void inline power_save(void)
+int powersave_mode = HID0_DOZE;
+
+void power_save(void)
 {
        unsigned long msr, hid0;
 
-       /* no powersaving modes on the 601 */
-       if(  (_get_PVR()>>16) == 1 )
+       /* only sleep on the 603-family/750 processors */
+       switch (_get_PVR() >> 16) {
+       case 3:                 /* 603 */
+       case 6:                 /* 603e */
+       case 7:                 /* 603ev */
+       case 8:                 /* 750 */
+               break;
+       default:
                return;
+       }
        
-       __sti();
-       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));
+       save_flags(msr);
+       cli();
+       if (!need_resched) {
+               asm("mfspr %0,1008" : "=r" (hid0) :);
+               hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
+               hid0 |= powersave_mode | HID0_DPM;
+               asm("mtspr 1008,%0" : : "r" (hid0));
+               msr |= MSR_POW;
+       }
+       restore_flags(msr);
 }
index 4616d59a2505c10ce6879eac97d3d552043492f9..462805a65953eb64b8d7889fbee8c28042d30edf 100644 (file)
  * instead of just grabbing them. Thus setups with different IRQ numbers
  * shouldn't result in any weird surprises, and installing new handlers
  * should be easier.
+ *
+ * The MPC8xx has an interrupt mask in the SIU.  If a bit is set, the
+ * interrupt is _enabled_.  As expected, IRQ0 is bit 0 in the 32-bit
+ * mask register (of which only 16 are defined), hence the weird shifting
+ * and compliment of the cached_irq_mask.  I want to be able to stuff
+ * this right into the SIU SMASK register.
+ * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx
+ * to reduce code space and undefined function references.
  */
 
 
 #include <linux/malloc.h>
 #include <linux/openpic.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/openpic.h>
 
 #include <asm/hydra.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/gg2.h>
+#include <asm/cache.h>
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#include <asm/mbx.h>
+#endif
 
 #undef SHOW_IRQ
 
 unsigned lost_interrupts = 0;
 unsigned int local_irq_count[NR_CPUS];
-static struct irqaction irq_action[NR_IRQS];
+static struct irqaction *irq_action[NR_IRQS];
 static int spurious_interrupts = 0;
+#ifndef CONFIG_8xx
+static unsigned int cached_irq_mask = 0xffffffff;
+#else
 static unsigned int cached_irq_mask = 0xffffffff;
+#endif
 static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-spinlock_t irq_controller_lock;
+/*spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;*/
 #ifdef __SMP__
 atomic_t __ppc_bh_counter = ATOMIC_INIT(0);
 #else
 int __ppc_bh_counter = 0;
 #endif
+static volatile unsigned char *gg2_int_ack_special;
+extern volatile unsigned long ipi_count;
 
 #define cached_21      (((char *)(&cached_irq_mask))[3])
 #define cached_A1      (((char *)(&cached_irq_mask))[2])
@@ -61,9 +80,19 @@ int __ppc_bh_counter = 0;
 /*
  * These are set to the appropriate functions by init_IRQ()
  */
+#ifndef CONFIG_8xx
 void (*mask_and_ack_irq)(int irq_nr);
 void (*mask_irq)(unsigned int irq_nr);
 void (*unmask_irq)(unsigned int irq_nr);
+#else /* CONFIG_8xx */
+/* init_IRQ() happens too late for the MBX because we initialize the
+ * CPM early and it calls request_irq() before we have these function
+ * pointers initialized.
+ */
+#define mask_and_ack_irq(irq)  mbx_mask_irq(irq)
+#define mask_irq(irq) mbx_mask_irq(irq)
+#define unmask_irq(irq) mbx_unmask_irq(irq)
+#endif /* CONFIG_8xx */
 
 
 /* prep */
@@ -79,9 +108,46 @@ extern unsigned long route_pci_interrupts(void);
 #define PMAC_IRQ_MASK  (~ld_le32(IRQ_ENABLE))
 
 
+
+/* nasty hack for shared irq's since we need to do kmalloc calls but
+ * can't very very early in the boot when we need to do a request irq.
+ * this needs to be removed.
+ * -- Cort
+ */
+static char cache_bitmask = 0;
+static struct irqaction malloc_cache[4];
+extern int mem_init_done;
+
+void *irq_kmalloc(size_t size, int pri)
+{
+       unsigned int i;
+       if ( mem_init_done )
+               return kmalloc(size,pri);
+       for ( i = 0; i <= 3 ; i++ )
+               if ( ! ( cache_bitmask & (1<<i) ) )
+               {
+                       cache_bitmask |= (1<<i);
+                       return (void *)(&malloc_cache[i]);
+               }
+       return 0;
+}
+
+void irq_kfree(void *ptr)
+{
+       unsigned int i;
+       for ( i = 0 ; i <= 3 ; i++ )
+               if ( ptr == &malloc_cache[i] )
+               {
+                       cache_bitmask &= ~(1<<i);
+                       return;
+               }
+       kfree(ptr);
+}
+
+#ifndef CONFIG_8xx     
 void i8259_mask_and_ack_irq(int irq_nr)
 {
-       spin_lock(&irq_controller_lock);
+  /*   spin_lock(&irq_controller_lock);*/
        cached_irq_mask |= 1 << irq_nr;
        if (irq_nr > 7) {
                inb(0xA1);      /* DUMMY */
@@ -96,20 +162,22 @@ void i8259_mask_and_ack_irq(int irq_nr)
                outb(0x60|irq_nr,0x20); /* specific eoi */
                  
        }
-       spin_unlock(&irq_controller_lock);
+       /*      spin_unlock(&irq_controller_lock);*/
 }
 
 void pmac_mask_and_ack_irq(int irq_nr)
 {
        unsigned long bit = 1UL << irq_nr;
 
-       spin_lock(&irq_controller_lock);
+       /*      spin_lock(&irq_controller_lock);*/
        cached_irq_mask |= bit;
        lost_interrupts &= ~bit;
        out_le32(IRQ_ACK, bit);
        out_le32(IRQ_ENABLE, ~cached_irq_mask);
        out_le32(IRQ_ACK, bit);
-       spin_unlock(&irq_controller_lock);
+       /*      spin_unlock(&irq_controller_lock);*/
+       /*if ( irq_controller_lock.lock )
+  panic("irq controller lock still held in mask and ack\n");*/
 }
 
 void chrp_mask_and_ack_irq(int irq_nr)
@@ -188,44 +256,96 @@ static void chrp_unmask_irq(unsigned int irq_nr)
        else
                openpic_enable_irq(irq_to_openpic(irq_nr));
 }
+#else /* CONFIG_8xx */
+static void mbx_mask_irq(unsigned int irq_nr)
+{
+       cached_irq_mask &= ~(1 << (31-irq_nr));
+       ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_simask =
+                                                       cached_irq_mask;
+}
+
+static void mbx_unmask_irq(unsigned int irq_nr)
+{
+       cached_irq_mask |= (1 << (31-irq_nr));
+       ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_simask =
+                                                       cached_irq_mask;
+}
+#endif /* CONFIG_8xx */
 
 void disable_irq(unsigned int irq_nr)
 {
-       unsigned long flags;
+       /*unsigned long flags;*/
 
-       spin_lock_irqsave(&irq_controller_lock, flags);
+       /*      spin_lock_irqsave(&irq_controller_lock, flags);*/
        mask_irq(irq_nr);
-       spin_unlock_irqrestore(&irq_controller_lock, flags);
+       /*      spin_unlock_irqrestore(&irq_controller_lock, flags);*/
        synchronize_irq();
 }
 
 void enable_irq(unsigned int irq_nr)
 {
-       unsigned long flags;
+       /*unsigned long flags;*/
 
-       spin_lock_irqsave(&irq_controller_lock, flags);
+       /*      spin_lock_irqsave(&irq_controller_lock, flags);*/
        unmask_irq(irq_nr);
-       spin_unlock_irqrestore(&irq_controller_lock, flags);
+       /*      spin_unlock_irqrestore(&irq_controller_lock, flags);*/
 }
 
 int get_irq_list(char *buf)
 {
-       int i, len = 0;
+       int i, len = 0, j;
        struct irqaction * action;
 
+       len += sprintf(buf+len, "           ");
+       for (j=0; j<smp_num_cpus; j++)
+               len += sprintf(buf+len, "CPU%d       ",j);
+       *(char *)(buf+len++) = '\n';
+
        for (i = 0 ; i < NR_IRQS ; i++) {
-               action = irq_action + i;
+               action = irq_action[i];
                if (!action || !action->handler)
                        continue;
-               len += sprintf(buf+len, "%2d: %10u   %s",
-                       i, kstat.interrupts[i], action->name);
+               len += sprintf(buf+len, "%3d: ", i);            
+#ifdef __SMP__
+               for (j = 0; j < smp_num_cpus; j++)
+                       len += sprintf(buf+len, "%10u ",
+                               kstat.irqs[cpu_logical_map(j)][i]);
+#else          
+               len += sprintf(buf+len, "%10u ", kstat_irqs(i));
+#endif /* __SMP__ */
+               switch( _machine )
+               {
+               case _MACH_prep:
+                       len += sprintf(buf+len, "    82c59 ");
+                       break;
+               case _MACH_Pmac:
+                       len += sprintf(buf+len, " PMAC-PIC ");
+                       break;
+               case _MACH_chrp:
+                       if ( is_8259_irq(i) )
+                               len += sprintf(buf+len, "    82c59 ");
+                       else
+                               len += sprintf(buf+len, "  OpenPIC ");
+                       break;
+               }
+
+               len += sprintf(buf+len, "   %s",action->name);
                for (action=action->next; action; action = action->next) {
                        len += sprintf(buf+len, ", %s", action->name);
                }
                len += sprintf(buf+len, "\n");
        }
-       len += sprintf(buf+len, "99: %10u   spurious or short\n",
-                      spurious_interrupts);
+#ifdef __SMP__
+       /* should this be per processor send/receive? */
+       len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
+       for ( i = 0 ; i <= smp_num_cpus-1; i++ )
+               len += sprintf(buf+len,"          ");
+       len += sprintf(buf+len, "    interprocessor messages received\n");
+#endif         
+       len += sprintf(buf+len, "BAD: %10u",spurious_interrupts);
+       for ( i = 0 ; i <= smp_num_cpus-1; i++ )
+               len += sprintf(buf+len,"          ");
+       len += sprintf(buf+len, "    spurious or short\n");
        return len;
 }
 
@@ -394,20 +514,31 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
        int status;
        int openpic_eoi_done = 0;
 
+       /* save the HID0 in case dcache was off - see idle.c
+        * this hack should leave for a better solution -- Cort */
+       unsigned dcache_locked;
+       
+       dcache_locked = unlock_dcache();        
+       hardirq_enter(cpu);
+#ifndef CONFIG_8xx               
 #ifdef __SMP__
        if ( cpu != 0 )
-               panic("cpu %d received interrupt", cpu);
-#endif /* __SMP__ */           
-
-       hardirq_enter(cpu);
+       {
+               if ( !lost_interrupts )
+               {
+                       extern smp_message_recv(void);
+                       goto out;
+                       
+                       ipi_count++;
+                       smp_message_recv();
+                       goto out;
+               }
+               /* could be here due to a do_fake_interrupt call but we don't
+                  mess with the controller from the second cpu -- Cort */
+               goto out;
+       }
+#endif /* __SMP__ */                   
 
-       /*
-        * I'll put this ugly mess of code into a function
-        * such as get_pending_irq() or some such clear thing
-        * so we don't have a switch in the irq code and
-        * the chrp code is merged a bit with the prep.
-        * -- Cort
-        */
        switch ( _machine )
        {
        case _MACH_Pmac:
@@ -425,7 +556,7 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
                         * 
                         * This should go in the above mask/ack code soon. -- Cort
                         */
-                       irq = *(volatile unsigned char *)GG2_INT_ACK_SPECIAL;
+                       irq = *gg2_int_ack_special;
                        /*
                         * Acknowledge as soon as possible to allow i8259
                         * interrupt nesting
@@ -456,7 +587,6 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
                }
                break;
        case _MACH_prep:
-#if 1
                outb(0x0C, 0x20);
                irq = inb(0x20) & 7;
                if (irq == 2)
@@ -470,23 +600,6 @@ retry_cascade:
                        irq = (irq&7) + 8;
                }
                bits = 1UL << irq;
-#else
-               /*
-                * get the isr from the intr controller since
-                * the bit in the irr has been cleared
-                */
-               outb(0x0a, 0x20);
-               bits = inb(0x20)&0xff;
-               /* handle cascade */
-               if ( bits & 4 )
-               {
-                       bits &= ~4UL;
-                       outb(0x0a, 0xA0);
-                       bits |= inb(0xA0)<<8;
-               }
-               /* ignore masked irqs */
-               bits &= ~cached_irq_mask;
-#endif         
                break;
        }
        
@@ -494,43 +607,62 @@ retry_cascade:
                printk("Bogus interrupt from PC = %lx\n", regs->nip);
                goto out;
        }
+       
+#else /* CONFIG_8xx */
+       /* For MPC8xx, read the SIVEC register and shift the bits down
+        * to get the irq number.
+        */
+       bits = ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sivec;
+       irq = bits >> 26;
+#endif /* CONFIG_8xx */
 
        mask_and_ack_irq(irq);
 
        status = 0;
-       action = irq_action + irq;
-       kstat.interrupts[irq]++;
-       if (action->handler) {
+       action = irq_action[irq];
+       kstat.irqs[cpu][irq]++;
+       if ( action && action->handler) {
                if (!(action->flags & SA_INTERRUPT))
                        __sti();
-               status |= action->flags;
-               action->handler(irq, action->dev_id, regs);
-               /*if (status & SA_SAMPLE_RANDOM)
-                       add_interrupt_randomness(irq);*/
-               __cli(); /* in case the handler turned them on */
-               spin_lock(&irq_controller_lock);
+               do { 
+                       status |= action->flags;
+                       action->handler(irq, action->dev_id, regs);
+                       /*if (status & SA_SAMPLE_RANDOM)
+                                 add_interrupt_randomness(irq);*/
+                       action = action->next;
+               } while ( action );
+               __cli();
+               /*              spin_lock(&irq_controller_lock);*/
                unmask_irq(irq);
-               spin_unlock(&irq_controller_lock);
+               /*              spin_unlock(&irq_controller_lock);*/
        } else {
+#ifndef CONFIG_8xx       
                if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
+#endif           
                        spurious_interrupts++;
                disable_irq( irq );
        }
        
        /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
+#ifndef CONFIG_8xx     
        if ( is_prep && (irq > 7) )
                goto retry_cascade;
        /* do_bottom_half is called if necessary from int_return in head.S */
 out:
        if (_machine == _MACH_chrp && !openpic_eoi_done)
                openpic_eoi(0);
+#endif /* CONFIG_8xx */
        hardirq_exit(cpu);
+       
+       /* restore the HID0 in case dcache was off - see idle.c
+        * this hack should leave for a better solution -- Cort */
+       lock_dcache(dcache_locked);
 }
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
        unsigned long irqflags, const char * devname, void *dev_id)
 {
-       struct irqaction * action;
+       struct irqaction *old, **p, *action;
        unsigned long flags;
 
 #ifdef SHOW_IRQ
@@ -540,49 +672,58 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
 
        if (irq >= NR_IRQS)
                return -EINVAL;
-       action = irq + irq_action;
-       if (action->handler)
-               return -EBUSY;
+
        if (!handler)
-               return -EINVAL;
+       {
+               /* Free */
+               for (p = irq + irq_action; (action = *p) != NULL; p = &action->next)
+               {
+                       /* Found it - now free it */
+                       save_flags(flags);
+                       cli();
+                       *p = action->next;
+                       restore_flags(flags);
+                       irq_kfree(action);
+                       return 0;
+               }
+               return -ENOENT;
+       }
+       
+       action = (struct irqaction *)
+               irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+       if (!action)
+               return -ENOMEM;
        save_flags(flags);
        cli();
+       
        action->handler = handler;
        action->flags = irqflags;
        action->mask = 0;
        action->name = devname;
        action->dev_id = dev_id;
+       action->next = NULL;
        enable_irq(irq);
-       restore_flags(flags);
+       p = irq_action + irq;
+       
+       if ((old = *p) != NULL) {
+               /* Can't share interrupts unless both agree to */
+               if (!(old->flags & action->flags & SA_SHIRQ))
+                       return -EBUSY;
+               /* add new interrupt at end of irq queue */
+               do {
+                       p = &old->next;
+                       old = *p;
+               } while (old);
+       }
+       *p = action;
+       
+       restore_flags(flags);   
        return 0;
 }
 
 void free_irq(unsigned int irq, void *dev_id)
 {
-       struct irqaction * action = irq + irq_action;
-       unsigned long flags;
-
-#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;
-       }
-       if (!action->handler) {
-               printk("Trying to free free IRQ%d\n",irq);
-               return;
-       }
-       disable_irq(irq);
-       save_flags(flags);
-       cli();
-       action->handler = NULL;
-       action->flags = 0;
-       action->mask = 0;
-       action->name = NULL;
-       action->dev_id = NULL;
-       restore_flags(flags);
+       request_irq(irq, NULL, 0, NULL, dev_id);
 }
 
 unsigned long probe_irq_on (void)
@@ -595,6 +736,7 @@ int probe_irq_off (unsigned long irqs)
        return 0;
 }
 
+#ifndef CONFIG_8xx 
 __initfunc(static void i8259_init(void))
 {
        /* init master interrupt controller */
@@ -616,11 +758,17 @@ __initfunc(static void i8259_init(void))
                panic("Could not allocate cascade IRQ!");
        enable_irq(2);  /* Enable cascade interrupt */
 }
+#endif /* CONFIG_8xx */
 
+/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug.  External
+ * interrupts can be either edge or level triggered, but there is no
+ * reason for us to change the EPPC-bug values (it would not work if we did).
+ */
 __initfunc(void init_IRQ(void))
 {
        extern void xmon_irq(int, void *, struct pt_regs *);
 
+#ifndef CONFIG_8xx
        switch (_machine)
        {
        case _MACH_Pmac:
@@ -637,7 +785,8 @@ __initfunc(void init_IRQ(void))
                mask_and_ack_irq = chrp_mask_and_ack_irq;
                mask_irq = chrp_mask_irq;
                unmask_irq = chrp_unmask_irq;
-               ioremap(GG2_INT_ACK_SPECIAL, 1);
+               gg2_int_ack_special = (volatile unsigned char *)
+                       ioremap(GG2_INT_ACK_SPECIAL, 1);
                openpic_init();
                i8259_init();
 #ifdef CONFIG_XMON
@@ -653,7 +802,7 @@ __initfunc(void init_IRQ(void))
                i8259_init();
                route_pci_interrupts();
                /*
-                * According to the Carolina spec from ibm irq's 0,1,2, and 8
+                * According to the Carolina spec from ibm irqs 0,1,2, and 8
                 * must be edge triggered.  Also, the pci intrs must be level
                 * triggered and _only_ isa intrs can be level sensitive
                 * which are 3-7,9-12,14-15. 13 is special - it can be level.
@@ -686,5 +835,6 @@ __initfunc(void init_IRQ(void))
 
                }
                break;
-       }
+       }       
+#endif /* CONFIG_8xx */
 }
diff --git a/arch/ppc/kernel/mbx_pci.c b/arch/ppc/kernel/mbx_pci.c
new file mode 100644 (file)
index 0000000..30b7b11
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * MBX pci routines.
+ * The MBX uses the QSpan PCI bridge.  The config address register
+ * is located 0x500 from the base of the bridge control/status registers.
+ * The data register is located at 0x504.
+ * This is a two step operation.  First, the address register is written,
+ * then the data register is read/written as required.
+ * I don't know what to do about interrupts (yet).
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/mbx.h>
+
+
+/*
+ * This blows......The MBX uses the Tundra QSpan PCI bridge.  When
+ * reading the configuration space, if something does not respond
+ * the bus times out and we get a machine check interrupt.  So, the
+ * good ol' exception tables come to mind to trap it and return some
+ * value.
+ *
+ * On an error we just return a -1, since that is what the caller wants
+ * returned if nothing is present.  I copied this from __get_user_asm,
+ * with the only difference of returning -1 instead of EFAULT.
+ * There is an associated hack in the machine check trap code.
+ *
+ * The QSPAN is also a big endian device, that is it makes the PCI
+ * look big endian to us.  This presents a problem for the Linux PCI
+ * functions, which assume little endian.  For example, we see the
+ * first 32-bit word like this:
+ *     ------------------------
+ *     | Device ID | Vendor ID |
+ *     ------------------------
+ * If we read/write as a double word, that's OK.  But in our world,
+ * when read as a word, device ID is at location 0, not location 2 as
+ * the little endian PCI would believe.  We have to switch bits in
+ * the PCI addresses given to us to get the data to/from the correct
+ * byte lanes.
+ *
+ * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
+ * It always forces the MS bit to zero.  Therefore, dev_fn values
+ * greater than 128 are returned as "no device found" errors.
+ *
+ * The QSPAN can only perform long word (32-bit) configuration cycles.
+ * The "offset" must have the two LS bits set to zero.  Read operations
+ * require we read the entire word and then sort out what should be
+ * returned.  Write operations other than long word require that we
+ * read the long word, update the proper word or byte, then write the
+ * entire long word back.
+ *
+ * PCI Bridge hack.  We assume (correctly) that bus 0 is the primary
+ * PCI bus from the QSPAN.  If we are called with a bus number other
+ * than zero, we create a Type 1 configuration access that a downstream
+ * PCI bridge will interpret.
+ */
+
+#define __get_mbx_pci_config(x, addr, op)              \
+       __asm__ __volatile__(                           \
+               "1:     "op" %0,0(%1)\n"                \
+               "       eieio\n"                        \
+               "2:\n"                                  \
+               ".section .fixup,\"ax\"\n"              \
+               "3:     li %0,-1\n"                     \
+               "       b 2b\n"                         \
+               ".section __ex_table,\"a\"\n"           \
+               "       .align 2\n"                     \
+               "       .long 1b,3b\n"                  \
+               ".text"                                 \
+               : "=r"(x) : "r"(addr))
+
+#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500))
+#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504))
+
+#define mk_config_addr(bus, dev, offset) \
+       (((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
+
+#define mk_config_type1(bus, dev, offset) \
+       mk_config_addr(bus, dev, offset) | 1;
+
+int mbx_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+                                 unsigned char offset, unsigned char *val)
+{
+       uint    temp;
+       u_char  *cp;
+
+       if ((bus > 7) || (dev_fn > 127)) {
+               *val = 0xff;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       if (bus == 0)
+               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+       else
+               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+       __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz");
+
+       offset ^= 0x03;
+       cp = ((u_char *)&temp) + (offset & 0x03);
+       *val = *cp;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                                 unsigned char offset, unsigned short *val)
+{
+       uint    temp;
+       ushort  *sp;
+
+       if ((bus > 7) || (dev_fn > 127)) {
+               *val = 0xffff;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       if (bus == 0)
+               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+       else
+               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+       __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz");
+       offset ^= 0x02;
+
+       sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+       *val = *sp;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned int *val)
+{
+       if ((bus > 7) || (dev_fn > 127)) {
+               *val = 0xffffffff;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+       if (bus == 0)
+               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+       else
+               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+       __get_mbx_pci_config(*val, QS_CONFIG_DATA, "lwz");
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned char val)
+{
+       uint    temp;
+       u_char  *cp;
+
+       if ((bus > 7) || (dev_fn > 127))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
+
+       offset ^= 0x03;
+       cp = ((u_char *)&temp) + (offset & 0x03);
+       *cp = val;
+
+       if (bus == 0)
+               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+       else
+               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+       *QS_CONFIG_DATA = temp;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                                  unsigned char offset, unsigned short val)
+{
+       uint    temp;
+       ushort  *sp;
+
+       if ((bus > 7) || (dev_fn > 127))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
+
+       offset ^= 0x02;
+       sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+       *sp = val;
+
+       if (bus == 0)
+               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+       else
+               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+       *QS_CONFIG_DATA = temp;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+                                   unsigned char offset, unsigned int val)
+{
+       if ((bus > 7) || (dev_fn > 127))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (bus == 0)
+               *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+       else
+               *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+       *(unsigned int *)QS_CONFIG_DATA = val;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+                            unsigned short index, unsigned char *bus_ptr,
+                            unsigned char *dev_fn_ptr)
+{
+    int num, devfn;
+    unsigned int x, vendev;
+
+    if (vendor == 0xffff)
+       return PCIBIOS_BAD_VENDOR_ID;
+    vendev = (dev_id << 16) + vendor;
+    num = 0;
+    for (devfn = 0;  devfn < 32;  devfn++) {
+       mbx_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
+       if (x == vendev) {
+           if (index == num) {
+               *bus_ptr = 0;
+               *dev_fn_ptr = devfn<<3;
+               return PCIBIOS_SUCCESSFUL;
+           }
+           ++num;
+       }
+    }
+    return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int mbx_pcibios_find_class(unsigned int class_code, unsigned short index,
+                           unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+    int devnr, x, num;
+
+    num = 0;
+    for (devnr = 0;  devnr < 32;  devnr++) {
+       mbx_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
+       if ((x>>8) == class_code) {
+           if (index == num) {
+               *bus_ptr = 0;
+               *dev_fn_ptr = devnr<<3;
+               return PCIBIOS_SUCCESSFUL;
+           }
+           ++num;
+       }
+    }
+    return PCIBIOS_DEVICE_NOT_FOUND;
+}
diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c
new file mode 100644 (file)
index 0000000..c028bb1
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *  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)
+ *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#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 <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/mbx.h>
+
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+
+#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
+
+extern char saved_command_line[256];
+
+extern unsigned long find_available_memory(void);
+extern void mbx_cpm_reset(uint);
+
+
+void mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+
+       *p = 0;
+       *irq = 0;
+
+       if (base != 0)          /* Only map the first ATA flash drive */
+               return;
+#ifdef ATA_FLASH
+       base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
+       for (i = 0; i < 8; ++i)
+               *p++ = base++;
+       *p = ++base;            /* Does not matter */
+       if (irq)
+               *irq = 13;
+#endif
+}
+
+int
+mbx_get_cpuinfo(char *buffer)
+{
+       int     pvr = _get_PVR();
+       int     len;
+       char    *model;
+       bd_t    *bp;
+       extern  RESIDUAL res;
+  
+       /* I know the MPC860 is 0x50.  I don't have the book handy
+        * to check the others.
+        */
+       if ((pvr>>16) == 0x50)
+               model = "MPC860";
+       else
+               model = "unknown";
+
+#ifdef __SMP__
+#define CD(X)          (cpu_data[n].X)  
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+       bp = (bd_t *)&res;
+
+       len = sprintf(buffer,"processor\t: %d\n"
+                     "cpu\t\t: %s\n"
+                     "revision\t: %d.%d\n"
+                     "clock\t\t: %d MHz\n"
+                     "bus clock\t: %d MHz\n",
+                     CPUN,
+                     model,
+                     MAJOR(pvr), MINOR(pvr),
+                     bp->bi_intfreq / 1000000,
+                     bp->bi_busfreq / 1000000
+               );
+  
+       return len;
+}
+
+__initfunc(void
+mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+       int     cpm_page;
+
+       cpm_page = *memory_start_p;
+       *memory_start_p += PAGE_SIZE;
+
+       /* Reset the Communication Processor Module.
+       */
+       mbx_cpm_reset(cpm_page);
+
+#ifdef notdef
+       ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+#endif
+       
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+       ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
+       rd_prompt = 1;
+       rd_doload = 1;
+       rd_image_start = 0;
+#endif
+       /* initrd_start and size are setup by boot/head.S and kernel/head.S */
+       if ( initrd_start )
+       {
+               if (initrd_end > *memory_end_p)
+               {
+                       printk("initrd extends beyond end of memory "
+                              "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+                              initrd_end,*memory_end_p);
+                       initrd_start = 0;
+               }
+       }
+#endif
+
+#ifdef notdef
+       request_region(0x20,0x20,"pic1");
+       request_region(0xa0,0x20,"pic2");
+       request_region(0x00,0x20,"dma1");
+       request_region(0x40,0x20,"timer");
+       request_region(0x80,0x10,"dma page reg");
+       request_region(0xc0,0x20,"dma2");
+#endif
+}
+
+void
+abort(void)
+{
+#ifdef CONFIG_XMON
+       extern void xmon(void *);
+       xmon(0);
+#endif
+       machine_restart(NULL);
+}
index 2c866eed86982becd83a91365b62c27e4d654f22..1c075c0236a3b24d5a6c6b4c3d7107b40ed4e9d8 100644 (file)
@@ -19,6 +19,7 @@
 #include "ppc_asm.tmpl"
 #include "ppc_defs.h"
 
+#ifndef CONFIG_8xx
 /* This instruction is not implemented on the PPC 601 or 603 */
 #define tlbia \
        li      r4,128; \
@@ -27,7 +28,7 @@
 0:     tlbie   r4; \
        addi    r4,r4,0x1000; \
        bdnz    0b
-       
+#endif 
        .text
 
 /*
@@ -323,6 +324,18 @@ _GLOBAL(_get_SP)
        mr      r3,r1           /* Close enough */
        blr
 
+_GLOBAL(_get_THRM1)
+       mfspr   r3,THRM1
+       blr
+
+_GLOBAL(_set_THRM1)
+       mtspr   THRM1,r3
+       blr
+       
+_GLOBAL(_get_L2CR)
+       mfspr   r3,L2CR
+       blr
+       
 _GLOBAL(_get_PVR)
        mfspr   r3,PVR
        blr
@@ -348,33 +361,6 @@ cvt_df:
        stfs    0,0(r4)
        blr
 
-
-_GLOBAL(lock_dcache)
-       mfspr   r3,PVR          /* nop on 601 */
-       rlwinm  r3,r3,16,16,31
-       cmpwi   0,r3,1
-       beqlr-
-       mfspr   r3,HID0
-       ori     r3,r3,HID0_DLOCK
-       mtspr   HID0,r3
-       sync
-       isync
-       blr
-
-_GLOBAL(unlock_dcache)
-       mfspr   r3,PVR          /* nop on 601 */
-       rlwinm  r3,r3,16,16,31
-       cmpwi   0,r3,1
-       beqlr-
-       mfspr   r3,HID0
-       li      r4,HID0_DLOCK
-       andc    r3,r3,r4
-       mtspr   HID0,r3
-       sync
-       isync
-       blr
-       
-
 /*
  * Create a kernel thread
  *   __kernel_thread(flags, fn, arg)
@@ -386,6 +372,16 @@ _GLOBAL(__kernel_thread)
        bnelr                   /* return if parent */
        mtlr    r4              /* fn addr in lr */
        mr      r3,r5           /* load arg and call fn */
+#if 0/*def __SMP__*/
+       /* drop scheduler_lock since schedule() called us */
+       lis     r4,scheduler_lock@ha
+       li      r5,0
+       stw     r5,scheduler_lock@l+4(r4)       /* owner_pc */
+       stw     r5,scheduler_lock@l+8(r4)       /* owner_cpu */
+       stw     r5,scheduler_lock@l(r4)
+       sync
+       isync
+#endif /* __SMP__ */
        blrl
        li      r0,__NR_exit    /* exit after child exits */
         li     r3,0
@@ -413,7 +409,9 @@ SYSCALL(execve)
 SYSCALL(open)
 SYSCALL(close)
 SYSCALL(waitpid)
+SYSCALL(fork)
 SYSCALL(delete_module)
+SYSCALL(_exit)
 
 
 /* Why isn't this a) automatic, b) written in 'C'? */  
@@ -593,5 +591,7 @@ sys_call_table:
        .long sys_setresgid     
        .long sys_getresgid     /* 170 */
        .long sys_prctl
-       .space (NR_syscalls-171)*4
+       .long sys_xstat
+       .long sys_xmknod
+       .space (NR_syscalls-173)*4
 
index 8db1763dbd3bf4a43c1e22fae9252324cea63b02..9de0565047e8f5b4b4c946c935ff4f98a3615c9f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <asm/io.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 void
 main(void)
 {
+       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(PROCESSOR, offsetof(struct task_struct, processor));
        DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending));
        DEFINE(TSS, offsetof(struct task_struct, tss));
        DEFINE(MM, offsetof(struct task_struct, mm));
@@ -45,6 +48,7 @@ main(void)
        DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
        DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
        DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+       DEFINE(TSS_SMP_FORK_RET, offsetof(struct thread_struct, smp_fork_ret));
        /* Interrupt register frame */
        DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
        DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff --git a/arch/ppc/kernel/pci-bridge.c b/arch/ppc/kernel/pci-bridge.c
deleted file mode 100644 (file)
index 0e44203..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Support for PCI bridges found on Power Macintoshes.
- * At present the "bandit" and "chaos" bridges are supported.
- * Fortunately you access configuration space in the same
- * way with either bridge.
- *
- * Copyright (C) 1997 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/bios32.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-
-struct bridge_data {
-       volatile unsigned int *cfg_addr;
-       volatile unsigned char *cfg_data;
-       void *io_base;
-       int bus_number;
-       int max_bus;
-       struct bridge_data *next;
-       struct device_node *node;
-};
-
-static struct bridge_data **bridges, *bridge_list;
-static int max_bus;
-
-static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
-
-/*
- * Magic constants for enabling cache coherency in the bandit/PSX bridge.
- */
-#define APPLE_VENDID   0x106b
-#define BANDIT_DEVID   1
-#define BANDIT_REVID   3
-
-#define BANDIT_DEVNUM  11
-#define BANDIT_MAGIC   0x50
-#define BANDIT_COHERENT        0x40
-
-/*
- * For a bandit bridge, turn on cache coherency if necessary.
- * N.B. we can't use pcibios_*_config_* here because bridges[]
- * is not initialized yet.
- */
-static void init_bandit(struct bridge_data *bp)
-{
-       unsigned int vendev, magic;
-       int rev;
-
-       /* read the word at offset 0 in config space for device 11 */
-       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
-       udelay(2);
-       vendev = in_le32((volatile unsigned int *)bp->cfg_data);
-       if (vendev != (BANDIT_DEVID << 16) + APPLE_VENDID) {
-               printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
-               return;
-       }
-
-       /* read the revision id */
-       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
-       udelay(2);
-       rev = in_8(bp->cfg_data);
-       if (rev != BANDIT_REVID)
-               printk(KERN_WARNING "Unknown revision %d for bandit at %p\n",
-                      rev, bp->io_base);
-
-       /* read the word at offset 0x50 */
-       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
-       udelay(2);
-       magic = in_le32((volatile unsigned int *)bp->cfg_data);
-       if ((magic & BANDIT_COHERENT) != 0)
-               return;
-       magic |= BANDIT_COHERENT;
-       udelay(2);
-       out_le32((volatile unsigned int *)bp->cfg_data, magic);
-       printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %p\n",
-              bp->io_base);
-}
-
-unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
-{
-       int bus;
-       struct bridge_data *bridge;
-
-       bridge_list = 0;
-       max_bus = 0;
-       add_bridges(find_devices("bandit"), &mem_start);
-       add_bridges(find_devices("chaos"), &mem_start);
-       bridges = (struct bridge_data **) mem_start;
-       mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
-       memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
-       for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
-               for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
-                       bridges[bus] = bridge;
-
-       return mem_start;
-}
-
-static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
-{
-       int *bus_range;
-       int len;
-       struct bridge_data *bp;
-
-       for (; dev != NULL; dev = dev->next) {
-               if (dev->n_addrs < 1) {
-                       printk(KERN_WARNING "Can't use %s: no address\n",
-                              dev->full_name);
-                       continue;
-               }
-               bus_range = (int *) get_property(dev, "bus-range", &len);
-               if (bus_range == NULL || len < 2 * sizeof(int)) {
-                       printk(KERN_WARNING "Can't get bus-range for %s\n",
-                              dev->full_name);
-                       continue;
-               }
-               if (bus_range[1] == bus_range[0])
-                       printk(KERN_INFO "PCI bus %d", bus_range[0]);
-               else
-                       printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
-                              bus_range[1]);
-               printk(" controlled by %s at %x\n",
-                      dev->name, dev->addrs[0].address);
-               bp = (struct bridge_data *) *mem_ptr;
-               *mem_ptr += sizeof(struct bridge_data);
-               bp->cfg_addr = (volatile unsigned int *)
-                       (dev->addrs[0].address + 0x800000);
-               bp->cfg_data = (volatile unsigned char *)
-                       (dev->addrs[0].address + 0xc00000);
-               bp->io_base = (void *) dev->addrs[0].address;
-               ioremap(dev->addrs[0].address, 0x800000);
-               bp->bus_number = bus_range[0];
-               bp->max_bus = bus_range[1];
-               bp->next = bridge_list;
-               bp->node = dev;
-               bridge_list = bp;
-               if (bp->max_bus > max_bus)
-                       max_bus = bp->max_bus;
-
-               if (strcmp(dev->name, "bandit") == 0)
-                       init_bandit(bp);
-       }
-}
-
-void *pci_io_base(unsigned int bus)
-{
-       struct bridge_data *bp;
-
-       if (bus > max_bus || (bp = bridges[bus]) == 0)
-               return 0;
-       return bp->io_base;
-}
-
-int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
-                  unsigned char *devfn_ptr)
-{
-       unsigned int *reg;
-       int len;
-
-       reg = (unsigned int *) get_property(dev, "reg", &len);
-       if (reg == 0 || len < 5 * sizeof(unsigned int)) {
-               /* doesn't look like a PCI device */
-               *bus_ptr = 0xff;
-               *devfn_ptr = 0xff;
-               return -1;
-       }
-       *bus_ptr = reg[0] >> 16;
-       *devfn_ptr = reg[0] >> 8;
-       return 0;
-}
-
-int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
-                                 unsigned char offset, unsigned char *val)
-{
-       struct bridge_data *bp;
-
-       *val = 0xff;
-       if (bus > max_bus || (bp = bridges[bus]) == 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       if (bus == bp->bus_number) {
-               if (dev_fn < (11 << 3))
-                       return PCIBIOS_DEVICE_NOT_FOUND;
-               out_le32(bp->cfg_addr,
-                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
-                        + (offset & ~3));
-       } else {
-               out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
-       }
-       udelay(2);
-       *val = in_8(bp->cfg_data + (offset & 3));
-
-       if (offset == PCI_INTERRUPT_LINE) {
-               /*
-                * Open Firmware often doesn't initialize this
-                * register properly, so we find the node and see
-                * if it has an AAPL,interrupts property.
-                */
-               struct device_node *node;
-               unsigned int *reg;
-
-               for (node = bp->node->child; node != 0; node = node->sibling) {
-                       reg = (unsigned int *) get_property(node, "reg", 0);
-                       if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
-                               continue;
-                       /* this is the node, see if it has interrupts */
-                       if (node->n_intrs > 0)
-                               *val = node->intrs[0];
-                       break;
-               }
-       }
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
-                                 unsigned char offset, unsigned short *val)
-{
-       struct bridge_data *bp;
-
-       *val = 0xffff;
-       if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       if (bus == bp->bus_number) {
-               if (dev_fn < (11 << 3))
-                       return PCIBIOS_DEVICE_NOT_FOUND;
-               out_le32(bp->cfg_addr,
-                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
-                        + (offset & ~3));
-       } else {
-               out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
-       }
-       udelay(2);
-       *val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
-                                  unsigned char offset, unsigned int *val)
-{
-       struct bridge_data *bp;
-
-       *val = 0xffffffff;
-       if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       if (bus == bp->bus_number) {
-               if (dev_fn < (11 << 3))
-                       return PCIBIOS_DEVICE_NOT_FOUND;
-               out_le32(bp->cfg_addr,
-                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
-                        + offset);
-       } else {
-               out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
-       }
-       udelay(2);
-       *val = in_le32((volatile unsigned int *)bp->cfg_data);
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
-                                  unsigned char offset, unsigned char val)
-{
-       struct bridge_data *bp;
-
-       if (bus > max_bus || (bp = bridges[bus]) == 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       if (bus == bp->bus_number) {
-               if (dev_fn < (11 << 3))
-                       return PCIBIOS_DEVICE_NOT_FOUND;
-               out_le32(bp->cfg_addr,
-                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
-                        + (offset & ~3));
-       } else {
-               out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
-       }
-       udelay(2);
-       out_8(bp->cfg_data + (offset & 3), val);
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
-                                  unsigned char offset, unsigned short val)
-{
-       struct bridge_data *bp;
-
-       if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       if (bus == bp->bus_number) {
-               if (dev_fn < (11 << 3))
-                       return PCIBIOS_DEVICE_NOT_FOUND;
-               out_le32(bp->cfg_addr,
-                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
-                        + (offset & ~3));
-       } else {
-               out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
-       }
-       udelay(2);
-       out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-                                   unsigned char offset, unsigned int val)
-{
-       struct bridge_data *bp;
-
-       if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       if (bus == bp->bus_number) {
-               if (dev_fn < (11 << 3))
-                       return PCIBIOS_DEVICE_NOT_FOUND;
-               out_le32(bp->cfg_addr,
-                        (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
-                        + offset);
-       } else {
-               out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
-       }
-       udelay(2);
-       out_le32((volatile unsigned int *)bp->cfg_data, val);
-       return PCIBIOS_SUCCESSFUL;
-}
-
-int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
-                            unsigned short index, unsigned char *bus_ptr,
-                            unsigned char *dev_fn_ptr)
-{
-       int bus, unit, fn, num, devfn;
-       unsigned int x, vendev;
-       unsigned char h;
-
-       if (vendor == 0xffff)
-               return PCIBIOS_BAD_VENDOR_ID;
-       vendev = (dev_id << 16) + vendor;
-       num = 0;
-       for (bus = 0; bus <= max_bus; ++bus) {
-               if (bridges[bus] == 0)
-                       continue;
-               unit = fn = 0;
-               if (bus == bridges[bus]->bus_number)
-                       unit = 11;
-               while (unit < 32) {
-                       devfn = PCI_DEVFN(unit, fn);
-                       if (pcibios_read_config_dword(bus, devfn,
-                                                     PCI_VENDOR_ID, &x)
-                           == PCIBIOS_SUCCESSFUL && x == vendev) {
-                               if (index == num) {
-                                       *bus_ptr = bus;
-                                       *dev_fn_ptr = devfn;
-                                       return PCIBIOS_SUCCESSFUL;
-                               }
-                               ++num;
-                       }
-                       if (fn != 0) {
-                               if (++fn >= 8) {
-                                       ++unit;
-                                       fn = 0;
-                               }
-                               continue;
-                       }
-                       if (pcibios_read_config_byte(bus, devfn,
-                                                    PCI_HEADER_TYPE, &h)
-                           == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
-                               ++fn;
-                       else
-                               ++unit;
-               }
-       }
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
-                           unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
-{
-       int bus, unit, fn, num, devfn;
-       unsigned int x;
-       unsigned char h;
-
-       num = 0;
-       for (bus = 0; bus <= max_bus; ++bus) {
-               if (bridges[bus] == 0)
-                       continue;
-               unit = fn = 0;
-               if (bus == bridges[bus]->bus_number)
-                       unit = 11;
-               while (unit < 32) {
-                       devfn = PCI_DEVFN(unit, fn);
-                       if (pcibios_read_config_dword(bus, devfn,
-                                                     PCI_CLASS_REVISION, &x)
-                           == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
-                               if (index == num) {
-                                       *bus_ptr = bus;
-                                       *dev_fn_ptr = devfn;
-                                       return PCIBIOS_SUCCESSFUL;
-                               }
-                               ++num;
-                       }
-                       if (fn != 0) {
-                               if (++fn >= 8) {
-                                       ++unit;
-                                       fn = 0;
-                               }
-                               continue;
-                       }
-                       if (pcibios_read_config_byte(bus, devfn,
-                                                    PCI_HEADER_TYPE, &h)
-                           == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
-                               ++fn;
-                       else
-                               ++unit;
-               }
-       }
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-__initfunc(unsigned long route_pci_interrupts(void))
-{
-       return 0;
-}
index 7e39487d80a6160dd4f02305de4c801c241cd717..186165a46cb2e698c083644a93dafc3c521cde64 100644 (file)
@@ -1,24 +1,27 @@
 /*
- * $Id: pci.c,v 1.18 1997/10/29 03:35:07 cort Exp $
+ * $Id: pci.c,v 1.24 1998/02/19 21:29:49 cort Exp $
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/config.h>
 #include <linux/pci.h>
+#include <linux/openpic.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
+#include <asm/irq.h>
 
-#if !defined(CONFIG_MACH_SPECIFIC)
+#if !defined(CONFIG_MACH_SPECIFIC) || defined(CONFIG_PMAC)
 unsigned long isa_io_base;
+#endif /* CONFIG_MACH_SPECIFIC || CONFIG_PMAC */
+#if !defined(CONFIG_MACH_SPECIFIC)
 unsigned long isa_mem_base;
 unsigned long pci_dram_offset;
 #endif /* CONFIG_MACH_SPECIFIC */
@@ -121,49 +124,6 @@ int pcibios_present(void)
        return 1;
 }
 
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
-                        unsigned short index, unsigned char *bus,
-                        unsigned char *devfn)
-{
-       unsigned int curr = 0;
-       struct pci_dev *dev;
-       for (dev = pci_devices; dev; dev = dev->next) {
-               if (dev->vendor == vendor && dev->device == device_id) {
-                       if (curr == index) {
-                               *devfn = dev->devfn;
-                               *bus = dev->bus->number;
-                               return PCIBIOS_SUCCESSFUL;
-                       }
-                       ++curr;
-               }
-       }
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-/*
- * Given the class, find the n'th instance of that device
- * in the system.
- */
-int pcibios_find_class (unsigned int class_code, unsigned short index,
-                       unsigned char *bus, unsigned char *devfn)
-{
-       unsigned int curr = 0;
-       struct pci_dev *dev;
-
-       for (dev = pci_devices; dev; dev = dev->next) {
-               if (dev->class == class_code) {
-                       if (curr == index) {
-                               *devfn = dev->devfn;
-                               *bus = dev->bus->number;
-                               return PCIBIOS_SUCCESSFUL;
-                       }
-                       ++curr;
-               }
-       }
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-
 __initfunc(unsigned long
           pcibios_init(unsigned long mem_start,unsigned long mem_end))
 {
@@ -203,6 +163,70 @@ __initfunc(void
 
 __initfunc(unsigned long
           pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
+
 {
+       extern route_pci_interrupts(void);
+       struct pci_dev *dev;
+       extern struct bridge_data **bridges;
+       extern unsigned char *Motherboard_map;
+       extern unsigned char *Motherboard_routes;
+       
+       /*
+        * FIXME: This is broken: We should not assign IRQ's to IRQless
+        *        devices (look at PCI_INTERRUPT_PIN) and we also should
+        *        honor the existence of multi-function devices where
+        *        different functions have different interrupt pins. [mj]
+        */
+       switch (_machine )
+       {
+       case _MACH_prep:
+               route_pci_interrupts();
+               for(dev=pci_devices; dev; dev=dev->next)
+               {
+                       unsigned char d = PCI_SLOT(dev->devfn);
+                       dev->irq = Motherboard_routes[Motherboard_map[d]];
+               }
+               break;
+       case _MACH_chrp:
+               /* PCI interrupts are controlled by the OpenPIC */
+               for(dev=pci_devices; dev; dev=dev->next)
+                       if (dev->irq)
+                               dev->irq = openpic_to_irq(dev->irq);
+               break;
+       case _MACH_Pmac:
+               for(dev=pci_devices; dev; dev=dev->next)
+               {
+                       /*
+                        * Open Firmware often doesn't initialize the,
+                        * PCI_INTERRUPT_LINE config register properly, so we
+                        * should find the device node and se if it has an
+                        * AAPL,interrupts property.
+                        */
+                       struct bridge_data *bp = bridges[dev->bus->number];
+                       struct device_node *node;
+                       unsigned int *reg;
+                       unsigned char pin;
+                       
+                       if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
+                           !pin)
+                               continue;       /* No interrupt generated -> no fixup */
+                       for (node = bp->node->child; node != 0;
+                            node = node->sibling) {
+                               reg = (unsigned int *) get_property(node, "reg", 0);
+                               if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
+                                       continue;
+                               /* this is the node, see if it has interrupts */
+                               if (node->n_intrs > 0)
+                                       dev->irq = node->intrs[0].line;
+                               break;
+                       }
+               }
+               break;
+       }
        return mem_start;
 }
+
+__initfunc(char *pcibios_setup(char *str))
+{
+       return str;
+}
index d0144a56759ef6e09c555b5dd25096fecba7b7f1..6b471bfca7bd3eebaedfd9865260cab6ec3a85ca 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 
-struct bridge_data {
-       volatile unsigned int *cfg_addr;
-       volatile unsigned char *cfg_data;
-       void *io_base;
-       int bus_number;
-       int max_bus;
-       struct bridge_data *next;
-       struct device_node *node;
-};
-
-static struct bridge_data **bridges, *bridge_list;
+struct bridge_data **bridges, *bridge_list;
 static int max_bus;
 
 static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
@@ -112,9 +102,11 @@ static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
        int *bus_range;
        int len;
        struct bridge_data *bp;
+       struct reg_property *addr;
 
        for (; dev != NULL; dev = dev->next) {
-               if (dev->n_addrs < 1) {
+               addr = (struct reg_property *) get_property(dev, "reg", &len);
+               if (addr == NULL || len < sizeof(*addr)) {
                        printk(KERN_WARNING "Can't use %s: no address\n",
                               dev->full_name);
                        continue;
@@ -130,15 +122,18 @@ static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
                else
                        printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
                               bus_range[1]);
-               printk(" controlled by %s at %x\n",
-                      dev->name, dev->addrs[0].address);
+               printk(" controlled by %s at %x\n", dev->name, addr->address);
                bp = (struct bridge_data *) *mem_ptr;
                *mem_ptr += sizeof(struct bridge_data);
                bp->cfg_addr = (volatile unsigned int *)
-                       ioremap(dev->addrs[0].address + 0x800000, 0x1000);
+                       ioremap(addr->address + 0x800000, 0x1000);
                bp->cfg_data = (volatile unsigned char *)
-                       ioremap(dev->addrs[0].address + 0xc00000, 0x1000);
-               bp->io_base = (void *) ioremap(dev->addrs[0].address, 0x10000);
+                       ioremap(addr->address + 0xc00000, 0x1000);
+               bp->io_base = (void *) ioremap(addr->address, 0x10000);
+#ifdef CONFIG_PMAC
+               if (isa_io_base == 0)
+                       isa_io_base = (unsigned long) bp->io_base;
+#endif
                bp->bus_number = bus_range[0];
                bp->max_bus = bus_range[1];
                bp->next = bridge_list;
@@ -180,7 +175,7 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
 }
 
 int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
-                            unsigned char offset, unsigned char *val)
+                                 unsigned char offset, unsigned char *val)
 {
        struct bridge_data *bp;
 
@@ -198,32 +193,11 @@ int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
        }
        udelay(2);
        *val = in_8(bp->cfg_data + (offset & 3));
-
-       if (offset == PCI_INTERRUPT_LINE) {
-               /*
-                * Open Firmware often doesn't initialize this
-                * register properly, so we find the node and see
-                * if it has an AAPL,interrupts property.
-                */
-               struct device_node *node;
-               unsigned int *reg;
-
-               for (node = bp->node->child; node != 0; node = node->sibling) {
-                       reg = (unsigned int *) get_property(node, "reg", 0);
-                       if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
-                               continue;
-                       /* this is the node, see if it has interrupts */
-                       if (node->n_intrs > 0)
-                               *val = node->intrs[0];
-                       break;
-               }
-       }
-
        return PCIBIOS_SUCCESSFUL;
 }
 
 int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
-                            unsigned char offset, unsigned short *val)
+                                 unsigned char offset, unsigned short *val)
 {
        struct bridge_data *bp;
 
@@ -245,7 +219,7 @@ int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 }
 
 int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
-                             unsigned char offset, unsigned int *val)
+                                  unsigned char offset, unsigned int *val)
 {
        struct bridge_data *bp;
 
@@ -267,7 +241,7 @@ int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
 }
 
 int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
-                             unsigned char offset, unsigned char val)
+                                  unsigned char offset, unsigned char val)
 {
        struct bridge_data *bp;
 
@@ -288,7 +262,7 @@ int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
 }
 
 int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
-                             unsigned char offset, unsigned short val)
+                                  unsigned char offset, unsigned short val)
 {
        struct bridge_data *bp;
 
@@ -309,7 +283,7 @@ int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
 }
 
 int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-                              unsigned char offset, unsigned int val)
+                                   unsigned char offset, unsigned int val)
 {
        struct bridge_data *bp;
 
index 4e37becd565b60c9c1d6d2b9016e84e7bfef607a..afcd4fd8b1706be93414d124d409179796fc9198 100644 (file)
 #include <asm/ide.h>
 #include <asm/pci-bridge.h>
 #include <asm/adb.h>
+#include <asm/mediabay.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
 #include "time.h"
 
-/*
- * A magic address and value to put into it on machines with the
- * "ohare" I/O controller.  This makes the IDE CD work on Starmaxes.
- * Contributed by Harry Eaton.
- */
-#define OMAGICPLACE    ((volatile unsigned *) 0xf3000038)
-#define OMAGICCONT     0xbeff7a
-
 extern int root_mountflags;
 
 unsigned char drive_info;
 
 #define DEFAULT_ROOT_DEVICE 0x0801     /* sda1 - slightly silly choice */
 
-static void gc_init(const char *, int);
+static void ohare_init(void);
 
 void
 pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)
@@ -91,27 +86,44 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)
                        loops_per_sec = 50000000;
        }
 
+       /* this area has the CPU identification register
+          and some registers used by smp boards */
+       ioremap(0xf8000000, 0x1000);
+
        *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
-       gc_init("gc", 0);
-       gc_init("ohare", 1);
 
-#ifdef CONFIG_ABSTRACT_CONSOLE
+       ohare_init();
+
+#ifdef CONFIG_FB
        /* Frame buffer device based console */
        conswitchp = &fb_con;
 #endif
 }
 
-static void gc_init(const char *name, int isohare)
+static volatile u32 *feature_addr;
+
+static void ohare_init(void)
 {
        struct device_node *np;
 
-       for (np = find_devices(name); np != NULL; np = np->next) {
-               if (np->n_addrs > 0)
-                       ioremap(np->addrs[0].address, np->addrs[0].size);
-               if (isohare) {
-                       printk(KERN_INFO "Twiddling the magic ohare bits\n");
-                       out_le32(OMAGICPLACE, OMAGICCONT);
-               }
+       np = find_devices("ohare");
+       if (np == 0)
+               return;
+       if (np->next != 0)
+               printk(KERN_WARNING "only using the first ohare\n");
+       if (np->n_addrs == 0) {
+               printk(KERN_ERR "No addresses for %s\n", np->full_name);
+               return;
+       }
+       feature_addr = (volatile u32 *)
+               ioremap(np->addrs[0].address + OHARE_FEATURE_REG, 4);
+
+       if (find_devices("via-pmu") == 0) {
+               printk(KERN_INFO "Twiddling the magic ohare bits\n");
+               out_le32(feature_addr, STARMAX_FEATURES);
+       } else {
+               out_le32(feature_addr, in_le32(feature_addr) | PBOOK_FEATURES);
+               printk(KERN_DEBUG "feature reg = %x\n", in_le32(feature_addr));
        }
 }
 
@@ -125,10 +137,15 @@ kdev_t boot_dev;
 unsigned long
 powermac_init(unsigned long mem_start, unsigned long mem_end)
 {
-       pmac_nvram_init();
+#ifdef CONFIG_KGDB
+       extern void zs_kgdb_hook(int tty_num);
+       zs_kgdb_hook(0);
+#endif
        adb_init();
+       pmac_nvram_init();
        if (_machine == _MACH_Pmac) {
                pmac_read_rtc_time();
+               media_bay_init();
        }
 #ifdef CONFIG_PMAC_CONSOLE
        pmac_find_display();
@@ -175,7 +192,7 @@ note_scsi_host(struct device_node *node, void *host)
 #include "../../../drivers/scsi/sd.h"
 #include "../../../drivers/scsi/hosts.h"
 
-int sd_find_target(void *host, int tgt)
+kdev_t sd_find_target(void *host, int tgt)
 {
     Scsi_Disk *dp;
     int i;
@@ -190,7 +207,7 @@ int sd_find_target(void *host, int tgt)
 
 void find_boot_device(void)
 {
-       int dev;
+       kdev_t dev;
 
        if (kdev_t_to_nr(ROOT_DEV) != 0)
                return;
@@ -201,7 +218,7 @@ void find_boot_device(void)
        dev = sd_find_target(boot_host, boot_target);
        if (dev == 0)
                return;
-       boot_dev = to_kdev_t(dev + boot_part);
+       boot_dev = MKDEV(MAJOR(dev), MINOR(dev) + boot_part);
 #endif
        /* XXX should cope with booting from IDE also */
 }
@@ -221,39 +238,92 @@ void note_bootable_part(kdev_t dev, int part)
        }
 }
 
+#ifdef CONFIG_BLK_DEV_IDE
+int pmac_ide_ports_known;
+ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
+int pmac_ide_irq[MAX_HWIFS];
+
 void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
 {
-       struct device_node *np;
        int i;
-       static struct device_node *atas;
-       static int atas_valid;
 
        *p = 0;
-       *irq = 0;
-       if (!atas_valid) {
-               atas = find_devices("ATA");
-               atas_valid = 1;
-       }
-       for (i = (int)base, np = atas; i > 0 && np != NULL; --i, np = np->next)
-               ;
-       if (np == NULL)
+       if (base == 0)
                return;
-       if (np->n_addrs == 0) {
-               printk("ide: no addresses for device %s\n", np->full_name);
+       if (base == mb_cd_base && !check_media_bay(MB_CD)) {
+               mb_cd_index = -1;
                return;
        }
-       if (np->n_intrs == 0) {
-               printk("ide: no intrs for device %s, using 13\n",
-                      np->full_name);
-               *irq = 13;
-       } else {
-               *irq = np->intrs[0];
-       }
-       base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
        for (i = 0; i < 8; ++i)
                *p++ = base + i * 0x10;
        *p = base + 0x160;
+       if (irq != NULL) {
+               *irq = 0;
+               for (i = 0; i < MAX_HWIFS; ++i) {
+                       if (base == pmac_ide_regbase[i]) {
+                               *irq = pmac_ide_irq[i];
+                               break;
+                       }
+               }
+       }
+}
+
+void pmac_ide_probe(void)
+{
+       struct device_node *np;
+       int i;
+       struct device_node *atas;
+       struct device_node *p, **pp, *removables, **rp;
+
+       pp = &atas;
+       rp = &removables;
+       p = find_devices("ATA");
+       if (p == NULL)
+               p = find_devices("IDE");
+       /* Move removable devices such as the media-bay CDROM
+          on the PB3400 to the end of the list. */
+       for (; p != NULL; p = p->next) {
+               if (p->parent && p->parent->name
+                   && strcasecmp(p->parent->name, "media-bay") == 0) {
+                       *rp = p;
+                       rp = &p->next;
+               } else {
+                       *pp = p;
+                       pp = &p->next;
+               }
+       }
+       *rp = NULL;
+       *pp = removables;
+
+       for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
+               if (np->n_addrs == 0) {
+                       printk(KERN_WARNING "ide: no address for device %s\n",
+                              np->full_name);
+                       continue;
+               }
+               pmac_ide_regbase[i] = (unsigned long)
+                       ioremap(np->addrs[0].address, 0x200);
+               if (np->n_intrs == 0) {
+                       printk("ide: no intrs for device %s, using 13\n",
+                              np->full_name);
+                       pmac_ide_irq[i] = 13;
+               } else {
+                       pmac_ide_irq[i] = np->intrs[0].line;
+               }
+
+               if (np->parent && np->parent->name
+                   && strcasecmp(np->parent->name, "media-bay") == 0) {
+                       mb_cd_index = i;
+                       mb_cd_base = pmac_ide_regbase[i];
+                       mb_cd_irq = pmac_ide_irq[i];
+               }
+
+               ++i;
+       }
+
+       pmac_ide_ports_known = 1;
 }
+#endif /* CONFIG_BLK_DEV_IDE */
 
 int
 pmac_get_cpuinfo(char *buffer)
index 17226f8ff376bb1ae3d70b1914b679e883fe0f47..4ceaa0dc91c1297b7ca58d678e386350ad509164 100644 (file)
@@ -7,8 +7,11 @@
 #include <linux/nvram.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/prom.h>
+#include <asm/adb.h>
+#include <asm/pmu.h>
 
 /*
  * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
@@ -32,8 +35,7 @@ void pmac_nvram_init(void)
        }
        nvram_naddrs = dp->n_addrs;
        if (_machine == _MACH_chrp && nvram_naddrs == 1) {
-               /* XXX for now */
-               nvram_data = ioremap(0xf70e0000, NVRAM_SIZE);
+               nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
                nvram_mult = 1;
        } else if (nvram_naddrs == 1) {
                nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
@@ -41,6 +43,8 @@ void pmac_nvram_init(void)
        } else if (nvram_naddrs == 2) {
                nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
                nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+       } else if (nvram_naddrs == 0 && adb_hardware == ADB_VIAPMU) {
+               nvram_naddrs = -1;
        } else {
                printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
                       nvram_naddrs);
@@ -49,7 +53,16 @@ void pmac_nvram_init(void)
 
 unsigned char nvram_read_byte(int addr)
 {
+       struct adb_request req;
+
        switch (nvram_naddrs) {
+       case -1:
+               if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
+                               (addr >> 8) & 0xff, addr & 0xff))
+                       break;
+               while (!req.complete)
+                       pmu_poll();
+               return req.reply[1];
        case 1:
                return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
        case 2:
@@ -62,7 +75,16 @@ unsigned char nvram_read_byte(int addr)
 
 void nvram_write_byte(unsigned char val, int addr)
 {
+       struct adb_request req;
+
        switch (nvram_naddrs) {
+       case -1:
+               if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
+                               (addr >> 8) & 0xff, addr & 0xff, val))
+                       break;
+               while (!req.complete)
+                       pmu_poll();
+               break;
        case 1:
                nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
                break;
index 1a31ffa9ac0b0bbc25b3e60dccea7ec405231b36..3c976506e1579b5a22c061c7c82737cd57eac571 100644 (file)
 #include <linux/mm.h>
 #include <asm/adb.h>
 #include <asm/cuda.h>
+#include <asm/pmu.h>
 #include <asm/prom.h>
 #include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
 
 #include "time.h"
 
 /* Bits in IFR and IER */
 #define T1_INT         0x40            /* Timer 1 interrupt */
 
-static int via_calibrate_decr(void)
+/*
+ * Calibrate the decrementer register using VIA timer 1.
+ * This is used both on powermacs and CHRP machines.
+ */
+int via_calibrate_decr(void)
 {
        struct device_node *vias;
        volatile unsigned char *via;
@@ -54,9 +61,12 @@ static int via_calibrate_decr(void)
        vias = find_devices("via-cuda");
        if (vias == 0)
                vias = find_devices("via-pmu");
+       if (vias == 0)
+               vias = find_devices("via");
        if (vias == 0 || vias->n_addrs == 0)
                return 0;
-       via = (volatile unsigned char *) vias->addrs[0].address;
+       via = (volatile unsigned char *)
+               ioremap(vias->addrs[0].address, vias->addrs[0].size);
 
        /* set timer 1 for continuous interrupts */
        out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
@@ -123,14 +133,30 @@ pmac_get_rtc_time(void)
        struct adb_request req;
 
        /* Get the time from the RTC */
-       cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
-       while (!req.complete)
-               cuda_poll();
-       if (req.reply_len != 7)
-               printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-                     req.reply_len);
-       return (req.reply[3] << 24) + (req.reply[4] << 16)
-               + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+       switch (adb_hardware) {
+       case ADB_VIACUDA:
+               if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+                       return 0;
+               while (!req.complete)
+                       cuda_poll();
+               if (req.reply_len != 7)
+                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+                              req.reply_len);
+               return (req.reply[3] << 24) + (req.reply[4] << 16)
+                       + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+       case ADB_VIAPMU:
+               if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+                       return 0;
+               while (!req.complete)
+                       pmu_poll();
+               if (req.reply_len != 5)
+                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+                              req.reply_len);
+               return (req.reply[1] << 24) + (req.reply[2] << 16)
+                       + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET;
+       default:
+               return 0;
+       }
 }
 
 int pmac_set_rtc_time(unsigned long nowtime)
diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c
new file mode 100644 (file)
index 0000000..b7eab0f
--- /dev/null
@@ -0,0 +1,705 @@
+/* $Id: ppc-stub.c,v 1.2 1998/04/11 17:29:03 geert Exp $
+ * ppc-stub.c:  KGDB support for the Linux kernel.
+ *
+ * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
+ * some stuff borrowed from Paul Mackerras' xmon
+ * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu)
+ *
+ * Modifications to run under Linux
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * This file originally came from the gdb sources, and the
+ * copyright notices have been retained below.
+ */
+
+/****************************************************************************
+
+               THIS SOFTWARE IS NOT COPYRIGHTED
+
+   HP offers the following for use in the public domain.  HP makes no
+   warranty with regard to the software or its performance and the
+   user accepts the software "AS IS" with all faults.
+
+   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:      Glenn Engel $
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:           See Below $
+ *
+ *  Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ *  This code has been extensively tested on the Fujitsu SPARClite demo board.
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing a trap #1.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *    qOffsets      Get section offsets.  Reply is Text=xxx;Data=yyy;Bss=zzz
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ *    bBB..BB      Set baud rate to BB..BB                OK or BNN, then sets
+ *                                                        baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/system.h>
+#include <asm/signal.h>
+#include <asm/system.h>
+#include <asm/kgdb.h>
+#include <asm/pgtable.h>
+#include <asm/ptrace.h>
+
+void breakinst(void);
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+static int initialized = 0;
+static int kgdb_active = 0;
+static u_int fault_jmp_buf[100];
+static int kdebug;
+
+static const char hexchars[]="0123456789abcdef";
+
+/* Place where we save old trap entries for restoration - sparc*/
+/* struct tt_entry kgdb_savettable[256]; */
+/* typedef void (*trapfunc_t)(void); */
+
+#if 0
+/* Install an exception handler for kgdb */
+static void exceptionHandler(int tnum, unsigned int *tfunc)
+{
+       /* We are dorking with a live trap table, all irqs off */
+}
+#endif
+
+int
+kgdb_setjmp(long *buf)
+{
+       asm ("mflr 0; stw 0,0(%0);"
+            "stw 1,4(%0); stw 2,8(%0);"
+            "mfcr 0; stw 0,12(%0);"
+            "stmw 13,16(%0)"
+            : : "r" (buf));
+       /* XXX should save fp regs as well */
+       return 0;
+}
+void
+kgdb_longjmp(long *buf, int val)
+{
+       if (val == 0)
+               val = 1;
+       asm ("lmw 13,16(%0);"
+            "lwz 0,12(%0); mtcrf 0x38,0;"
+            "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
+            "mtlr 0; mr 3,%1"
+            : : "r" (buf), "r" (val));
+}
+/* Convert ch from a hex digit to an int */
+static int
+hex(unsigned char ch)
+{
+       if (ch >= 'a' && ch <= 'f')
+               return ch-'a'+10;
+       if (ch >= '0' && ch <= '9')
+               return ch-'0';
+       if (ch >= 'A' && ch <= 'F')
+               return ch-'A'+10;
+       return -1;
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ */
+static unsigned char *
+mem2hex(char *mem, char *buf, int count)
+{
+       unsigned char ch;
+
+       if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+               debugger_fault_handler = kgdb_fault_handler;
+               while (count-- > 0) {
+                       ch = *mem++;
+                       *buf++ = hexchars[ch >> 4];
+                       *buf++ = hexchars[ch & 0xf];
+               }
+       } else {
+               /* error condition */
+       }
+       debugger_fault_handler = 0;
+       *buf = 0;
+       return buf;
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written.
+*/
+static char *
+hex2mem(char *buf, char *mem, int count)
+{
+       int i;
+       unsigned char ch;
+
+       if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+               debugger_fault_handler = kgdb_fault_handler;
+               for (i=0; i<count; i++) {
+                       ch = hex(*buf++) << 4;
+                       ch |= hex(*buf++);
+                       *mem++ = ch;
+               }
+               flush_icache_range((int)mem, (int)mem+count);
+       } else {
+               /* error condition */
+       }
+       debugger_fault_handler = 0;
+       return mem;
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int
+hexToInt(char **ptr, int *intValue)
+{
+       int numChars = 0;
+       int hexValue;
+
+       *intValue = 0;
+
+       if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+               debugger_fault_handler = kgdb_fault_handler;
+               while (**ptr) {
+                       hexValue = hex(**ptr);
+                       if (hexValue < 0)
+                               break;
+
+                       *intValue = (*intValue << 4) | hexValue;
+                       numChars ++;
+
+                       (*ptr)++;
+               }
+       } else {
+            /* error condition */
+       }
+       debugger_fault_handler = 0;
+
+       return (numChars);
+}
+
+/* scan for the sequence $<data>#<checksum>     */
+static void
+getpacket(char *buffer)
+{
+       unsigned char checksum;
+       unsigned char xmitcsum;
+       int i;
+       int count;
+       unsigned char ch;
+
+       do {
+               /* wait around for the start character, ignore all other
+                * characters */
+               while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+               checksum = 0;
+               xmitcsum = -1;
+
+               count = 0;
+
+               /* now, read until a # or end of buffer is found */
+               while (count < BUFMAX) {
+                       ch = getDebugChar() & 0x7f;
+                       if (ch == '#')
+                               break;
+                       checksum = checksum + ch;
+                       buffer[count] = ch;
+                       count = count + 1;
+               }
+
+               if (count >= BUFMAX)
+                       continue;
+
+               buffer[count] = 0;
+
+               if (ch == '#') {
+                       xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+                       xmitcsum |= hex(getDebugChar() & 0x7f);
+                       if (checksum != xmitcsum)
+                               putDebugChar('-');      /* failed checksum */
+                       else {
+                               putDebugChar('+'); /* successful transfer */
+                               /* if a sequence char is present, reply the ID */
+                               if (buffer[2] == ':') {
+                                       putDebugChar(buffer[0]);
+                                       putDebugChar(buffer[1]);
+                                       /* remove sequence chars from buffer */
+                                       count = strlen(buffer);
+                                       for (i=3; i <= count; i++)
+                                               buffer[i-3] = buffer[i];
+                               }
+                       }
+               }
+       } while (checksum != xmitcsum);
+}
+
+/* send the packet in buffer.  */
+static void putpacket(unsigned char *buffer)
+{
+       unsigned char checksum;
+       int count;
+       unsigned char ch, recv;
+
+       /*  $<packet info>#<checksum>. */
+       do {
+               putDebugChar('$');
+               checksum = 0;
+               count = 0;
+
+               while ((ch = buffer[count])) {
+                       putDebugChar(ch);
+                       checksum += ch;
+                       count += 1;
+               }
+
+               putDebugChar('#');
+               putDebugChar(hexchars[checksum >> 4]);
+               putDebugChar(hexchars[checksum & 0xf]);
+               recv = getDebugChar();
+       } while ((recv & 0x7f) != '+');
+}
+
+static void kgdb_flush_cache_all(void)
+{
+       flush_instruction_cache();
+}
+
+static inline int get_msr()
+{
+       int msr;
+       asm volatile("mfmsr %0" : "=r" (msr):);
+       return msr;
+}
+
+static inline void set_msr(int msr)
+{
+       asm volatile("mfmsr %0" : : "r" (msr));
+}
+
+/* Set up exception handlers for tracing and breakpoints
+ * [could be called kgdb_init()]
+ */
+void set_debug_traps(void)
+{
+#if 0
+       unsigned char c;
+
+       save_and_cli(flags);
+
+       /* In case GDB is started before us, ack any packets (presumably
+        * "$?#xx") sitting there.
+        *
+        * I've found this code causes more problems than it solves,
+        * so that's why it's commented out.  GDB seems to work fine
+        * now starting either before or after the kernel   -bwb
+        */
+
+       while((c = getDebugChar()) != '$');
+       while((c = getDebugChar()) != '#');
+       c = getDebugChar(); /* eat first csum byte */
+       c = getDebugChar(); /* eat second csum byte */
+       putDebugChar('+'); /* ack it */
+#endif
+       debugger = kgdb;
+       debugger_bpt = kgdb_bpt;
+       debugger_sstep = kgdb_sstep;
+       debugger_iabr_match = kgdb_iabr_match;
+       debugger_dabr_match = kgdb_dabr_match;
+
+       kgdb_interruptible(1);
+       initialized = 1;
+}
+
+static void kgdb_fault_handler(struct pt_regs *regs)
+{
+       kgdb_longjmp((long*)fault_jmp_buf, 1);
+}
+
+int kgdb_bpt(struct pt_regs *regs)
+{
+       handle_exception(regs);
+       return 1;
+}
+
+int kgdb_sstep(struct pt_regs *regs)
+{
+       handle_exception(regs);
+       return 1;
+}
+
+void kgdb(struct pt_regs *regs)
+{
+       handle_exception(regs);
+}
+
+int kgdb_iabr_match(struct pt_regs *regs)
+{
+       printk("kgdb doesn't support iabr, what?!?\n");
+       handle_exception(regs);
+       return 1;
+}
+
+int kgdb_dabr_match(struct pt_regs *regs)
+{
+       printk("kgdb doesn't support dabr, what?!?\n");
+       handle_exception(regs);
+       return 1;
+}
+
+/* Convert the SPARC hardware trap type code to a unix signal number. */
+/*
+ * This table contains the mapping between PowerPC hardware trap types, and
+ * signals, which are primarily what GDB understands.
+ */
+static struct hard_trap_info
+{
+       unsigned int tt;                /* Trap type code for powerpc */
+       unsigned char signo;            /* Signal that we map this trap into */
+} hard_trap_info[] = {
+       { 0x200, SIGSEGV },                     /* machine check */
+       { 0x300, SIGSEGV },                     /* address error (store) */
+       { 0x400, SIGBUS },                      /* instruction bus error */
+       { 0x500, SIGINT },                      /* interrupt */
+       { 0x600, SIGBUS },                      /* alingment */
+       { 0x700, SIGILL },                      /* reserved instruction or sumpin' */
+       { 0x800, SIGFPE },                      /* fpu unavail */
+       { 0x900, SIGALRM },                     /* decrementer */
+       { 0xa00, SIGILL },                      /* reserved */
+       { 0xb00, SIGILL },                      /* reserved */
+       { 0xc00, SIGCHLD },                     /* syscall */
+       { 0xd00, SIGINT },                      /* watch */
+       { 0xe00, SIGFPE },                      /* fp assist */
+       { 0, 0}                         /* Must be last */
+};
+
+static int computeSignal(unsigned int tt)
+{
+       struct hard_trap_info *ht;
+
+       for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+               if (ht->tt == tt)
+                       return ht->signo;
+
+       return SIGHUP;         /* default for things we don't know about */
+}
+
+/*
+ * This function does all command processing for interfacing to gdb.
+ */
+static void
+handle_exception (struct pt_regs *regs)
+{
+       int sigval;
+       int addr;
+       int length;
+       char *ptr;
+       unsigned int msr;
+
+       if (debugger_fault_handler) {
+               debugger_fault_handler(regs);
+               panic("kgdb longjump failed!\n");
+       }
+       if (kgdb_active) {
+               printk("interrupt while in kgdb, returning\n");
+               return;
+       }
+       kgdb_active = 1;
+
+       printk("kgdb: entering handle_exception; trap [0x%x]\n",
+              (unsigned int)regs->trap);
+
+       kgdb_interruptible(0);
+       lock_kernel();
+       msr = get_msr();
+       set_msr(msr & ~MSR_EE); /* disable interrupts */
+
+       if (regs->nip == (unsigned long)breakinst) {
+               /* Skip over breakpoint trap insn */
+               regs->nip += 4;
+       }
+
+       /* reply to host that an exception has occurred */
+       sigval = computeSignal(regs->trap);
+       ptr = remcomOutBuffer;
+
+       *ptr++ = 'S';
+       *ptr++ = hexchars[sigval >> 4];
+       *ptr++ = hexchars[sigval & 0xf];
+
+       *ptr++ = 0;
+
+       putpacket(remcomOutBuffer);
+
+       /* XXX We may want to add some features dealing with poking the
+        * XXX page tables, ... (look at sparc-stub.c for more info)
+        * XXX also required hacking to the gdb sources directly...
+        */
+
+       while (1) {
+               remcomOutBuffer[0] = 0;
+
+               getpacket(remcomInBuffer);
+               switch (remcomInBuffer[0]) {
+               case '?':               /* report most recent signal */
+                       remcomOutBuffer[0] = 'S';
+                       remcomOutBuffer[1] = hexchars[sigval >> 4];
+                       remcomOutBuffer[2] = hexchars[sigval & 0xf];
+                       remcomOutBuffer[3] = 0;
+                       break;
+#if 0
+               case 'q': /* this screws up gdb for some reason...*/
+               {
+                       extern long _start, sdata, __bss_start;
+
+                       ptr = &remcomInBuffer[1];
+                       if (strncmp(ptr, "Offsets", 7) != 0)
+                               break;
+
+                       ptr = remcomOutBuffer;
+                       sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x",
+                               &_start, &sdata, &__bss_start);
+                       break;
+               }
+#endif
+               case 'd':
+                       /* toggle debug flag */
+                       kdebug ^= 1;
+                       break;
+
+               case 'g':       /* return the value of the CPU registers.
+                                * some of them are non-PowerPC names :(
+                                * they are stored in gdb like:
+                                * struct {
+                                *     u32 gpr[32];
+                                *     f64 fpr[32];
+                                *     u32 pc, ps, cnd, lr; (ps=msr)
+                                *     u32 cnt, xer, mq;
+                                * }
+                                */
+               {
+                       int i;
+                       ptr = remcomOutBuffer;
+                       /* General Purpose Regs */
+                       ptr = mem2hex((char *)regs, ptr, 32 * 4);
+                       /* Floating Point Regs - FIXME */
+                       /*ptr = mem2hex((char *), ptr, 32 * 8);*/
+                       for(i=0; i<(32*8*2); i++) { /* 2chars/byte */
+                               ptr[i] = '0';
+                       }
+                       ptr += 32*8*2;
+                       /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
+                       ptr = mem2hex((char *)&regs->nip, ptr, 4);
+                       ptr = mem2hex((char *)&regs->msr, ptr, 4);
+                       ptr = mem2hex((char *)&regs->ccr, ptr, 4);
+                       ptr = mem2hex((char *)&regs->link, ptr, 4);
+                       ptr = mem2hex((char *)&regs->ctr, ptr, 4);
+                       ptr = mem2hex((char *)&regs->xer, ptr, 4);
+               }
+                       break;
+
+               case 'G':   /* set the value of the CPU registers */
+               {
+                       ptr = &remcomInBuffer[1];
+
+                       /*
+                        * If the stack pointer has moved, you should pray.
+                        * (cause only god can help you).
+                        */
+
+                       /* General Purpose Regs */
+                       hex2mem(ptr, (char *)regs, 32 * 4);
+
+                       /* Floating Point Regs - FIXME?? */
+                       /*ptr = hex2mem(ptr, ??, 32 * 8);*/
+                       ptr += 32*8*2;
+
+                       /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
+                       ptr = hex2mem(ptr, (char *)&regs->nip, 4);
+                       ptr = hex2mem(ptr, (char *)&regs->msr, 4);
+                       ptr = hex2mem(ptr, (char *)&regs->ccr, 4);
+                       ptr = hex2mem(ptr, (char *)&regs->link, 4);
+                       ptr = hex2mem(ptr, (char *)&regs->ctr, 4);
+                       ptr = hex2mem(ptr, (char *)&regs->xer, 4);
+
+                       strcpy(remcomOutBuffer,"OK");
+               }
+                       break;
+               case 'H':
+                       /* dont do anything, yet, just acknowledge */
+                       hexToInt(&ptr, &addr);
+                       strcpy(remcomOutBuffer,"OK");
+                       break;
+
+               case 'm':       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+                               /* Try to read %x,%x.  */
+
+                       ptr = &remcomInBuffer[1];
+
+                       if (hexToInt(&ptr, &addr)
+                           && *ptr++ == ','
+                           && hexToInt(&ptr, &length)) {
+                               if (mem2hex((char *)addr, remcomOutBuffer,length))
+                                       break;
+                               strcpy (remcomOutBuffer, "E03");
+                       } else {
+                               strcpy(remcomOutBuffer,"E01");
+                       }
+                       break;
+
+               case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+                       /* Try to read '%x,%x:'.  */
+
+                       ptr = &remcomInBuffer[1];
+
+                       if (hexToInt(&ptr, &addr)
+                           && *ptr++ == ','
+                           && hexToInt(&ptr, &length)
+                           && *ptr++ == ':') {
+                               if (hex2mem(ptr, (char *)addr, length)) {
+                                       strcpy(remcomOutBuffer, "OK");
+                               } else {
+                                       strcpy(remcomOutBuffer, "E03");
+                               }
+                       } else {
+                               strcpy(remcomOutBuffer, "E02");
+                       }
+                       break;
+
+
+               case 'k':    /* kill the program, actually just continue */
+               case 'c':    /* cAA..AA  Continue; address AA..AA optional */
+                       /* try to read optional parameter, pc unchanged if no parm */
+
+                       ptr = &remcomInBuffer[1];
+                       if (hexToInt(&ptr, &addr)) {
+                               regs->nip = addr;
+                       }
+
+/* Need to flush the instruction cache here, as we may have deposited a
+ * breakpoint, and the icache probably has no way of knowing that a data ref to
+ * some location may have changed something that is in the instruction cache.
+ */
+                       kgdb_flush_cache_all();
+                       set_msr(msr);
+                       kgdb_interruptible(1);
+                       unlock_kernel();
+                       kgdb_active = 0;
+                       return;
+
+               case 's':
+                       kgdb_flush_cache_all();
+                       regs->msr |= MSR_SE;
+                       set_msr(msr | MSR_SE);
+                       unlock_kernel();
+                       kgdb_active = 0;
+                       return;
+
+               case 'r':               /* Reset (if user process..exit ???)*/
+                       panic("kgdb reset.");
+                       break;
+               }                       /* switch */
+               if (remcomOutBuffer[0] && kdebug) {
+                       printk("remcomInBuffer: %s\n", remcomInBuffer);
+                       printk("remcomOutBuffer: %s\n", remcomOutBuffer);
+               }
+               /* reply to the request */
+               putpacket(remcomOutBuffer);
+       } /* while(1) */
+}
+
+/* This function will generate a breakpoint exception.  It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+
+void
+breakpoint(void)
+{
+       if (!initialized) {
+               printk("breakpoint() called b4 kgdb init\n");
+               return;
+       }
+
+       asm("   .globl breakinst
+            breakinst: trap
+            ");
+}
index 386bfe3ac9debf505cda383a471b4f80e44b82aa..4e918ab78fc87a2c2fb1af01df3e25e801f32530 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ppc_htab.c,v 1.16 1997/11/17 18:25:04 cort Exp $
+ * $Id: ppc_htab.c,v 1.17 1998/03/14 07:52:49 cort Exp $
  *
  * PowerPC hash table management proc entry.  Will show information
  * about the current hash table and will allow changes to it.
@@ -88,6 +88,7 @@ struct inode_operations proc_ppc_htab_inode_operations = {
 #define PMC1 953
 #define PMC2 954
 
+#ifndef CONFIG_8xx
 char *pmc1_lookup(unsigned long mmcr0)
 {
        switch ( mmcr0 & (0x7f<<7) )
@@ -123,7 +124,7 @@ char *pmc2_lookup(unsigned long mmcr0)
                return "unknown";
        }
 }      
-
+#endif /* CONFIG_8xx */
 
 /*
  * print some useful info about the hash table.  This function
@@ -133,6 +134,7 @@ char *pmc2_lookup(unsigned long mmcr0)
 static ssize_t ppc_htab_read(struct file * file, char * buf,
                             size_t count, loff_t *ppos)
 {
+#ifndef CONFIG_8xx
        unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
        int n = 0, valid;
        unsigned int kptes = 0, overflow = 0, uptes = 0, zombie_ptes = 0;
@@ -249,6 +251,9 @@ return_string:
        copy_to_user(buf, buffer + *ppos, n);
        *ppos += n;
        return n;
+#else /* CONFIG_8xx */
+       return 0;
+#endif /* CONFIG_8xx */
 }
 
 /*
@@ -257,6 +262,7 @@ return_string:
 static ssize_t ppc_htab_write(struct file * file, const char * buffer,
                              size_t count, loff_t *ppos)
 {
+#ifndef CONFIG_8xx
        unsigned long tmp;
        if ( current->uid != 0 )
                return -EACCES;
@@ -493,6 +499,9 @@ static ssize_t ppc_htab_write(struct file * file, const char * buffer,
        reset_SDR1();
 #endif 
        return count;
+#else /* CONFIG_8xx */
+       return 0;
+#endif /* CONFIG_8xx */
 }
 
 
@@ -512,4 +521,3 @@ ppc_htab_lseek(struct file * file, loff_t offset, int orig)
        return(-EINVAL);
     }
 }
-
index 6ec6258ab401d3a27bbb1d05980a08900f2c3dc3..29df507d3b736330433c3c289cc31aeabdff0b25 100644 (file)
@@ -4,9 +4,7 @@
 #include <linux/elfcore.h>
 #include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/bios32.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
 #include <asm/adb.h>
 #include <asm/cuda.h>
+#include <asm/pmu.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pci-bridge.h>
+#include <asm/irq.h>
 
 extern void transfer_to_handler(void);
 extern void int_return(void);
@@ -49,9 +49,13 @@ EXPORT_SYMBOL(sys_sigreturn);
 EXPORT_SYMBOL(lost_interrupts);
 EXPORT_SYMBOL(do_lost_interrupts);
 EXPORT_SYMBOL(__ppc_bh_counter);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
 
-#if !defined(CONFIG_MACH_SPECIFIC)
+#if !defined(CONFIG_MACH_SPECIFIC) || defined(CONFIG_PMAC)
 EXPORT_SYMBOL(isa_io_base);
+#endif
+#if !defined(CONFIG_MACH_SPECIFIC)
 EXPORT_SYMBOL(pci_dram_offset);
 #endif
 
@@ -114,11 +118,15 @@ EXPORT_SYMBOL(outw);
 EXPORT_SYMBOL(outl);
 EXPORT_SYMBOL(outsl);*/
 
+EXPORT_SYMBOL(_insb);
+EXPORT_SYMBOL(_outsb);
 EXPORT_SYMBOL(_insw);
 EXPORT_SYMBOL(_outsw);
 EXPORT_SYMBOL(_insl);
 EXPORT_SYMBOL(_outsl);
 EXPORT_SYMBOL(ioremap);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
 
 EXPORT_SYMBOL(start_thread);
 
@@ -140,6 +148,10 @@ EXPORT_SYMBOL(adb_autopoll);
 EXPORT_SYMBOL(adb_register);
 EXPORT_SYMBOL(cuda_request);
 EXPORT_SYMBOL(cuda_send_request);
+EXPORT_SYMBOL(cuda_poll);
+EXPORT_SYMBOL(pmu_request);
+EXPORT_SYMBOL(pmu_send_request);
+EXPORT_SYMBOL(pmu_poll);
 EXPORT_SYMBOL(abort);
 EXPORT_SYMBOL(find_devices);
 EXPORT_SYMBOL(find_type_devices);
@@ -148,7 +160,3 @@ EXPORT_SYMBOL(get_property);
 EXPORT_SYMBOL(pci_io_base);
 EXPORT_SYMBOL(pci_device_loc);
 EXPORT_SYMBOL(note_scsi_host);
-
-#if CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
index 193ded4df247d890c352deab2b7e174115ff8870..99940620086fb89f886e37f029f11ebb24165d94 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: prep_pci.c,v 1.12 1997/10/29 03:35:08 cort Exp $
+ * $Id: prep_pci.c,v 1.16 1998/02/23 02:47:32 davem Exp $
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -271,6 +270,12 @@ static char Nobis_pci_IRQ_routes[] = {
 #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] */
 
+/*
+ * FIXME: This code incorrectly assumes there's only bus #0, breaking all
+ *       PCI-to-PCI bridges. Also multi-function devices are not supported
+ *       at all. [mj]
+ */
+
 int
 prep_pcibios_read_config_dword (unsigned char bus,
                           unsigned char dev, unsigned char offset, unsigned int *val)
@@ -319,16 +324,6 @@ prep_pcibios_read_config_byte (unsigned char bus,
        unsigned char _val;
        volatile unsigned char *ptr;
        dev >>= 3;
-       /* Note: the configuration registers don't always have this right! */
-       if (offset == PCI_INTERRUPT_LINE)
-       {
-               *val = Motherboard_routes[Motherboard_map[dev]];
-/*printk("dev %d map %d route %d on board %d\n",
-  dev,Motherboard_map[dev],
-  Motherboard_routes[Motherboard_map[dev]],
-  *(unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1)));*/
-               return PCIBIOS_SUCCESSFUL;
-       }
        if ((bus != 0) || (dev > MAX_DEVNR))
        {
                *(unsigned long *)val = (unsigned long) 0xFFFFFFFF;
@@ -406,7 +401,7 @@ __initfunc(unsigned long route_pci_interrupts(void))
        int i;
        
        if ( _prep_type == _PREP_Motorola)
-       { 
+       {
                switch (inb(0x800) & 0xF0)
                {
                case 0x10: /* MVME16xx */
@@ -430,7 +425,6 @@ __initfunc(unsigned long route_pci_interrupts(void))
                        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;
@@ -474,3 +468,4 @@ __initfunc(unsigned long route_pci_interrupts(void))
        *ibc_pcicon |= 0x20;
        return 0;
 }
+
index 0aee7cff4c41cd5976dc8a9aac7357f51de7c6c3..5234435cadab853de8c4f0e83b556c434e0921bd 100644 (file)
@@ -80,8 +80,7 @@ prep_get_cpuinfo(char *buffer)
 {
        extern char *Motherboard_map_name;
        extern RESIDUAL res;
-       int i;
-       int len;
+       int len, i;
   
 #ifdef __SMP__
 #define CD(X)          (cpu_data[n].X)  
@@ -93,7 +92,7 @@ prep_get_cpuinfo(char *buffer)
        
        if ( res.ResidualLength == 0 )
                return len;
-
+       
        /* print info about SIMMs */
        len += sprintf(buffer+len,"simms\t\t: ");
        for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
@@ -106,6 +105,7 @@ prep_get_cpuinfo(char *buffer)
        }
        len += sprintf(buffer+len,"\n");
 
+#if 0  
        /* TLB */
        len += sprintf(buffer+len,"tlb\t\t:");
        switch(res.VitalProductData.TLBAttrib)
@@ -123,7 +123,6 @@ prep_get_cpuinfo(char *buffer)
                len += sprintf(buffer+len," not present\n");
                break;
        }
-
        /* L1 */
        len += sprintf(buffer+len,"l1\t\t: ");
        switch(res.VitalProductData.CacheAttrib)
@@ -144,6 +143,7 @@ prep_get_cpuinfo(char *buffer)
                len += sprintf(buffer+len,"not present\n");
                break;
        }
+#endif
 
        /* L2 */
        if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
@@ -201,7 +201,11 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
                }
        }
 #endif
-
+       /* make the serial port the console */
+       /* strcat(cmd_line,"console=ttyS0,9600n8"); */
+       /* use the normal console but send output to the serial port, too */
+       /*strcat(cmd_line,"console=tty0 console=ttyS0,9600n8");*/
+        sprintf(cmd_line,"%s console=tty0 console=ttyS0,9600n8", cmd_line);
        printk("Boot arguments: %s\n", cmd_line);
        
 #ifdef CONFIG_CS4232
@@ -256,9 +260,5 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
 #ifdef CONFIG_VGA_CONSOLE
         conswitchp = &vga_con;
 #endif
-#ifdef CONFIG_FB
-       /* Frame buffer device based console */
-       conswitchp = &fb_con;
-#endif
 #endif
 }
index 4c3a91f9192c14112d29de55a0ca9b04451e4b0c..3536eab437fbc1b79d2a0907dedd80739ce94532 100644 (file)
@@ -220,7 +220,7 @@ static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
 #ifdef CONFIG_HEARTBEAT
        /* use hard disk LED as a heartbeat instead -- much more useful
           for debugging -- Cort */
-       switch(kstat.interrupts[0] % 101)
+       switch(kstat_irqs(0) % 101)
        {
        /* act like an actual heart beat -- ie thump-thump-pause... */
        case 0:
index 7ffaf58c07f72360dcb9f48bb778f854d4da49df..1c993bdc18a5df8b4485136916a81b8aed02636d 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  *  linux/arch/ppc/kernel/process.c
  *
@@ -77,8 +76,13 @@ struct task_struct *current_set[NR_CPUS] = {&init_task, };
 int
 dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
 {
+#ifdef __SMP__
+       if ( regs->msr & MSR_FP )
+               smp_giveup_fpu(current);
+#else
        if (last_task_used_math == current)
                giveup_fpu();
+#endif 
        memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
        return 1;
 }
@@ -98,7 +102,7 @@ int check_stack(struct task_struct *tsk)
                printk("tss.magic bad: %08x\n", tsk->tss.magic);
        }
 #endif
-       
+
        if ( !tsk )
                printk("check_stack(): tsk bad tsk %p\n",tsk);
        
@@ -157,17 +161,21 @@ switch_to(struct task_struct *prev, struct task_struct *new)
 #endif
 
 #ifdef SHOW_TASK_SWITCHES
-       printk("%s/%d -> %s/%d cpu %d\n",
+       printk("%s/%d -> %s/%d NIP %08lx cpu %d sfr %d lock %x\n",
               prev->comm,prev->pid,
-              new->comm,new->pid,new->processor);
+              new->comm,new->pid,new->tss.regs->nip,new->processor,
+              new->tss.smp_fork_ret,scheduler_lock.lock);
 #endif
 #ifdef __SMP__
-       /* bad news if last_task_used_math changes processors right now -- Cort */
-       if ( (last_task_used_math == new) &&
-            (new->processor != new->last_processor) )
-               panic("last_task_used_math switched processors");
+       /* avoid complexity of lazy save/restore of fpu
+        * by just saving it every time we switch out -- Cort
+        */
+       if ( prev->tss.regs->msr & MSR_FP )
+               smp_giveup_fpu(prev);
+
        /* be noisy about processor changes for debugging -- Cort */
-       if ( new->last_processor != new->processor )
+       if ( (new->last_processor != NO_PROC_ID) &&
+            (new->last_processor != new->processor) )
                printk("switch_to(): changing cpu's %d -> %d %s/%d\n",
                       new->last_processor,new->processor,
                       new->comm,new->pid);
@@ -181,11 +189,6 @@ switch_to(struct task_struct *prev, struct task_struct *new)
        _enable_interrupts(s);
 }
 
-asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
-{
-       return 0;
-}
-
 void show_regs(struct pt_regs * regs)
 {
        int i;
@@ -257,12 +260,11 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
                     ((unsigned long)p + sizeof(union task_union)
                      - STACK_FRAME_OVERHEAD)) - 2;
        *childregs = *regs;
-
        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 - STACK_FRAME_OVERHEAD;
-       p->tss.regs = childregs;
+       p->tss.regs = childregs;        
        if (usp >= (unsigned long) regs) {
                /* Stack is in kernel space - must adjust */
                childregs->gpr[1] = (unsigned long)(childregs + 1);
@@ -271,18 +273,28 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
                childregs->gpr[1] = usp;
        }
        p->tss.last_syscall = -1;
-
+         
        /*
         * copy fpu info - assume lazy fpu switch now always
         *  -- Cort
         */
+#ifdef __SMP__
+       if ( regs->msr & MSR_FP )
+               smp_giveup_fpu(current);
+#else  
        if ( last_task_used_math == current )
                giveup_fpu();
+#endif   
 
        memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
        p->tss.fpscr = current->tss.fpscr;
        childregs->msr &= ~MSR_FP;
 
+#ifdef __SMP__
+       if ( (p->pid != 0) || !(clone_flags & CLONE_PID) )
+               p->tss.smp_fork_ret = 1;
+       p->last_processor = NO_PROC_ID;
+#endif /* __SMP__ */
        return 0;
 }
 
@@ -337,20 +349,48 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
        shove_aux_table(sp);
 }
 
+asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+                        struct pt_regs *regs)
+{
+       unsigned long clone_flags = p1;
+       int res;
+       lock_kernel();
+       res = do_fork(clone_flags, regs->gpr[1], regs);
+       /*
+        * only parent returns here, child returns to either
+        * syscall_ret_1() or kernel_thread()
+        * -- Cort
+        */
+#ifdef __SMP__
+       /* When we clone the idle task we keep the same pid but
+        * the return value of 0 for both causes problems.
+        * -- Cort
+        */
+       if ((current->pid == 0) && (current == &init_task))
+               res = 1;
+#endif /* __SMP__ */
+       unlock_kernel();
+       return res;
+}
 
 asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
                        struct pt_regs *regs)
 {
-       int ret;
 
+       int res;
        lock_kernel();
-       ret = do_fork(SIGCHLD, regs->gpr[1], regs);
-#if 0/*def __SMP__*/
-       if ( ret ) /* drop scheduler lock in child */
-               scheduler_lock.lock = 0L;
-#endif /* __SMP__ */   
+       res = do_fork(SIGCHLD, regs->gpr[1], regs);
+       /* only parent returns here */
+#ifdef __SMP__
+       /* When we clone the idle task we keep the same pid but
+        * the return value of 0 for both causes problems.
+        * -- Cort
+        */
+       if ((current->pid == 0) && (current == &init_task))
+               res = 1;
+#endif /* __SMP__ */
        unlock_kernel();
-       return ret;
+       return res;
 }
 
 asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
@@ -374,28 +414,6 @@ out:
        return error;
 }
 
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
-                        struct pt_regs *regs)
-{
-       unsigned long clone_flags = p1;
-       int res;
-
-       lock_kernel();
-       res = do_fork(clone_flags, regs->gpr[1], regs);
-#ifdef __SMP__
-       /* When we clone the idle task we keep the same pid but
-        * the return value of 0 for both causes problems.
-        * -- Cort
-        */
-       if ((current->pid == 0) && (current == &init_task))
-               res = 1;
-       if ( 0 /*res*/ ) /* drop scheduler lock in child */
-               scheduler_lock.lock = 0L;
-#endif /* __SMP__ */   
-       unlock_kernel();
-       return res;
-}
-
 void
 print_backtrace(unsigned long *sp)
 {
index 121ffea73c9f263c085b5315f926787d334fa74d..0e656caa13963e71429caef88eff22326b125642 100644 (file)
@@ -16,6 +16,8 @@
 #include <asm/prom.h>
 #include <asm/page.h>
 #include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -50,6 +52,19 @@ struct pci_range {
        unsigned size_lo;
 };
 
+struct isa_reg_property {
+       unsigned space;
+       unsigned address;
+       unsigned size;
+};
+
+typedef unsigned long interpret_func(struct device_node *, unsigned long);
+static interpret_func interpret_pci_props;
+static interpret_func interpret_dbdma_props;
+static interpret_func interpret_isa_props;
+static interpret_func interpret_macio_props;
+static interpret_func interpret_root_props;
+
 char *prom_display_paths[FB_MAX] __initdata = { 0, };
 unsigned int prom_num_displays = 0;
 
@@ -60,19 +75,21 @@ extern char *klimit;
 char *bootpath = 0;
 char *bootdevice = 0;
 
-unsigned int rtas_data = 0;
-unsigned int rtas_entry = 0;
+unsigned int rtas_data = 0;   /* virtual pointer */
+unsigned int rtas_entry = 0;  /* physical pointer */
+unsigned int rtas_size = 0;
+char chunk[PAGE_SIZE*64];
 
 static struct device_node *allnodes = 0;
 
 static void *call_prom(const char *service, int nargs, int nret, ...);
-static void prom_print(const char *msg);
+ void prom_print(const char *msg);
 static void prom_exit(void);
 static unsigned long copy_device_tree(unsigned long, unsigned long);
 static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
                                  unsigned long, struct device_node ***);
 static unsigned long finish_node(struct device_node *, unsigned long,
-                                unsigned long);
+                                interpret_func *);
 static unsigned long check_display(unsigned long);
 static int prom_next_node(phandle *);
 
@@ -119,6 +136,18 @@ prom_exit()
                ;
 }
 
+void
+prom_enter(void)
+{
+       struct prom_args args;
+       unsigned long offset = reloc_offset();
+
+       args.service = RELOC("enter");
+       args.nargs = 0;
+       args.nret = 0;
+       RELOC(prom)(&args);
+}
+
 static void *
 call_prom(const char *service, int nargs, int nret, ...)
 {
@@ -140,7 +169,7 @@ call_prom(const char *service, int nargs, int nret, ...)
        return prom_args.args[nargs];
 }
 
-static void
+void
 prom_print(const char *msg)
 {
        const char *p, *q;
@@ -160,6 +189,11 @@ prom_print(const char *msg)
        }
 }
 
+
+#ifdef CONFIG_ALL_PPC
+unsigned char OF_type[16], OF_model[16];
+#endif
+
 /*
  * We enter here early on, when the Open Firmware prom is still
  * handling exceptions and the MMU hash table for us.
@@ -169,11 +203,14 @@ prom_init(int r3, int r4, prom_entry pp)
 {
        unsigned long mem;
        ihandle prom_rtas;
-       unsigned int rtas_size;
        unsigned long offset = reloc_offset();
        int l;
        char *p, *d;
 
+       /* check if we're prep, return if we are */
+       if ( *(unsigned long *)(0) == 0xdeadc0de )
+               return;
+       
        /* First get a handle for the stdout device */
        RELOC(prom) = pp;
        RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1,
@@ -209,27 +246,57 @@ prom_init(int r3, int r4, prom_entry pp)
 
        prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
        if (prom_rtas != (void *) -1) {
-               rtas_size = 0;
+               RELOC(rtas_size) = 0;
                call_prom(RELOC("getprop"), 4, 1, prom_rtas,
-                         RELOC("rtas-size"), &rtas_size, sizeof(rtas_size));
+                         RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size));
                prom_print(RELOC("instantiating rtas..."));
-               if (rtas_size == 0) {
+               if (RELOC(rtas_size) == 0) {
                        RELOC(rtas_data) = 0;
                } else {
                        mem = (mem + 4095) & -4096; /* round to page bdry */
                        RELOC(rtas_data) = mem - KERNELBASE;
-                       mem += rtas_size;
+                       mem += RELOC(rtas_size);
+               }
+               prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));
+               RELOC(rtas_data) = ((ulong)chunk+4095)&-4096;
+               {
+                       int i, nargs;
+                       struct prom_args prom_args;
+                       nargs = 3;
+                       prom_args.service = RELOC("call-method");
+                       prom_args.nargs = nargs;
+                       prom_args.nret = 2;
+                       prom_args.args[0] = RELOC("instantiate-rtas");
+                       prom_args.args[1] = prom_rtas;
+                       prom_args.args[2] = ((void *)RELOC(rtas_data)-KERNELBASE);
+                       RELOC(prom)(&prom_args);
+                       if (prom_args.args[nargs] != 0)
+                               i = 0;
+                       else
+                               i = (int)prom_args.args[nargs+1];
+                       RELOC(rtas_entry) = i;
                }
-               RELOC(rtas_entry) = (unsigned int)
-                       call_prom(RELOC("instantiate-rtas"), 1, 1,
-                                 RELOC(rtas_data));
-               if (RELOC(rtas_entry) == -1)
+               if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0))
                        prom_print(RELOC(" failed\n"));
                else
                        prom_print(RELOC(" done\n"));
        }
 
        RELOC(klimit) = (char *) (mem - offset);
+#ifdef CONFIG_ALL_PPC
+       {
+
+               ihandle prom_root;
+
+               RELOC(prom_root) = call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
+               call_prom(RELOC("getprop"), 4, 1, RELOC(prom_root),
+                         RELOC("device_type"), RELOC(OF_type),
+                         (void *) 16);
+               call_prom(RELOC("getprop"), 4, 1, RELOC(prom_root),
+                         RELOC("model"), RELOC(OF_model),
+                         (void *) 16);
+       }
+#endif
 }
 
 /*
@@ -397,12 +464,18 @@ inspect_node(phandle node, struct device_node *dad,
        return mem_start;
 }
 
+/*
+ * finish_device_tree is called once things are running normally
+ * (i.e. with text and data mapped to the address they were linked at).
+ * It traverses the device tree and fills in the name, type,
+ * {n_}addrs and {n_}intrs fields of each node.
+ */
 void
 finish_device_tree(void)
 {
        unsigned long mem = (unsigned long) klimit;
 
-       mem = finish_node(allnodes, mem, 0UL);
+       mem = finish_node(allnodes, mem, NULL);
        printk(KERN_INFO "device tree used %lu bytes\n",
               mem - (unsigned long) allnodes);
        klimit = (char *) mem;
@@ -410,23 +483,53 @@ finish_device_tree(void)
 
 static unsigned long
 finish_node(struct device_node *np, unsigned long mem_start,
-           unsigned long base_address)
+           interpret_func *ifunc)
 {
-       struct reg_property *rp;
-       struct pci_reg_property *pci_addrs;
-       struct address_range *adr;
        struct device_node *child;
-       int i, l;
 
        np->name = get_property(np, "name", 0);
        np->type = get_property(np, "device_type", 0);
 
-       /* get all the device addresses and interrupts */
-       adr = (struct address_range *) mem_start;
+       /* get the device addresses and interrupts */
+       if (ifunc != NULL)
+               mem_start = ifunc(np, mem_start);
+
+       if (!strcmp(np->name, "device-tree"))
+               ifunc = interpret_root_props;
+       else if (np->type == 0)
+               ifunc = NULL;
+       else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
+               ifunc = interpret_pci_props;
+       else if (!strcmp(np->type, "dbdma")
+               || (ifunc == interpret_dbdma_props
+                   && (!strcmp(np->type, "escc")
+                       || !strcmp(np->type, "media-bay"))))
+               ifunc = interpret_dbdma_props;
+       else if (!strcmp(np->type, "mac-io"))
+               ifunc = interpret_macio_props;
+       else if (!strcmp(np->type, "isa"))
+               ifunc = interpret_isa_props;
+       else
+               ifunc = NULL;
+
+       for (child = np->child; child != NULL; child = child->sibling)
+               mem_start = finish_node(child, mem_start, ifunc);
+
+       return mem_start;
+}
+
+static unsigned long
+interpret_pci_props(struct device_node *np, unsigned long mem_start)
+{
+       struct address_range *adr;
+       struct pci_reg_property *pci_addrs;
+       int i, l, *ip;
+
        pci_addrs = (struct pci_reg_property *)
                get_property(np, "assigned-addresses", &l);
-       i = 0;
-       if (pci_addrs != 0) {
+       if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
+               i = 0;
+               adr = (struct address_range *) mem_start;
                while ((l -= sizeof(struct pci_reg_property)) >= 0) {
                        /* XXX assumes PCI addresses mapped 1-1 to physical */
                        adr[i].space = pci_addrs[i].addr.a_hi;
@@ -434,36 +537,194 @@ finish_node(struct device_node *np, unsigned long mem_start,
                        adr[i].size = pci_addrs[i].size_lo;
                        ++i;
                }
-       } else {
-               rp = (struct reg_property *) get_property(np, "reg", &l);
-               if (rp != 0) {
-                       while ((l -= sizeof(struct reg_property)) >= 0) {
-                               adr[i].space = 0;
-                               adr[i].address = rp[i].address + base_address;
-                               adr[i].size = rp[i].size;
-                               ++i;
-                       }
+               np->addrs = adr;
+               np->n_addrs = i;
+               mem_start += i * sizeof(struct address_range);
+       }
+
+       ip = (int *) get_property(np, "AAPL,interrupts", &l);
+       if (ip == 0)
+               ip = (int *) get_property(np, "interrupts", &l);
+       if (ip != 0) {
+               np->intrs = (struct interrupt_info *) mem_start;
+               np->n_intrs = l / sizeof(int);
+               mem_start += np->n_intrs * sizeof(struct interrupt_info);
+               for (i = 0; i < np->n_intrs; ++i) {
+                       np->intrs[i].line = *ip++;
+                       np->intrs[i].sense = 0;
+               }
+       }
+
+       return mem_start;
+}
+
+static unsigned long
+interpret_dbdma_props(struct device_node *np, unsigned long mem_start)
+{
+       struct reg_property *rp;
+       struct address_range *adr;
+       unsigned long base_address;
+       int i, l, *ip;
+       struct device_node *db;
+
+       base_address = 0;
+       for (db = np->parent; db != NULL; db = db->parent) {
+               if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
+                       base_address = db->addrs[0].address;
+                       break;
                }
        }
-       if (i > 0) {
+
+       rp = (struct reg_property *) get_property(np, "reg", &l);
+       if (rp != 0 && l >= sizeof(struct reg_property)) {
+               i = 0;
+               adr = (struct address_range *) mem_start;
+               while ((l -= sizeof(struct reg_property)) >= 0) {
+                       adr[i].space = 0;
+                       adr[i].address = rp[i].address + base_address;
+                       adr[i].size = rp[i].size;
+                       ++i;
+               }
                np->addrs = adr;
                np->n_addrs = i;
                mem_start += i * sizeof(struct address_range);
        }
 
-       np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
-       if (np->intrs == 0)
-               np->intrs = (int *) get_property(np, "interrupts", &l);
-       if (np->intrs != 0)
+       ip = (int *) get_property(np, "AAPL,interrupts", &l);
+       if (ip == 0)
+               ip = (int *) get_property(np, "interrupts", &l);
+       if (ip != 0) {
+               np->intrs = (struct interrupt_info *) mem_start;
                np->n_intrs = l / sizeof(int);
+               mem_start += np->n_intrs * sizeof(struct interrupt_info);
+               for (i = 0; i < np->n_intrs; ++i) {
+                       np->intrs[i].line = *ip++;
+                       np->intrs[i].sense = 0;
+               }
+       }
 
-       if (np->type != 0 && np->n_addrs > 0
-           && (strcmp(np->type, "dbdma") == 0
-               || strcmp(np->type, "mac-io") == 0))
-               base_address = np->addrs[0].address;
+       return mem_start;
+}
 
-       for (child = np->child; child != NULL; child = child->sibling)
-               mem_start = finish_node(child, mem_start, base_address);
+static unsigned long
+interpret_macio_props(struct device_node *np, unsigned long mem_start)
+{
+       struct reg_property *rp;
+       struct address_range *adr;
+       unsigned long base_address;
+       int i, l, *ip;
+       struct device_node *db;
+
+       base_address = 0;
+       for (db = np->parent; db != NULL; db = db->parent) {
+               if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
+                       base_address = db->addrs[0].address;
+                       break;
+               }
+       }
+
+       rp = (struct reg_property *) get_property(np, "reg", &l);
+       if (rp != 0 && l >= sizeof(struct reg_property)) {
+               i = 0;
+               adr = (struct address_range *) mem_start;
+               while ((l -= sizeof(struct reg_property)) >= 0) {
+                       adr[i].space = 0;
+                       adr[i].address = rp[i].address + base_address;
+                       adr[i].size = rp[i].size;
+                       ++i;
+               }
+               np->addrs = adr;
+               np->n_addrs = i;
+               mem_start += i * sizeof(struct address_range);
+       }
+
+       ip = (int *) get_property(np, "interrupts", &l);
+       if (ip == 0)
+               ip = (int *) get_property(np, "AAPL,interrupts", &l);
+       if (ip != 0) {
+               np->intrs = (struct interrupt_info *) mem_start;
+               np->n_intrs = l / (2 * sizeof(int));
+               mem_start += np->n_intrs * sizeof(struct interrupt_info);
+               for (i = 0; i < np->n_intrs; ++i) {
+                       np->intrs[i].line = openpic_to_irq(*ip++);
+                       np->intrs[i].sense = *ip++;
+               }
+       }
+
+       return mem_start;
+}
+
+static unsigned long
+interpret_isa_props(struct device_node *np, unsigned long mem_start)
+{
+       struct isa_reg_property *rp;
+       struct address_range *adr;
+       int i, l, *ip;
+
+       rp = (struct isa_reg_property *) get_property(np, "reg", &l);
+       if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
+               i = 0;
+               adr = (struct address_range *) mem_start;
+               while ((l -= sizeof(struct reg_property)) >= 0) {
+                       adr[i].space = rp[i].space;
+                       adr[i].address = rp[i].address
+                               + (adr[i].space? 0: _ISA_MEM_BASE);
+                       adr[i].size = rp[i].size;
+                       ++i;
+               }
+               np->addrs = adr;
+               np->n_addrs = i;
+               mem_start += i * sizeof(struct address_range);
+       }
+
+       ip = (int *) get_property(np, "interrupts", &l);
+       if (ip != 0) {
+               np->intrs = (struct interrupt_info *) mem_start;
+               np->n_intrs = l / (2 * sizeof(int));
+               mem_start += np->n_intrs * sizeof(struct interrupt_info);
+               for (i = 0; i < np->n_intrs; ++i) {
+                       np->intrs[i].line = *ip++;
+                       np->intrs[i].sense = *ip++;
+               }
+       }
+
+       return mem_start;
+}
+
+static unsigned long
+interpret_root_props(struct device_node *np, unsigned long mem_start)
+{
+       struct reg_property *rp;
+       struct address_range *adr;
+       int i, l, *ip;
+
+       rp = (struct reg_property *) get_property(np, "reg", &l);
+       if (rp != 0 && l >= sizeof(struct reg_property)) {
+               i = 0;
+               adr = (struct address_range *) mem_start;
+               while ((l -= sizeof(struct reg_property)) >= 0) {
+                       adr[i].space = 0;
+                       adr[i].address = rp[i].address;
+                       adr[i].size = rp[i].size;
+                       ++i;
+               }
+               np->addrs = adr;
+               np->n_addrs = i;
+               mem_start += i * sizeof(struct address_range);
+       }
+
+       ip = (int *) get_property(np, "AAPL,interrupts", &l);
+       if (ip == 0)
+               ip = (int *) get_property(np, "interrupts", &l);
+       if (ip != 0) {
+               np->intrs = (struct interrupt_info *) mem_start;
+               np->n_intrs = l / sizeof(int);
+               mem_start += np->n_intrs * sizeof(struct interrupt_info);
+               for (i = 0; i < np->n_intrs; ++i) {
+                       np->intrs[i].line = *ip++;
+                       np->intrs[i].sense = 0;
+               }
+       }
 
        return mem_start;
 }
@@ -648,14 +909,14 @@ call_rtas(const char *service, int nargs, int nret,
                printk(KERN_ERR "No RTAS service called %s\n", service);
                return -1;
        }
-       u.words[0] = *tokp;
+       u.words[0] = __pa(*tokp);
        u.words[1] = nargs;
        u.words[2] = nret;
        va_start(list, outputs);
        for (i = 0; i < nargs; ++i)
                u.words[i+3] = va_arg(list, unsigned long);
        va_end(list);
-       enter_rtas(&u);
+       enter_rtas((void *)__pa(&u));
        if (nret > 1 && outputs != NULL)
                for (i = 0; i < nret-1; ++i)
                        outputs[i] = u.words[i+nargs+4];
index 4f6068c6d21e60fa4a722bab30df61140417dd12..ce2f35058f1d65660c65c9c08d2561d90029caed 100644 (file)
@@ -390,8 +390,14 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                tmp = get_reg(child, addr);
                        }
                        else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
+#ifdef __SMP__
+                               if (child->tss.regs->msr & MSR_FP )
+                                       smp_giveup_fpu(child);
+#else                    
+                         /* only current can be last task to use math on SMP */
                                if (last_task_used_math == child)
                                        giveup_fpu();
+#endif                         
                                tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
                        }
                        else
@@ -423,8 +429,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                goto out;
                        }
                        if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+#ifndef __SMP__
+                               if (child->tss.regs->msr & MSR_FP )
+                                       smp_giveup_fpu(child);
+#else  
                                if (last_task_used_math == child)
                                        giveup_fpu();
+#endif                         
                                ((long *)child->tss.fpr)[addr - PT_FPR0] = data;
                                ret = 0;
                                goto out;
index fdf62e921764668852ff02c54191d3acde6a0a29..b5516d0e532f80418952ebf226e5fb0a61a649e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: residual.c,v 1.5 1997/10/30 21:25:19 cort Exp $
+ * $Id: residual.c,v 1.7 1998/03/08 05:49:20 davem Exp $
  *
  * Code to deal with the PReP residual data.
  *
index 86407e2730c6b56259b0ff7ef841f12be87700b3..bdf05af761b7ff8682d89391ea0ac165d8ac3426 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.48 1998/01/01 10:04:44 paulus Exp $
+ * $Id: setup.c,v 1.68 1998/04/07 08:20:33 geert Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
 
 #include <asm/adb.h>
 #include <asm/cuda.h>
+#include <asm/pmu.h>
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/ide.h>
 #include <asm/prom.h>
+#include <asm/processor.h>
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+#endif
+/* ifdef APUS specific stuff until the merge is completed. -jskov */
+#ifdef CONFIG_APUS
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/amigappc.h>
+extern unsigned long m68k_machtype;
+extern void amiga_reset (void);
+extern struct mem_info m68k_ramdisk;
+extern int m68k_parse_bootinfo(const struct bi_record *);
+extern char _end[];
+#endif
 
 extern char cmd_line[512];
 char saved_command_line[256];
@@ -26,13 +42,13 @@ unsigned char aux_device_present;
 unsigned long ISA_DMA_THRESHOLD;
 unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
 int _machine;
+/* if we have openfirmware */
+unsigned long have_of;
 #endif /* ! CONFIG_MACH_SPECIFIC */
 
 /* copy of the residual data */
 RESIDUAL res;
 int _prep_type;
-/* if we have openfirmware */
-unsigned long have_of;
 
 /*
  * Perhaps we can put the pmac screen_info[] here
@@ -40,6 +56,7 @@ unsigned long have_of;
  * Until we get multiple-console support in here
  * that is.  -- Cort
  */ 
+#ifndef CONFIG_MBX
 #if !defined(CONFIG_PMAC_CONSOLE)
 struct screen_info screen_info = {
        0, 25,                  /* orig-x, orig-y */
@@ -65,29 +82,66 @@ void pmac_find_display(void)
 }
 #endif
 
+#else /* CONFIG_MBX */
+
+/* We need this to satisfy some external references until we can
+ * strip the kernel down.
+ */
+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 */
+       0,                      /* orig-video-isVGA */
+       16                      /* orig-video-points */
+};
+#endif /* CONFIG_MBX */
+
 /* cmd is ignored for now... */
 void machine_restart(char *cmd)
 {
        struct adb_request req;
        unsigned long flags;
        unsigned long i = 10000;
-#if 0  
+#if 0
        int err;
 #endif 
 
        switch(_machine)
        {
        case _MACH_Pmac:
-               cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
-               for (;;)
-                       cuda_poll();
+               switch (adb_hardware) {
+               case ADB_VIACUDA:
+                       cuda_request(&req, NULL, 2, CUDA_PACKET,
+                                    CUDA_RESET_SYSTEM);
+                       for (;;)
+                               cuda_poll();
+                       break;
+               case ADB_VIAPMU:
+                       pmu_request(&req, NULL, 1, PMU_RESET);
+                       for (;;)
+                               pmu_poll();
+                       break;
+               default:
+               }
                break;
+
        case _MACH_chrp:
 #if 0          /* RTAS doesn't seem to work on Longtrail.
                   For now, do it the same way as the PReP. */
-               err = call_rtas("system-reboot", 0, 1, NULL);
+               /*err = call_rtas("system-reboot", 0, 1, NULL);
                printk("RTAS system-reboot returned %d\n", err);
-               for (;;);
+               for (;;);*/
+               
+               {
+                       extern unsigned int rtas_entry, rtas_data, rtas_size;
+                       unsigned long status, value;
+                       printk("rtas_entry: %08x rtas_data: %08x rtas_size: %08x\n",
+                              rtas_entry,rtas_data,rtas_size);
+       }
 #endif
        case _MACH_prep:
                _disable_interrupts();
@@ -104,6 +158,23 @@ void machine_restart(char *cmd)
                while ( i != 0 ) i++;
                panic("restart failed\n");
                break;
+       case _MACH_apus:
+               cli();
+               /* APUS:FIXME: Reset the system. Apparently there's
+                * more magic to it than this!?!?
+                */
+#if 0
+               APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
+               APUS_WRITE(APUS_REG_RESET, 
+                          REGRESET_PPCRESET|REGRESET_M68KRESET|
+                          REGRESET_AMIGARESET|REGRESET_AUXRESET|
+                          REGRESET_SCSIRESET);
+#endif
+               printk("\n**************************************\n");
+               printk("*** You can make a hard reset now! ***\n");
+               printk("**************************************\n");
+               for(;;);
+               break;
        }
 }
 
@@ -116,9 +187,23 @@ void machine_power_off(void)
 
        switch (_machine) {
        case _MACH_Pmac:
-               cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
-               for (;;)
-                       cuda_poll();
+               switch (adb_hardware) {
+               case ADB_VIACUDA:
+                       cuda_request(&req, NULL, 2, CUDA_PACKET,
+                                    CUDA_POWERDOWN);
+                       for (;;)
+                               cuda_poll();
+                       break;
+               case ADB_VIAPMU:
+                       pmu_request(&req, NULL, 5, PMU_SHUTDOWN,
+                                   'M', 'A', 'T', 'T');
+                       for (;;)
+                               pmu_poll();
+                       break;
+               default:
+               }
+               break;
+
        case _MACH_chrp:
 #if 0          /* RTAS doesn't seem to work on Longtrail.
                   For now, do it the same way as the PReP. */
@@ -126,9 +211,19 @@ void machine_power_off(void)
                printk("RTAS system-reboot returned %d\n", err);
                for (;;);
 #endif
+
        case _MACH_prep:
                machine_restart(NULL);
+#ifdef CONFIG_APUS
+       case _MACH_apus:
+#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
+               apm_set_power_state(APM_STATE_OFF);
+               for (;;);
+#endif
+#endif
        }
+       for (;;)
+               ;
 }
 
 void machine_halt(void)
@@ -141,18 +236,90 @@ void machine_halt(void)
                machine_power_off();    /* for now */
 #endif
        }
-       else /* prep or chrp */
+       else /* prep, chrp or apus */
                machine_restart(NULL);
 
 }
 
+#ifdef CONFIG_BLK_DEV_IDE
 void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
 {
-       if ( _machine == _MACH_Pmac )
+       switch (_machine) {
+       case _MACH_Pmac:
                pmac_ide_init_hwif_ports(p,base,irq);
-       else /* prep or chrp */
+               break;
+       case _MACH_chrp:
+               chrp_ide_init_hwif_ports(p,base,irq);
+               break;
+       case _MACH_prep:
                prep_ide_init_hwif_ports(p,base,irq);
+               break;
+       }
+}
+#endif
+
+unsigned long cpu_temp(void)
+{
+       unsigned long i, temp, thrm1, dir;
+       int sanity;
        
+       /*
+        * setup thrm3 - need to give TAU at least 20us
+        * to do the compare so assume a 300MHz clock.
+        * We need 300*20 ticks then.
+        * -- Cort
+        */
+       asm("mtspr 1020, %1\n\t"
+           "mtspr 1021, %1\n\t"
+           "mtspr 1022, %0\n\t"::
+           "r" ( ((300*20)<<18) | THRM3_E), "r" (0) );
+               
+#if 0
+       for ( i = 127 ; i >= 0 ; i-- )
+       {
+               asm("mtspr 1020, %0\n\t"::
+                   "r" (THRM1_TID|THRM1_V|(i<<2)) );
+               /* check value */
+               while ( !( thrm1 & THRM1_TIV) )
+                       asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );
+               if ( thrm1 & THRM1_TIN )
+               {
+                       printk("tin set: %x tiv %x\n", thrm1,thrm1&THRM1_TIV);
+                       goto out;
+               }
+
+       }
+#endif
+#if 0
+       i = 32;                 /* increment */
+       dir = 1;                /* direction we're checking 0=up 1=down */
+       temp = 64;              /* threshold checking against */
+       while ( i )
+       {
+               _set_THRM1((1<<29) | THRM1_V | (temp<<2) );
+               printk("checking %d in dir %d thrm set to %x/%x\n", temp,dir,
+                      ( (1<<29) | THRM1_V | (temp<<2)),_get_THRM1());
+               /* check value */
+               sanity = 0x0fffffff;
+               while ( (!( thrm1 & THRM1_TIV)) && (sanity--) )
+                       thrm1 = _get_THRM1();
+                       /*asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );*/
+               if ( ! sanity || sanity==0xffffffff ) printk("no sanity\n");
+               /* temp is not in that direction */
+               if ( !(thrm1 & THRM1_TIN) )
+               {
+                       printk("not in that dir thrm1 %x\n",thrm1);
+                       if ( dir == 0 ) dir = 1;
+                       else dir = 0;
+               }
+               if ( dir ) temp -= i;
+               else temp += i;
+               i /= 2;
+       }
+       asm("mtspr 1020, %0\n\t"
+           "mtspr 1022, %0\n\t" ::"r" (0) );
+#endif 
+       return temp;
 }
 
 int get_cpuinfo(char *buffer)
@@ -160,9 +327,11 @@ int get_cpuinfo(char *buffer)
        extern int pmac_get_cpuinfo(char *);
        extern int chrp_get_cpuinfo(char *);    
        extern int prep_get_cpuinfo(char *);
+       extern int apus_get_cpuinfo(char *);
        unsigned long len = 0;
        unsigned long bogosum = 0;
        unsigned long i;
+       unsigned long cr;
 #ifdef __SMP__
        extern unsigned long cpu_present_map;   
        extern struct cpuinfo_PPC cpu_data[NR_CPUS];
@@ -202,7 +371,18 @@ int get_cpuinfo(char *buffer)
                        len += sprintf(len+buffer, "603ev\n");
                        break;
                case 8:
-                       len += sprintf(len+buffer, "750 (Arthur)\n");
+                       len += sprintf(len+buffer,"750\n");
+                       cr = _get_L2CR();
+                       len += sprintf(len+buffer,"L2CR\t\t: %lx\n",cr);
+                       if ( cr & (0x1<<1)) cr = 256;
+                       else if ( cr & (0x2<<1)) cr = 512;
+                       else if ( cr & (0x3<<1)) cr = 1024;
+                       else cr = 0;
+                       len += sprintf(len+buffer,"on-chip l2\t: "
+                                      "%ld KB (%s)\n",
+                                      cr,(_get_L2CR()&1) ? "on" : "off");
+                       len += sprintf(len+buffer,"temperature \t: %lu C\n",
+                                      cpu_temp());
                        break;
                case 9:
                        len += sprintf(len+buffer, "604e\n");
@@ -216,6 +396,7 @@ int get_cpuinfo(char *buffer)
                        break;
                }
 
+
                /*
                 * Assume here that all clock rates are the same in a
                 * smp system.  -- Cort
@@ -290,6 +471,11 @@ int get_cpuinfo(char *buffer)
        case _MACH_chrp:
                len += chrp_get_cpuinfo(buffer+len);
                break;
+#ifdef CONFIG_APUS
+       case _MACH_apus:
+               len += apus_get_cpuinfo(buffer+len);
+               break;
+#endif
        }
        return len;
 }
@@ -302,43 +488,63 @@ __initfunc(unsigned long
 identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                 unsigned long r6, unsigned long r7))
 {
-       extern unsigned long initrd_start, initrd_end;
        extern setup_pci_ptrs(void);
-       unsigned long boot_sdr1;
-       ihandle prom_root;
-       unsigned char type[16], model[16];
-
-       asm("mfspr %0,25\n\t" :"=r" (boot_sdr1));
+#ifndef CONFIG_MBX8xx
 
-       /* 
-        * if we have a sdr1 then we have openfirmware 
-        * and can ask it what machine we are (chrp/pmac/prep).
-        * otherwise we're definitely prep. -- Cort
-        */
-       if ( !boot_sdr1 )
+#ifdef CONFIG_APUS
+       if ( r3 == 0x61707573 )
        {
-               /* we know for certain we're prep if no OF */
+               /* Parse bootinfo. The bootinfo is located right after
+                   the kernel bss */
+               m68k_parse_bootinfo((const struct bi_record *)&_end);
+
                have_of = 0;
-               /* make a copy of residual data */
-               if ( r3 )
-                       memcpy((void *)&res,(void *)(r3+KERNELBASE),
-                              sizeof(RESIDUAL));
+               
+#ifdef CONFIG_BLK_DEV_INITRD
+               /* Take care of initrd if we have one. Use data from
+                  bootinfo to avoid the need to initialize PPC
+                  registers when kernel is booted via a PPC reset. */
+               if ( m68k_ramdisk.addr ) {
+                       initrd_start = (unsigned long) __va(m68k_ramdisk.addr);
+                       initrd_end = (unsigned long) 
+                               __va(m68k_ramdisk.size + m68k_ramdisk.addr);
+               }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+               return 0;
+       }
+#endif
+
 #ifndef CONFIG_MACH_SPECIFIC
+       /* prep boot loader tells us if we're prep or not */
+       if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
+       {
                _machine = _MACH_prep;
-#endif /* CONFIG_MACH_SPECIFIC */
+               have_of = 0;
+       } else
+       {
+               /* need to ask OF if we're chrp or pmac */
+               extern unsigned char OF_type[16], OF_model[16];
+               prom_print(OF_type);
+               prom_print(OF_model);
+               if ( !strncmp("chrp", OF_type,4) )
+               {
+                       _machine = _MACH_chrp;
+               }
+               else 
+               {
+                       /*if ( !strncmp("Power Macintosh", type,15) )*/
+                       _machine = _MACH_Pmac;
+                }
+               _machine = _MACH_Pmac;
+
        }
-       else
+#endif /* CONFIG_MACH_SPECIFIC */              
+
+       if ( have_of )
        {
-               /*
-                * init prom here, then ask the openfirmware
-                * what machine we are (prep/chrp/pmac).  We don't use
-                * OF on prep just yet.  -- Cort
-                */
-#ifndef CONFIG_PREP            /* don't use OF on prep yet */
-               have_of = 1;
                /* prom_init has already been called from __start */
                finish_device_tree();
-
                /*
                 * If we were booted via quik, r3 points to the physical
                 * address of the command-line parameters.
@@ -356,7 +562,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                } else {
                        struct device_node *chosen;
                        char *p;
-
+                       
 #ifdef CONFIG_BLK_DEV_INITRD
                        if (r3 - KERNELBASE < 0x800000
                            && r4 != 0 && r4 != 0xdeadbeef) {
@@ -365,7 +571,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                                ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
                        }
 #endif
-                       chosen = find_path_device("/chosen");
+                       chosen = find_devices("chosen");
                        if (chosen != NULL) {
                                p = get_property(chosen, "bootargs", NULL);
                                if (p != NULL)
@@ -373,47 +579,18 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                        }
                }
                cmd_line[sizeof(cmd_line) - 1] = 0;
-#endif /* CONFIG_PREP */
-
-#ifndef CONFIG_MACH_SPECIFIC
-#if 0
-               prom_root = call_prom("finddevice", 1, 1, "/");         
-               call_prom("getprop", 4, 1, prom_root, "device_type", &type,
-                         (void *) sizeof(type));
-               call_prom("getprop", 4, 1, prom_root, "model", &type,
-                         (void *) sizeof(model));
-               if ( !strncmp("chrp", type,4) )
-               {
-                       _machine = _MACH_chrp;
-               }
-               else 
-               {
-                       /*if ( !strncmp("Power Macintosh", type,15) )*/
-                       _machine = _MACH_Pmac;
-                }
-#else
-
-#ifdef CONFIG_CHRP             
-               _machine = _MACH_chrp;
-#endif /* CONFIG_CHRP */
-#ifdef CONFIG_PMAC             
-               _machine = _MACH_Pmac;
-#endif /* CONFIG_PMAC */
-#ifdef CONFIG_PREP
-               _machine = _MACH_Prep;
-#endif /* CONFIG_PREP */
-#endif /* #if */               
-#endif /* CONFIG_MACH_SPECIFIC */
        }
 
+#ifdef CONFIG_PCI
        /* so that pmac/chrp can use pci to find its console -- Cort */
        setup_pci_ptrs();
-       
+#endif
+
        switch (_machine)
        {
        case _MACH_Pmac:
 #if !defined(CONFIG_MACH_SPECIFIC)
-               isa_io_base = PMAC_ISA_IO_BASE;
+               /* isa_io_base gets set in pmac_find_bridges */
                isa_mem_base = PMAC_ISA_MEM_BASE;
                pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
                ISA_DMA_THRESHOLD = ~0L;
@@ -422,6 +599,10 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 #endif /* ! CONFIG_MACH_SPECIFIC */
                break;
        case _MACH_prep:
+               /* make a copy of residual data */
+               if ( r3 )
+                       memcpy((void *)&res,(void *)(r3+KERNELBASE),
+                              sizeof(RESIDUAL));
 #if !defined(CONFIG_MACH_SPECIFIC)
                isa_io_base = PREP_ISA_IO_BASE;
                isa_mem_base = PREP_ISA_MEM_BASE;
@@ -434,13 +615,12 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                if ( res.ResidualLength != 0 )
                {
                        if ( !strncmp(res.VitalProductData.PrintableModel,"IBM",3) )
-                               _prep_type = 0x00;
+                               _prep_type = _PREP_IBM;
                        else
-                               _prep_type = 0x01;
+                               _prep_type = _PREP_Motorola;
                }
                else /* assume motorola if no residual (netboot?) */
                        _prep_type = _PREP_Motorola;
-
 #ifdef CONFIG_BLK_DEV_RAM
                /* take care of initrd if we have one */
                if ( r4 )
@@ -457,7 +637,14 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                }
                break;
        case _MACH_chrp:
-               /* LongTrail */
+#ifdef CONFIG_BLK_DEV_RAM
+               /* take care of initrd if we have one */
+               if ( r3 )
+               {
+                       initrd_start = r3 + KERNELBASE;
+                       initrd_end = r3+ r4 + KERNELBASE;
+               }
+#endif /* CONFIG_BLK_DEV_RAM */
 #if !defined(CONFIG_MACH_SPECIFIC)
                isa_io_base = CHRP_ISA_IO_BASE;
                isa_mem_base = CHRP_ISA_MEM_BASE;
@@ -470,13 +657,33 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
        default:
                printk("Unknown machine type in identify_machine!\n");
        }
-       return 0;
-}
+#else /* CONFIG_MBX8xx */
+       extern setup_pci_ptrs(void);
 
-__initfunc(unsigned long
-bios32_init(unsigned long memory_start, unsigned long memory_end))
-{
-       return memory_start;
+       if ( r3 )
+               memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+
+       setup_pci_ptrs();
+
+#ifdef CONFIG_BLK_DEV_RAM
+       /* take care of initrd if we have one */
+       if ( r4 )
+       {
+               initrd_start = r4 + KERNELBASE;
+               initrd_end = r5 + KERNELBASE;
+       }
+#endif /* CONFIG_BLK_DEV_RAM */
+       /* take care of cmd line */
+       if ( r6 )
+       {
+               
+               *(char *)(r7+KERNELBASE) = 0;
+               strcpy(cmd_line, (char *)(r6+KERNELBASE));
+       }
+
+#endif /* CONFIG_MBX */
+       
+       return 0;
 }
 
 __initfunc(void setup_arch(char **cmdline_p,
@@ -485,12 +692,18 @@ __initfunc(void setup_arch(char **cmdline_p,
        extern void pmac_setup_arch(unsigned long *, unsigned long *);
        extern void chrp_setup_arch(unsigned long *, unsigned long *);
        extern void prep_setup_arch(unsigned long *, unsigned long *);
+       extern void apus_setup_arch(char **, unsigned long *, unsigned long *);
        extern int panic_timeout;
        extern char _etext[], _edata[];
        extern char *klimit;
        extern unsigned long find_available_memory(void);
        extern unsigned long *end_of_DRAM;
 
+#ifdef CONFIG_XMON
+       extern void xmon_map_scc(void);
+       xmon_map_scc();
+#endif /* CONFIG_XMON */
+
        /* reboot on panic */   
        panic_timeout = 180;
        
@@ -516,6 +729,12 @@ __initfunc(void setup_arch(char **cmdline_p,
        case _MACH_chrp:
                chrp_setup_arch(memory_start_p, memory_end_p);
                break;
+#ifdef CONFIG_APUS
+       case _MACH_apus:
+               m68k_machtype = MACH_AMIGA;
+               apus_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+               break;
+#endif
        default:
                printk("Unknown machine %d in setup_arch()\n", _machine);
        }
index ae6d3c5aa3bbe64c9969dc44ef0ccf979a3d2827..1c977bb51e151181309a98043f4b28cc397ac525 100644 (file)
@@ -201,8 +201,13 @@ int sys_sigreturn(struct pt_regs *regs)
        if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
                /* Last stacked signal - restore registers */
                sr = (struct sigregs *) sigctx.regs;
+#ifdef __SMP__
+               if ( regs->msr & MSR_FP  )
+                       smp_giveup_fpu(current);
+#else  
                if (last_task_used_math == current)
                        giveup_fpu();
+#endif         
                if (copy_from_user(saved_regs, &sr->gp_regs,
                                   sizeof(sr->gp_regs)))
                        goto badframe;
@@ -249,8 +254,13 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame,
 
        if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
                goto badframe;
-       if (last_task_used_math == current)
-               giveup_fpu();
+#ifdef __SMP__
+               if ( regs->msr & MSR_FP  )
+                       smp_giveup_fpu(current);
+#else  
+               if (last_task_used_math == current)
+                       giveup_fpu();
+#endif         
        if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
            || __copy_to_user(&frame->fp_regs, current->tss.fpr,
                              ELF_NFPREG * sizeof(double))
index 33d3a23b4cc4eb54fc88235fcc667244d89d7d28..217e695f8a99c09ff19a4f58c930e138a5ed1085 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: smp.c,v 1.8 1998/01/06 06:44:57 cort Exp $
+ * $Id: smp.c,v 1.22 1998/04/10 01:53:34 cort Exp $
  *
  * Smp support for ppc.
  *
 #include <asm/init.h>
 #include <asm/io.h>
 
+#include "time.h"
+
 int smp_threads_ready = 0;
 volatile int smp_commenced = 0;
 int smp_num_cpus = 1;
 unsigned long cpu_present_map = 0;
 volatile int cpu_number_map[NR_CPUS];
 volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
+volatile int __cpu_logical_map[NR_CPUS];
 static unsigned char boot_cpu_id = 0;
 struct cpuinfo_PPC cpu_data[NR_CPUS];
-struct klock_info klock_info = { KLOCK_CLEAR, 0 };
+struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 volatile unsigned char active_kernel_processor = NO_PROC_ID;   /* Processor holding kernel spinlock            */
 
-volatile unsigned long hash_table_lock;
+volatile unsigned long ipi_count;
+
+unsigned int prof_multiplier[NR_CPUS];
+unsigned int prof_counter[NR_CPUS];
 
 int start_secondary(void *);
 
-extern void init_IRQ(void);
 extern int cpu_idle(void *unused);
 
 void smp_boot_cpus(void)
@@ -56,49 +61,75 @@ void smp_boot_cpus(void)
        struct task_struct *p;
        
         printk("Entering SMP Mode...\n");
+
+       for (i = 0; i < NR_CPUS; i++) {
+               cpu_number_map[i] = -1;
+               prof_counter[i] = 1;
+               prof_multiplier[i] = 1;
+       }
+       
        cpu_present_map = 0;
        for(i=0; i < NR_CPUS; i++)
-               cpu_number_map[i] = -1;
+               __cpu_logical_map[i] = -1;
 
         smp_store_cpu_info(boot_cpu_id);
         active_kernel_processor = boot_cpu_id;
        current->processor = boot_cpu_id;
-       
         cpu_present_map |= 1;
+        cpu_number_map[boot_cpu_id] = 0;
+       __cpu_logical_map[0] = boot_cpu_id;
+       
+       if ( _machine != _MACH_Pmac )
+       {
+               printk("SMP not supported on this machine.\n");
+               return;
+       }
+       
         /* assume a 2nd processor for now */   
         cpu_present_map |= (1 << 1); 
        smp_num_cpus = 2;
-        cpu_number_map[boot_cpu_id] = 0;
        
        /* create a process for second processor */
         kernel_thread(start_secondary, NULL, CLONE_PID);
-        cpu_number_map[1] = 1;
        p = task[1];
        if ( !p )
                panic("No idle task for secondary processor\n");
        p->processor = 1;
        current_set[1] = p;
+       /* need to flush here since secondary bat's aren't setup */
+       dcbf((volatile unsigned long *)&current_set[1]);
+       
        /* setup entry point of secondary processor */
        *(volatile unsigned long *)(0xf2800000)
                = (unsigned long)secondary_entry-KERNELBASE;
-       /* interrupt secondary to begin executing code */
        eieio();
-       *(volatile unsigned long *)(0xf80000c0) = 0;
+       /* interrupt secondary to begin executing code */
+       *(volatile unsigned long *)(0xf80000c0) = 0L;
        eieio();
        /* wait to see if the secondary made a callin (is actually up) */
-       for ( timeout = 0; timeout < 1500 ; timeout++ )
+       for ( timeout = 0; timeout < 15000 ; timeout++ )
+       {
+               if(cpu_callin_map[1])
+                       break;
                udelay(100);
+       }
        if(cpu_callin_map[1]) {
                cpu_number_map[1] = 1;
+               __cpu_logical_map[i] = 1;
                printk("Processor 1 found.\n");
+
+#if 0 /* this sync's the decr's */
+               set_dec(decrementer_count);
+#endif
+               /* interrupt secondary to sync the time bases */
+               smp_message_pass(1,0xf0f0, 0, 0);
+               /* interrupt secondary to begin executing code */
+               /**(volatile unsigned long *)(0xf80000c0) = 0L;
+               eieio();*/
        } else {
                smp_num_cpus--;
                printk("Processor %d is stuck.\n", 1);
        }
-{
-  extern unsigned long amhere;
-  printk("amhere: %x\n", amhere);
-}
 }
 
 void smp_commence(void)
@@ -128,16 +159,15 @@ int start_secondary(void *unused)
 void smp_callin(void)
 {
        printk("SMP %d: smp_callin()\n",current->processor);
-       /*calibrate_delay();*/
         smp_store_cpu_info(1);
-       
-       /* assume we're just the secondary processor for now */
-       cpu_callin_map[1] = 1;
-       dcbf(&cpu_callin_map[1]);
+       set_dec(decrementer_count);
        
        current->mm->mmap->vm_page_prot = PAGE_SHARED;
        current->mm->mmap->vm_start = PAGE_OFFSET;
        current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+       
+       /* assume we're just the secondary processor for now */
+       cpu_callin_map[1] = 1;
 
        while(!smp_commenced)
                barrier();
@@ -149,21 +179,120 @@ void smp_setup(char *str, int *ints)
        printk("SMP %d: smp_setup()\n",current->processor);
 }
 
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
+void smp_local_timer_interrupt(struct pt_regs * regs)
 {
-       printk("SMP %d: sending smp message\n",current->processor);
-#if 0  
-       if ( smp_processor_id() == 0 )
+       int cpu = smp_processor_id();
+       extern void update_one_process(struct task_struct *,unsigned long,
+                                      unsigned long,unsigned long,int);
+
+       if (!--prof_counter[cpu]) {
+               int user=0,system=0;
+               struct task_struct * p = current;
+
+               /*
+                * After doing the above, we need to make like
+                * a normal interrupt - otherwise timer interrupts
+                * ignore the global interrupt lock, which is the
+                * WrongThing (tm) to do.
+                */
+
+               if (user_mode(regs))
+                       user=1;
+               else
+                       system=1;
+
+               if (p->pid) {
+                       update_one_process(p, 1, user, system, cpu);
+
+                       p->counter -= 1;
+                       if (p->counter < 0) {
+                               p->counter = 0;
+                               need_resched = 1;
+                       }
+                       if (p->priority < DEF_PRIORITY) {
+                               kstat.cpu_nice += user;
+                               kstat.per_cpu_nice[cpu] += user;
+                       } else {
+                               kstat.cpu_user += user;
+                               kstat.per_cpu_user[cpu] += user;
+                       }
+
+                       kstat.cpu_system += system;
+                       kstat.per_cpu_system[cpu] += system;
+
+               }
+               prof_counter[cpu]=prof_multiplier[cpu];
+       }
+}
+
+/*
+ * Dirty hack to get smp message passing working.
+ * Right now it only works for stop cpu's but will be setup
+ * later for more general message passing.
+ *
+ * As it is now, if we're sending two message as the same time
+ * we have race conditions.  I avoided doing locks here since
+ * all that works right now is the stop cpu message.
+ *
+ *  -- Cort
+ */
+int smp_message[NR_CPUS];
+void smp_message_recv(void)
+{
+       int msg = smp_message[smp_processor_id()];
+       
+       printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);
+       
+       /* make sure msg is for us */
+       if ( msg == -1 ) return;
+printk("recv after msg check\n");      
+       switch( msg )
        {
-               /* interrupt secondary */
-               *(volatile unsigned long *)(0xf80000c0) = 0;
+       case MSG_STOP_CPU:
+               __cli();
+               while (1) ;
+               break;
+       case 0xf0f0: /* syncing time bases - just return */
+               break;
+       default:
+               printk("SMP %d: smp_message_recv(): unknown msg %d\n",
+                      smp_processor_id(), msg);
+               break;
        }
-       else
+       /* reset message */
+       smp_message[smp_processor_id()] = -1;
+}
+
+spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+       printk("SMP %d: sending smp message\n", current->processor);
+
+       spin_lock(&mesg_pass_lock);
+       if ( _machine != _MACH_Pmac )
+               return;
+
+#define OTHER (~smp_processor_id() & 1)
+       
+       switch( target )
        {
-               /* interrupt primary */
-               *(volatile unsigned long *)(0xf3019000);
+       case MSG_ALL:
+               smp_message[smp_processor_id()] = msg;
+               /* fall through */
+       case MSG_ALL_BUT_SELF:
+               smp_message[OTHER] = msg;
+               break;
+       default:
+               smp_message[target] = msg;
+               break;
        }
-#endif 
+       /* interrupt secondary processor */
+       /**(volatile unsigned long *)(0xf80000c0) = 0xffffffff;
+       eieio();*/
+       *(volatile unsigned long *)(0xf80000c0) = 0;
+       /* interrupt primary */
+       /**(volatile unsigned long *)(0xf3019000);*/
+       spin_unlock(&mesg_pass_lock);   
 }
 
 int setup_profiling_timer(unsigned int multiplier)
diff --git a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c
new file mode 100644 (file)
index 0000000..db02be6
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Software emulation of some PPC instructions for the 8xx core.
+ *
+ * Copyright (C) 1998 Dan Malek (dmalek@jlc.net)
+ *
+ * Software floating emuation for the MPC8xx processor.  I did this mostly
+ * because it was easier than trying to get the libraries compiled for
+ * software floating point.  The goal is still to get the libraries done,
+ * but I lost patience and needed some hacks to at least get init and
+ * shells running.  The first problem is the setjmp/longjmp that save
+ * and restore the floating point registers.
+ *
+ * For this emulation, our working registers are found on the register
+ * save area.
+ */
+
+#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/interrupt.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+/* Eventually we may need a look-up table, but this works for now.
+*/
+#define LFD    50
+#define LFDU   51
+#define STFD   54
+#define STFDU  55
+
+/*
+ * We return 0 on success, 1 on unimplemented instruction, and EFAULT
+ * if a load/store faulted.
+ */
+int
+Soft_emulate_8xx(struct pt_regs *regs)
+{
+       uint    inst, instword;
+       uint    flreg, idxreg, disp;
+       uint    retval;
+       uint    *ea, *ip;
+
+       retval = 0;
+
+       instword = *((uint *)regs->nip);
+       inst = instword >> 26;
+
+       flreg = (instword >> 21) & 0x1f;
+       idxreg = (instword >> 16) & 0x1f;
+       disp = instword & 0xffff;
+
+       ea = (uint *)(regs->gpr[idxreg] + disp);
+       ip = (uint *)&current->tss.fpr[flreg];
+
+       if (inst == LFD) {
+               if (copy_from_user(ip, ea, sizeof(double)))
+                       retval = EFAULT;
+       }
+       else if (inst == LFDU) {
+
+               if (copy_from_user(ip, ea, sizeof(double)))
+                       retval = EFAULT;
+               else
+                       regs->gpr[idxreg] = (uint)ea;
+       }
+       else if (inst == STFD) {
+
+               if (copy_to_user(ea, ip, sizeof(double)))
+                       retval = EFAULT;
+       }
+       else if (inst == STFDU) {
+
+               if (copy_to_user(ea, ip, sizeof(double)))
+                       retval = EFAULT;
+               else
+                       regs->gpr[idxreg] = (uint)ea;
+       }
+       else {
+               retval = 1;
+       }
+
+       if (retval == 0)
+               regs->nip += 4;
+       return(retval);
+}
index 319db15deb9b0bcdad62e3ce3cd329f4f794545d..dc24439d4c2f39ec553a30669d254fcf62dd7f21 100644 (file)
@@ -1,9 +1,22 @@
 /*
- * $Id: time.c,v 1.17 1997/12/28 22:47:21 paulus Exp $
+ * $Id: time.c,v 1.28 1998/04/07 18:49:49 cort Exp $
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
  * Paul Mackerras' version and mine for PReP and Pmac.
+ * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net).
+ *
+ * Since the MPC8xx has a programmable interrupt timer, I decided to
+ * use that rather than the decrementer.  Two reasons: 1.) the clock
+ * frequency is low, causing 2.) a long wait in the timer interrupt
+ *             while ((d = get_dec()) == dval)
+ * loop.  The MPC8xx can be driven from a variety of input clocks,
+ * so a number of assumptions have been made here because the kernel
+ * parameter HZ is a constant.  We assume (correctly, today :-) that
+ * the MPC8xx on the MBX board is driven from a 32.768 kHz crystal.
+ * This is then divided by 4, providing a 8192 Hz clock into the PIT.
+ * Since it is not possible to get a nice 100 Hz clock out of this, without
+ * creating a software PLL, I have set HZ to 128.  -- Dan
  */
 
 #include <linux/errno.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/nvram.h>
+#include <asm/cache.h>
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+#endif
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#endif
 
 #include "time.h"
 
 /* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */
 int (*set_rtc_time)(unsigned long);
 
+void smp_local_timer_interrupt(struct pt_regs *);
+
 /* keep track of when we need to update the rtc */
 unsigned long last_rtc_update = 0;
 
@@ -48,6 +70,14 @@ unsigned count_period_den;   /* count_period_num / count_period_den us */
 void timer_interrupt(struct pt_regs * regs)
 {
        int dval, d;
+       unsigned long cpu = smp_processor_id();
+       /* save the HID0 in case dcache was off - see idle.c
+        * this hack should leave for a better solution -- Cort */
+       unsigned dcache_locked = unlock_dcache();
+       
+if ( smp_processor_id() ) printk("SMP 1: timer intr\n");       
+       hardirq_enter(cpu);
+       
        while ((dval = get_dec()) < 0) {
                /*
                 * Wait for the decrementer to change, then jump
@@ -57,17 +87,49 @@ void timer_interrupt(struct pt_regs * regs)
                while ((d = get_dec()) == dval)
                        ;
                set_dec(d + decrementer_count);
-               do_timer(regs);
-               /*
-                * update the rtc when needed
-                */
-               if ( xtime.tv_sec > last_rtc_update + 660 )
-                       if (set_rtc_time(xtime.tv_sec) == 0)
-                               last_rtc_update = xtime.tv_sec;
-                       else
-                               last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+               if ( !smp_processor_id() )
+               {
+                       do_timer(regs);
+                       /*
+                        * update the rtc when needed
+                        */
+                       if ( xtime.tv_sec > last_rtc_update + 660 )
+                               if (set_rtc_time(xtime.tv_sec) == 0)
+                                       last_rtc_update = xtime.tv_sec;
+                               else
+                                       last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+               }
        }
+#ifdef __SMP__
+       smp_local_timer_interrupt(regs);
+#endif         
+       
+       hardirq_exit(cpu);
+       /* restore the HID0 in case dcache was off - see idle.c
+        * this hack should leave for a better solution -- Cort */
+       lock_dcache(dcache_locked);
+}
+
+#ifdef CONFIG_MBX
+/* A place holder for time base interrupts, if they are ever enabled.
+*/
+void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+static int
+mbx_set_rtc_time(unsigned long time)
+{
+       ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+       ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
+       ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+       return(0);
 }
+#endif /* CONFIG_MBX */
 
 /*
  * This version of gettimeofday has microsecond resolution.
@@ -108,6 +170,7 @@ void do_settimeofday(struct timeval *tv)
 void
 time_init(void)
 {
+#ifndef CONFIG_MBX
        if ((_get_PVR() >> 16) == 1) {
                /* 601 processor: dec counts down by 128 every 128ns */
                decrementer_count = DECREMENTER_COUNT_601;
@@ -119,9 +182,10 @@ time_init(void)
        case _MACH_Pmac:
                /* can't call pmac_get_rtc_time() yet,
                   because via-cuda isn't initialized yet. */
-               if ((_get_PVR() >> 16) != 1)
+               if ( (_get_PVR() >> 16) != 1 && (!smp_processor_id()) )
                        pmac_calibrate_decr();
-               set_rtc_time = pmac_set_rtc_time;
+               if ( !smp_processor_id() )
+                       set_rtc_time = pmac_set_rtc_time;
                break;
        case _MACH_chrp:
                chrp_time_init();
@@ -135,18 +199,63 @@ time_init(void)
                prep_calibrate_decr();
                set_rtc_time = prep_set_rtc_time;
                break;
+/* ifdef APUS specific stuff until the merge is completed. -jskov */
+#ifdef CONFIG_APUS
+       case _MACH_apus:
+       {
+               xtime.tv_sec = apus_get_rtc_time();
+               apus_calibrate_decr();
+               set_rtc_time = apus_set_rtc_time;
+               break;
        }
+#endif
+       }
+       xtime.tv_usec = 0;
+       set_dec(decrementer_count);
+#else
+       mbx_calibrate_decr();
+       set_rtc_time = mbx_set_rtc_time;
+
+       /* First, unlock all of the registers we are going to modify.
+        * To protect them from corruption during power down, registers
+        * that are maintained by keep alive power are "locked".  To
+        * modify these registers we have to write the key value to
+        * the key location associated with the register.
+        */
+       ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+       ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+
+
+       /* Disable the RTC one second and alarm interrupts.
+       */
+       ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
+                                               ~(RTCSC_SIE | RTCSC_ALE);
+
+       /* Enabling the decrementer also enables the timebase interrupts
+        * (or from the other point of view, to get decrementer interrupts
+        * we have to enable the timebase).  The decrementer interrupt
+        * is wired into the vector table, nothing to do here for that.
+        */
+       ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
+                               ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
+                                        (TBSCR_TBF | TBSCR_TBE));
+       if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+               panic("Could not allocate timer IRQ!");
+
+       /* Get time from the RTC.
+       */
+       xtime.tv_sec = ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
        xtime.tv_usec = 0;
 
-       /*
-        * mark the rtc/on-chip timer as in sync
+#endif /* CONFIG_MBX */
+       
+       /* mark the rtc/on-chip timer as in sync
         * so we don't update right away
         */
        last_rtc_update = xtime.tv_sec;
-
-       set_dec(decrementer_count);
 }
 
+#ifndef CONFIG_MBX
 /*
  * Uses the on-board timer to calibrate the on-chip decrementer register
  * for prep systems.  On the pmac the OF tells us what the frequency is
@@ -158,6 +267,27 @@ volatile int *done_ptr = &calibrate_done;
 void prep_calibrate_decr(void)
 {
        unsigned long flags;
+
+       /* the Powerstack II's have trouble with the timer so
+        * we use a default value -- Cort
+        */
+       if ( (_prep_type == _PREP_Motorola) &&
+            ((inb(0x800) & 0xF0) & 0x40) )
+       {
+               unsigned long freq, divisor;
+               static unsigned long t2 = 0;
+               
+               t2 = 998700000/60;
+               freq = t2 * 60; /* try to make freq/1e6 an integer */
+               divisor = 60;
+               printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+                      freq, divisor,t2>>20);
+               decrementer_count = freq / HZ / divisor;
+               count_period_num = divisor;
+               count_period_den = freq / 1000000;
+               return;
+       }
+       
        
        save_flags(flags);
 
@@ -181,7 +311,7 @@ void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
 {
        unsigned long freq, divisor;
        static unsigned long t1 = 0, t2 = 0;
-
+       
        if ( !t1 )
                t1 = get_dec();
        else if (!t2)
@@ -189,11 +319,6 @@ void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
                t2 = get_dec();
                t2 = t1-t2;  /* decr's in 1/HZ */
                t2 = t2*HZ;  /* # decrs in 1s - thus in Hz */
-if ( (t2>>20) > 100 )
-{
-  printk("Decrementer frequency too high: %luMHz.  Using 15MHz.\n",t2>>20);
-  t2 = 998700000/60;
-}
                freq = t2 * 60; /* try to make freq/1e6 an integer */
                divisor = 60;
                printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
@@ -205,6 +330,32 @@ if ( (t2>>20) > 100 )
        }
 }
 
+#else /* CONFIG_MBX */
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four.  Currently, we only
+ * support the MBX, which is system clock divided by sixteen.
+ */
+void mbx_calibrate_decr(void)
+{
+       int freq, fp, divisor;
+
+       if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
+               printk("WARNING: Wrong decrementer source clock.\n");
+
+       /* The manual says the frequency is in Hz, but it is really
+        * as MHz.  The value 'fp' is the number of decrementer ticks
+        * per second.
+        */
+       /*fp = (mbx_board_info.bi_intfreq * 1000000) / 16;*/
+       freq = fp*60;   /* try to make freq/1e6 an integer */
+        divisor = 60;
+        printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+        decrementer_count = freq / HZ / divisor;
+        count_period_num = divisor;
+        count_period_den = freq / 1000000;
+}
+#endif /* CONFIG_MBX */
 
 /* 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
index 538ac7bb196fa0cd6d697f9955e630ea3af29ad9..64a07250cfd7637067b28a765d12c5ad3affdca6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: time.h,v 1.7 1997/12/28 22:47:24 paulus Exp $
+ * $Id: time.h,v 1.10 1998/04/01 07:46:03 geert Exp $
  * Common time prototypes and such for all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -12,6 +12,7 @@
 void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
 void prep_calibrate_decr(void);
 void pmac_calibrate_decr(void);
+extern void apus_calibrate_decr(void);
 extern unsigned decrementer_count;
 extern unsigned count_period_num;
 extern unsigned count_period_den;
@@ -24,12 +25,16 @@ extern unsigned long last_rtc_update;
 unsigned long prep_get_rtc_time(void);
 unsigned long pmac_get_rtc_time(void);
 unsigned long chrp_get_rtc_time(void);
+unsigned long apus_get_rtc_time(void);
 int prep_set_rtc_time(unsigned long nowtime);
 int pmac_set_rtc_time(unsigned long nowtime);
 int chrp_set_rtc_time(unsigned long nowtime);
+int apus_set_rtc_time(unsigned long nowtime);
 void pmac_read_rtc_time(void);
 void chrp_calibrate_decr(void);
 void chrp_time_init(void);
+int via_calibrate_decr(void);
+void mbx_calibrate_decr(void);
 
 /* Accessor functions for the decrementer register. */
 static __inline__ unsigned int get_dec(void)
index 7199dd5c1d283b7c9310d7976d1cc0be82718f2a..c5c90b5278809ce8e5b3fcd3cdec67a4fd554134 100644 (file)
@@ -39,13 +39,31 @@ extern int fix_alignment(struct pt_regs *);
 extern void bad_page_fault(struct pt_regs *, unsigned long);
 
 #ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *regs);
 extern int xmon_bpt(struct pt_regs *regs);
 extern int xmon_sstep(struct pt_regs *regs);
-extern void xmon(struct pt_regs *regs);
 extern int xmon_iabr_match(struct pt_regs *regs);
+extern int xmon_dabr_match(struct pt_regs *regs);
 extern void (*xmon_fault_handler)(struct pt_regs *regs);
 #endif
 
+#ifdef CONFIG_XMON
+void (*debugger)(struct pt_regs *regs) = xmon;
+int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
+int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
+int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
+int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#else
+#ifdef CONFIG_KGDB
+void (*debugger)(struct pt_regs *regs);
+int (*debugger_bpt)(struct pt_regs *regs);
+int (*debugger_sstep)(struct pt_regs *regs);
+int (*debugger_iabr_match)(struct pt_regs *regs);
+int (*debugger_dabr_match)(struct pt_regs *regs);
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#endif
+#endif
 /*
  * Trap & Exception support
  */
@@ -61,8 +79,8 @@ _exception(int signr, struct pt_regs *regs)
        if (!user_mode(regs))
        {
                show_regs(regs);
-#ifdef CONFIG_XMON
-               xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+               debugger(regs);
 #endif
                print_backtrace((unsigned long *)regs->gpr[1]);
                panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
@@ -75,9 +93,9 @@ MachineCheckException(struct pt_regs *regs)
 {
        if ( !user_mode(regs) )
        {
-#ifdef CONFIG_XMON
-               if (xmon_fault_handler) {
-                       xmon_fault_handler(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+               if (debugger_fault_handler) {
+                       debugger_fault_handler(regs);
                        return;
                }
 #endif
@@ -103,8 +121,8 @@ MachineCheckException(struct pt_regs *regs)
                        printk("Unknown values in msr\n");
                }
                show_regs(regs);
-#ifdef CONFIG_XMON
-               xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+               debugger(regs);
 #endif
                print_backtrace((unsigned long *)regs->gpr[1]);
                panic("machine check");
@@ -123,8 +141,8 @@ UnknownException(struct pt_regs *regs)
 void
 InstructionBreakpoint(struct pt_regs *regs)
 {
-#ifdef CONFIG_XMON
-       if (xmon_iabr_match(regs))
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+       if (debugger_iabr_match(regs))
                return;
 #endif
        _exception(SIGTRAP, regs);
@@ -144,8 +162,8 @@ ProgramCheckException(struct pt_regs *regs)
                _exception(SIGFPE, regs);
        } else if (regs->msr & 0x20000) {
                /* trap exception */
-#ifdef CONFIG_XMON
-               if (xmon_bpt(regs))
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+               if (debugger_bpt(regs))
                        return;
 #endif
                _exception(SIGTRAP, regs);
@@ -158,8 +176,8 @@ void
 SingleStepException(struct pt_regs *regs)
 {
        regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
-#ifdef CONFIG_XMON
-       if (xmon_sstep(regs))
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+       if (debugger_sstep(regs))
                return;
 #endif
        _exception(SIGTRAP, regs);      
@@ -170,8 +188,13 @@ AlignmentException(struct pt_regs *regs)
 {
        int fixed;
 
+#ifdef __SMP__
+       if (regs->msr & MSR_FP )
+               smp_giveup_fpu(current);
+#else  
        if (last_task_used_math == current)
                giveup_fpu();
+#endif 
        fixed = fix_alignment(regs);
        if (fixed == 1) {
                regs->nip += 4; /* skip over emulated instruction */
@@ -190,8 +213,8 @@ StackOverflow(struct pt_regs *regs)
 {
        printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
               current, regs->gpr[1]);
-#ifdef CONFIG_XMON
-       xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+       debugger(regs);
 #endif
        show_regs(regs);
        print_backtrace((unsigned long *)regs->gpr[1]);
@@ -205,3 +228,41 @@ trace_syscall(struct pt_regs *regs)
               current, current->pid, regs->nip, regs->link, regs->gpr[0],
               regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
 }
+
+#ifdef CONFIG_8xx
+
+void
+SoftwareEmulation(struct pt_regs *regs)
+{
+       int     errcode;
+       extern int      Soft_emulate_8xx (struct pt_regs *regs);
+
+       if (user_mode(regs)) {
+#if 0
+               printk("(user mode)\n");
+               _exception(SIGTRAP, regs);
+#else
+               if (errcode = Soft_emulate_8xx(regs)) {
+printk("Software Emulation 0x%x: 0x%x ",
+                       regs->nip, *((uint *)regs->nip));
+print_8xx_pte(current->mm, regs->nip);
+                       if (errcode == EFAULT)
+                               _exception(SIGBUS, regs);
+                       else
+                               _exception(SIGILL, regs);
+               }
+#endif
+       }
+       else {
+               printk("(kernel mode)\n");
+               panic("Kernel Mode Software Emulation");
+       }
+}
+#endif
+
+void
+TAUException(struct pt_regs *regs)
+{
+       printk("TAU trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
+}
index 5e2ceb88918a90ec07972341972feaf405328190..55cc665d73cba5ab42c5ef9d0526159bd5732fe0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: locks.c,v 1.7 1998/01/06 06:44:59 cort Exp $
+ * $Id: locks.c,v 1.17 1998/03/26 22:19:38 cort Exp $
  *
  * Locks for smp ppc 
  * 
@@ -9,53 +9,78 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/spinlock.h>
+#include <asm/io.h>
 
 #define DEBUG_LOCKS 1
 
 #undef INIT_STUCK
-#define INIT_STUCK 10000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock(%p) CPU#%d nip %08lx\n", lock, cpu, nip); stuck = INIT_STUCK; }
+#define INIT_STUCK 1000000
 
 void _spin_lock(spinlock_t *lock)
 {
-       unsigned long val, nip = (unsigned long)__builtin_return_address(0);
        int cpu = smp_processor_id();
+#ifdef DEBUG_LOCKS
        int stuck = INIT_STUCK;
-       
-again: 
+#endif /* DEBUG_LOCKS */
        /* try expensive atomic load/store to get lock */
-       __asm__ __volatile__(
-               "10: \n\t"
-               "lwarx %0,0,%1 \n\t"
-               "stwcx. %2,0,%1 \n\t"
-               "bne- 10b \n\t"
-               : "=r" (val)
-               : "r" (&(lock->lock)), "r" ( (cpu&3)|(nip&~3L) ));
-       if(val) {
+       while((unsigned long )xchg_u32((void *)&lock->lock,0xffffffff)) {
                /* try cheap load until it's free */
                while(lock->lock) {
-                       STUCK;
+#ifdef DEBUG_LOCKS
+                       if(!--stuck)
+                       {
+                               printk("_spin_lock(%p) CPU#%d NIP %p"
+                                      " holder: cpu %ld pc %08lX\n",
+                                      lock, cpu, __builtin_return_address(0),
+                                      lock->owner_cpu,lock->owner_pc);
+                               stuck = INIT_STUCK;
+                               /* steal the lock */
+                               /*xchg_u32((void *)&lock->lock,0);*/
+                       }
+#endif /* DEBUG_LOCKS */
                        barrier();
                }
-               goto again;
        }
+       lock->owner_pc = (unsigned long)__builtin_return_address(0);
+       lock->owner_cpu = cpu;
+}
+
+int spin_trylock(spinlock_t *lock)
+{
+       unsigned long result;
+
+       result = (unsigned long )xchg_u32((void *)&lock->lock,0xffffffff);
+       if ( !result ) 
+       { 
+               lock->owner_cpu = smp_processor_id(); 
+               lock->owner_pc = (unsigned long)__builtin_return_address(0);
+       } 
+       return (result == 0);
 }
 
+
+
 void _spin_unlock(spinlock_t *lp)
 {
+#ifdef DEBUG_LOCKS
+       if ( !lp->lock )
+               panic("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp,
+                      smp_processor_id(),current->comm,current->pid);
+       if ( lp->owner_cpu != smp_processor_id() )
+               panic("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
+                      lp, smp_processor_id(), (int)lp->owner_cpu,
+                      lp->owner_pc,lp->lock);
+#endif /* DEBUG_LOCKS */
+       lp->owner_pc = lp->owner_cpu = 0;
+       eieio();
        lp->lock = 0;
+       eieio();
 }
                
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("_read_lock(%p) CPU#%d\n", rw, cpu); stuck = INIT_STUCK; }
-
 /*
  * Just like x86, implement read-write locks as a 32-bit counter
  * with the high bit (sign) being the "write" bit.
@@ -63,8 +88,10 @@ if(!--stuck) { printk("_read_lock(%p) CPU#%d\n", rw, cpu); stuck = INIT_STUCK; }
  */
 void _read_lock(rwlock_t *rw)
 {
+#ifdef DEBUG_LOCKS
        unsigned long stuck = INIT_STUCK;
        int cpu = smp_processor_id();
+#endif /* DEBUG_LOCKS */                 
 
 again: 
        /* get our read lock in there */
@@ -76,7 +103,13 @@ again:
                /* wait for the write lock to go away */
                while ((signed long)((rw)->lock) < 0)
                {
-                       STUCK;
+#ifdef DEBUG_LOCKS
+                       if(!--stuck)
+                       {
+                               printk("_read_lock(%p) CPU#%d\n", rw, cpu);
+                               stuck = INIT_STUCK;
+                       }
+#endif /* DEBUG_LOCKS */
                }
                /* try to get the read lock again */
                goto again;
@@ -87,33 +120,34 @@ void _read_unlock(rwlock_t *rw)
 {
 #ifdef DEBUG_LOCKS
        if ( rw->lock == 0 )
-       {
-               if ( current)
                printk("_read_unlock(): %s/%d (nip %08lX) lock %lx",
-                     current->comm,current->pid,current->tss.regs->nip,
+                      current->comm,current->pid,current->tss.regs->nip,
                      rw->lock);
-               else
-                 printk("no current\n");
-       }
 #endif /* DEBUG_LOCKS */
        atomic_dec((atomic_t *) &(rw)->lock);
 }
 
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock(%p) CPU#%d lock %lx)\n", rw, cpu,rw->lock); stuck = INIT_STUCK; }
-
 void _write_lock(rwlock_t *rw)
 {
+#ifdef DEBUG_LOCKS
        unsigned long stuck = INIT_STUCK;
        int cpu = smp_processor_id();
+#endif /* DEBUG_LOCKS */                 
 
 again: 
        if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */
        {
                while ( (rw)->lock & (1<<31) ) /* wait for write lock */
                {
-                       STUCK;
+#ifdef DEBUG_LOCKS
+                       if(!--stuck)
+                       {
+                               printk("write_lock(%p) CPU#%d lock %lx)\n",
+                                      rw, cpu,rw->lock);
+                               stuck = INIT_STUCK;
+                       }
+#endif /* DEBUG_LOCKS */                 
+                       barrier();
                }
                goto again;
        }
@@ -124,7 +158,15 @@ again:
                clear_bit(31,&(rw)->lock);
                while ( (rw)->lock & ~(1<<31) )
                {
-                       STUCK;
+#ifdef DEBUG_LOCKS
+                       if(!--stuck)
+                       {
+                               printk("write_lock(%p) 2 CPU#%d lock %lx)\n",
+                                      rw, cpu,rw->lock);
+                               stuck = INIT_STUCK;
+                       }
+#endif /* DEBUG_LOCKS */
+                       barrier();
                }
                goto again;
        }
@@ -134,14 +176,9 @@ void _write_unlock(rwlock_t *rw)
 {
 #ifdef DEBUG_LOCKS
        if ( !(rw->lock & (1<<31)) )
-       {
-               if ( current)
                printk("_write_lock(): %s/%d (nip %08lX) lock %lx",
                      current->comm,current->pid,current->tss.regs->nip,
                      rw->lock);
-               else
-                 printk("no current\n");
-       }
 #endif /* DEBUG_LOCKS */
        clear_bit(31,&(rw)->lock);
 }
@@ -149,6 +186,8 @@ void _write_unlock(rwlock_t *rw)
 void __lock_kernel(struct task_struct *task)
 {
 #ifdef DEBUG_LOCKS
+       unsigned long stuck = INIT_STUCK;
+       
        if ( (signed long)(task->lock_depth) < 0 )
        {
                printk("__lock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
@@ -156,20 +195,40 @@ void __lock_kernel(struct task_struct *task)
                      task->lock_depth);
        }
 #endif /* DEBUG_LOCKS */
+
+       if ( atomic_inc_return((atomic_t *) &task->lock_depth) != 1 )
+               return;
        /* mine! */
-       if ( atomic_inc_return((atomic_t *) &task->lock_depth) == 1 )
-               klock_info.akp = smp_processor_id();
+       while ( xchg_u32( (void *)&klock_info.kernel_flag, KLOCK_HELD) )
+       {
+               /* try cheap load until it's free */
+               while(klock_info.kernel_flag) {
+#ifdef DEBUG_LOCKS
+                       if(!--stuck)
+                       {
+                               printk("_lock_kernel() CPU#%d NIP %p\n",
+                                      smp_processor_id(),
+                                      __builtin_return_address(0));
+                               stuck = INIT_STUCK;
+                       }
+#endif /* DEBUG_LOCKS */
+                       barrier();
+               }
+       }
+       
+       klock_info.akp = smp_processor_id();
        /* my kernel mode! mine!!! */
 }
+
 void __unlock_kernel(struct task_struct *task)
 {
 #ifdef DEBUG_LOCKS
-       if ( task->lock_depth == 0 )
+       if ( (task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD) )
        {
-               printk("__unlock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
-                     task->comm,task->pid,task->tss.regs->nip,
-                     task->lock_depth);
+               printk("__unlock_kernel(): %s/%d (nip %08lX) "
+                      "lock depth %x flags %lx\n",
+                      task->comm,task->pid,task->tss.regs->nip,
+                      task->lock_depth, klock_info.kernel_flag);
                klock_info.akp = NO_PROC_ID;            
                klock_info.kernel_flag = 0;
                return;
@@ -177,8 +236,8 @@ void __unlock_kernel(struct task_struct *task)
 #endif /* DEBUG_LOCKS */
        if ( atomic_dec_and_test((atomic_t *) &task->lock_depth) )
        {
-               klock_info.akp = NO_PROC_ID;            
-               klock_info.kernel_flag = 0;
+               klock_info.akp = NO_PROC_ID;
+               klock_info.kernel_flag = KLOCK_CLEAR;
        }
 }      
 
@@ -192,4 +251,3 @@ void reacquire_kernel_lock(struct task_struct *task, int cpu,int depth)
                __sti();
        }
 }
-
diff --git a/arch/ppc/mbx_defconfig b/arch/ppc/mbx_defconfig
new file mode 100644 (file)
index 0000000..e498b52
--- /dev/null
@@ -0,0 +1,196 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+# CONFIG_6xx is not set
+CONFIG_8xx=y
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+# CONFIG_CHRP is not set
+# CONFIG_ALL_PPC is not set
+CONFIG_MBX=y
+CONFIG_MACH_SPECIFIC=y
+
+#
+# General setup
+#
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_MODULES is not set
+CONFIG_PCI=y
+CONFIG_PCI_OLD_PROC=y
+CONFIG_NET=y
+# CONFIG_SYSCTL is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PMAC_CONSOLE is not set
+# CONFIG_MAC_KEYBOARD is not set
+# CONFIG_MAC_FLOPPY is not set
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_XMON is not set
+CONFIG_VGA_CONSOLE=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_BLK_DEV_HD_ONLY is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# NEW devices (io_request, all ALPHA and dangerous)
+#
+# CONFIG_IO_REQUEST is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_RARP is not set
+CONFIG_IP_NOSR=y
+# CONFIG_SKB_LARGE is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_WAN_DRIVERS is not set
+# CONFIG_LAPBETHER is not set
+# CONFIG_X25_ASY is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_CDROM is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_PROC_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
index 8eaa49e9218cb43d09237c2b21dbcee6cb4e2ce0..9d0914979d420563234a0435a75db71af72d5bef 100644 (file)
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_XMON
-extern void xmon(struct pt_regs *);
-extern void (*xmon_fault_handler)(struct pt_regs *);
-extern int xmon_dabr_match(struct pt_regs *);
-int xmon_kernel_faults = 0;
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+extern void (*debugger)(struct pt_regs *);
+extern void (*debugger_fault_handler)(struct pt_regs *);
+extern int (*debugger_dabr_match)(struct pt_regs *);
+int debugger_kernel_faults = 0;
 #endif
 
 unsigned long htab_reloads = 0; /* updated by head.S:hash_page() */
@@ -72,14 +72,14 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
               (regs->trap == 0x400)?"instr":"data"
               );*/
               
-#ifdef CONFIG_XMON
-       if (xmon_fault_handler && regs->trap == 0x300) {
-               xmon_fault_handler(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+       if (debugger_fault_handler && regs->trap == 0x300) {
+               debugger_fault_handler(regs);
                return;
        }
        if (error_code & 0x00400000) {
                /* DABR match */
-               if (xmon_dabr_match(regs))
+               if (debugger_dabr_match(regs))
                        return;
        }
 #endif
@@ -90,9 +90,9 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
                        printk("page fault in interrupt handler, addr=%lx\n",
                               address);
                        show_regs(regs);
-#ifdef CONFIG_XMON
-                       if (xmon_kernel_faults)
-                               xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+                       if (debugger_kernel_faults)
+                               debugger(regs);
 #endif
                }
        }
@@ -112,11 +112,22 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
                goto bad_area;
 
 good_area:
+#ifdef CONFIG_6xx
        if (error_code & 0x95700000)
                /* an error such as lwarx to I/O controller space,
                   address matching DABR, eciwx, etc. */
+#endif /* CONFIG_6xx */
+#ifdef CONFIG_8xx
+        /* The MPC8xx seems to always set 0x80000000, which is
+         * "undefined".  Of those that can be set, this is the only
+         * one which seems bad.
+         */
+       if (error_code & 0x10000000)
+                /* Guarded storage error. */
+#endif /* CONFIG_8xx */
                goto bad_area;
        
+       
        /* a write */
        if (error_code & 0x02000000) {
                if (!(vma->vm_flags & VM_WRITE))
@@ -190,14 +201,47 @@ bad_page_fault(struct pt_regs *regs, unsigned long address)
        /* kernel has accessed a bad area */
        show_regs(regs);
        print_backtrace( (unsigned long *)regs->gpr[1] );
-#ifdef CONFIG_XMON
-       if (xmon_kernel_faults)
-               xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+       if (debugger_kernel_faults)
+               debugger(regs);
 #endif
        panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
              regs->nip,regs->link,address,current->comm,current->pid);
 }
 
+/*
+ * I need a va to pte function for the MPC8xx so I can set the cache
+ * attributes on individual pages used by the Communication Processor
+ * Module.
+ */
+pte_t *va_to_pte(struct task_struct *tsk, unsigned long address)
+{
+        pgd_t *dir;
+        pmd_t *pmd;
+        pte_t *pte;
+        
+        dir = pgd_offset(tsk->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))
+                        {
+                                return(pte);
+                        }
+                } else
+                {
+                        return (0);
+                }
+        } else
+        {
+                return (0);
+        }
+        return (0);
+}
+
 unsigned long va_to_phys(unsigned long address)
 {
        pgd_t *dir;
@@ -226,6 +270,57 @@ unsigned long va_to_phys(unsigned long address)
        return (0);
 }
 
+void
+print_8xx_pte(struct mm_struct *mm, unsigned long addr)
+{
+        pgd_t * pgd;
+        pmd_t * pmd;
+        pte_t * pte;
+
+        printk(" pte @ 0x%8lx: ", addr);
+        pgd = pgd_offset(mm, addr & PAGE_MASK);
+        if (pgd) {
+                pmd = pmd_offset(pgd, addr & PAGE_MASK);
+                if (pmd && pmd_present(*pmd)) {
+                        pte = pte_offset(pmd, addr & PAGE_MASK);
+                        if (pte) {
+                                printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n",
+                                        (long)pgd, (long)pte, (long)pte_val(*pte));
+                        }
+                        else {
+                                printk("no pte\n");
+                        }
+                }
+                else {
+                        printk("no pmd\n");
+                }
+        }
+        else {
+                printk("no pgd\n");
+        }
+}
+
+int
+get_8xx_pte(struct mm_struct *mm, unsigned long addr)
+{
+        pgd_t * pgd;
+        pmd_t * pmd;
+        pte_t * pte;
+        int     retval = 0;
+
+        pgd = pgd_offset(mm, addr & PAGE_MASK);
+        if (pgd) {
+                pmd = pmd_offset(pgd, addr & PAGE_MASK);
+                if (pmd && pmd_present(*pmd)) {
+                        pte = pte_offset(pmd, addr & PAGE_MASK);
+                        if (pte) {
+                                        retval = (int)pte_val(*pte);
+                        }
+                }
+        }
+        return(retval);
+}
+
 #if 0
 /*
  * Misc debugging functions.  Please leave them here. -- Cort
index 273076d1517a47176261997f76ca80face98df71..5967e29e64277f079720609b697b4f1f63f8e9e5 100644 (file)
@@ -7,6 +7,7 @@
  *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
  *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
  *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
  *
  *  Derived from "arch/i386/mm/init.c"
  *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
@@ -31,6 +32,7 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/stddef.h>
+#include <linux/vmalloc.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/mmu_context.h>
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>         /* for initrd_* */
 #endif
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#endif
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+#endif
 
-int prom_trashed;
-int next_mmu_context;
+#ifndef CONFIG_8xx
 unsigned long _SDR1;
 PTE *Hash, *Hash_end;
 unsigned long Hash_size, Hash_mask;
+#endif /* CONFIG_8xx */
+
+/* ifdef APUS specific stuff until the merge is completed. -jskov */
+#ifdef CONFIG_APUS
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#endif
+
+int prom_trashed;
+int next_mmu_context;
 unsigned long *end_of_DRAM;
 int mem_init_done;
 extern pgd_t swapper_pg_dir[];
@@ -55,10 +72,16 @@ extern char __init_begin, __init_end;
 extern RESIDUAL res;
 char *klimit = _end;
 struct device_node *memory_node;
+unsigned long ioremap_base;
+unsigned long ioremap_bot;
+#ifndef __SMP__
+struct pgtable_cache_struct quicklists;
+#endif
 
-void *find_mem_piece(unsigned, unsigned);
-static void mapin_ram(void);
+#ifndef CONFIG_8xx
 static void hash_init(void);
+#endif /* CONFIG_8xx */
+static void mapin_ram(void);
 static void *MMU_get_page(void);
 void map_page(struct task_struct *, unsigned long va,
                     unsigned long pa, int flags);
@@ -68,6 +91,38 @@ extern unsigned long *find_end_of_memory(void);
 
 extern struct task_struct *current_set[NR_CPUS];
 
+#ifdef CONFIG_MBX
+/* This is a big hack that may not yet work correctly.
+ * The MBX8xx boards have a single DIMM socket for additional memory.
+ * Although it appears you can set magical locations in the serial
+ * EEPROM to get EPPC-Bug to configure this memory, there are no tools
+ * (i.e. commands) to make this easy.  If you screw up, you will most
+ * likely end up with a board that will not boot until you find a
+ * way to program the EEPROM correctly.  I decided to simply program
+ * the memory controller here to add the additional memory.
+ * The reason this may not work correctly is that depending upon the
+ * on-board and DIMM memory size, there may be holes in the physical
+ * address space.  This is the case for me, I have a 4 MB local memory
+ * and a 32 MB DIMM.
+ * The DIMM is 64 bits wide, and we see it as two banks of 32 bit
+ * memory.  The holes are caused by the requirement to map the
+ * memory on a natural alignment, that is a 16 MB bank must begin on
+ * a 16 MB boundary.  The DIMM_SIZE below represents the size of the
+ * bank, which is the total size divided by two.
+ * Although I may not have all of this working, the intention is to
+ * mark all of the page maps in the "hole" as reserved, and adjust
+ * num_physpages accordingly.  In the current implementation, this
+ * seems to work, but there are some assumptions about contiguous
+ * memory.  The correct solution is to modify the memory allocators
+ * to know about holes, but that will have to wait for another day.
+ *
+ * define DIMM_8xx to enable this feature.
+ * define DIMM_SIZE to reflect the bank size (DIMM size divided by two).
+ */
+/*#define DIMM_8xx      1 */
+#define DIMM_SIZE       (16 * 1024 * 1024)
+#endif /* CONFIG_MBX */
+
 /*
  * this tells the system to map all of ram with the segregs
  * (i.e. page tables) instead of the bats.
@@ -77,6 +132,34 @@ extern struct task_struct *current_set[NR_CPUS];
 /* optimization for 603 to load the tlb directly from the linux table */
 #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
 
+void __bad_pte(pmd_t *pmd)
+{
+       printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+       pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+        pte_t *pte;
+
+        pte = (pte_t *) __get_free_page(GFP_KERNEL);
+        if (pmd_none(*pmd)) {
+                if (pte) {
+                        clear_page((unsigned long)pte);
+                        pmd_val(*pmd) = (unsigned long)pte;
+                        return pte + offset;
+                }
+               pmd_val(*pmd) = (unsigned long)BAD_PAGETABLE;
+                return NULL;
+        }
+        free_page((unsigned long)pte);
+        if (pmd_bad(*pmd)) {
+                __bad_pte(pmd);
+                return NULL;
+        }
+        return (pte_t *) pmd_page(*pmd) + offset;
+}
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -121,65 +204,32 @@ 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 sort_mem_pieces(struct mem_pieces *);
-static void coalesce_mem_pieces(struct mem_pieces *);
-static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
 static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
+void *find_mem_piece(unsigned, unsigned);
 static void print_mem_pieces(struct mem_pieces *);
 
-static void
-sort_mem_pieces(struct mem_pieces *mp)
-{
-       unsigned long a, s;
-       int i, j;
-
-       for (i = 1; i < mp->n_regions; ++i) {
-               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;
-       }
-}
-
-static void
-coalesce_mem_pieces(struct mem_pieces *mp)
+/*
+ * Scan a region for a piece of a given size with the required alignment.
+ */
+void *
+find_mem_piece(unsigned size, unsigned align)
 {
-       unsigned long a, e;
-       int i, j, d;
+       int i;
+       unsigned a, e;
+       struct mem_pieces *mp = &phys_avail;
 
-       d = 0;
-       for (i = 0; i < mp->n_regions; i = j) {
+       for (i = 0; i < mp->n_regions; ++i) {
                a = mp->regions[i].address;
                e = a + mp->regions[i].size;
-               for (j = i + 1; j < mp->n_regions
-                            && mp->regions[j].address <= e; ++j)
-                       e = mp->regions[j].address + mp->regions[j].size;
-               mp->regions[d].address = a;
-               mp->regions[d].size = e - a;
-               ++d;
+               a = (a + align - 1) & -align;
+               if (a + size <= e) {
+                       remove_mem_piece(mp, a, size, 1);
+                       return __va(a);
+               }
        }
-       mp->n_regions = d;
-}
-
-/*
- * Add some memory to an array of pieces
- */
-static void
-append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)
-{
-       struct reg_property *rp;
-
-       if (mp->n_regions >= MAX_MEM_REGIONS)
-               return;
-       rp = &mp->regions[mp->n_regions++];
-       rp->address = start;
-       rp->size = size;
+       printk("Couldn't find %u bytes at %u alignment\n", size, align);
+       abort();
+       return NULL;
 }
 
 /*
@@ -252,33 +302,73 @@ print_mem_pieces(struct mem_pieces *mp)
        printk("\n");
 }
 
-/*
- * Scan a region for a piece of a given size with the required alignment.
- */
-void *
-find_mem_piece(unsigned size, unsigned align)
+
+
+#ifndef CONFIG_8xx
+static void hash_init(void);
+static void get_mem_prop(char *, struct mem_pieces *);
+static void sort_mem_pieces(struct mem_pieces *);
+static void coalesce_mem_pieces(struct mem_pieces *);
+static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
+
+static void
+sort_mem_pieces(struct mem_pieces *mp)
 {
-       int i;
-       unsigned a, e;
-       struct mem_pieces *mp = &phys_avail;
+       unsigned long a, s;
+       int i, j;
 
-       for (i = 0; i < mp->n_regions; ++i) {
+       for (i = 1; 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);
+               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;
        }
-       printk("Couldn't find %u bytes at %u alignment\n", size, align);
-       abort();
-       return NULL;
+}
+
+static void
+coalesce_mem_pieces(struct mem_pieces *mp)
+{
+       unsigned long a, e;
+       int i, j, d;
+
+       d = 0;
+       for (i = 0; i < mp->n_regions; i = j) {
+               a = mp->regions[i].address;
+               e = a + mp->regions[i].size;
+               for (j = i + 1; j < mp->n_regions
+                            && mp->regions[j].address <= e; ++j)
+                       e = mp->regions[j].address + mp->regions[j].size;
+               mp->regions[d].address = a;
+               mp->regions[d].size = e - a;
+               ++d;
+       }
+       mp->n_regions = d;
+}
+
+/*
+ * Add some memory to an array of pieces
+ */
+static void
+append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)
+{
+       struct reg_property *rp;
+
+       if (mp->n_regions >= MAX_MEM_REGIONS)
+               return;
+       rp = &mp->regions[mp->n_regions++];
+       rp->address = start;
+       rp->size = size;
 }
 
 /*
  * Read in a property describing some pieces of memory.
  */
+
 static void
 get_mem_prop(char *name, struct mem_pieces *mp)
 {
@@ -365,6 +455,41 @@ unsigned long *pmac_find_end_of_memory(void)
 
        return __va(total);
 }
+#endif /* CONFIG_8xx */
+
+#ifdef CONFIG_APUS
+#define HARDWARE_MAPPED_SIZE (512*1024)
+unsigned long *apus_find_end_of_memory(void)
+{
+       unsigned long kstart, ksize;
+
+       /* Add the chunk that ADOS does not see. Removed again below. */
+       m68k_memory[0].size += HARDWARE_MAPPED_SIZE;
+
+       append_mem_piece(&phys_mem, m68k_memory[0].addr, m68k_memory[0].size);
+
+       phys_avail = phys_mem;
+       kstart = __pa(_stext);
+       ksize = PAGE_ALIGN(klimit - _stext);
+       remove_mem_piece(&phys_avail, kstart, ksize, 1);
+
+       /* Remove the upper HARDWARE_MAPPED_SIZE bytes where the address
+        * range 0xfff00000-0xfffx0000 is mapped to.
+        * We do it this way to ensure that the memory registered in the
+        * system has a power-of-two size.
+        */
+       remove_mem_piece(&phys_avail, 
+                        (m68k_memory[0].addr + m68k_memory[0].size 
+                         - HARDWARE_MAPPED_SIZE),
+                        HARDWARE_MAPPED_SIZE, 1);
+
+       /* FIXME:APUS: Only handles one block of memory! Problem is
+        * that the VTOP/PTOV code in head.S would be a mess if it had
+        * to handle more than one block.
+        */
+       return __va(m68k_memory[0].addr + m68k_memory[0].size);
+}
+#endif
 
 /*
  * Find some memory for setup_arch to return.
@@ -381,6 +506,16 @@ unsigned long find_available_memory(void)
        unsigned long start, end;
 
        free = 0;
+       if (_machine == _MACH_mbx) {
+               /* Return the first, not the last region, because we
+                 * may not yet have properly initialized the additonal
+                 * memory DIMM.
+                 */
+                a = PAGE_ALIGN(phys_avail.regions[0].address);
+                avail_start = (unsigned long) __va(a);
+                return avail_start;
+        }
+       
        for (i = 0; i < phys_avail.n_regions - 1; ++i) {
                start = phys_avail.regions[i].address;
                end = start + phys_avail.regions[i].size;
@@ -396,7 +531,7 @@ unsigned long find_available_memory(void)
 void show_mem(void)
 {
        int i,free = 0,total = 0,reserved = 0;
-       int shared = 0;
+       int shared = 0, cached = 0;
        struct task_struct *p;
 
        printk("Mem-info:\n");
@@ -407,6 +542,8 @@ void show_mem(void)
                total++;
                if (PageReserved(mem_map+i))
                        reserved++;
+               else if (PageSwapCache(mem_map+i))
+                       cached++;
                else if (!atomic_read(&mem_map[i].count))
                        free++;
                else
@@ -416,6 +553,8 @@ void show_mem(void)
        printk("%d free pages\n",free);
        printk("%d reserved pages\n",reserved);
        printk("%d pages shared\n",shared);
+       printk("%d pages swap cached\n",cached);
+       printk("%d pages in page table cache\n",(int)pgtable_cache_size);
        show_buffers();
 #ifdef CONFIG_NET
        show_net_buffers();
@@ -487,6 +626,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
        int codepages = 0;
        int datapages = 0;
        int initpages = 0;
+       extern unsigned int rtas_data, rtas_size;
 
        end_mem &= PAGE_MASK;
        high_memory = (void *) end_mem;
@@ -496,6 +636,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
        /* mark usable pages in the mem_map[] */
        start_mem = PAGE_ALIGN(start_mem);
 
+#ifndef CONFIG_8xx
        remove_mem_piece(&phys_avail, __pa(avail_start),
                         start_mem - avail_start, 1);
 
@@ -520,7 +661,52 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
                        clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
        }
        prom_trashed = 1;
-
+#else /* CONFIG_8xx */
+       /* When we get here, all of the page maps have been set up and
+         * Linux thinks we have contiguous memory.  Since the MBX can
+         * have memory holes, we need to compensate for that here.
+         * The memory holes are currently pages marked reserved (all
+         * pages right now are marked reserved).
+         * All of the memory allocated by the kernel up to this point
+         * had to come from region 0.
+         */
+
+        /* First, unreserve all memory from the page following start_mem
+         * to the end of region 0.
+         */
+        for (addr = start_mem + PAGE_SIZE ;
+              addr < (ulong) __va(phys_mem.regions[0].size);
+                addr += PAGE_SIZE) {
+                        clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+        }
+
+        /* Now add any additional regions to the system.
+        */
+        for (i = 1; 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);
+        }
+        phys_avail.n_regions = 0;       /* Nothing available, kernel owns */
+        /* Count up the size of the holes.  We look for the space
+         * between the end of one region and the start of the next.
+         */
+        lim = 0;
+        for (i = 0; i < phys_mem.n_regions-1; ++i) {
+                a = (unsigned long) phys_mem.regions[i].address;
+                a += phys_mem.regions[i].size;
+                lim += phys_mem.regions[i+1].address - a;
+        }
+
+        /* It appears that num_physpages is only used for quota checking,
+         * when pages are locked down.  We subtract the size of the holes
+         * from it now.
+         */
+        num_physpages -= lim/PAGE_SIZE;
+#endif /* CONFIG_8xx */
+       
        for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
                if (PageReserved(mem_map + MAP_NR(addr))) {
                        if (addr < (ulong) etext)
@@ -537,7 +723,12 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
                if (!initrd_start ||
                    addr < (initrd_start & PAGE_MASK) || addr >= initrd_end)
 #endif /* CONFIG_BLK_DEV_INITRD */
-                       free_page(addr);
+#ifndef CONFIG_8xx               
+                       if ( !rtas_data ||
+                            addr < (rtas_data & PAGE_MASK) ||
+                            addr >= (rtas_data+rtas_size))
+#endif /* CONFIG_8xx */
+                               free_page(addr);
        }
 
         printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
@@ -594,6 +785,7 @@ void si_meminfo(struct sysinfo *val)
        return;
 }
 
+#ifndef CONFIG_8xx
 union ubat {                   /* BAT register values to be loaded */
        BAT     bat;
        P601_BAT bat_601;
@@ -692,7 +884,7 @@ unsigned long *prep_find_end_of_memory(void)
 
        return (__va(total));
 }
-
+#endif /* CONFIG_8xx */
 
 /*
  * Map in all of physical memory starting at KERNELBASE.
@@ -702,8 +894,9 @@ unsigned long *prep_find_end_of_memory(void)
 static void mapin_ram()
 {
        int i;
-       unsigned long tot, bl, done;
        unsigned long v, p, s, f;
+#ifndef CONFIG_8xx
+       unsigned long tot, mem_base, bl, done;
 
 #ifndef MAP_RAM_WITH_SEGREGS
        /* Set up BAT2 and if necessary BAT3 to cover RAM. */
@@ -711,15 +904,17 @@ static void mapin_ram()
        for (bl = 128<<10; bl < 256<<20; bl <<= 1)
                if (bl * 2 > tot)
                        break;
-       setbat(2, KERNELBASE, 0, bl, RAM_PAGE);
-       done = __pa(bat_addrs[2].limit) + 1;
+
+       mem_base = __pa(KERNELBASE);
+       setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE);
+       done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
        if (done < tot) {
                /* use BAT3 to cover a bit more */
                tot -= done;
                for (bl = 128<<10; bl < 256<<20; bl <<= 1)
                        if (bl * 2 > tot)
                                break;
-               setbat(3, KERNELBASE+done, done, bl, RAM_PAGE);
+               setbat(3, KERNELBASE+done, mem_base+done, bl, RAM_PAGE);
        }
 #endif
 
@@ -734,6 +929,27 @@ static void mapin_ram()
                                /* On the powerpc, no user access
                                   forces R/W kernel access */
                                f |= _PAGE_USER;
+#else  /* CONFIG_8xx */
+            for (i = 0; i < phys_mem.n_regions; ++i) {
+                    v = (ulong)__va(phys_mem.regions[i].address);
+                    p = phys_mem.regions[i].address;
+                    for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+                        /* On the MPC8xx, we want the page shared so we
+                         * don't get ASID compares on kernel space.
+                         */
+                            f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
+
+                        /* I don't really need the rest of this code, but
+                         * I grabbed it because I think the line:
+                         *      f |= _PAGE_USER
+                         * is incorrect.  It needs to be set to bits we
+                         * don't define to cause a kernel read-only.  On
+                         * the MPC8xx, the PAGE_DIRTY takes care of that
+                         * for us (along with the RW software state).
+                         */
+                            if ((char *) v < _stext || (char *) v >= etext)
+                                    f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+#endif /* CONFIG_8xx */
                        map_page(&init_task, v, p, f);
                        v += PAGE_SIZE;
                        p += PAGE_SIZE;
@@ -741,6 +957,7 @@ static void mapin_ram()
        }           
 }
 
+#ifndef CONFIG_8xx
 /*
  * Initialize the hash table and patch the instructions in head.S.
  */
@@ -820,7 +1037,7 @@ static void hash_init(void)
                Hash_end = 0;
 
 }
-
+#endif /* CONFIG_8xx */
 
 /*
  * Do very early mm setup such as finding the size of memory
@@ -832,13 +1049,19 @@ static void hash_init(void)
 void
 MMU_init(void)
 {
+#ifndef CONFIG_8xx
        if (have_of)
                end_of_DRAM = pmac_find_end_of_memory();
+#ifdef CONFIG_APUS
+       else if (_machine == _MACH_apus )
+               end_of_DRAM = apus_find_end_of_memory();
+#endif
        else /* prep */
                end_of_DRAM = prep_find_end_of_memory();
 
         hash_init();
         _SDR1 = __pa(Hash) | (Hash_mask >> 10);
+       ioremap_base = 0xf8000000;
 
        /* Map in all of RAM starting at KERNELBASE */
        mapin_ram();
@@ -856,16 +1079,40 @@ MMU_init(void)
                       IO_PAGE + ((_prep_type == _PREP_IBM)? _PAGE_USER: 0));
                break;
        case _MACH_chrp:
-               setbat(0, 0xc0000000, 0xc0000000, 0x10000000, IO_PAGE);
-               setbat(1, 0xf8000000, 0xf8000000, 0x20000, IO_PAGE);
-               setbat(3, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
+               setbat(0, 0xf8000000, 0xf8000000, 0x20000, IO_PAGE);
                break;
        case _MACH_Pmac:
                setbat(0, 0xf3000000, 0xf3000000, 0x100000, IO_PAGE);
-               /* this is used to cover registers used by smp boards -- Cort */
-               setbat(3, 0xf8000000, 0xf8000000, 0x100000, IO_PAGE);
+               ioremap_base = 0xf0000000;
                break;
+#ifdef CONFIG_APUS
+       case _MACH_apus:
+               /* Map Cyberstorm PPC registers. */
+               /* FIXME:APUS: Performance penalty here. Restrict it
+                *             to the Cyberstorm registers.
+                */
+               setbat(0, 0xfff00000, 0xfff00000, 0x00080000, IO_PAGE);
+               /* Map chip and ZorroII memory */
+               setbat(1, zTwoBase,   0x00000000, 0x01000000, IO_PAGE);
+               break;
+#endif
        }
+       ioremap_bot = ioremap_base;
+#else /* CONFIG_8xx */
+
+        /* Map in all of RAM starting at KERNELBASE */
+        mapin_ram();
+
+        /* Now map in some of the I/O space that is generically needed
+         * or shared with multiple devices.
+         * All of this fits into the same 4Mbyte region, so it only
+         * requires one page table page.
+         */
+        ioremap(NVRAM_ADDR, NVRAM_SIZE);
+        ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE);
+        ioremap(MBX_IMAP_ADDR, MBX_IMAP_SIZE);
+        ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE);
+#endif /* CONFIG_8xx */
 }
 
 static void *
@@ -887,27 +1134,98 @@ MMU_get_page()
 void *
 ioremap(unsigned long addr, unsigned long size)
 {
-       unsigned long p, end = addr + size;
+       return __ioremap(addr, size, _PAGE_NO_CACHE);
+}
+
+void *
+__ioremap(unsigned long addr, unsigned long size, unsigned long flags)
+{
+       unsigned long p, v, i;
+
+       /*
+        * Choose an address to map it to.
+        * Once the vmalloc system is running, we use it.
+        * Before then, we map addresses >= ioremap_base
+        * virt == phys; for addresses below this we use
+        * space going down from ioremap_base (ioremap_bot
+        * records where we're up to).
+        *
+        * We should also look out for a frame buffer and
+        * map it with a free BAT register, if there is one.
+        */
+       p = addr & PAGE_MASK;
+       size = PAGE_ALIGN(addr + size) - p;
+       if (size == 0)
+               return NULL;
 
-       for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
-               map_page(&init_task, p, p,
-                        pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
-       return (void *) addr;
+       if (mem_init_done) {
+               struct vm_struct *area;
+               area = get_vm_area(size);
+               if (area == 0)
+                       return NULL;
+               v = VMALLOC_VMADDR(area->addr);
+       } else {
+               if (p >= ioremap_base)
+                       v = p;
+               else
+                       v = (ioremap_bot -= size);
+       }
+
+       flags |= pgprot_val(PAGE_KERNEL);
+       if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))
+               flags |= _PAGE_GUARDED;
+       for (i = 0; i < size; i += PAGE_SIZE)
+               map_page(&init_task, v+i, p+i, flags);
+
+       return (void *) (v + (addr & ~PAGE_MASK));
 }
 
-void iounmap(unsigned long *addr)
+void iounmap(void *addr)
 {
        /* XXX todo */
 }
 
+unsigned long iopa(unsigned long addr)
+{
+       unsigned long idx;
+       pmd_t *pd;
+       pte_t *pg;
+#ifndef CONFIG_8xx
+       int b;
+#endif
+       idx = addr & ~PAGE_MASK;
+       addr = addr & PAGE_MASK;
+
+#ifndef CONFIG_8xx
+       /* Check the BATs */
+       for (b = 0; b < 4; ++b)
+               if (addr >= bat_addrs[b].start && addr <= bat_addrs[b].limit)
+                       return bat_addrs[b].phys | idx;
+#endif /* CONFIG_8xx */
+       /* Do we have a page table? */
+       if (init_task.mm->pgd == NULL)
+               return 0;
+
+       /* Use upper 10 bits of addr to index the first level map */
+       pd = (pmd_t *) (init_task.mm->pgd + (addr >> PGDIR_SHIFT));
+       if (pmd_none(*pd))
+               return 0;
+
+       /* Use middle 10 bits of addr to index the second-level map */
+       pg = pte_offset(pd, addr);
+       return (pte_val(*pg) & PAGE_MASK) | idx;
+}
+
 void
 map_page(struct task_struct *tsk, unsigned long va,
         unsigned long pa, int flags)
 {
        pmd_t *pd;
        pte_t *pg;
+#ifndef CONFIG_8xx
        int b;
-
+#endif
+       
        if (tsk->mm->pgd == NULL) {
                /* Allocate upper level page map */
                tsk->mm->pgd = (pgd_t *) MMU_get_page();
@@ -915,6 +1233,7 @@ map_page(struct task_struct *tsk, unsigned long va,
        /* Use upper 10 bits of VA to index the first level map */
        pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
        if (pmd_none(*pd)) {
+#ifndef CONFIG_8xx
                /*
                 * Need to allocate second-level table, but first
                 * check whether this address is already mapped by
@@ -927,14 +1246,16 @@ map_page(struct task_struct *tsk, unsigned long va,
                                return;
                        }
                }
+#endif /* CONFIG_8xx */
                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);*/
+#ifndef CONFIG_8xx
        flush_hash_page(0, va);
+#endif 
 }
 
 /*
@@ -957,11 +1278,14 @@ map_page(struct task_struct *tsk, unsigned long va,
 void
 local_flush_tlb_all(void)
 {
+#ifndef CONFIG_8xx
        memset(Hash, 0, Hash_size);
        _tlbia();
+#else
+       asm volatile ("tlbia" : : );
+#endif
 }
 
-
 /*
  * Flush all the (user) entries for the address space described
  * by mm.  We can't rely on mm->mmap describing all the entries
@@ -970,33 +1294,43 @@ local_flush_tlb_all(void)
 void
 local_flush_tlb_mm(struct mm_struct *mm)
 {
+#ifndef CONFIG_8xx
        mm->context = NO_CONTEXT;
        if (mm == current->mm) {
                get_mmu_context(current);
                /* done by get_mmu_context() now -- Cort */
                /*set_context(current->mm->context);*/
        }
+#else
+       asm volatile ("tlbia" : : );
+#endif
 }
 
 void
 local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 {
+#ifndef CONFIG_8xx
        if (vmaddr < TASK_SIZE)
                flush_hash_page(vma->vm_mm->context, vmaddr);
        else
                flush_hash_page(0, vmaddr);
+#else
+       asm volatile ("tlbia" : : );
+#endif
 }
 
 
-/* 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
-   */
+/*
+ * 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
+ */
 void
 local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
+#ifndef CONFIG_8xx
        start &= PAGE_MASK;
 
        if (end - start > 20 * PAGE_SIZE)
@@ -1009,6 +1343,9 @@ local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long e
        {
                flush_hash_page(mm->context, start);
        }
+#else
+       asm volatile ("tlbia" : : );
+#endif
 }
 
 /*
@@ -1020,6 +1357,7 @@ local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long e
 void
 mmu_context_overflow(void)
 {
+#ifndef CONFIG_8xx
        struct task_struct *tsk;
 
        printk(KERN_DEBUG "mmu_context_overflow\n");
@@ -1034,6 +1372,12 @@ mmu_context_overflow(void)
        /* make sure current always has a context */
        current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
        set_context(current->mm->context);
+#else
+       /* We set the value to -1 because it is pre-incremented before
+        * before use.
+        */
+       next_mmu_context = -1;
+#endif
 }
 
 #if 0
@@ -1090,3 +1434,69 @@ void local_flush_cache_range(struct mm_struct *mm, unsigned long start,
 }
 #endif
 
+#ifdef CONFIG_MBX
+/*
+ * This is a big hack right now, but it may turn into something real
+ * someday.
+ *
+ * For the MBX860 (at this time anyway), there is nothing to initialize
+ * associated the the PROM.  Rather than include all of the prom.c
+ * functions in the image just to get prom_init, all we really need right
+ * now is the initialization of the physical memory region.
+ */
+void
+set_mbx_memory(void)
+{
+       unsigned long kstart, ksize;
+       bd_t    *binfo;
+#ifdef DIMM_8xx
+       volatile memctl8xx_t    *mcp;
+#endif
+
+       binfo = (bd_t *)&res;
+
+       /* The MBX can have up to three memory regions, the on-board
+        * DRAM plus two more banks of DIMM socket memory.  The DIMM is
+        * 64 bits, seen from the processor as two 32 bit banks.
+        * The on-board DRAM is reflected in the board information
+        * structure, and is either 4 Mbytes or 16 Mbytes.
+        * I think there is a way to program the serial EEPROM information
+        * so EPPC-Bug will initialize this memory, but I have not
+        * done that and it may not be a wise thing to do.  If you
+        * remove the DIMM without reprogramming the EEPROM, bad things
+        * could happen since EPPC-Bug tries to use the upper 128K of
+        * memory.
+        */
+       phys_mem.n_regions = 1;
+       phys_mem.regions[0].address = 0;
+       phys_mem.regions[0].size = binfo->bi_memsize;
+       end_of_DRAM = __va(binfo->bi_memsize);
+
+#ifdef DIMM_8xx
+       /* This is a big hack.  It assumes my 32 Mbyte DIMM in a 40 MHz
+        * MPC860.  Don't do this (or change this) if you are running
+        * something else.
+        */
+       mcp = (memctl8xx_t *)(&(((immap_t *)MBX_IMAP_ADDR)->im_memctl));
+
+       mcp->memc_or2 = (~(DIMM_SIZE-1) | 0x00000400);
+       mcp->memc_br2 = DIMM_SIZE | 0x00000081;
+       mcp->memc_or3 = (~((2*DIMM_SIZE)-1) | 0x00000400);
+       mcp->memc_br3 = 2*DIMM_SIZE | 0x00000081;
+
+
+       phys_mem.regions[phys_mem.n_regions].address = DIMM_SIZE;
+       phys_mem.regions[phys_mem.n_regions++].size = DIMM_SIZE;
+       phys_mem.regions[phys_mem.n_regions].address = 2 * DIMM_SIZE;
+       phys_mem.regions[phys_mem.n_regions++].size = DIMM_SIZE;
+
+       end_of_DRAM = __va(3 * DIMM_SIZE);
+#endif
+
+       phys_avail = phys_mem;
+
+       kstart = __pa(_stext);  /* should be 0 */
+       ksize = PAGE_ALIGN(_end - _stext);
+       remove_mem_piece(&phys_avail, kstart, ksize, 0);
+}
+#endif
index 529b3313894e80f529bc4b0bbad08499b6675b01..8cf7eb8a67d709e4c1c03d01234a4dcfbc5d6b43 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -7,11 +7,12 @@
 #
 CONFIG_PPC=y
 CONFIG_NATIVE=y
+CONFIG_PPC6XX=y
+# CONFIG_PPC8XX is not set
 CONFIG_MACH_SPECIFIC=y
 CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_COMMON=y
 
 #
 # General setup
@@ -19,8 +20,9 @@ CONFIG_COMMON=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
 # CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+CONFIG_KERNELD=y
 CONFIG_PCI=y
+CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -28,14 +30,20 @@ CONFIG_SYSVIPC=y
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 CONFIG_BINFMT_MISC=m
-CONFIG_BINFMT_JAVA=m
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_ABSTRACT_CONSOLE is not set
 CONFIG_PMAC_CONSOLE=y
 CONFIG_MAC_KEYBOARD=y
 CONFIG_MAC_FLOPPY=y
+CONFIG_MACMOUSE=y
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_XMON is not set
+CONFIG_CONTROL_VIDEO=y
+CONFIG_PLATINUM_VIDEO=y
+CONFIG_VALKYRIE_VIDEO=y
 CONFIG_ATY_VIDEO=y
 CONFIG_IMSTT_VIDEO=y
+CONFIG_CHIPS_VIDEO=y
 
 #
 # Plug and Play support
@@ -47,6 +55,10 @@ CONFIG_IMSTT_VIDEO=y
 #
 # CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -55,14 +67,20 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_EZ is not set
+CONFIG_PARIDE_PARPORT=m
+# CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -77,6 +95,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
 CONFIG_NET_ALIAS=y
+# CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -85,37 +104,56 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_MASQUERADE is not set
 # CONFIG_IP_ROUTER is not set
-CONFIG_NET_IPIP=m
+# CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
 # CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=y
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
 
 #
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
 
 #
 # SCSI low-level drivers
@@ -124,7 +162,12 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
+CONFIG_SCSI_AIC7XXX=m
+# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set
+# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_PAGE_ENABLE is not set
+CONFIG_AIC7XXX_PROC_STATS=y
+CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -134,12 +177,16 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # 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_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_SEAGATE is not set
@@ -158,26 +205,46 @@ CONFIG_NETDEVICES=y
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_ETHERTAP is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
-CONFIG_DEC_ELCP=m
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA is not set
+CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=m
+CONFIG_DEC_ELCP=m
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=m
-# CONFIG_NET_RADIO is not set
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 # CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
 
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
 #
 # ISDN subsystem
 #
@@ -187,28 +254,68 @@ CONFIG_PPP=m
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
 #
 # CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
 
 #
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-CONFIG_MINIX_FS=m
+# CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
 CONFIG_ISO9660_FS=y
-# CONFIG_NLS is not set
+# CONFIG_JOLIET is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=m
 # CONFIG_ROMFS_FS is not set
 CONFIG_AUTOFS_FS=y
 # CONFIG_UFS_FS is not set
+# CONFIG_ADFS_FS is not set
 CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
 
 #
 # Character devices
@@ -217,20 +324,25 @@ CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_SOFTCURSOR is not set
 CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_PRINTER is not set
 # CONFIG_MOUSE is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
-# CONFIG_VIDEO_BT848 is not set
 CONFIG_NVRAM=y
 # CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
 
 #
 # Sound
index 147fa3005086241e20753c66f484bdbb523f3240..21d7e07f621a6f5e1d22fab233abddba4e594cda 100644 (file)
@@ -6,12 +6,14 @@
 # Platform support
 #
 CONFIG_PPC=y
-CONFIG_NATIVE=y
-CONFIG_MACH_SPECIFIC=y
+CONFIG_6xx=y
+# CONFIG_8xx is not set
 # CONFIG_PMAC is not set
 CONFIG_PREP=y
 # CONFIG_CHRP is not set
-CONFIG_COMMON=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_MBX is not set
+CONFIG_MACH_SPECIFIC=y
 
 #
 # General setup
@@ -19,20 +21,24 @@ CONFIG_COMMON=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
+CONFIG_KERNELD=y
 CONFIG_PCI=y
 # CONFIG_PCI_OPTIMIZE is not set
+CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+# CONFIG_ABSTRACT_CONSOLE is not set
 # CONFIG_PMAC_CONSOLE is not set
 # CONFIG_MAC_KEYBOARD is not set
 # CONFIG_MAC_FLOPPY is not set
+# CONFIG_MACMOUSE is not set
 # CONFIG_PROC_DEVICETREE is not set
 # CONFIG_XMON is not set
 CONFIG_VGA_CONSOLE=y
@@ -55,14 +61,16 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_EZ is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -77,32 +85,34 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
 # CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
-# CONFIG_IP_ACCT is not set
-# CONFIG_IP_MASQUERADE is not set
+CONFIG_IP_ACCT=y
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
 CONFIG_INET_RARP=y
 # CONFIG_IP_NOSR is not set
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
 
 #
 # SCSI support
@@ -115,6 +125,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y
 # CONFIG_CHR_DEV_SG is not set
 # CONFIG_SCSI_MULTI_LUN is not set
 # CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
 
 #
 # SCSI low-level drivers
@@ -133,6 +144,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y
 # CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
@@ -143,8 +155,10 @@ CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
 CONFIG_SCSI_NCR53C8XX_SYNC=5
 # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
-# CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_SEAGATE is not set
@@ -152,6 +166,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=5
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
 
@@ -162,12 +177,13 @@ CONFIG_NETDEVICES=y
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
-# CONFIG_ETHERTAP is not set
 CONFIG_NET_ETHERNET=y
 # CONFIG_NET_VENDOR_3COM is not set
 CONFIG_LANCE=y
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 CONFIG_PCNET32=y
@@ -184,13 +200,17 @@ CONFIG_DE4X5=y
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=m
-# CONFIG_NET_RADIO is not set
+CONFIG_PPP=y
 # CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
 
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
 #
 # ISDN subsystem
 #
@@ -200,6 +220,7 @@ CONFIG_PPP=m
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
 #
 # CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
 
 #
 # Filesystems
@@ -208,29 +229,59 @@ CONFIG_PPP=m
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
+CONFIG_JOLIET=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=y
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_ADFS_FS is not set
 # CONFIG_MAC_PARTITION is not set
+CONFIG_NLS=y
 
 #
 # Native Language Support
 #
-# CONFIG_NLS is not set
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
 
 #
 # Character devices
@@ -239,14 +290,9 @@ CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_SOFTCURSOR is not set
 CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
 CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_PRINTER is not set
 CONFIG_MOUSE=y
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
@@ -256,14 +302,18 @@ CONFIG_PSMOUSE=y
 # CONFIG_PC110_PAD is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
-# CONFIG_VIDEO_BT848 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
 
 #
 # Sound
index 7a8d46a07339ffcfd4c78a43d646bee269fe3dff..a4870e117a350c1f2e8ade94f9cae6b75afd6402 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.29 1997/07/11 11:05:23 jj Exp $
+# $Id: Makefile,v 1.34 1998/04/06 16:09:34 jj Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -23,14 +23,18 @@ LINKFLAGS = -T arch/sparc/vmlinux.lds
 
 HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
 
-SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \
-       arch/sparc/prom
+# Note arch/sparc/mm has to be the last subdir
+SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/prom \
+       arch/sparc/mm
 
 CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES)
 
 LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \
        $(TOPDIR)/arch/sparc/lib/lib.a
 
+SUBDIRS += arch/sparc/math-emu
+CORE_FILES += arch/sparc/math-emu/math-emu.o
+
 ifdef CONFIG_AP1000
 SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp
 CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o \
@@ -40,11 +44,30 @@ CFLAGS := $(CFLAGS) -D__MPP__=1
 endif
 
 archclean:
+       -$(MAKE) -C arch/sparc/boot archclean
+       -$(MAKE) -C arch/sparc/math-emu cleansymlinks
 
 archdep:
+       -$(MAKE) -C arch/sparc/math-emu symlinks
 
 check_asm:
        $(MAKE) -C arch/sparc/kernel check_asm
 
 tftpboot.img:
        $(MAKE) -C arch/sparc/boot tftpboot.img
+
+vmlinux.o: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
+       $(LD) -r $(VMLINUX.OBJS) -o vmlinux.o
+
+arch/sparc/boot/btfix.s: arch/sparc/boot/btfixupprep vmlinux.o
+       $(OBJDUMP) -x vmlinux.o | arch/sparc/boot/btfixupprep > arch/sparc/boot/btfix.s
+
+arch/sparc/boot/btfix.o: arch/sparc/boot/btfix.s
+       $(CC) -c -o arch/sparc/boot/btfix.o arch/sparc/boot/btfix.s
+
+arch/sparc/boot/btfixupprep: arch/sparc/boot/btfixupprep.c
+       $(MAKE) -C arch/sparc/boot btfixupprep
+
+vmlinux: arch/sparc/boot/btfix.o
+       $(LD) $(LINKFLAGS) vmlinux.o arch/sparc/boot/btfix.o -o vmlinux
+       $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
index 0bafe3fc95c16f70e4505e3c466fe1cf41b98ec4..e07b4f4b193aa9a455f1fc69e0bceaeb67824be3 100644 (file)
 #include <asm/viking.h>
 
 
-static unsigned long (*mmu_getpage)(void);
-static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp);
-static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep);
-
-static void (*flush_page_for_dma)(unsigned long page);
-static void (*flush_cache_page_to_uncache)(unsigned long page);
-static void (*flush_tlb_page_for_cbit)(unsigned long page);
-
 extern void mc_tlb_flush_all(void);
 
+static void poke_viking(void);
+static void viking_flush_tlb_page_for_cbit)(unsigned long page);
 
 static struct apmmu_stats {
        int invall;
@@ -103,11 +97,6 @@ static inline unsigned long apmmu_swap(unsigned long *addr, unsigned long value)
 static unsigned int apmmu_pmd_align(unsigned int addr) { return APMMU_PMD_ALIGN(addr); }
 static unsigned int apmmu_pgdir_align(unsigned int addr) { return APMMU_PGDIR_ALIGN(addr); }
 
-static unsigned long apmmu_vmalloc_start(void)
-{
-       return APMMU_VMALLOC_START;
-}
-
 static inline int apmmu_device_memory(unsigned long x) 
 {
        return ((x & 0xF0000000) != 0);
@@ -152,13 +141,6 @@ static int apmmu_pgd_present(pgd_t pgd)
 
 static void apmmu_pgd_clear(pgd_t * pgdp)     { set_pte((pte_t *)pgdp, __pte(0)); }
 
-static int apmmu_pte_write(pte_t pte)         { return pte_val(pte) & APMMU_WRITE; }
-static int apmmu_pte_dirty(pte_t pte)         { return pte_val(pte) & APMMU_DIRTY; }
-static int apmmu_pte_young(pte_t pte)         { return pte_val(pte) & APMMU_REF; }
-
-static pte_t apmmu_pte_wrprotect(pte_t pte)   { return __pte(pte_val(pte) & ~APMMU_WRITE);}
-static pte_t apmmu_pte_mkclean(pte_t pte)     { return __pte(pte_val(pte) & ~APMMU_DIRTY);}
-static pte_t apmmu_pte_mkold(pte_t pte)       { return __pte(pte_val(pte) & ~APMMU_REF);}
 static pte_t apmmu_pte_mkwrite(pte_t pte)     { return __pte(pte_val(pte) | APMMU_WRITE);}
 static pte_t apmmu_pte_mkdirty(pte_t pte)     { return __pte(pte_val(pte) | APMMU_DIRTY);}
 static pte_t apmmu_pte_mkyoung(pte_t pte)     { return __pte(pte_val(pte) | APMMU_REF);}
@@ -221,7 +203,7 @@ static void apmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
 {
        if(tsk->mm->context != NO_CONTEXT) {
                flush_cache_mm(current->mm);
-               ctxd_set(&apmmu_context_table[tsk->mm->context], pgdp);
+               apmmu_ctxd_set(&apmmu_context_table[tsk->mm->context], pgdp);
                flush_tlb_mm(current->mm);
        }
 }
@@ -311,8 +293,6 @@ static inline unsigned long apmmu_hwprobe(unsigned long vaddr)
        return retval;
 }
 
-
-
 static inline void apmmu_uncache_page(unsigned long addr)
 {
        pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr);
@@ -330,9 +310,8 @@ static inline void apmmu_uncache_page(unsigned long addr)
                }
        }
 
-       flush_cache_page_to_uncache(addr);
        set_pte(ptep, __pte((pte_val(*ptep) & ~APMMU_CACHE)));
-       flush_tlb_page_for_cbit(addr);
+       viking_flush_tlb_page_for_cbit(addr);
 }
 
 static inline void apmmu_recache_page(unsigned long addr)
@@ -352,10 +331,10 @@ static inline void apmmu_recache_page(unsigned long addr)
                }
        }
        set_pte(ptep, __pte((pte_val(*ptep) | APMMU_CACHE)));
-       flush_tlb_page_for_cbit(addr);
+       viking_flush_tlb_page_for_cbit(addr);
 }
 
-static unsigned long apmmu_getpage(void)
+static inline unsigned long apmmu_getpage(void)
 {
        unsigned long page = get_free_page(GFP_KERNEL);
 
@@ -368,13 +347,44 @@ static inline void apmmu_putpage(unsigned long page)
 }
 
 /* The easy versions. */
-#define NEW_PGD() (pgd_t *) mmu_getpage()
-#define NEW_PMD() (pmd_t *) mmu_getpage()
-#define NEW_PTE() (pte_t *) mmu_getpage()
+#define NEW_PGD() (pgd_t *) apmmu_getpage()
+#define NEW_PMD() (pmd_t *) apmmu_getpage()
+#define NEW_PTE() (pte_t *) apmmu_getpage()
 #define FREE_PGD(chunk) apmmu_putpage((unsigned long)(chunk))
 #define FREE_PMD(chunk) apmmu_putpage((unsigned long)(chunk))
 #define FREE_PTE(chunk) apmmu_putpage((unsigned long)(chunk))
 
+static pte_t *apmmu_get_pte_fast(void)
+{
+       return (pte_t *)0;
+}
+
+static pmd_t *apmmu_get_pmd_fast(void)
+{
+       return (pmd_t *)0;
+}
+
+static pgd_t *apmmu_get_pgd_fast(void)
+{
+       return (pgd_t *)0;
+}
+
+static void apmmu_free_pte_slow(pte_t *pte)
+{
+/* TBD */
+}
+
+static void apmmu_free_pmd_slow(pmd_t *pmd)
+{
+/* TBD */
+}
+
+static void apmmu_free_pgd_slow(pgd_t *pgd)
+{
+/* TBD */
+}
+
+
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
@@ -392,17 +402,17 @@ static pte_t *apmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
                pte_t *page = NEW_PTE();
                if(apmmu_pmd_none(*pmd)) {
                        if(page) {
-                               pmd_set(pmd, page);
+                               apmmu_pmd_set(pmd, page);
                                return page + address;
                        }
-                       pmd_set(pmd, BAD_PAGETABLE);
+                       apmmu_pmd_set(pmd, BAD_PAGETABLE);
                        return NULL;
                }
                FREE_PTE(page);
        }
        if(apmmu_pmd_bad(*pmd)) {
                printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_set(pmd, BAD_PAGETABLE);
+               apmmu_pmd_set(pmd, BAD_PAGETABLE);
                return NULL;
        }
        return (pte_t *) apmmu_pmd_page(*pmd) + address;
@@ -449,17 +459,17 @@ static pte_t *apmmu_pte_alloc(pmd_t * pmd, unsigned long address)
                pte_t *page = NEW_PTE();
                if(apmmu_pmd_none(*pmd)) {
                        if(page) {
-                               pmd_set(pmd, page);
+                               apmmu_pmd_set(pmd, page);
                                return page + address;
                        }
-                       pmd_set(pmd, BAD_PAGETABLE);
+                       apmmu_pmd_set(pmd, BAD_PAGETABLE);
                        return NULL;
                }
                FREE_PTE(page);
        }
        if(apmmu_pmd_bad(*pmd)) {
                printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_set(pmd, BAD_PAGETABLE);
+               apmmu_pmd_set(pmd, BAD_PAGETABLE);
                return NULL;
        }
        return ((pte_t *) apmmu_pmd_page(*pmd)) + address;
@@ -525,7 +535,7 @@ static inline void alloc_context(struct task_struct *tsk)
        struct mm_struct *mm = tsk->mm;
        struct ctx_list *ctxp;
 
-        if (tsk->taskid >= MPP_TASK_BASE) {
+       if (tsk->taskid >= MPP_TASK_BASE) {
                mm->context = MPP_CONTEXT_BASE + (tsk->taskid - MPP_TASK_BASE);
                return;
        }
@@ -570,7 +580,7 @@ static void apmmu_switch_to_context(struct task_struct *tsk)
        if(tsk->mm->context == NO_CONTEXT) {
                alloc_context(tsk);
                flush_cache_mm(current->mm);
-               ctxd_set(&apmmu_context_table[tsk->mm->context], tsk->mm->pgd);
+               apmmu_ctxd_set(&apmmu_context_table[tsk->mm->context], tsk->mm->pgd);
                flush_tlb_mm(current->mm);
        }
        apmmu_set_context(tsk->mm->context);
@@ -590,29 +600,11 @@ struct task_struct *apmmu_alloc_task_struct(void)
        return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL);
 }
 
-static unsigned long apmmu_alloc_kernel_stack(struct task_struct *tsk)
-{
-       unsigned long kstk = __get_free_pages(GFP_KERNEL, 1);
-
-       if(!kstk)
-               kstk = (unsigned long) vmalloc(PAGE_SIZE << 1);
-
-       return kstk;
-}
-
 static void apmmu_free_task_struct(struct task_struct *tsk)
 {
        kfree(tsk);
 }
 
-static void apmmu_free_kernel_stack(unsigned long stack)
-{
-       if(stack < VMALLOC_START)
-               free_pages(stack, 1);
-       else
-               vfree((char *)stack);
-}
-
 static void apmmu_null_func(void)
 {
 }
@@ -925,22 +917,20 @@ extern unsigned long sparc_context_init(unsigned long, int);
 extern int physmem_mapped_contig;
 extern int linux_num_cpus;
 
-void (*poke_apmmu)(void);
-
 __initfunc(unsigned long apmmu_paging_init(unsigned long start_mem, unsigned long end_mem))
 {
        int i;
 
        physmem_mapped_contig = 1;   /* for init.c:taint_real_pages()   */
 
-        num_contexts = AP_NUM_CONTEXTS;
+       num_contexts = AP_NUM_CONTEXTS;
        mempool = PAGE_ALIGN(start_mem);
        memset(swapper_pg_dir, 0, PAGE_SIZE);
 
        apmmu_allocate_ptable_skeleton(KERNBASE, end_mem);
        mempool = PAGE_ALIGN(mempool);
        map_kernel();
-        ap_setup_mappings();
+       ap_setup_mappings();
 
        /* the MSC wants this aligned on a 16k boundary */
        apmmu_context_table = 
@@ -950,14 +940,14 @@ __initfunc(unsigned long apmmu_paging_init(unsigned long start_mem, unsigned lon
                           num_contexts*sizeof(ctxd_t));
        apmmu_ctx_table_phys = (ctxd_t *) apmmu_v2p((unsigned long) apmmu_context_table);
        for(i = 0; i < num_contexts; i++)
-               ctxd_set(&apmmu_context_table[i], swapper_pg_dir);
+               apmmu_ctxd_set(&apmmu_context_table[i], swapper_pg_dir);
 
        start_mem = PAGE_ALIGN(mempool);
 
        flush_cache_all();
        apmmu_set_ctable_ptr((unsigned long) apmmu_ctx_table_phys);
        flush_tlb_all();
-       poke_apmmu();
+       poke_viking();
 
        /* on the AP we don't put the top few contexts into the free
           context list as these are reserved for parallel tasks */
@@ -967,11 +957,10 @@ __initfunc(unsigned long apmmu_paging_init(unsigned long start_mem, unsigned lon
        return PAGE_ALIGN(start_mem);
 }
 
-static char apmmuinfo[512];
-
-static char *apmmu_mmu_info(void)
+static int apmmu_mmu_info(char *buf)
 {
-       sprintf(apmmuinfo, "MMU type\t: %s\n"
+       return sprintf(buf, 
+               "MMU type\t: %s\n"
                "invall\t\t: %d\n"
                "invmm\t\t: %d\n"
                "invrnge\t\t: %d\n"
@@ -984,35 +973,12 @@ static char *apmmu_mmu_info(void)
                module_stats.invpg,
                num_contexts
                );
-       return apmmuinfo;
 }
 
 static void apmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
 {
 }
 
-static void apmmu_exit_hook(void)
-{
-       struct mm_struct *mm = current->mm;
-
-       if(mm->context != NO_CONTEXT && mm->count == 1) {
-               ctxd_set(&apmmu_context_table[mm->context], swapper_pg_dir);
-               viking_flush_tlb_mm(mm);
-               free_context(mm->context);
-               mm->context = NO_CONTEXT;
-       }
-}
-
-static void apmmu_flush_hook(void)
-{
-       if(current->tss.flags & SPARC_FLAG_KTHREAD) {
-               alloc_context(current);
-               ctxd_set(&apmmu_context_table[current->mm->context], current->mm->pgd);
-               viking_flush_tlb_mm(current->mm);
-               apmmu_set_context(current->mm->context);
-       }
-}
-
 __initfunc(static void poke_viking(void))
 {
        unsigned long mreg = apmmu_get_mmureg();
@@ -1020,7 +986,7 @@ __initfunc(static void poke_viking(void))
        mreg |= VIKING_SPENABLE;
        mreg |= (VIKING_ICENABLE | VIKING_DCENABLE);
        mreg &= ~VIKING_ACENABLE;
-        mreg &= ~VIKING_SBENABLE;
+       mreg &= ~VIKING_SBENABLE;
        mreg |= VIKING_TCENABLE;
        apmmu_set_mmureg(mreg);
 }
@@ -1029,24 +995,18 @@ __initfunc(static void init_viking(void))
 {
        apmmu_name = "TI Viking/AP1000";
 
-       flush_cache_page_to_uncache = apmmu_null_func;
-       flush_page_for_dma = apmmu_null_func;
-
-       flush_cache_all = apmmu_null_func;
-       flush_cache_mm = apmmu_null_func;
-       flush_cache_page = apmmu_null_func;
-       flush_cache_range = apmmu_null_func;
+       BTFIXUPSET_CALL(flush_cache_all, apmmu_null_func, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_cache_mm, apmmu_null_func, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_cache_page, apmmu_null_func, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_cache_range, apmmu_null_func, BTFIXUPCALL_NOP);
 
-       flush_tlb_all = viking_flush_tlb_all;
-       flush_tlb_mm = viking_flush_tlb_mm;
-       flush_tlb_page = viking_flush_tlb_page;
-       flush_tlb_range = viking_flush_tlb_range;
+       BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM);
 
-       flush_page_to_ram = apmmu_null_func;
-       flush_sig_insns = apmmu_null_func;
-       flush_tlb_page_for_cbit = viking_flush_tlb_page_for_cbit;
-
-       poke_apmmu = poke_viking;
+       BTFIXUPSET_CALL(flush_page_to_ram, apmmu_null_func, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_sig_insns, apmmu_null_func, BTFIXUPCALL_NOP);
 }
 
 
@@ -1062,7 +1022,7 @@ extern unsigned long srmmu_fault;
                iaddr = &(insn); \
                daddr = &(dest); \
                *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
-        } while(0);
+       } while(0);
 
 __initfunc(static void patch_window_trap_handlers(void))
 {
@@ -1077,113 +1037,109 @@ __initfunc(static void patch_window_trap_handlers(void))
        PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault);
 }
 
-/* Load up routines and constants for sun4m mmu */
+/* Load up routines and constants for apmmu */
 __initfunc(void ld_mmu_apmmu(void))
 {
        /* First the constants */
-       pmd_shift = APMMU_PMD_SHIFT;
-       pmd_size = APMMU_PMD_SIZE;
-       pmd_mask = APMMU_PMD_MASK;
-       pgdir_shift = APMMU_PGDIR_SHIFT;
-       pgdir_size = APMMU_PGDIR_SIZE;
-       pgdir_mask = APMMU_PGDIR_MASK;
-
-       ptrs_per_pte = APMMU_PTRS_PER_PTE;
-       ptrs_per_pmd = APMMU_PTRS_PER_PMD;
-       ptrs_per_pgd = APMMU_PTRS_PER_PGD;
-
-       page_none = APMMU_PAGE_NONE;
-       page_shared = APMMU_PAGE_SHARED;
-       page_copy = APMMU_PAGE_COPY;
-       page_readonly = APMMU_PAGE_RDONLY;
-       page_kernel = APMMU_PAGE_KERNEL;
+       BTFIXUPSET_SIMM13(pmd_shift, APMMU_PMD_SHIFT);
+       BTFIXUPSET_SETHI(pmd_size, APMMU_PMD_SIZE);
+       BTFIXUPSET_SETHI(pmd_mask, APMMU_PMD_MASK);
+       BTFIXUPSET_SIMM13(pgdir_shift, APMMU_PGDIR_SHIFT);
+       BTFIXUPSET_SETHI(pgdir_size, APMMU_PGDIR_SIZE);
+       BTFIXUPSET_SETHI(pgdir_mask, APMMU_PGDIR_MASK);
+
+       BTFIXUPSET_SIMM13(ptrs_per_pte, APMMU_PTRS_PER_PTE);
+       BTFIXUPSET_SIMM13(ptrs_per_pmd, APMMU_PTRS_PER_PMD);
+       BTFIXUPSET_SIMM13(ptrs_per_pgd, APMMU_PTRS_PER_PGD);
+
+       BTFIXUPSET_INT(page_none, pgprot_val(APMMU_PAGE_NONE));
+       BTFIXUPSET_INT(page_shared, pgprot_val(APMMU_PAGE_SHARED));
+       BTFIXUPSET_INT(page_copy, pgprot_val(APMMU_PAGE_COPY));
+       BTFIXUPSET_INT(page_readonly, pgprot_val(APMMU_PAGE_RDONLY));
+       BTFIXUPSET_INT(page_kernel, pgprot_val(APMMU_PAGE_KERNEL));
        pg_iobits = APMMU_VALID | APMMU_WRITE | APMMU_REF;
            
        /* Functions */
-       mmu_getpage = apmmu_getpage;
-       set_pte = apmmu_set_pte_cacheable;
-       switch_to_context = apmmu_switch_to_context;
-       pmd_align = apmmu_pmd_align;
-       pgdir_align = apmmu_pgdir_align;
-       vmalloc_start = apmmu_vmalloc_start;
-
-       pte_page = apmmu_pte_page;
-       pmd_page = apmmu_pmd_page;
-       pgd_page = apmmu_pgd_page;
-
-       sparc_update_rootmmu_dir = apmmu_update_rootmmu_dir;
-
-       pte_none = apmmu_pte_none;
-       pte_present = apmmu_pte_present;
-       pte_clear = apmmu_pte_clear;
-
-       pmd_none = apmmu_pmd_none;
-       pmd_bad = apmmu_pmd_bad;
-       pmd_present = apmmu_pmd_present;
-       pmd_clear = apmmu_pmd_clear;
-
-       pgd_none = apmmu_pgd_none;
-       pgd_bad = apmmu_pgd_bad;
-       pgd_present = apmmu_pgd_present;
-       pgd_clear = apmmu_pgd_clear;
-
-       mk_pte = apmmu_mk_pte;
-       mk_pte_phys = apmmu_mk_pte_phys;
-       pgd_set = apmmu_pgd_set;
-       mk_pte_io = apmmu_mk_pte_io;
-       pte_modify = apmmu_pte_modify;
-       pgd_offset = apmmu_pgd_offset;
-       pmd_offset = apmmu_pmd_offset;
-       pte_offset = apmmu_pte_offset;
-       pte_free_kernel = apmmu_pte_free_kernel;
-       pmd_free_kernel = apmmu_pmd_free_kernel;
-       pte_alloc_kernel = apmmu_pte_alloc_kernel;
-       pmd_alloc_kernel = apmmu_pmd_alloc_kernel;
-       pte_free = apmmu_pte_free;
-       pte_alloc = apmmu_pte_alloc;
-       pmd_free = apmmu_pmd_free;
-       pmd_alloc = apmmu_pmd_alloc;
-       pgd_free = apmmu_pgd_free;
-       pgd_alloc = apmmu_pgd_alloc;
-       pgd_flush = apmmu_pgd_flush;
-
-       pte_write = apmmu_pte_write;
-       pte_dirty = apmmu_pte_dirty;
-       pte_young = apmmu_pte_young;
-       pte_wrprotect = apmmu_pte_wrprotect;
-       pte_mkclean = apmmu_pte_mkclean;
-       pte_mkold = apmmu_pte_mkold;
-       pte_mkwrite = apmmu_pte_mkwrite;
-       pte_mkdirty = apmmu_pte_mkdirty;
-       pte_mkyoung = apmmu_pte_mkyoung;
-       update_mmu_cache = apmmu_update_mmu_cache;
-       mmu_exit_hook = apmmu_exit_hook;
-       mmu_flush_hook = apmmu_flush_hook;
-       mmu_lockarea = apmmu_lockarea;
-       mmu_unlockarea = apmmu_unlockarea;
-
-       mmu_get_scsi_one = NULL;
-       mmu_get_scsi_sgl = NULL;
-       mmu_release_scsi_one = NULL;
-       mmu_release_scsi_sgl = NULL;
-
-       mmu_info = apmmu_mmu_info;
-        mmu_v2p = apmmu_v2p;
-        mmu_p2v = apmmu_p2v;
+       BTFIXUPSET_CALL(get_pte_fast, apmmu_get_pte_fast, BTFIXUPCALL_RETINT(0));
+       BTFIXUPSET_CALL(get_pmd_fast, apmmu_get_pmd_fast, BTFIXUPCALL_RETINT(0));
+       BTFIXUPSET_CALL(get_pgd_fast, apmmu_get_pgd_fast, BTFIXUPCALL_RETINT(0));
+       BTFIXUPSET_CALL(free_pte_slow, apmmu_free_pte_slow, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(free_pmd_slow, apmmu_free_pmd_slow, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(free_pgd_slow, apmmu_free_pgd_slow, BTFIXUPCALL_NOP);
 
-       /* Task struct and kernel stack allocating/freeing. */
-       alloc_kernel_stack = apmmu_alloc_kernel_stack;
-       alloc_task_struct = apmmu_alloc_task_struct;
-       free_kernel_stack = apmmu_free_kernel_stack;
-       free_task_struct = apmmu_free_task_struct;
+       BTFIXUPSET_CALL(set_pte, apmmu_set_pte_cacheable, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(switch_to_context, apmmu_switch_to_context, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(pte_page, apmmu_pte_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_page, apmmu_pmd_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_page, apmmu_pgd_page, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(sparc_update_rootmmu_dir, apmmu_update_rootmmu_dir, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_SETHI(none_mask, 0xF0000000);
+
+       BTFIXUPSET_CALL(pte_present, apmmu_pte_present, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_clear, apmmu_pte_clear, BTFIXUPCALL_NORM);
 
-       quick_kernel_fault = apmmu_quick_kernel_fault;
+       BTFIXUPSET_CALL(pmd_bad, apmmu_pmd_bad, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_present, apmmu_pmd_present, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_clear, apmmu_pmd_clear, BTFIXUPCALL_NORM);
 
-       ctxd_set = apmmu_ctxd_set;
-       pmd_set = apmmu_pmd_set;
+       BTFIXUPSET_CALL(pgd_none, apmmu_pgd_none, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_bad, apmmu_pgd_bad, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_present, apmmu_pgd_present, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_clear, apmmu_pgd_clear, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(mk_pte, apmmu_mk_pte, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mk_pte_phys, apmmu_mk_pte_phys, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mk_pte_io, apmmu_mk_pte_io, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_set, apmmu_pgd_set, BTFIXUPCALL_NORM);
+       
+       BTFIXUPSET_INT(pte_modify_mask, APMMU_CHG_MASK);
+       BTFIXUPSET_CALL(pgd_offset, apmmu_pgd_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_offset, apmmu_pmd_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_offset, apmmu_pte_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_free_kernel, apmmu_pte_free_kernel, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_free_kernel, apmmu_pmd_free_kernel, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_alloc_kernel, apmmu_pte_alloc_kernel, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_alloc_kernel, apmmu_pmd_alloc_kernel, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_free, apmmu_pte_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_alloc, apmmu_pte_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_free, apmmu_pmd_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_alloc, apmmu_pmd_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_free, apmmu_pgd_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_alloc, apmmu_pgd_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_flush, apmmu_pgd_flush, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_HALF(pte_writei, APMMU_WRITE);
+       BTFIXUPSET_HALF(pte_dirtyi, APMMU_DIRTY);
+       BTFIXUPSET_HALF(pte_youngi, APMMU_REF);
+       BTFIXUPSET_HALF(pte_wrprotecti, APMMU_WRITE);
+       BTFIXUPSET_HALF(pte_mkcleani, APMMU_DIRTY);
+       BTFIXUPSET_HALF(pte_mkoldi, APMMU_REF);
+       BTFIXUPSET_CALL(pte_mkwrite, apmmu_pte_mkwrite, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_mkdirty, apmmu_pte_mkdirty, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_mkyoung, apmmu_pte_mkyoung, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(update_mmu_cache, apmmu_update_mmu_cache, BTFIXUPCALL_NOP);
+
+       BTFIXUPSET_CALL(mmu_lockarea, apmmu_lockarea, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_unlockarea, apmmu_unlockarea, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(mmu_get_scsi_one, apmmu_null_func, BTFIXUPCALL_RETO0);
+       BTFIXUPSET_CALL(mmu_get_scsi_sgl, apmmu_null_func, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(mmu_release_scsi_one, apmmu_null_func, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(mmu_release_scsi_sgl, apmmu_null_func, BTFIXUPCALL_NOP);
+
+       BTFIXUPSET_CALL(mmu_info, apmmu_mmu_info, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_v2p, apmmu_v2p, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_p2v, apmmu_p2v, BTFIXUPCALL_NORM);
+
+       /* Task struct and kernel stack allocating/freeing. */
+       BTFIXUPSET_CALL(alloc_task_struct, apmmu_alloc_task_struct, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(free_task_struct, apmmu_free_task_struct, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(quick_kernel_fault, apmmu_quick_kernel_fault, BTFIXUPCALL_NORM);
 
        init_viking();
        patch_window_trap_handlers();
 }
-
-
index af462db3aae6cc914354688339a7d7d243f229e1..c9301a79e4d4a94bc0161f5e1c9e3de813589b6d 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.4 1997/07/11 11:05:18 jj Exp $
+# $Id: Makefile,v 1.6 1998/02/23 01:44:39 rth Exp $
 # Makefile for the Sparc boot stuff.
 #
 # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -19,5 +19,11 @@ tftpboot.img: piggyback
 piggyback: piggyback.c
        $(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c
 
+btfixupprep: btfixupprep.c
+       $(HOSTCC) $(HOSTCFLAGS) -o btfixupprep btfixupprep.c
+
+archclean:
+       rm -f btfixupprep piggyback tftpboot.img
+
 dep:
 
diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c
new file mode 100644 (file)
index 0000000..1bef965
--- /dev/null
@@ -0,0 +1,345 @@
+/* $Id: btfixupprep.c,v 1.3 1998/03/09 14:03:10 jj Exp $
+   Simple utility to prepare vmlinux image for sparc.
+   Resolves all BTFIXUP uses and settings and creates
+   a special .s object to link to the image.
+   
+   Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+   
+   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.
+   
+   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; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#define MAXSYMS 1024
+
+static char *relrec = "RELOCATION RECORDS FOR [";
+static int rellen;
+
+struct _btfixup;
+
+typedef struct _btfixuprel {
+       char *sect;
+       unsigned long offset;
+       struct _btfixup *f;
+       int frel;
+       struct _btfixuprel *next;
+} btfixuprel;
+
+typedef struct _btfixup {
+       int type;
+       int setinitval;
+       unsigned int initval;
+       char *initvalstr;
+       char *name;
+       btfixuprel *rel;
+} btfixup;
+
+btfixup array[MAXSYMS];
+int last = 0;
+char buffer[1024];
+unsigned long lastfoffset = -1;
+unsigned long lastfrelno;
+btfixup *lastf;
+
+void fatal(void) __attribute__((noreturn));
+void fatal(void)
+{
+       fprintf(stderr, "Malformed output from objdump\n%s\n", buffer);
+       exit(1);
+}
+
+btfixup *find(int type, char *name)
+{
+       int i;
+       for (i = 0; i < last; i++) {
+               if (array[i].type == type && !strcmp(array[i].name, name))
+                       return array + i;
+       }
+       array[last].type = type;
+       array[last].name = strdup(name);
+       array[last].setinitval = 0;
+       if (!array[last].name) fatal();
+       array[last].rel = NULL;
+       last++;
+       if (last >= MAXSYMS) {
+               fprintf(stderr, "Ugh. Something strange. More than %d different BTFIXUP symbols\n", MAXSYMS);
+               exit(1);
+       }
+       return array + last - 1;
+}
+
+int main(int argc,char **argv)
+{
+       char *p, *q;
+       char *sect;
+       int i, j, k;
+       unsigned int initval;
+       int shift;
+       btfixup *f;
+       btfixuprel *r, **rr;
+       unsigned long offset;
+       char *initvalstr;
+
+       rellen = strlen(relrec);
+       while (fgets (buffer, 1024, stdin) != NULL)
+               if (!strncmp (buffer, relrec, rellen))
+                       goto main1;
+       fatal();
+main1:
+       sect = malloc(strlen (buffer + rellen) + 1);
+       if (!sect) fatal();
+       strcpy (sect, buffer + rellen);
+       p = strchr (sect, ']');
+       if (!p) fatal();
+       *p = 0;
+       if (fgets (buffer, 1024, stdin) == NULL)
+               fatal();
+       while (fgets (buffer, 1024, stdin) != NULL) {
+               if (!strncmp (buffer, relrec, rellen))
+                       goto main1;
+               p = strchr (buffer, '\n');
+               if (p) *p = 0;
+               if (strlen (buffer) < 30)
+                       continue;
+               if (strncmp (buffer + 8, " R_SPARC_", 9))
+                       continue;
+               if (buffer[27] != '_' || buffer[28] != '_' || buffer[29] != '_')
+                       continue;
+               switch (buffer[30]) {
+                       case 'f':       /* CALL */
+                       case 'b':       /* BLACKBOX */
+                       case 's':       /* SIMM13 */
+                       case 'a':       /* HALF */
+                       case 'h':       /* SETHI */
+                       case 'i':       /* INT */
+                               break;
+                       default:
+                               continue;
+               }
+               p = strchr (buffer + 32, '+');
+               if (p) *p = 0;
+               shift = 32;
+               if (buffer[31] == 's' && buffer[32] == '_') {
+                       shift = 33;
+                       if (strcmp (sect, ".text.init")) {
+                               fprintf(stderr, "Wrong use of '%s' BTFIXUPSET.\nBTFIXUPSET_CALL can be used only in __init sections\n", buffer+shift);
+                               exit(1);
+                       }
+               } else if (buffer[31] != '_')
+                       continue;
+               if (strcmp (sect, ".text") && strcmp (sect, ".text.init") && (strcmp (sect, "__ksymtab") || buffer[30] != 'f')) {
+                       if (buffer[30] == 'f')
+                               fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .text.init and __ksymtab\n", buffer + shift, sect);
+                       else
+                               fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text and .text.init\n", buffer + shift, sect);
+                       exit(1);
+               }
+               p = strstr (buffer + shift, "__btset_");
+               if (p && buffer[31] == 's') {
+                       fprintf(stderr, "__btset_ in BTFIXUP name can only be used when defining the variable, not for setting\n%s\n", buffer);
+                       exit(1);
+               }
+               initval = 0;
+               initvalstr = NULL;
+               if (p) {
+                       if (p[8] != '0' || p[9] != 'x') {
+                               fprintf(stderr, "Pre-initialized values can be only initialized with hexadecimal constants starting 0x\n%s\n", buffer);
+                               exit(1);
+                       }
+                       initval = strtoul(p + 10, &q, 16);
+                       if (*q || !initval) {
+                               fprintf(stderr, "Pre-initialized values can be only in the form name__btset_0xXXXXXXXX where X are hex digits.\nThey cannot be name__btset_0x00000000 though. Use BTFIXUPDEF_XX instead of BTFIXUPDEF_XX_INIT then.\n%s\n", buffer);
+                               exit(1);
+                       }
+                       initvalstr = p + 10;
+                       *p = 0;
+               }
+               f = find(buffer[30], buffer + shift);
+               if (buffer[31] == 's')
+                       continue;
+               switch (buffer[30]) {
+               case 'f':
+                       if (initval) {
+                               fprintf(stderr, "Cannot use pre-initalized fixups for calls\n%s\n", buffer);
+                               exit(1);
+                       }
+                       if (!strcmp (sect, "__ksymtab")) {
+                               if (strncmp (buffer + 17, "32        ", 10)) {
+                                       fprintf(stderr, "BTFIXUP_CALL in EXPORT_SYMBOL results in relocation other than R_SPARC_32\n\%s\n", buffer);
+                                       exit(1);
+                               }
+                       } else if (strncmp (buffer + 17, "WDISP30   ", 10) &&
+                                  strncmp (buffer + 17, "HI22      ", 10) &&
+                                  strncmp (buffer + 17, "LO10      ", 10)) {
+                               fprintf(stderr, "BTFIXUP_CALL results in relocation other than R_SPARC_WDISP30, R_SPARC_HI22 or R_SPARC_LO10\n%s\n", buffer);
+                               exit(1);
+                       }
+                       break;
+               case 'b':
+                       if (initval) {
+                               fprintf(stderr, "Cannot use pre-initialized fixups for blackboxes\n%s\n", buffer);
+                               exit(1);
+                       }
+                       if (strncmp (buffer + 17, "HI22      ", 10)) {
+                               fprintf(stderr, "BTFIXUP_BLACKBOX results in relocation other than R_SPARC_HI22\n%s\n", buffer);
+                               exit(1);
+                       }
+                       break;
+               case 's':
+                       if (initval + 0x1000 >= 0x2000) {
+                               fprintf(stderr, "Wrong initializer for SIMM13. Has to be from $fffff000 to $00000fff\n%s\n", buffer);
+                               exit(1);
+                       }
+                       if (strncmp (buffer + 17, "13        ", 10)) {
+                               fprintf(stderr, "BTFIXUP_SIMM13 results in relocation other than R_SPARC_13\n%s\n", buffer);
+                               exit(1);
+                       }
+                       break;
+               case 'a':
+                       if (initval + 0x1000 >= 0x2000 && (initval & 0x3ff)) {
+                               fprintf(stderr, "Wrong initializer for HALF.\n%s\n", buffer);
+                               exit(1);
+                       }
+                       if (strncmp (buffer + 17, "13        ", 10)) {
+                               fprintf(stderr, "BTFIXUP_HALF results in relocation other than R_SPARC_13\n%s\n", buffer);
+                               exit(1);
+                       }
+                       break;
+               case 'h':
+                       if (initval & 0x3ff) {
+                               fprintf(stderr, "Wrong initializer for SETHI. Cannot have set low 10 bits\n%s\n", buffer);
+                               exit(1);
+                       }
+                       if (strncmp (buffer + 17, "HI22      ", 10)) {
+                               fprintf(stderr, "BTFIXUP_SETHI results in relocation other than R_SPARC_HI22\n%s\n", buffer);
+                               exit(1);
+                       }
+                       break;
+               case 'i':
+                       if (initval) {
+                               fprintf(stderr, "Cannot use pre-initalized fixups for INT\n%s\n", buffer);
+                               exit(1);
+                       }
+                       if (strncmp (buffer + 17, "HI22      ", 10) && strncmp (buffer + 17, "LO10      ", 10)) {
+                               fprintf(stderr, "BTFIXUP_INT results in relocation other than R_SPARC_HI22 and R_SPARC_LO10\n%s\n", buffer);
+                               exit(1);
+                       }
+                       break;
+               }
+               if (!f->setinitval) {
+                       f->initval = initval;
+                       if (initvalstr) {
+                               f->initvalstr = strdup(initvalstr);
+                               if (!f->initvalstr) fatal();
+                       }
+                       f->setinitval = 1;
+               } else if (f->initval != initval) {
+                       fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer\n%s\n",
+                                       f->name, f->initvalstr ? : "0x00000000", buffer);
+                       exit(1);
+               } else if (initval && strcmp(f->initvalstr, initvalstr)) {
+                       fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer.\n"
+                                       "Initializers have to match literally as well.\n%s\n",
+                                       f->name, f->initvalstr, buffer);
+                       exit(1);
+               }
+               offset = strtoul(buffer, &q, 16);
+               if (q != buffer + 8 || (!offset && strncmp (buffer, "00000000 ", 9))) {
+                       fprintf(stderr, "Malformed relocation address in\n%s\n", buffer);
+                       exit(1);
+               }
+               for (k = 0, r = f->rel, rr = &f->rel; r; rr = &r->next, r = r->next, k++)
+                       if (r->offset == offset && !strcmp(r->sect, sect)) {
+                               fprintf(stderr, "Ugh. One address has two relocation records\n");
+                               exit(1);
+                       }
+               *rr = malloc(sizeof(btfixuprel));
+               if (!*rr) fatal();
+               (*rr)->offset = offset;
+               (*rr)->f = NULL;
+               if (buffer[30] == 'f') {
+                       lastf = f;
+                       lastfoffset = offset;
+                       lastfrelno = k;
+               } else if (lastfoffset + 4 == offset) {
+                       (*rr)->f = lastf;
+                       (*rr)->frel = lastfrelno;
+               }
+               (*rr)->sect = sect;
+               (*rr)->next = NULL;
+       }
+       printf("! Generated by btfixupprep. Do not edit.\n\n");
+       printf("\t.section\t\".data.init\",#alloc,#write\n\t.align\t4\n\n");
+       printf("\t.global\t___btfixup_start\n___btfixup_start:\n\n");
+       for (i = 0; i < last; i++) {
+               f = array + i;
+               printf("\t.global\t___%cs_%s\n", f->type, f->name);
+               if (f->type == 'f')
+                       printf("___%cs_%s:\n\t.word 0x%08x,0,0,", f->type, f->name, f->type << 24);
+               else
+                       printf("___%cs_%s:\n\t.word 0x%08x,0,", f->type, f->name, f->type << 24);
+               for (j = 0, r = f->rel; r != NULL; j++, r = r->next);
+               if (j)
+                       printf("%d\n\t.word\t", j * 2);
+               else
+                       printf("0\n");
+               for (r = f->rel, j--; r != NULL; j--, r = r->next) {
+                       if (!strcmp (r->sect, ".text"))
+                               printf ("_stext+0x%08x", r->offset);
+                       else if (!strcmp (r->sect, ".text.init"))
+                               printf ("__init_begin+0x%08x", r->offset);
+                       else if (!strcmp (r->sect, "__ksymtab"))
+                               printf ("__start___ksymtab+0x%08x", r->offset);
+                       else
+                               fatal();
+                       if (f->type == 'f' || !r->f)
+                               printf (",0");
+                       else
+                               printf (",___fs_%s+0x%08x", r->f->name, (4 + r->frel*2)*4 + 4);
+                       if (j) printf (",");
+                       else printf ("\n");
+               }
+               printf("\n");
+       }
+       printf("\n\t.global\t___btfixup_end\n___btfixup_end:\n");
+       printf("\n\n! Define undefined references\n\n");
+       for (i = 0; i < last; i++) {
+               f = array + i;
+               if (f->type == 'f') {
+                       printf("\t.global\t___f_%s\n", f->name);
+                       printf("___f_%s:\n", f->name);
+               }
+       }
+       printf("\tretl\n\t nop\n\n");
+       for (i = 0; i < last; i++) {
+               f = array + i;
+               if (f->type != 'f') {
+                       if (!f->initval) {
+                               printf("\t.global\t___%c_%s\n", f->type, f->name);
+                               printf("___%c_%s = 0\n", f->type, f->name);
+                       } else {
+                               printf("\t.global\t___%c_%s__btset_0x%s\n", f->type, f->name, f->initvalstr);
+                               printf("___%c_%s__btset_0x%s = 0x%08x\n", f->type, f->name, f->initvalstr, f->initval);
+                       }
+               }
+       }
+       printf("\n\n");
+       exit(0);
+}
index 6e3d501c0a404c639d6a3b7ea8b158163e16e62f..3f0ab09b6213b3eef2b1a0492fc725dd979e67df 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.51 1998/01/08 04:16:54 baccala Exp $
+# $Id: config.in,v 1.54 1998/03/27 06:59:39 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -34,6 +34,8 @@ if [ "$CONFIG_AP1000" = "y" ]; then
        define_bool CONFIG_APBIF y
        tristate 'OPIU DDV Driver' CONFIG_DDV
 else
+       bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
+
        # Global things across all Sun machines.
        define_bool CONFIG_SBUS y
        define_bool CONFIG_SBUSCHAR y
@@ -45,8 +47,13 @@ else
        define_bool CONFIG_SUN_CONSOLE y
        define_bool CONFIG_SUN_AUXIO y
        define_bool CONFIG_SUN_IO y
-       source drivers/sbus/char/Config.in
-       source drivers/sbus/audio/Config.in
+       if [ "$CONFIG_SUN4" = "y" ]; then
+               bool 'Sun FB drivers appear in PROCFS' SUN_FBS_IN_PROCFS
+               bool 'bwtwo support' SUN_FB_BWTWO
+       else
+               source drivers/sbus/char/Config.in
+               source drivers/sbus/audio/Config.in
+       fi
 fi
 
 tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS
index 38b6096ccd11519c130b6edbdd513312792d2a45..1abeca2d63c8c8ac00092ce7f7ec0eda8e5d2fbe 100644 (file)
@@ -20,11 +20,13 @@ CONFIG_KMOD=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_AP1000 is not set
+# CONFIG_SUN4 is not set
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
 CONFIG_SUN_MOUSE=y
 CONFIG_SERIAL=y
 CONFIG_SUN_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
 CONFIG_SUN_KEYBOARD=y
 CONFIG_SUN_CONSOLE=y
 CONFIG_SUN_AUXIO=y
@@ -80,6 +82,7 @@ CONFIG_MD_RAID5=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
 
 #
 # Networking options
@@ -89,8 +92,8 @@ CONFIG_NETLINK=y
 CONFIG_RTNETLINK=y
 # CONFIG_NETLINK_DEV is not set
 CONFIG_FIREWALL=y
-# CONFIG_NET_SECURITY is not set
 CONFIG_NET_ALIAS=y
+# CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -107,11 +110,18 @@ CONFIG_IP_MASQUERADE=y
 #
 # Protocol-specific masquerading support will be built as modules.
 #
+# CONFIG_IP_MASQUERADE_ICMP is not set
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_IPAUTOFW is not set
+# CONFIG_IP_MASQUERADE_IPPORTFW is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=m
+CONFIG_IP_ALIAS=y
 # CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
 
@@ -123,31 +133,39 @@ CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 CONFIG_IPV6=m
 # CONFIG_IPV6_EUI64 is not set
-# CONFIG_IPV6_NO_PB is not set
 
 #
 #  
 #
 CONFIG_IPX=m
+
+#
+# IPX options
+#
 # CONFIG_IPX_INTERN is not set
-# CONFIG_IPX_PPROP_ROUTING is not set
 CONFIG_ATALK=m
-# CONFIG_AX25 is not set
 CONFIG_X25=m
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_CBQ=m
 CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_HFQ=m
 CONFIG_NET_SCH_RED=m
 CONFIG_NET_SCH_SFQ=m
 CONFIG_NET_SCH_TBF=y
 CONFIG_NET_SCH_PFIFO=y
 CONFIG_NET_SCH_PRIO=y
+# CONFIG_NET_PROFILE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
 
 #
 # SCSI support
@@ -175,6 +193,21 @@ CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SUNESP=y
 CONFIG_SCSI_QLOGICPTI=m
 
+#
+# Fibre Channel support
+#
+CONFIG_FC4=m
+
+#
+# FC4 drivers
+#
+CONFIG_FC4_SOC=m
+
+#
+# FC4 targets
+#
+CONFIG_SCSI_PLUTO=m
+
 #
 # Network device support
 #
@@ -193,6 +226,7 @@ CONFIG_SUNLANCE=y
 CONFIG_HAPPYMEAL=m
 CONFIG_SUNQE=m
 CONFIG_MYRI_SBUS=m
+CONFIG_CDROM=y
 
 #
 # Filesystems
@@ -211,24 +245,35 @@ CONFIG_NFS_FS=y
 CONFIG_NFSD=m
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
 CONFIG_SMB_FS=m
 CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
 CONFIG_HPFS_FS=m
+# CONFIG_NTFS_FS is not set
 CONFIG_SYSV_FS=m
 CONFIG_AFFS_FS=m
+# CONFIG_HFS_FS is not set
 CONFIG_ROMFS_FS=m
 CONFIG_AUTOFS_FS=m
 CONFIG_AMIGA_PARTITION=y
 CONFIG_UFS_FS=y
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_ADFS_FS is not set
 # CONFIG_MAC_PARTITION is not set
+CONFIG_NLS=y
 
 #
 # Native Language Support
 #
-CONFIG_NLS=y
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
index 7be8ddd3afe9036102d4524b06bf0abb796ee88e..53ed6d340db4c7b0d7139216e48f23c458904409 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.41 1997/11/19 15:11:59 jj Exp $
+# $Id: Makefile,v 1.43 1998/03/09 14:03:34 jj Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -15,8 +15,6 @@ ifdef SMP
 .S.o:
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
 
-CHECKASM_CC    =       $(CC) -D__SMP__
-
 else
 
 .S.s:
@@ -25,7 +23,6 @@ else
 .S.o:
        $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
-CHECKASM_CC    =       $(CC)
 endif
 
 all: kernel.o head.o init_task.o
@@ -42,7 +39,7 @@ O_OBJS   := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \
 OX_OBJS  := sparc_ksyms.o
 
 ifdef SMP
-O_OBJS += trampoline.o smp.o
+O_OBJS += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
 endif
 
 ifdef CONFIG_SUN_AUXIO
@@ -62,18 +59,61 @@ head.o: head.S
 endif
 
 check_asm: dummy
+       @echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
+       @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
+       @echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#ifndef __SMP__" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#include <linux/sched.h>" > tmp.c
+       $(CC) -E tmp.c -o tmp.i
+       @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/sched.h>" >> check_asm.c
+       @echo 'struct task_struct _task;' >> check_asm.c
+       @echo 'struct mm_struct _mm;' >> check_asm.c
+       @echo 'struct thread_struct _thread;' >> check_asm.c
+       @echo 'int main(void) {' >> check_asm.c
+       $(SH) ./check_asm.sh task tmp.i check_asm.c
+       $(SH) ./check_asm.sh mm tmp.i check_asm.c
+       $(SH) ./check_asm.sh thread tmp.i check_asm.c
+       @echo 'return 0; }' >> check_asm.c
+       @rm -f tmp.[ci]
+       $(CC) -o check_asm check_asm.c
+       ./check_asm >> asm_offsets.h
+       @rm -f check_asm check_asm.c
+       @echo "" >> asm_offsets.h
+       @echo "#else /* __SMP__ */" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
        @echo "#include <linux/sched.h>" > tmp.c
-       $(CHECKASM_CC) -E tmp.c -o tmp.i
-       @echo "/* Automatically generated. Do not edit. */" > check_asm.c; echo "#include <linux/sched.h>" >> check_asm.c; echo 'struct task_struct _task; struct mm_struct _mm; struct thread_struct _thread; int main(void) { printf ("/* Automatically generated. Do not edit. */\n#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n\n");' >> check_asm.c
+       $(CC) -D__SMP__ -E tmp.c -o tmp.i
+       @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/sched.h>" >> check_asm.c
+       @echo 'struct task_struct _task;' >> check_asm.c
+       @echo 'struct mm_struct _mm;' >> check_asm.c
+       @echo 'struct thread_struct _thread;' >> check_asm.c
+       @echo 'int main(void) {' >> check_asm.c
        $(SH) ./check_asm.sh task tmp.i check_asm.c
        $(SH) ./check_asm.sh mm tmp.i check_asm.c
        $(SH) ./check_asm.sh thread tmp.i check_asm.c
-       @echo 'printf ("\n#endif /* __ASM_OFFSETS_H__ */\n"); return 0; }' >> check_asm.c
+       @echo 'return 0; }' >> check_asm.c
        @rm -f tmp.[ci]
-       $(CHECKASM_CC) -o check_asm check_asm.c
-       ./check_asm > asm_offsets.h
-       @if test -r $(HPATH)/asm/asm_offsets.h; then if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then echo $(HPATH)/asm/asm_offsets.h is unchanged; rm -f asm_offsets.h; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi
+       $(CC) -D__SMP__ -o check_asm check_asm.c
+       ./check_asm >> asm_offsets.h
        @rm -f check_asm check_asm.c
+       @echo "" >> asm_offsets.h
+       @echo "#endif /* __SMP__ */" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
+       @if test -r $(HPATH)/asm/asm_offsets.h; then \
+         if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \
+           echo $(HPATH)/asm/asm_offsets.h is unchanged; \
+           rm -f asm_offsets.h; \
+         else \
+           mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
+         fi; \
+       else \
+         mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
+       fi
 
 
 include $(TOPDIR)/Rules.make
index 5835347d19ce324ec2a5530afd994cfe4e8d102b..13d34310f8c36af2dc35efeea5aad7a222c3fdf9 100644 (file)
@@ -17,9 +17,13 @@ __initfunc(void auxio_probe(void))
        int node, auxio_nd;
        struct linux_prom_registers auxregs[1];
 
-       if (sparc_cpu_model == sun4d) {
+       switch (sparc_cpu_model) {
+       case sun4d:
+       case sun4:
                auxio_register = 0;
                return;
+       default:
+               break;
        }
        node = prom_getchild(prom_root_node);
        auxio_nd = prom_searchsiblings(node, "auxiliary-io");
index aeb5a46c816acf6714c988fb4c6c468da799385e..1ca98407ab935189dce65d2492873684813065df 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/tasks.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
 #include <asm/head.h>
@@ -116,22 +118,25 @@ struct cpu_iu_info linux_sparc_chips[] = {
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
 
-char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+char *sparc_cpu_type[NR_CPUS] = { 0 };
+char *sparc_fpu_type[NR_CPUS] = { 0 };
 
 unsigned int fsr_storage;
 
 __initfunc(void cpu_probe(void))
 {
        int psr_impl, psr_vers, fpu_vers;
-       int i, cpuid;
+       int i, cpuid, psr;
 
-       cpuid = get_cpuid();
+       cpuid = hard_smp_processor_id();
 
        psr_impl = ((get_psr()>>28)&0xf);
        psr_vers = ((get_psr()>>24)&0xf);
 
+       psr = get_psr();
+       put_psr(psr | PSR_EF);
        fpu_vers = ((get_fsr()>>17)&0x7);
+       put_psr(psr);
 
        for(i = 0; i<NSPARCCHIPS; i++) {
                if(linux_sparc_chips[i].psr_impl == psr_impl)
index b9c6495cf0ab7e31bc42f4b1fb6ba360c2f55ae0..dd4dbb3c66e188f41c707b6ad3d40f1e46c1554c 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/smp.h>
 #include <asm/system.h>
 
-struct prom_cpuinfo linux_cpus[NCPUS];
+struct prom_cpuinfo linux_cpus[NR_CPUS];
 int linux_num_cpus;
 
 extern void cpu_probe(void);
@@ -26,7 +26,7 @@ device_scan(unsigned long mem_start))
 {
        char node_str[128];
        int nd, prom_node_cpu, thismid;
-       int cpu_nds[NCPUS];  /* One node for each cpu */
+       int cpu_nds[NR_CPUS];  /* One node for each cpu */
        int cpu_ctr = 0;
 
        prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
@@ -62,11 +62,9 @@ device_scan(unsigned long mem_start))
                                        prom_getstring(node, "device_type", node_str, sizeof(node_str));
                                        if (strcmp(node_str, "cpu") == 0) {
                                                prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
-                                               if (cpu_ctr < NCPUS) {
-                                                       cpu_nds[cpu_ctr] = node;
-                                                       linux_cpus[cpu_ctr].prom_node = node;
-                                                       linux_cpus[cpu_ctr].mid = thismid;
-                                               }
+                                               cpu_nds[cpu_ctr] = node;
+                                               linux_cpus[cpu_ctr].prom_node = node;
+                                               linux_cpus[cpu_ctr].mid = thismid;
                                                prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
                                                            cpu_ctr, (unsigned long) node,
                                                            thismid);
@@ -74,8 +72,6 @@ device_scan(unsigned long mem_start))
                                        }
                                }
                        }
-                       if (cpu_ctr > NCPUS)
-                               cpu_ctr = NCPUS;
                }
                if(cpu_ctr == 0) {
                        printk("No CPU nodes found, cannot continue.\n");
@@ -99,7 +95,7 @@ device_scan(unsigned long mem_start))
 #endif
        clock_stop_probe();
 
-       if (sparc_cpu_model == sun4c)
+       if (ARCH_SUN4C_SUN4)
                sun4c_probe_memerr_reg();
 
        return mem_start;
index d82c098d5a7ec55b3026d4448a93975138aad184..d393a9543a987aec30c4761a3b0b09710c53bc4f 100644 (file)
@@ -1,10 +1,11 @@
-/* $Id: entry.S,v 1.142 1998/01/07 06:33:47 baccala Exp $
+/* $Id: entry.S,v 1.149 1998/03/19 15:36:30 jj Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1998 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
  */
 
 #include <linux/config.h>
 #include <asm/vaddrs.h>
 #include <asm/memreg.h>
 #include <asm/page.h>
+#ifdef CONFIG_SUN4
+#include <asm/pgtsun4.h>
+#else
 #include <asm/pgtsun4c.h>
+#endif
 #include <asm/winmacro.h>
 #include <asm/signal.h>
+#include <asm/obio.h>
+#include <asm/mxcc.h>
 
 #include <asm/asmmacro.h>
 
@@ -288,10 +295,14 @@ real_irq_entry:
        SAVE_ALL
 
 #ifdef __SMP__
+       .globl  patchme_maybe_smp_msg
+
        cmp     %l7, 12
-       bgu     maybe_smp_msg
+patchme_maybe_smp_msg:
+       bgu     maybe_smp4m_msg
         nop
 #endif
+
 real_irq_continue:
        or      %l0, PSR_PIL, %g2
        wr      %g2, 0x0, %psr
@@ -309,14 +320,14 @@ patch_handler_irq:
 
 #ifdef __SMP__
        /* SMP per-cpu ticker interrupts are handled specially. */
-smp_ticker:
-       bne     real_irq_continue
+smp4m_ticker:
+       bne     real_irq_continue+4
         or     %l0, PSR_PIL, %g2
        wr      %g2, 0x0, %psr
        WRITE_PAUSE
        wr      %g2, PSR_ET, %psr
        WRITE_PAUSE
-       call    C_LABEL(smp_percpu_timer_interrupt)
+       call    C_LABEL(smp4m_percpu_timer_interrupt)
         add    %sp, REGWIN_SZ, %o0
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
@@ -326,7 +337,7 @@ smp_ticker:
         * on some level other than 15 which is the NMI and only used
         * for cross calls.  That has a seperate entry point below.
         */
-maybe_smp_msg:
+maybe_smp4m_msg:
        GET_PROCESSOR_MID(o3, o2)
        set     C_LABEL(sun4m_interrupts), %l5
        ld      [%l5], %o5
@@ -334,7 +345,7 @@ maybe_smp_msg:
        sll     %o3, 12, %o3
        ld      [%o5 + %o3], %o1
        andcc   %o1, %o4, %g0
-       be,a    smp_ticker
+       be,a    smp4m_ticker
         cmp    %l7, 14
        cmp     %l7, 13
        add     %o5, %o3, %o5
@@ -383,7 +394,7 @@ linux_trap_ipi15_sun4m:
        WRITE_PAUSE
        wr      %l4, PSR_ET, %psr
        WRITE_PAUSE
-       call    C_LABEL(smp_cross_call_irq)
+       call    C_LABEL(smp4m_cross_call_irq)
         nop
        b       ret_trap_lockless_ipi
         clr    %l6
@@ -409,6 +420,64 @@ linux_trap_ipi15_sun4m:
        ld      [%l5], %g0
        WRITE_PAUSE
        RESTORE_ALL
+
+       .globl  smp4d_ticker
+       /* SMP per-cpu ticker interrupts are handled specially. */
+smp4d_ticker:
+       SAVE_ALL
+       or      %l0, PSR_PIL, %g2
+       sethi   %hi(CC_ICLR), %o0
+       sethi   %hi(1 << 14), %o1
+       or      %o0, %lo(CC_ICLR), %o0
+       stha    %o1, [%o0] ASI_M_MXCC   /* Clear PIL 14 in MXCC's ICLR */
+       wr      %g2, 0x0, %psr
+       WRITE_PAUSE
+       wr      %g2, PSR_ET, %psr
+       WRITE_PAUSE
+       call    C_LABEL(smp4d_percpu_timer_interrupt)
+        add    %sp, REGWIN_SZ, %o0
+       wr      %l0, PSR_ET, %psr
+       WRITE_PAUSE
+       RESTORE_ALL
+
+       .align  4
+       .globl  linux_trap_ipi15_sun4d
+linux_trap_ipi15_sun4d:
+       SAVE_ALL
+       sethi   %hi(CC_BASE), %o4
+       sethi   %hi(MXCC_ERR_ME|MXCC_ERR_PEW|MXCC_ERR_ASE|MXCC_ERR_PEE), %o2
+       or      %o4, (CC_EREG - CC_BASE), %o0
+       ldda    [%o0] ASI_M_MXCC, %o0
+       andcc   %o0, %o2, %g0
+       bne     1f
+        sethi  %hi(BB_STAT2), %o2
+       lduba   [%o2] ASI_M_CTL, %o2
+       andcc   %o2, BB_STAT2_MASK, %g0
+       bne     2f
+        or     %o4, (CC_ICLR - CC_BASE), %o0
+       sethi   %hi(1 << 15), %o1
+       stha    %o1, [%o0] ASI_M_MXCC   /* Clear PIL 15 in MXCC's ICLR */
+       or      %l0, PSR_PIL, %l4
+       wr      %l4, 0x0, %psr
+       WRITE_PAUSE
+       wr      %l4, PSR_ET, %psr
+       WRITE_PAUSE
+       call    C_LABEL(smp4d_cross_call_irq)
+        nop
+       b       ret_trap_lockless_ipi
+        clr    %l6
+
+1:     /* MXCC error */
+2:     /* BB error */
+       /* Disable PIL 15 */
+       set     CC_IMSK, %l4
+       lduha   [%l4] ASI_M_MXCC, %l5
+       sethi   %hi(1 << 15), %l7
+       or      %l5, %l7, %l5
+       stha    %l5, [%l4] ASI_M_MXCC
+       /* FIXME */
+1:     b,a     1b
+
 #endif /* __SMP__ */
 
        /* This routine handles illegal instructions and privileged
@@ -417,6 +486,12 @@ linux_trap_ipi15_sun4m:
        .align  4
        .globl  bad_instruction
 bad_instruction:
+       sethi   %hi(0xc1f80000), %l4
+       ld      [%l1], %l5
+       sethi   %hi(0x81d80000), %l7
+       and     %l5, %l4, %l5
+       cmp     %l5, %l7
+       be      1f
        SAVE_ALL
 
        wr      %l0, PSR_ET, %psr               ! re-enable traps
@@ -430,6 +505,10 @@ bad_instruction:
 
        RESTORE_ALL
 
+1:     /* unimplemented flush - just skip */
+       jmpl    %l2, %g0
+        rett   %l2 + 4
+
        .align  4
        .globl  priv_instruction
 priv_instruction:
@@ -601,23 +680,6 @@ do_cp_disabled:
 
        RESTORE_ALL
 
-       /* This routine handles Unimplemented FLUSH Exceptions. */
-       .align  4
-       .globl  do_bad_flush
-do_bad_flush:
-       SAVE_ALL
-
-       wr      %l0, PSR_ET, %psr               ! re-enable traps
-       WRITE_PAUSE
-
-       add     %sp, REGWIN_SZ, %o0
-       mov     %l1, %o1
-       mov     %l2, %o2
-       call    C_LABEL(handle_bad_flush)
-        mov    %l0, %o3
-
-       RESTORE_ALL
-
        /* This routine handles Co-Processor Exceptions. */
        .align  4
        .globl  do_cp_exception
@@ -765,6 +827,12 @@ linux_trap_nmi_sun4c:
 C_LABEL(invalid_segment_patch1_ff):    cmp     %l4, 0xff
 C_LABEL(invalid_segment_patch2_ff):    mov     0xff, %l4
 
+       .align  4
+       .globl  C_LABEL(invalid_segment_patch1_1ff)
+       .globl  C_LABEL(invalid_segment_patch2_1ff)
+C_LABEL(invalid_segment_patch1_1ff):   cmp     %l4, 0x1ff
+C_LABEL(invalid_segment_patch2_1ff):   mov     0x1ff, %l4
+
        .align  4
        .globl  C_LABEL(num_context_patch1_16), C_LABEL(num_context_patch2_16)
 C_LABEL(num_context_patch1_16):                mov     0x10, %l7
@@ -776,7 +844,17 @@ C_LABEL(vac_linesize_patch_32):            subcc   %l7, 32, %l7
 
        .align  4
        .globl  C_LABEL(vac_hwflush_patch1_on), C_LABEL(vac_hwflush_patch2_on)
+
+/*
+ * Ugly, but we cant use hardware flushing on the sun4 and we'd require
+ * two instructions (Anton)
+ */
+#ifdef CONFIG_SUN4
+C_LABEL(vac_hwflush_patch1_on):                nop
+#else
 C_LABEL(vac_hwflush_patch1_on):                subcc   %l7, (PAGE_SIZE - 4), %l7
+#endif
+
 C_LABEL(vac_hwflush_patch2_on):                sta     %g0, [%l3 + %l7] ASI_HWFLUSHSEG
 
        .globl  C_LABEL(invalid_segment_patch1), C_LABEL(invalid_segment_patch2)
@@ -786,11 +864,50 @@ C_LABEL(vac_hwflush_patch2_on):           sta     %g0, [%l3 + %l7] ASI_HWFLUSHSEG
 
        .align  4
        .globl  sun4c_fault
+
+! %l0 = %psr
+! %l1 = %pc
+! %l2 = %npc
+! %l3 = %wim
+! %l7 = 1 for textfault
+! We want error in %l5, vaddr in %l6
 sun4c_fault:
+#ifdef CONFIG_SUN4
+       sethi   C_LABEL(sun4c_memerr_reg), %l4
+       ld      [%l4+%lo(C_LABEL(sun4c_memerr_reg))], %l4  ! memerr ctrl reg addr
+       ld      [%l4], %l6              ! memerr ctrl reg
+       ld      [%l4 + 4], %l5          ! memerr vaddr reg
+       andcc   %l6, 0x80, %g0          ! check for error type
+       st      %g0, [%l4 + 4]          ! clear the error
+       be      0f                      ! normal error
+        sethi  %hi(AC_BUS_ERROR), %l4  ! bus err reg addr
+
+       call    C_LABEL(prom_halt)      ! something weird happened
+                                       ! what exactly did happen?
+                                       ! what should we do here?
+
+0:     or      %l4, %lo(AC_BUS_ERROR), %l4     ! bus err reg addr
+       lduba   [%l4] ASI_CONTROL, %l6  ! bus err reg
+
+       cmp    %l7, 1                   ! text fault?
+       be      1f                      ! yes
+        nop
+
+       ld     [%l1], %l4               ! load instruction that caused fault
+       srl     %l4, 21, %l4
+       andcc   %l4, 1, %g0             ! store instruction?
+
+       be      1f                      ! no
+        sethi  %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep
+                                       ! %lo(SUN4C_SYNC_BADWRITE) = 0
+       or      %l4, %l6, %l6           ! set write bit to emulate sun4c
+1:
+#else
        sethi   %hi(AC_SYNC_ERR), %l4
        add     %l4, 0x4, %l6                   ! AC_SYNC_VA in %l6
        lda     [%l6] ASI_CONTROL, %l5          ! Address
        lda     [%l4] ASI_CONTROL, %l6          ! Error, retained for a bit
+#endif
 
        andn    %l5, 0xfff, %l5                 ! Encode all info into l7
        srl     %l6, 14, %l4
@@ -830,17 +947,21 @@ sun4c_fault:
        sethi   %hi(SUN4C_VMALLOC_START), %l4
        cmp     %l5, %l4
        blu,a   C_LABEL(invalid_segment_patch1)
-        lduba  [%l5] ASI_SEGMAP, %l4
+        lduXa  [%l5] ASI_SEGMAP, %l4
 
-       srl     %l5, SUN4C_PGDIR_SHIFT, %l6
        sethi   %hi(C_LABEL(swapper_pg_dir)), %l4
+       srl     %l5, SUN4C_PGDIR_SHIFT, %l6
        or      %l4, %lo(C_LABEL(swapper_pg_dir)), %l4
        sll     %l6, 2, %l6
        ld      [%l4 + %l6], %l4
+#ifdef CONFIG_SUN4
+       sethi   PAGE_MASK, %l6
+       andcc   %l4, %l6, %g0
+#else
        andcc   %l4, PAGE_MASK, %g0
-
+#endif
        be      sun4c_fault_fromuser
-        lduba  [%l5] ASI_SEGMAP, %l4
+        lduXa  [%l5] ASI_SEGMAP, %l4
 
 C_LABEL(invalid_segment_patch1):
        cmp     %l4, 0x7f
@@ -889,7 +1010,11 @@ C_LABEL(invalid_segment_patch1):
        ld      [%l6 + 0x08], %l3       ! tmp = entry->vaddr
 
        ! Flush segment from the cache.
+#ifdef CONFIG_SUN4
+       sethi   %hi((128 * 1024)), %l7
+#else
        sethi   %hi((64 * 1024)), %l7
+#endif
 9:
 C_LABEL(vac_hwflush_patch1):
 C_LABEL(vac_linesize_patch):
@@ -928,7 +1053,7 @@ C_LABEL(invalid_segment_patch2):
        deccc   %l7
        stba    %l7, [%l3] ASI_CONTROL
        bne     3b
-        stba   %l4, [%l5] ASI_SEGMAP
+        stXa   %l4, [%l5] ASI_SEGMAP
 
        stba    %l6, [%l3] ASI_CONTROL
 
@@ -952,7 +1077,7 @@ C_LABEL(num_context_patch2):
        deccc   %l7
        stba    %l7, [%l3] ASI_CONTROL
        bne     3b
-        stba   %l4, [%l5] ASI_SEGMAP
+        stXa   %l4, [%l5] ASI_SEGMAP
 
        stba    %l6, [%l3] ASI_CONTROL
 
@@ -988,7 +1113,12 @@ C_LABEL(num_context_patch2):
        or      %l4, %lo(C_LABEL(swapper_pg_dir)), %l4
        sll     %l3, 2, %l3
        ld      [%l4 + %l3], %l4
+#ifndef CONFIG_SUN4
        and     %l4, PAGE_MASK, %l4
+#else
+       sethi   PAGE_MASK, %l6
+       and     %l4, %l6, %l4
+#endif
 
        srl     %l5, (PAGE_SHIFT - 2), %l6
        and     %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
@@ -1640,9 +1770,8 @@ C_LABEL(udelay):
        call    .umul
         ld     [%o3 + %lo(C_LABEL(loops_per_sec))], %o1
 #else
-       GET_PROCESSOR_OFFSET(o4)
+       GET_PROCESSOR_OFFSET(o4, o2)
        set     C_LABEL(cpu_data), %o3
-       sll     %o4, 1, %o4
        call    .umul
         ld     [%o3 + %o4], %o1
 #endif
@@ -1718,4 +1847,11 @@ kuw_patch1:
        retl                                    ! return
         st     %g0, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]        ! no windows saved
 
+       .align  4
+       .globl  C_LABEL(restore_current)
+C_LABEL(restore_current):
+       LOAD_CURRENT(g6, o0)
+       retl
+        nop
+
 /* End of entry.S */
index fc6c4ceadeed4f46ba7e7f7e8ad8578e22cf4b73..5496b061e68c3de2ba32db85f422789865aa4afc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.26 1997/05/01 08:53:32 davem Exp $
+/* $Id: etrap.S,v 1.29 1998/02/09 13:48:40 jj Exp $
  * etrap.S: Sparc trap window preparation for entry into the
  *          Linux kernel.
  *
@@ -13,6 +13,7 @@
 #include <asm/psr.h>
 #include <asm/ptrace.h>
 #include <asm/winmacro.h>
+#include <asm/asmmacro.h>
 
 /* Registers to not touch at all. */
 #define t_psr        l0 /* Set by caller */
@@ -126,13 +127,13 @@ tsetup_patch2:
        jmpl    %t_retpc + 0x8, %g0     ! return to caller
         mov    %t_kstack, %sp          ! and onto new kernel stack
 
+#define STACK_OFFSET (TASK_UNION_SIZE - (TRACEREG_SZ + REGWIN_SZ))
 trap_setup_from_user:
        /* We can't use %curptr yet. */
        LOAD_CURRENT(t_kstack, t_twinmask)
 
-       mov     1, %t_twinmask
-       sll     %t_twinmask, (PAGE_SHIFT + 1), %t_twinmask
-       sub     %t_twinmask, (TRACEREG_SZ + REGWIN_SZ), %t_twinmask
+       sethi   %hi(STACK_OFFSET), %t_twinmask
+       or      %t_twinmask, %lo(STACK_OFFSET), %t_twinmask
        add     %t_kstack, %t_twinmask, %t_kstack
 
        mov     1, %t_twinmask
@@ -141,11 +142,18 @@ trap_setup_from_user:
        /* Build pt_regs frame. */
        STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
 
-       /* Clear current->tss.w_saved */
-       mov     1, %curptr
-       sll     %curptr, (PAGE_SHIFT + 1), %curptr
-       sub     %curptr, (TRACEREG_SZ + REGWIN_SZ), %curptr
+#if 0
+       /* If we're sure every task_struct is TASK_UNION_SIZE aligned,
+          we can speed this up. */
+       sethi   %hi(STACK_OFFSET), %curptr
+       or      %curptr, %lo(STACK_OFFSET), %curptr
        sub     %t_kstack, %curptr, %curptr
+#else
+       sethi   %hi(~(TASK_UNION_SIZE - 1)), %curptr
+       and     %t_kstack, %curptr, %curptr
+#endif
+
+       /* Clear current->tss.w_saved */
        st      %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved]
 
        /* See if we are in the trap window. */
@@ -269,9 +277,8 @@ tsetup_sun4c_onepage:
        .globl  C_LABEL(tsetup_srmmu_stackchk)
 C_LABEL(tsetup_srmmu_stackchk):
        /* Check results of callers andcc %sp, 0x7, %g0 */
-       sethi   %hi(C_LABEL(page_offset)), %glob_tmp
        bne     trap_setup_user_stack_is_bolixed
-        ld     [%glob_tmp + %lo(C_LABEL(page_offset))], %glob_tmp
+        GET_PAGE_OFFSET(glob_tmp)
 
        cmp     %glob_tmp, %sp
        bleu,a  1f
index 2de97e92b445fa6d63c9b7933de454b6c7cc2da3..1536a5e55fd52fa2221c4672d2434d7c718d9a05 100644 (file)
@@ -1,10 +1,11 @@
-/* $Id: head.S,v 1.84 1997/11/19 15:12:01 jj Exp $
+/* $Id: head.S,v 1.90 1998/03/24 18:12:05 jj Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1995 Peter Zaitcev   (Zaitcev@ipmce.su)
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
  * Copyright (C) 1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
  */
 
 #include <linux/version.h>
@@ -60,9 +61,16 @@ C_LABEL(cputypvar_sun4m):
        .asciz "compatible"
 
        .align 4
+
+#ifndef CONFIG_SUN4
 sun4_notsup:
-       .asciz  "Sparc-Linux sun4 support not implemented yet\n\n"
+       .asciz  "Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\n\n"
+       .align 4
+#else
+sun4cdm_notsup:
+       .asciz  "Kernel compiled with CONFIG_SUN4 cannot run on SUN4C/SUN4M/SUN4D\nTurn CONFIG_SUN4 off.\n\n"
        .align 4
+#endif
 
 sun4e_notsup:
         .asciz  "Sparc-Linux sun4e support does not exist\n\n"
@@ -111,13 +119,14 @@ t_irq14:TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
 #ifndef __SMP__
 t_nmi: NMI_TRAP                            /* Level 15 (NMI)                */
 #else
-       TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
+       .globl  t_nmi
+t_nmi: TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
 #endif
 t_racc:        TRAP_ENTRY(0x20, do_reg_access)     /* General Register Access Error */
 t_iacce:BAD_TRAP(0x21)                      /* Instr Access Error            */
 t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23)
 t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)    /* Co-Processor Disabled         */
-t_uflsh:TRAP_ENTRY(0x25, do_bad_flush)      /* Unimplemented FLUSH inst.     */
+t_uflsh:SKIP_TRAP(0x25, unimp_flush)        /* Unimplemented FLUSH inst.     */
 t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27)
 t_cpexc:TRAP_ENTRY(0x28, do_cp_exception)   /* Co-Processor Exception        */
 t_dacce:SPARC_DFAULT                        /* Data Access Error             */
@@ -205,7 +214,7 @@ C_LABEL(trapbase_cpu1):
        TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
        TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
        TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
-       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) TRAP_ENTRY(0x25, do_bad_flush)
+       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
        BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
        SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
        BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
@@ -273,7 +282,7 @@ C_LABEL(trapbase_cpu2):
        TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
        TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
        TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
-       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) TRAP_ENTRY(0x25, do_bad_flush)
+       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
        BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
        SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
        BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
@@ -341,7 +350,7 @@ C_LABEL(trapbase_cpu3):
        TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14)
        TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m)
        TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22)
-       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) TRAP_ENTRY(0x25, do_bad_flush)
+       BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush)
        BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception)
        SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c)
        BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
@@ -394,28 +403,26 @@ C_LABEL(trapbase_cpu3):
        BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
 
 #endif
-       .skip 4096
+       .align 4096
 
 /* This was the only reasonable way I could think of to properly align
  * these page-table data structures.
  */
        .globl C_LABEL(bootup_user_stack)
-       .globl C_LABEL(bootup_kernel_stack)
        .globl C_LABEL(pg0), C_LABEL(pg1), C_LABEL(pg2), C_LABEL(pg3)
        .globl C_LABEL(empty_bad_page)
        .globl C_LABEL(empty_bad_page_table)
        .globl C_LABEL(empty_zero_page)
        .globl C_LABEL(swapper_pg_dir)
 C_LABEL(bootup_user_stack):            .skip 0x2000
-C_LABEL(bootup_kernel_stack):          .skip 0x2000
-C_LABEL(swapper_pg_dir):               .skip 0x1000
-C_LABEL(pg0):                          .skip 0x1000
-C_LABEL(pg1):                          .skip 0x1000
-C_LABEL(pg2):                          .skip 0x1000
-C_LABEL(pg3):                          .skip 0x1000
-C_LABEL(empty_bad_page):               .skip 0x1000
-C_LABEL(empty_bad_page_table):         .skip 0x1000
-C_LABEL(empty_zero_page):              .skip 0x1000
+C_LABEL(swapper_pg_dir):               .skip PAGE_SIZE
+C_LABEL(pg0):                          .skip PAGE_SIZE
+C_LABEL(pg1):                          .skip PAGE_SIZE
+C_LABEL(pg2):                          .skip PAGE_SIZE
+C_LABEL(pg3):                          .skip PAGE_SIZE
+C_LABEL(empty_bad_page):               .skip PAGE_SIZE
+C_LABEL(empty_bad_page_table):         .skip PAGE_SIZE
+C_LABEL(empty_zero_page):              .skip PAGE_SIZE
 
        .global C_LABEL(root_flags)
        .global C_LABEL(ram_flags)
@@ -778,18 +785,24 @@ execute_in_high_mem:
  * your code. Sun probably still does that because they don't even
  * trust their own "OpenBoot" specifications.
  */
-
                set     LOAD_ADDR, %g6
                cmp     %o0, %g6                ! an old sun4?
-               be      no_sun4_here
+               be      sun4_init
                 nop
 
 found_version:
-
+#ifdef CONFIG_SUN4
+/* For people who try sun4 kernels, even if Configure.help advises them. */
+               ld      [%g7 + 0x68], %o1
+               set     sun4cdm_notsup, %o0
+               call    %o1
+                nop
+               b       halt_me
+                nop
+#endif
 /* Get the machine type via the mysterious romvec node operations. */
 
-               or      %g0, %g7, %l1
-               add     %l1, 0x1c, %l1          
+               add     %g7, 0x1c, %l1          
                ld      [%l1], %l0
                ld      [%l0], %l0
                call    %l0
@@ -825,10 +838,11 @@ got_prop:
                set     C_LABEL(cputypval), %o2
                ldub    [%o2 + 0x4], %l1
 
-               cmp     %l1, 'c'                ! We already know we are not
-               be      1f                      ! on a plain sun4 because of
-                                               ! the check for 0x4000 in %o0
-                cmp    %l1, 'm'                ! at start
+               cmp     %l1, ' '
+               be      1f
+                cmp    %l1, 'c'
+               be      1f
+                cmp    %l1, 'm'
                be      1f
                 cmp    %l1, 'd'
                be      1f
@@ -853,6 +867,9 @@ got_prop:
                b       sun4c_continue_boot
                 nop
 
+/* CPUID in bootbus can be found at PA 0xff0140000 */
+#define SUN4D_BOOTBUS_CPUID     0xf0140000
+
 sun4d_init:
        /* Need to patch call to handler_irq */
        set     C_LABEL(patch_handler_irq), %g4
@@ -862,6 +879,21 @@ sun4d_init:
        srl     %g5, 2, %g5
        or      %g5, %g3, %g5
        st      %g5, [%g4]
+
+#ifdef __SMP__
+       /* Get our CPU id out of bootbus */
+       set     SUN4D_BOOTBUS_CPUID, %g3
+       lduba   [%g3] ASI_M_CTL, %g3
+       and     %g3, 0xf8, %g3
+       srl     %g3, 3, %g4
+       sta     %g4, [%g0] ASI_M_VIKING_TMP1
+       sethi   %hi(boot_cpu_id), %g5
+       stb     %g4, [%g5 + %lo(boot_cpu_id)]
+       sll     %g4, 2, %g4
+       sethi   %hi(boot_cpu_id4), %g5
+       stb     %g4, [%g5 + %lo(boot_cpu_id4)]
+#endif
+
        /* Fall through to sun4m_init */
 
 sun4m_init:
@@ -974,7 +1006,8 @@ sun4c_continue_boot:
 
                /* I want a kernel stack NOW! */
                set     C_LABEL(bootup_user_stack), %g1
-               add     %g1, (PAGE_SIZE - REGWIN_SZ), %sp
+               set     (0x2000 - REGWIN_SZ), %g2
+               add     %g1, %g2, %sp
                mov     0, %fp                  /* And for good luck */
 
                /* Zero out our BSS section. */
@@ -988,10 +1021,16 @@ sun4c_continue_boot:
                 add    %o0, 0x1, %o0
 
                /* Initialize the umask value for init_task just in case.
-                * But first make current_set[0] point to something useful.
+                * But first make current_set[boot_cpu_id] point to something useful.
                 */
                set     C_LABEL(init_task_union), %g6
                set     C_LABEL(current_set), %g2
+#ifdef __SMP__
+               sethi   %hi(C_LABEL(boot_cpu_id4)), %g3
+               ldub    [%g3 + %lo(C_LABEL(boot_cpu_id4))], %g3
+               st      %g6, [%g2]
+               add     %g2, %g3, %g2
+#endif
                st      %g6, [%g2]
 
                st      %g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask]
@@ -1114,19 +1153,28 @@ sun4c_continue_boot:
                call    halt_me
                 nop
 
+sun4_init:
+#ifdef CONFIG_SUN4
 /* There, happy now Adrian? */
+               set     C_LABEL(cputypval), %o2         ! Let everyone know we
+               set     ' ', %o0                        ! are a "sun4 " architecture
+               stb     %o0, [%o2 + 0x4]                
 
-               /* XXX Fix this... XXX */
-no_sun4_here:
-               sethi   %hi(SUN4_PROM_VECTOR+SUN4_PRINTF), %o1
-               ld      [%o1 + %lo(SUN4_PROM_VECTOR+SUN4_PRINTF)], %o1
-               set     sun4_notsup, %o0
-               call    %o1
+               b got_prop 
                 nop
-1:
-               ba      1b                      ! Cannot exit into KMON
+#else
+               sethi   %hi(SUN4_PROM_VECTOR+0x84), %o1
+               ld      [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
+               set     sun4_notsup, %o0
+               call    %o1     /* printf */
                 nop
-
+               sethi   %hi(SUN4_PROM_VECTOR+0xc4), %o1
+               ld      [%o1 + %lo(SUN4_PROM_VECTOR+0xc4)], %o1
+               call    %o1     /* exittomon */
+                nop
+1:             ba      1b                      ! Cannot exit into KMON
+                nop
+#endif
 no_sun4e_here:
                ld      [%g7 + 0x68], %o1
                set     sun4e_notsup, %o0
index 1829daeea8fe41e214ec6cc64b960095d6ab3460..506a986221e1d5aa5df1c54fbbfd612727fc4446 100644 (file)
@@ -11,9 +11,9 @@ static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM;
 
-/* .text section in head.S is aligned at 2 page boundry and this gets linked
+/* .text section in head.S is aligned at 8k boundry and this gets linked
  * right after that so that the init_task_union is aligned properly as well.
- * We really don't need this special alignment like the Intel does, but
- * I do it anyways for completeness.
+ * If this is not aligned on a 8k boundry, then you should change code
+ * in etrap.S which assumes it.
  */
 union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
index 08c0be5c6f96fd1617449462237eb46b3a2db68d..b29eca49633aeb9b7f92076fbbae03fd8e8f7c5b 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.77 1997/11/19 15:33:05 jj Exp $
+/*  $Id: irq.c,v 1.85 1998/03/09 14:03:40 jj Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -67,22 +67,9 @@ static void irq_panic(void)
     prom_halt();
 }
 
-void (*enable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
-void (*disable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
-void (*enable_pil_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
-void (*disable_pil_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
-void (*clear_clock_irq)(void) = irq_panic;
-void (*clear_profile_irq)(int) = (void (*)(int)) irq_panic;
-void (*load_profile_irq)(int, unsigned int) =  (void (*)(int, unsigned int)) irq_panic;
 void (*init_timers)(void (*)(int, void *,struct pt_regs *)) =
     (void (*)(void (*)(int, void *,struct pt_regs *))) irq_panic;
 
-#ifdef __SMP__
-void (*set_cpu_int)(int, int);
-void (*clear_cpu_int)(int, int);
-void (*set_irq_udt)(int);
-#endif
-
 /*
  * Dave Redman (djhr@tadpole.co.uk)
  *
@@ -109,6 +96,9 @@ int get_irq_list(char *buf)
 {
        int i, len = 0;
        struct irqaction * action;
+#ifdef __SMP__
+       int j;
+#endif
 
        if (sparc_cpu_model == sun4d) {
                extern int sun4d_get_irq_list(char *);
@@ -119,8 +109,15 @@ int get_irq_list(char *buf)
                action = *(i + irq_action);
                if (!action) 
                        continue;
-               len += sprintf(buf+len, "%2d: %8d %c %s",
-                       i, kstat.interrupts[i],
+               len += sprintf(buf+len, "%3d: ", i);
+#ifndef __SMP__
+               len += sprintf(buf+len, "%10u ", kstat_irqs(i));
+#else
+               for (j = 0; j < smp_num_cpus; j++)
+                       len += sprintf(buf+len, "%10u ",
+                               kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+               len += sprintf(buf+len, " %c %s",
                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
                        action->name);
                for (action=action->next; action; action = action->next) {
@@ -280,7 +277,7 @@ static inline void get_irqlock(int cpu, unsigned long where)
                        do {
                                STUCK;
                                barrier();
-                       } while (*((unsigned char *)&global_irq_lock));
+                       } while (*((volatile unsigned char *)&global_irq_lock));
                } while (!spin_trylock(&global_irq_lock));
        }
        /*
@@ -352,7 +349,7 @@ void irq_enter(int cpu, int irq, void *_opaque)
 
        hardirq_enter(cpu);
        barrier();
-       while (*((unsigned char *)&global_irq_lock)) {
+       while (*((volatile unsigned char *)&global_irq_lock)) {
                if ((unsigned char) cpu == global_irq_holder) {
                        struct pt_regs *regs = _opaque;
                        int sbh_cnt = atomic_read(&__sparc_bh_counter);
@@ -436,18 +433,20 @@ void handler_irq(int irq, struct pt_regs * regs)
        struct irqaction * action;
        int cpu = smp_processor_id();
 #ifdef __SMP__
-       extern void smp_irq_rotate(int cpu);
+       extern void smp4m_irq_rotate(int cpu);
 #endif
-       
+
        disable_pil_irq(irq);
+#if 0 /* FIXME: rotating IRQs halts the machine during SCSI probe. -ecd */
 #ifdef __SMP__
        /* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */
        if(irq < 10)
-               smp_irq_rotate(cpu);
+               smp4m_irq_rotate(cpu);
+#endif
 #endif
        irq_enter(cpu, irq, regs);
        action = *(irq + irq_action);
-       kstat.interrupts[irq]++;
+       kstat.irqs[cpu][irq]++;
        do {
                if (!action || !action->handler)
                        unexpected_irq(irq, 0, regs);
@@ -467,6 +466,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
 
        disable_pil_irq(irq);
        irq_enter(cpu, irq, regs);
+       kstat.irqs[cpu][irq]++;
        floppy_interrupt(irq, dev_id, regs);
        irq_exit(cpu, irq);
        enable_pil_irq(irq);
@@ -667,6 +667,7 @@ __initfunc(void init_IRQ(void))
     
        switch(sparc_cpu_model) {
        case sun4c:
+       case sun4:
                sun4c_init_IRQ();
                break;
 
@@ -688,4 +689,5 @@ __initfunc(void init_IRQ(void))
                prom_printf("Cannot initialize IRQ's on this Sun machine...");
                break;
        }
+       btfixup();
 }
index 32feff3debb470951d32387a6c0b62a2b4937e4b..8d4c29e623185688a98d3d752f4f0d607e94be00 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.102 1997/12/01 03:36:31 davem Exp $
+/*  $Id: process.c,v 1.110 1998/04/08 16:15:51 jj Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -40,6 +40,7 @@
 #include <asm/elf.h>
 
 extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
+extern void srmmu_check_pgt_cache(void);
 
 struct task_struct *current_set[NR_CPUS] = {&init_task, };
 
@@ -62,7 +63,7 @@ asmlinkage int sys_idle(void)
        current->priority = -100;
        current->counter = -100;
        for (;;) {
-               if (sparc_cpu_model == sun4c) {
+               if (ARCH_SUN4C_SUN4) {
                        static int count = HZ;
                        static unsigned long last_jiffies = 0;
                        static unsigned long last_faults = 0;
@@ -91,7 +92,9 @@ asmlinkage int sys_idle(void)
                                }
                        }
                        restore_flags(flags);
-               }
+                       check_pgt_cache();
+               } else
+                       srmmu_check_pgt_cache();
                schedule();
        }
        ret = 0;
@@ -109,6 +112,7 @@ int cpu_idle(void *unused)
 
        current->priority = -100;
        while(1) {
+               srmmu_check_pgt_cache();
                /*
                 * tq_scheduler currently assumes we're running in a process
                 * context (ie that we hold the kernel lock..)
@@ -187,12 +191,12 @@ void machine_power_off(void)
 
 void show_regwindow(struct reg_window *rw)
 {
-       printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx\n"
+       printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
               "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
               rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
               rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
-       printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx\n"
-              "i4: %08lx i5: %08lx i6: %08lx i7: %08lx\n",
+       printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
+              "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
               rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
               rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
 }
@@ -201,15 +205,13 @@ void show_regwindow(struct reg_window *rw)
 static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED;
 #endif
 
-void show_backtrace(void)
+void __show_backtrace(unsigned long fp)
 {
        struct reg_window *rw;
        unsigned long flags;
-       unsigned long fp;
        int cpu = smp_processor_id();
 
        spin_lock_irqsave(&sparc_backtrace_lock, flags);
-       __asm__ __volatile__("mov %%i6, %0" : "=r" (fp));
        rw = (struct reg_window *) fp;
        while(rw) {
                printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
@@ -223,6 +225,31 @@ void show_backtrace(void)
        spin_unlock_irqrestore(&sparc_backtrace_lock, flags);
 }
 
+void show_backtrace(void)
+{
+       unsigned long fp;
+
+       __asm__ __volatile__(
+               "save %%sp, -64, %%sp\n\t"
+               "save %%sp, -64, %%sp\n\t"
+               "save %%sp, -64, %%sp\n\t"
+               "save %%sp, -64, %%sp\n\t"
+               "save %%sp, -64, %%sp\n\t"
+               "save %%sp, -64, %%sp\n\t"
+               "save %%sp, -64, %%sp\n\t"
+               "save %%sp, -64, %%sp\n\t"
+               "restore\n\t"
+               "restore\n\t"
+               "restore\n\t"
+               "restore\n\t"
+               "restore\n\t"
+               "restore\n\t"
+               "restore\n\t"
+               "restore\n\t"
+               "mov %%i6, %0" : "=r" (fp));
+       __show_backtrace(fp);
+}
+
 #ifdef __SMP__
 void smp_show_backtrace_all_cpus(void)
 {
@@ -236,15 +263,15 @@ void show_stackframe(struct sparc_stackf *sf)
        unsigned long *stk;
        int i;
 
-       printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx\n"
+       printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
               "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
               sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3],
               sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]);
-       printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx\n"
-              "i4: %08lx i5: %08lx fp: %08lx ret_pc: %08lx\n",
+       printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
+              "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
               sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3],
               sf->ins[4], sf->ins[5], (unsigned long)sf->fp, sf->callers_pc);
-       printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx\n"
+       printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx "
               "x3: %08lx x4: %08lx x5: %08lx xx: %08lx\n",
               (unsigned long)sf->structptr, sf->xargs[0], sf->xargs[1],
               sf->xargs[2], sf->xargs[3], sf->xargs[4], sf->xargs[5],
@@ -265,36 +292,32 @@ void show_regs(struct pt_regs * regs)
 #endif
         printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx\n", regs->psr,
               regs->pc, regs->npc, regs->y);
-       printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx\n",
+       printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx ",
               regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
               regs->u_regs[3]);
        printk("g4: %08lx g5: %08lx g6: %08lx g7: %08lx\n",
               regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
               regs->u_regs[7]);
-       printk("o0: %08lx o1: %08lx o2: %08lx o3: %08lx\n",
+       printk("o0: %08lx o1: %08lx o2: %08lx o3: %08lx ",
               regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
               regs->u_regs[11]);
-       printk("o4: %08lx o5: %08lx sp: %08lx ret_pc: %08lx\n",
+       printk("o4: %08lx o5: %08lx sp: %08lx o7: %08lx\n",
               regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
               regs->u_regs[15]);
        show_regwindow((struct reg_window *)regs->u_regs[14]);
 }
 
+#if NOTUSED
 void show_thread(struct thread_struct *tss)
 {
        int i;
 
-       printk("uwinmask:          0x%08lx\n", tss->uwinmask);
-       printk("kregs:             0x%08lx\n", (unsigned long)tss->kregs);
+       printk("uwinmask:          0x%08lx  kregs:             0x%08lx\n", tss->uwinmask, (unsigned long)tss->kregs);
        show_regs(tss->kregs);
-       printk("sig_address:       0x%08lx\n", tss->sig_address);
-       printk("sig_desc:          0x%08lx\n", tss->sig_desc);
-       printk("ksp:               0x%08lx\n", tss->ksp);
-       printk("kpc:               0x%08lx\n", tss->kpc);
-       printk("kpsr:              0x%08lx\n", tss->kpsr);
-       printk("kwim:              0x%08lx\n", tss->kwim);
-       printk("fork_kpsr:         0x%08lx\n", tss->fork_kpsr);
-       printk("fork_kwim:         0x%08lx\n", tss->fork_kwim);
+       printk("sig_address:       0x%08lx  sig_desc:          0x%08lx\n", tss->sig_address, tss->sig_desc);
+       printk("ksp:               0x%08lx  kpc:               0x%08lx\n", tss->ksp, tss->kpc);
+       printk("kpsr:              0x%08lx  kwim:              0x%08lx\n", tss->kpsr, tss->kwim);
+       printk("fork_kpsr:         0x%08lx  fork_kwim:         0x%08lx\n", tss->fork_kpsr, tss->fork_kwim);
 
        for (i = 0; i < NSWINS; i++) {
                if (!tss->rwbuf_stkptrs[i])
@@ -306,19 +329,19 @@ void show_thread(struct thread_struct *tss)
        printk("w_saved:           0x%08lx\n", tss->w_saved);
 
        /* XXX missing: float_regs */
-       printk("fsr:               0x%08lx\n", tss->fsr);
-       printk("fpqdepth:          0x%08lx\n", tss->fpqdepth);
+       printk("fsr:               0x%08lx  fpqdepth:          0x%08lx\n", tss->fsr, tss->fpqdepth);
        /* XXX missing: fpqueue */
 
-       printk("sstk_info.stack:   0x%08lx\n",
-               (unsigned long)tss->sstk_info.the_stack);
-       printk("sstk_info.status:  0x%08lx\n",
-               (unsigned long)tss->sstk_info.cur_status);
-       printk("flags:             0x%08lx\n", tss->flags);
-       printk("current_ds:        0x%08x\n", tss->current_ds);
+       printk("sstk_info.stack:   0x%08lx  sstk_info.status:  0x%08lx\n", 
+                                                               (unsigned long)tss->sstk_info.the_stack,
+                                                               (unsigned long)tss->sstk_info.cur_status);
+       printk("flags:             0x%08lx  current_ds:        0x%08lx\n", tss->flags, tss->current_ds.seg);
+       
+       show_regwindow((struct reg_window *)tss->ksp);
 
        /* XXX missing: core_exec */
 }
+#endif
 
 /*
  * Free current thread data structures etc..
@@ -367,8 +390,11 @@ void flush_thread(void)
        }
 
        /* Now, this task is no longer a kernel thread. */
-       current->tss.flags &= ~SPARC_FLAG_KTHREAD;
        current->tss.current_ds = USER_DS;
+       if (current->tss.flags & SPARC_FLAG_KTHREAD) {
+               current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+               switch_to_context(current);
+       }
 }
 
 static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src)
@@ -475,7 +501,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
        }
 
        /* Calculate offset to stack_frame & pt_regs */
-       stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ);
+       stack_offset = TASK_UNION_SIZE - TRACEREG_SZ;
 
        if(regs->psr & PSR_PS)
                stack_offset -= REGWIN_SZ;
index 68f3dc9af09f0d458d445766c08ad07bb3eed375..3c0d311ba3b6b32345c0b69d96163168a517cd2c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.49 1997/12/14 23:24:24 ecd Exp $
+/* $Id: rtrap.S,v 1.50 1998/02/05 14:18:43 jj Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -296,9 +296,8 @@ sun4c_rett_onepage:
 
        .globl  C_LABEL(srmmu_rett_stackchk)
 C_LABEL(srmmu_rett_stackchk):
-       sethi   %hi(C_LABEL(page_offset)), %g1
        bne     ret_trap_user_stack_is_bolixed
-        ld     [%g1 + %lo(C_LABEL(page_offset))], %g1
+        GET_PAGE_OFFSET(g1)
        cmp     %g1, %fp
        bleu    ret_trap_user_stack_is_bolixed
         mov    AC_M_SFSR, %g1
index 06c028395d937a98c91dd0c5ddb16134d3d08959..4da88bd0e0593ae4207110a151edf78973a3f54d 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/errno.h>
 #include <asm/winmacro.h>
 #include <asm/psr.h>
+#include <asm/page.h>
 
 #define CC_AND_RETT  \
        set     PSR_C, %l4; \
@@ -94,7 +95,7 @@ LABEL(sunossmask):
 
        .globl  LABEL(getpagesize)
 LABEL(getpagesize):
-       set     4096, %i0
+       set     PAGE_SIZE, %i0
        CC_AND_RETT
 
        /* XXX sys_nice() XXX */
index e53c343da153222f3a503769f5312355731c701a..b5625cd1224f2c4e98bfa7ae0f74e3bfe54c66c6 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.87 1997/12/18 02:42:42 ecd Exp $
+/*  $Id: setup.c,v 1.93 1998/03/09 14:03:18 jj Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -43,6 +43,7 @@
 #include <asm/spinlock.h>
 #include <asm/softirq.h>
 #include <asm/hardirq.h>
+#include <asm/machines.h>
 
 struct screen_info screen_info = {
        0, 0,                   /* orig-x, orig-y */
@@ -58,11 +59,6 @@ struct screen_info screen_info = {
 
 unsigned int phys_bytes_of_ram, end_of_phys_memory;
 
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
-       return memory_start;
-}
-
 /* Typing sync at the prom prompt calls the function pointed to by
  * romvec->pv_synchook which I set to the following function.
  * This should sync all filesystems and return, for now it just
@@ -127,7 +123,7 @@ unsigned int boot_flags;
 extern char *console_fb_path;
 static int console_fb = 0;
 #endif
-static unsigned long memory_size = 0;
+static unsigned long memory_size __initdata = 0;
 
 void kernel_enter_debugger(void)
 {
@@ -260,7 +256,7 @@ extern void sun4c_probe_vac(void);
 extern char cputypval;
 extern unsigned long start, end;
 extern void panic_setup(char *, int *);
-extern unsigned long srmmu_endmem_fixup(unsigned long);
+extern void srmmu_end_memory(unsigned long, unsigned long *);
 extern unsigned long sun_serial_setup(unsigned long);
 
 extern unsigned short root_flags;
@@ -311,6 +307,13 @@ __initfunc(void setup_arch(char **cmdline_p,
        if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
        if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
        if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
+
+#ifdef CONFIG_SUN4
+       if (sparc_cpu_model != sun4) {
+               prom_printf("This kernel is for Sun4 architecture only.\n");
+               prom_halt();
+       }
+#endif
 #if CONFIG_AP1000
        sparc_cpu_model=ap1000;
        strcpy(&cputypval, "ap+");
@@ -320,12 +323,10 @@ __initfunc(void setup_arch(char **cmdline_p,
        switch(sparc_cpu_model) {
        case sun4:
                printk("SUN4\n");
-               sun4c_probe_vac();
                packed = 0;
                break;
        case sun4c:
                printk("SUN4C\n");
-               sun4c_probe_vac();
                packed = 0;
                break;
        case sun4m:
@@ -356,6 +357,8 @@ __initfunc(void setup_arch(char **cmdline_p,
        boot_flags_init(*cmdline_p);
 
        idprom_init();
+       if (ARCH_SUN4C_SUN4)
+               sun4c_probe_vac();
        load_mmu();
        total = prom_probe_memory();
        *memory_start_p = (((unsigned long) &end));
@@ -374,41 +377,37 @@ __initfunc(void setup_arch(char **cmdline_p,
                                }
                        }
                }
-       } else {
-               unsigned int sum = 0;
+               *memory_end_p = (end_of_phys_memory + KERNBASE);
+       } else
+               srmmu_end_memory(memory_size, memory_end_p);
 
-               for(i = 0; sp_banks[i].num_bytes != 0; i++) {
-                       sum += sp_banks[i].num_bytes;
-                       if (memory_size) {
-                               if (sum > memory_size) {
-                                       sp_banks[i].num_bytes -=
-                                                       (sum - memory_size);
-                                       sum = memory_size;
-                                       sp_banks[++i].base_addr = 0xdeadbeef;
-                                       sp_banks[i].num_bytes = 0;
-                                       break;
-                               }
-                       }
+       if (!root_flags)
+               root_mountflags &= ~MS_RDONLY;
+       ROOT_DEV = to_kdev_t(root_dev);
+#ifdef CONFIG_BLK_DEV_RAM
+       rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
+       rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
+       rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (ramdisk_image) {
+               initrd_start = ramdisk_image;
+               if (initrd_start < KERNBASE) initrd_start += KERNBASE;
+               initrd_end = initrd_start + ramdisk_size;
+               if (initrd_end > *memory_end_p) {
+                       printk(KERN_CRIT "initrd extends beyond end of memory "
+                                        "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+                                        initrd_end,*memory_end_p);
+                       initrd_start = 0;
+               }
+               if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) {
+                       initrd_below_start_ok = 1;
+                       *memory_start_p = PAGE_ALIGN (initrd_end);
                }
-               end_of_phys_memory = sum;
        }
-
+#endif 
        prom_setsync(prom_sync_me);
 
-       *memory_end_p = (end_of_phys_memory + KERNBASE);
-       if((sparc_cpu_model == sun4c) ||
-          (sparc_cpu_model == sun4))
-               goto not_relevant;
-       if(end_of_phys_memory >= 0x0d000000) {
-               *memory_end_p = 0xfd000000;
-       } else {
-               if((sparc_cpu_model == sun4m) ||
-                  (sparc_cpu_model == sun4d) ||
-                  (sparc_cpu_model == ap1000))
-                       *memory_end_p = srmmu_endmem_fixup(*memory_end_p);
-       }
-not_relevant:
-               
 #ifdef CONFIG_SUN_SERIAL
        *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
 #endif
@@ -459,31 +458,6 @@ not_relevant:
                breakpoint();
        }
 
-       if (!root_flags)
-               root_mountflags &= ~MS_RDONLY;
-       ROOT_DEV = to_kdev_t(root_dev);
-#ifdef CONFIG_BLK_DEV_RAM
-       rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
-       rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
-       rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (ramdisk_image) {
-               initrd_start = ramdisk_image;
-               if (initrd_start < KERNBASE) initrd_start += KERNBASE;
-               initrd_end = initrd_start + ramdisk_size;
-               if (initrd_end > *memory_end_p) {
-                       printk(KERN_CRIT "initrd extends beyond end of memory "
-                                        "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-                                        initrd_end,*memory_end_p);
-                       initrd_start = 0;
-               }
-               if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) {
-                       initrd_below_start_ok = 1;
-                       *memory_start_p = PAGE_ALIGN (initrd_end);
-               }
-       }
-#endif 
 
        /* Due to stack alignment restrictions and assumptions... */
        init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
@@ -504,13 +478,12 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 extern char *sparc_cpu_type[];
 extern char *sparc_fpu_type[];
 
-extern char *smp_info(void);
-
 int get_cpuinfo(char *buffer)
 {
-       int cpuid=get_cpuid();
+       int cpuid=hard_smp_processor_id();
+       int len;
 
-       return sprintf(buffer, "cpu\t\t: %s\n"
+       len = sprintf(buffer, "cpu\t\t: %s\n"
             "fpu\t\t: %s\n"
             "promlib\t\t: Version %d Revision %d\n"
             "prom\t\t: %d.%d\n"
@@ -519,34 +492,23 @@ int get_cpuinfo(char *buffer)
            "ncpus active\t: %d\n"
 #ifndef __SMP__
             "BogoMips\t: %lu.%02lu\n"
-#else
-           "Cpu0Bogo\t: %lu.%02lu\n"
-           "Cpu1Bogo\t: %lu.%02lu\n"
-           "Cpu2Bogo\t: %lu.%02lu\n"
-           "Cpu3Bogo\t: %lu.%02lu\n"
-#endif
-           "%s"
-#ifdef __SMP__
-           "%s"
 #endif
            ,
-            sparc_cpu_type[cpuid],
-            sparc_fpu_type[cpuid],
+           sparc_cpu_type[cpuid] ? : "undetermined",
+           sparc_fpu_type[cpuid] ? : "undetermined",
             romvec->pv_romvers, prom_rev, romvec->pv_printrev >> 16, (short)romvec->pv_printrev,
             &cputypval,
-           linux_num_cpus, smp_num_cpus,
+           linux_num_cpus, smp_num_cpus
 #ifndef __SMP__
-            loops_per_sec/500000, (loops_per_sec/5000) % 100,
-#else
-           cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100,
-           cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100,
-           cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100,
-           cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100,
+           , loops_per_sec/500000, (loops_per_sec/5000) % 100
 #endif
-           mmu_info()
+           );
 #ifdef __SMP__
-           , smp_info()
+       len += smp_bogo_info(buffer + len);
 #endif
-            );
-
+       len += mmu_info(buffer + len);
+#ifdef __SMP__
+       len += smp_info(buffer + len);
+#endif
+       return len;
 }
index 5c10faa816ae9f5de4a5b4828b3a163f30ffd4a9..efdb362a42fe73ada4ee8622bcb97bd708699b28 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.77 1997/12/22 03:06:32 ecd Exp $
+/*  $Id: signal.c,v 1.79 1998/04/04 07:11:41 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -78,9 +78,20 @@ struct new_signal_frame {
        __siginfo_fpu_t         fpu_state;
 };
 
+struct rt_signal_frame {
+       struct sparc_stackf     ss;
+       siginfo_t               info;
+       struct pt_regs          regs;
+       sigset_t                mask;
+       __siginfo_fpu_t         *fpu_save;
+       unsigned int            insns [2];
+       __siginfo_fpu_t         fpu_state;
+};
+
 /* Align macros */
 #define SF_ALIGNEDSZ  (((sizeof(struct signal_sframe) + 7) & (~7)))
 #define NF_ALIGNEDSZ  (((sizeof(struct new_signal_frame) + 7) & (~7)))
+#define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame) + 7) & (~7)))
 
 /*
  * atomically swap in the new signal mask, and wait for a signal.
@@ -318,7 +329,60 @@ segv_and_exit:
 
 asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
 {
-       printk("XXX: FIXME: write do_rt_sigreturn\n");
+       struct rt_signal_frame *sf;
+       unsigned int psr, pc, npc;
+       __siginfo_fpu_t *fpu_save;
+       sigset_t set;
+
+       synchronize_user_stack();
+       sf = (struct rt_signal_frame *) regs->u_regs[UREG_FP];
+       if(verify_area(VERIFY_READ, sf, sizeof(*sf)) ||
+          (((unsigned long) sf) & 0x03))
+               goto segv;
+
+       get_user(pc, &sf->regs.pc);
+       __get_user(npc, &sf->regs.npc);
+       if((pc | npc) & 0x03)
+               goto segv;
+
+       regs->pc = pc;
+       regs->npc = npc;
+
+       __get_user(regs->y, &sf->regs.y);
+       __get_user(psr, &sf->regs.psr);
+
+       __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]);
+       __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]);
+       __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]);
+       __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]);
+       __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]);
+       __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]);
+       __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]);
+       __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]);
+       __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]);
+       __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]);
+       __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]);
+       __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]);
+       __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]);
+       __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]);
+       __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]);
+
+       regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC);
+
+       __get_user(fpu_save, &sf->fpu_save);
+       if(fpu_save)
+               restore_fpu_state(regs, &sf->fpu_state);
+       if(copy_from_user(&set, &sf->mask, sizeof(sigset_t)))
+               goto segv;
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sigmask_lock);
+       current->blocked = set;
+       recalc_sigpending(current);
+       spin_unlock_irq(&current->sigmask_lock);
+       return;
+segv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 /* Checks if the fp is valid */
@@ -514,7 +578,63 @@ static inline void
 new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
                   int signo, sigset_t *oldset, siginfo_t *info)
 {
-       printk("XXX: FIXME: new_setup_rt_frame unimplemented\n");
+       struct rt_signal_frame *sf;
+       int sigframe_size;
+       unsigned int psr;
+       int i;
+
+       synchronize_user_stack();
+       sigframe_size = RT_ALIGNEDSZ;
+       if(!current->used_math)
+               sigframe_size -= sizeof(__siginfo_fpu_t);
+       sf = (struct rt_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
+       if(invalid_frame_pointer(sf, sigframe_size))
+               goto sigill;
+       if(current->tss.w_saved != 0)
+               goto sigill;
+
+       put_user(regs->pc, &sf->regs.pc);
+       __put_user(regs->npc, &sf->regs.npc);
+       __put_user(regs->y, &sf->regs.y);
+       psr = regs->psr;
+       if(current->used_math)
+               psr |= PSR_EF;
+       __put_user(psr, &sf->regs.psr);
+       for(i = 0; i < 16; i++)
+               __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+       if(psr & PSR_EF) {
+               save_fpu_state(regs, &sf->fpu_state);
+               __put_user(&sf->fpu_state, &sf->fpu_save);
+       } else {
+               __put_user(0, &sf->fpu_save);
+       }
+       __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
+       copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+                    sizeof (struct reg_window));       
+
+       regs->u_regs[UREG_FP] = (unsigned long) sf;
+       regs->u_regs[UREG_I0] = signo;
+       regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+
+       regs->pc = (unsigned long) ka->sa.sa_handler;
+       regs->npc = (regs->pc + 4);
+
+       if(ka->ka_restorer)
+               regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+       else {
+               regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
+
+               __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+               __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+
+               /* Flush instruction space. */
+               flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+       }
+       return;
+
+sigill:
+       lock_kernel();
+       do_exit(SIGILL);
 }
 
 /* Setup a Solaris stack frame */
@@ -783,6 +903,7 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
                spin_lock_irq(&current->sigmask_lock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
                sigaddset(&current->blocked, signr);
+               recalc_sigpending(current);
                spin_unlock_irq(&current->sigmask_lock);
        }
 }
index 15364d44fde34c9a16603cd95aa867c63bdcf180..7013004a35ed0ce16075c496f461768cd41c8499 100644 (file)
@@ -1,6 +1,7 @@
 /* smp.c: Sparc SMP support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/config.h> /* for CONFIG_PROFILE */
@@ -13,6 +14,7 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/init.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 #define IRQ_STOP_CPU           14
 #define IRQ_CROSS_CALL         15
 
-extern ctxd_t *srmmu_ctx_table_phys;
-extern int linux_num_cpus;
-
-extern void calibrate_delay(void);
-
-/* XXX Let's get rid of this thing if we can... */
-extern struct task_struct *current_set[NR_CPUS];
-
 volatile int smp_processors_ready = 0;
-
 unsigned long cpu_present_map = 0;
 int smp_num_cpus = 1;
 int smp_threads_ready=0;
 unsigned char mid_xlate[NR_CPUS] = { 0, 0, 0, 0, };
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
+volatile unsigned long cpu_callin_map[NR_CPUS] __initdata = {0,};
+#ifdef NOTUSED
 volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
+#endif
 unsigned long smp_proc_in_lock[NR_CPUS] = { 0, };
 struct cpuinfo_sparc cpu_data[NR_CPUS];
-static unsigned char boot_cpu_id = 0;
-static int smp_activated = 0;
+unsigned long cpu_offset[NR_CPUS];
+unsigned char boot_cpu_id = 0;
+unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
+int smp_activated = 0;
 volatile int cpu_number_map[NR_CPUS];
-volatile int cpu_logical_map[NR_CPUS];
+volatile int __cpu_logical_map[NR_CPUS];
 
 /* The only guaranteed locking primitive available on all Sparc
  * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
  * places the current byte at the effective address into dest_reg and
  * places 0xff there afterwards.  Pretty lame locking primitive
- * compared to the Alpha and the intel no?  Most Sparcs have 'swap'
+ * compared to the Alpha and the Intel no?  Most Sparcs have 'swap'
  * instruction which is much better...
  */
 struct klock_info klock_info = { KLOCK_CLEAR, 0 };
@@ -69,42 +66,11 @@ struct klock_info klock_info = { KLOCK_CLEAR, 0 };
 volatile unsigned long ipi_count;
 
 volatile int smp_process_available=0;
-
-/*#define SMP_DEBUG*/
-
-#ifdef SMP_DEBUG
-#define SMP_PRINTK(x)  printk x
-#else
-#define SMP_PRINTK(x)
-#endif
-
 volatile int smp_commenced = 0;
 
-static char smp_buf[512];
-
 /* Not supported on Sparc yet. */
-void smp_setup(char *str, int *ints)
-{
-}
-
-char *smp_info(void)
-{
-       sprintf(smp_buf,
-"        CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
-"State:  %s\t\t%s\t\t%s\t\t%s\n",
-(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline",
-(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline",
-(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline",
-(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline");
-       return smp_buf;
-}
-
-static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
+__initfunc(void smp_setup(char *str, int *ints))
 {
-       __asm__ __volatile__("swap [%1], %0\n\t" :
-                            "=&r" (val), "=&r" (ptr) :
-                            "0" (val), "1" (ptr));
-       return val;
 }
 
 /*
@@ -112,12 +78,12 @@ static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
  *     a given CPU
  */
 
-void smp_store_cpu_info(int id)
+__initfunc(void smp_store_cpu_info(int id))
 {
        cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */
 }
 
-void smp_commence(void)
+__initfunc(void smp_commence(void))
 {
        /*
         *      Lets the callin's below out of their loop.
@@ -129,65 +95,19 @@ void smp_commence(void)
        local_flush_tlb_all();
 }
 
-static void smp_setup_percpu_timer(void);
-
-void smp_callin(void)
-{
-       int cpuid = hard_smp_processor_id();
-
-       local_flush_cache_all();
-       local_flush_tlb_all();
-       set_irq_udt(mid_xlate[boot_cpu_id]);
-
-       /* Get our local ticker going. */
-       smp_setup_percpu_timer();
-
-       calibrate_delay();
-       smp_store_cpu_info(cpuid);
-       local_flush_cache_all();
-       local_flush_tlb_all();
-
-       /* Allow master to continue. */
-       swap((unsigned long *)&cpu_callin_map[cpuid], 1);
-       local_flush_cache_all();
-       local_flush_tlb_all();
-
-       while(!task[cpuid] || current_set[cpuid] != task[cpuid])
-               barrier();
-
-       /* Fix idle thread fields. */
-       __asm__ __volatile__("ld [%0], %%g6\n\t"
-                            : : "r" (&current_set[cpuid])
-                            : "memory" /* paranoid */);
-       current->mm->mmap->vm_page_prot = PAGE_SHARED;
-       current->mm->mmap->vm_start = PAGE_OFFSET;
-       current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
-       
-       while(!smp_commenced)
-               barrier();
-
-       local_flush_cache_all();
-       local_flush_tlb_all();
-
-       __sti();
-}
-
-extern int cpu_idle(void *unused);
-extern void init_IRQ(void);
-
 /* Only broken Intel needs this, thus it should not even be referenced
  * globally...
  */
-void initialize_secondary(void)
+__initfunc(void initialize_secondary(void))
 {
 }
 
+extern int cpu_idle(void *unused);
+
 /* Activate a secondary processor. */
 int start_secondary(void *unused)
 {
-       trap_init();
-       init_IRQ();
-       smp_callin();
+       prom_printf("Start secondary called. Should not happen\n");
        return cpu_idle(NULL);
 }
 
@@ -201,255 +121,25 @@ void cpu_panic(void)
  *     Cycle through the processors asking the PROM to start each one.
  */
  
-extern struct prom_cpuinfo linux_cpus[NCPUS];
-static struct linux_prom_registers penguin_ctable;
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+struct linux_prom_registers smp_penguin_ctable __initdata = { 0 };
 
-void smp_boot_cpus(void)
+__initfunc(void smp_boot_cpus(void))
 {
-       int cpucount = 0;
-       int i = 0;
-       int first, prev;
-
-       printk("Entering SMP Mode...\n");
-
-       penguin_ctable.which_io = 0;
-       penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
-       penguin_ctable.reg_size = 0;
-
-       __sti();
-       cpu_present_map = 0;
-       for(i=0; i < linux_num_cpus; i++)
-               cpu_present_map |= (1<<i);
-       for(i=0; i < NR_CPUS; i++)
-               cpu_number_map[i] = -1;
-       for(i=0; i < NR_CPUS; i++)
-               cpu_logical_map[i] = -1;
-       mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
-       cpu_number_map[boot_cpu_id] = 0;
-       cpu_logical_map[0] = boot_cpu_id;
-       klock_info.akp = boot_cpu_id;
-       current->processor = boot_cpu_id;
-       smp_store_cpu_info(boot_cpu_id);
-       set_irq_udt(mid_xlate[boot_cpu_id]);
-       smp_setup_percpu_timer();
-       local_flush_cache_all();
-       if(linux_num_cpus == 1)
-               return;  /* Not an MP box. */
-       for(i = 0; i < NR_CPUS; i++) {
-               if(i == boot_cpu_id)
-                       continue;
-
-               if(cpu_present_map & (1 << i)) {
-                       extern unsigned long sparc_cpu_startup;
-                       unsigned long *entry = &sparc_cpu_startup;
-                       struct task_struct *p;
-                       int timeout;
-
-                       /* Cook up an idler for this guy. */
-                       kernel_thread(start_secondary, NULL, CLONE_PID);
-
-                       p = task[++cpucount];
-
-                       p->processor = i;
-                       current_set[i] = p;
-
-                       /* See trampoline.S for details... */
-                       entry += ((i-1) * 3);
-
-                       /* whirrr, whirrr, whirrrrrrrrr... */
-                       printk("Starting CPU %d at %p\n", i, entry);
-                       mid_xlate[i] = (linux_cpus[i].mid & ~8);
-                       local_flush_cache_all();
-                       prom_startcpu(linux_cpus[i].prom_node,
-                                     &penguin_ctable, 0, (char *)entry);
-
-                       /* wheee... it's going... */
-                       for(timeout = 0; timeout < 5000000; timeout++) {
-                               if(cpu_callin_map[i])
-                                       break;
-                               udelay(100);
-                       }
-                       if(cpu_callin_map[i]) {
-                               /* Another "Red Snapper". */
-                               cpu_number_map[i] = i;
-                               cpu_logical_map[i] = i;
-                       } else {
-                               cpucount--;
-                               printk("Processor %d is stuck.\n", i);
-                       }
-               }
-               if(!(cpu_callin_map[i])) {
-                       cpu_present_map &= ~(1 << i);
-                       cpu_number_map[i] = -1;
-               }
-       }
-       local_flush_cache_all();
-       if(cpucount == 0) {
-               printk("Error: only one Processor found.\n");
-               cpu_present_map = (1 << smp_processor_id());
-       } else {
-               unsigned long bogosum = 0;
-               for(i = 0; i < NR_CPUS; i++) {
-                       if(cpu_present_map & (1 << i))
-                               bogosum += cpu_data[i].udelay_val;
-               }
-               printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
-                      cpucount + 1,
-                      (bogosum + 2500)/500000,
-                      ((bogosum + 2500)/5000)%100);
-               smp_activated = 1;
-               smp_num_cpus = cpucount + 1;
-       }
-
-       /* Setup CPU list for IRQ distribution scheme. */
-       first = prev = -1;
-       for(i = 0; i < NR_CPUS; i++) {
-               if(cpu_present_map & (1 << i)) {
-                       if(first == -1)
-                               first = i;
-                       if(prev != -1)
-                               cpu_data[i].next = i;
-                       cpu_data[i].mid = mid_xlate[i];
-                       prev = i;
-               }
-       }
-       cpu_data[prev].next = first;
-
-       /* Ok, they are spinning and ready to go. */
-       smp_processors_ready = 1;
-}
-
-/* At each hardware IRQ, we get this called to forward IRQ reception
- * to the next processor.  The caller must disable the IRQ level being
- * serviced globally so that there are no double interrupts received.
- */
-void smp_irq_rotate(int cpu)
-{
-       if(smp_processors_ready)
-               set_irq_udt(cpu_data[cpu_data[cpu].next].mid);
-}
-
-/* Cross calls, in order to work efficiently and atomically do all
- * the message passing work themselves, only stopcpu and reschedule
- * messages come through here.
- */
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
-{
-       static unsigned long smp_cpu_in_msg[NR_CPUS];
-       unsigned long mask;
-       int me = smp_processor_id();
-       int irq, i;
-
-       if(msg == MSG_RESCHEDULE) {
-               irq = IRQ_RESCHEDULE;
-
-               if(smp_cpu_in_msg[me])
-                       return;
-       } else if(msg == MSG_STOP_CPU) {
-               irq = IRQ_STOP_CPU;
-       } else {
-               goto barf;
-       }
-
-       smp_cpu_in_msg[me]++;
-       if(target == MSG_ALL_BUT_SELF || target == MSG_ALL) {
-               mask = cpu_present_map;
-               if(target == MSG_ALL_BUT_SELF)
-                       mask &= ~(1 << me);
-               for(i = 0; i < 4; i++) {
-                       if(mask & (1 << i))
-                               set_cpu_int(mid_xlate[i], irq);
-               }
-       } else {
-               set_cpu_int(mid_xlate[target], irq);
-       }
-       smp_cpu_in_msg[me]--;
-
-       return;
-barf:
-       printk("Yeeee, trying to send SMP msg(%d) on cpu %d\n", msg, me);
-       panic("Bogon SMP message pass.");
-}
-
-struct smp_funcall {
-       smpfunc_t func;
-       unsigned long arg1;
-       unsigned long arg2;
-       unsigned long arg3;
-       unsigned long arg4;
-       unsigned long arg5;
-       unsigned long processors_in[NR_CPUS];  /* Set when ipi entered. */
-       unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */
-} ccall_info;
-
-static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED;
-
-/* Cross calls must be serialized, at least currently. */
-void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-                   unsigned long arg3, unsigned long arg4, unsigned long arg5)
-{
-       if(smp_processors_ready) {
-               register int ncpus = smp_num_cpus;
-               unsigned long flags;
-
-               spin_lock_irqsave(&cross_call_lock, flags);
-
-               /* Init function glue. */
-               ccall_info.func = func;
-               ccall_info.arg1 = arg1;
-               ccall_info.arg2 = arg2;
-               ccall_info.arg3 = arg3;
-               ccall_info.arg4 = arg4;
-               ccall_info.arg5 = arg5;
-
-               /* Init receive/complete mapping, plus fire the IPI's off. */
-               {
-                       register void (*send_ipi)(int,int) = set_cpu_int;
-                       register unsigned long mask;
-                       register int i;
-
-                       mask = (cpu_present_map & ~(1 << smp_processor_id()));
-                       for(i = 0; i < ncpus; i++) {
-                               if(mask & (1 << i)) {
-                                       ccall_info.processors_in[i] = 0;
-                                       ccall_info.processors_out[i] = 0;
-                                       send_ipi(mid_xlate[i], IRQ_CROSS_CALL);
-                               } else {
-                                       ccall_info.processors_in[i] = 1;
-                                       ccall_info.processors_out[i] = 1;
-                               }
-                       }
-               }
-
-               /* First, run local copy. */
-               func(arg1, arg2, arg3, arg4, arg5);
-
-               {
-                       register int i;
-
-                       i = 0;
-                       do {
-                               while(!ccall_info.processors_in[i])
-                                       barrier();
-                       } while(++i < ncpus);
-
-                       i = 0;
-                       do {
-                               while(!ccall_info.processors_out[i])
-                                       barrier();
-                       } while(++i < ncpus);
-               }
-
-               spin_unlock_irqrestore(&cross_call_lock, flags);
-       } else
-               func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
+       extern void smp4m_boot_cpus(void);
+       extern void smp4d_boot_cpus(void);
+       
+       if (sparc_cpu_model == sun4m)
+               smp4m_boot_cpus();
+       else
+               smp4d_boot_cpus();
 }
 
 void smp_flush_cache_all(void)
-{ xc0((smpfunc_t) local_flush_cache_all); }
+{ xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all)); }
 
 void smp_flush_tlb_all(void)
-{ xc0((smpfunc_t) local_flush_tlb_all); }
+{ xc0((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_all)); }
 
 void smp_flush_cache_mm(struct mm_struct *mm)
 { 
@@ -457,7 +147,7 @@ void smp_flush_cache_mm(struct mm_struct *mm)
                if(mm->cpu_vm_mask == (1 << smp_processor_id()))
                        local_flush_cache_mm(mm);
                else
-                       xc1((smpfunc_t) local_flush_cache_mm, (unsigned long) mm);
+                       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm);
        }
 }
 
@@ -467,7 +157,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
                if(mm->cpu_vm_mask == (1 << smp_processor_id())) {
                        local_flush_tlb_mm(mm);
                } else {
-                       xc1((smpfunc_t) local_flush_tlb_mm, (unsigned long) mm);
+                       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
                        if(mm->count == 1 && current->mm == mm)
                                mm->cpu_vm_mask = (1 << smp_processor_id());
                }
@@ -481,7 +171,7 @@ void smp_flush_cache_range(struct mm_struct *mm, unsigned long start,
                if(mm->cpu_vm_mask == (1 << smp_processor_id()))
                        local_flush_cache_range(mm, start, end);
                else
-                       xc3((smpfunc_t) local_flush_cache_range, (unsigned long) mm,
+                       xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) mm,
                            start, end);
        }
 }
@@ -493,7 +183,7 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
                if(mm->cpu_vm_mask == (1 << smp_processor_id()))
                        local_flush_tlb_range(mm, start, end);
                else
-                       xc3((smpfunc_t) local_flush_tlb_range, (unsigned long) mm,
+                       xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) mm,
                            start, end);
        }
 }
@@ -506,7 +196,7 @@ void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
                if(mm->cpu_vm_mask == (1 << smp_processor_id()))
                        local_flush_cache_page(vma, page);
                else
-                       xc2((smpfunc_t) local_flush_cache_page,
+                       xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page),
                            (unsigned long) vma, page);
        }
 }
@@ -519,7 +209,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
                if(mm->cpu_vm_mask == (1 << smp_processor_id()))
                        local_flush_tlb_page(vma, page);
                else
-                       xc2((smpfunc_t) local_flush_tlb_page, (unsigned long) vma, page);
+                       xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page);
        }
 }
 
@@ -532,7 +222,7 @@ void smp_flush_page_to_ram(unsigned long page)
         * XXX This experiment failed, research further... -DaveM
         */
 #if 1
-       xc1((smpfunc_t) local_flush_page_to_ram, page);
+       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_to_ram), page);
 #else
        local_flush_page_to_ram(page);
 #endif
@@ -543,7 +233,7 @@ void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
        if(mm->cpu_vm_mask == (1 << smp_processor_id()))
                local_flush_sig_insns(mm, insn_addr);
        else
-               xc2((smpfunc_t) local_flush_sig_insns, (unsigned long) mm, insn_addr);
+               xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr);
 }
 
 /* Reschedule call back. */
@@ -552,17 +242,6 @@ void smp_reschedule_irq(void)
        need_resched = 1;
 }
 
-/* Running cross calls. */
-void smp_cross_call_irq(void)
-{
-       int i = smp_processor_id();
-
-       ccall_info.processors_in[i] = 1;
-       ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
-                       ccall_info.arg4, ccall_info.arg5);
-       ccall_info.processors_out[i] = 1;
-}
-
 /* Stopping processors. */
 void smp_stop_cpu_irq(void)
 {
@@ -571,84 +250,10 @@ void smp_stop_cpu_irq(void)
                barrier();
 }
 
-/* Protects counters touched during level14 ticker */
-spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
-
-#ifdef CONFIG_PROFILE
-
-/* 32-bit Sparc specific profiling function. */
-static inline void sparc_do_profile(unsigned long pc)
-{
-       if(prof_buffer && current->pid) {
-               extern int _stext;
-
-               pc -= (unsigned long) &_stext;
-               pc >>= prof_shift;
-
-               spin_lock(&ticker_lock);
-               if(pc < prof_len)
-                       prof_buffer[pc]++;
-               else
-                       prof_buffer[prof_len - 1]++;
-               spin_unlock(&ticker_lock);
-       }
-}
-
-#endif
-
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
-
-extern void update_one_process(struct task_struct *p, unsigned long ticks,
-                              unsigned long user, unsigned long system);
-
-void smp_percpu_timer_interrupt(struct pt_regs *regs)
-{
-       int cpu = smp_processor_id();
-
-       clear_profile_irq(mid_xlate[cpu]);
-#ifdef CONFIG_PROFILE
-       if(!user_mode(regs))
-               sparc_do_profile(regs->pc);
-#endif
-       if(!--prof_counter[cpu]) {
-               int user = user_mode(regs);
-               if(current->pid) {
-                       update_one_process(current, 1, user, !user);
-
-                       if(--current->counter < 0) {
-                               current->counter = 0;
-                               need_resched = 1;
-                       }
-
-                       spin_lock(&ticker_lock);
-                       if(user) {
-                               if(current->priority < DEF_PRIORITY)
-                                       kstat.cpu_nice++;
-                               else
-                                       kstat.cpu_user++;
-                       } else {
-                               kstat.cpu_system++;
-                       }
-                       spin_unlock(&ticker_lock);
-               }
-               prof_counter[cpu] = prof_multiplier[cpu];
-       }
-}
-
 extern unsigned int lvl14_resolution;
 
-static void smp_setup_percpu_timer(void)
-{
-       int cpu = smp_processor_id();
-
-       prof_counter[cpu] = prof_multiplier[cpu] = 1;
-       load_profile_irq(mid_xlate[cpu], lvl14_resolution);
-
-       if(cpu == boot_cpu_id)
-               enable_pil_irq(14);
-}
-
 int setup_profiling_timer(unsigned int multiplier)
 {
        int i;
index e259ffade80f84bb62ffb23af4afe76f2df02120..9426ec0d9f1c4c99fc0d16487e8200d4ad1b924c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.22 1998/01/07 06:33:48 baccala Exp $
+/* $Id: sparc-stub.c,v 1.24 1998/02/08 07:58:44 ecd Exp $
  * sparc-stub.c:  KGDB support for the Linux kernel.
  *
  * Modifications to run under Linux
@@ -165,9 +165,10 @@ unsigned long get_sun4csegmap(unsigned long addr)
        return entry;
 }
 
-static void flush_cache_all_nop(void)
-{
-}
+#if 0
+/* Have to sort this out. This cannot be done after initialization. */
+static void flush_cache_all_nop(void) {}
+#endif
 
 /* Place where we save old trap entries for restoration */
 struct tt_entry kgdb_savettable[256];
@@ -398,10 +399,12 @@ set_debug_traps(void)
 {
        struct hard_trap_info *ht;
        unsigned long flags;
-       unsigned char c;
 
        save_and_cli(flags);
-       flush_cache_all = flush_cache_all_nop;
+#if 0  
+/* Have to sort this out. This cannot be done after initialization. */
+       BTFIXUPSET_CALL(flush_cache_all, flush_cache_all_nop, BTFIXUPCALL_NOP);
+#endif
 
        /* Initialize our copy of the Linux Sparc trap table */
        eh_init();
index 92be6f74dfaffcc6463de11beca9360e19742e8e..1690a7c69d9847b1fce256939365917a4c369720 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.61 1997/11/19 07:57:44 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.64 1998/03/19 15:36:43 jj Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -15,7 +15,6 @@
 #include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/in6.h>
-#include <linux/pci.h>
 
 #include <asm/oplib.h>
 #include <asm/delay.h>
@@ -138,7 +137,6 @@ EXPORT_SYMBOL(page_offset);
 EXPORT_SYMBOL(stack_top);
 
 /* Atomic operations. */
-EXPORT_SYMBOL_PRIVATE(_xchg32);
 EXPORT_SYMBOL_PRIVATE(_atomic_add);
 EXPORT_SYMBOL_PRIVATE(_atomic_sub);
 
@@ -168,13 +166,23 @@ EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
 EXPORT_SYMBOL(io_remap_page_range);
-EXPORT_SYMBOL(mmu_v2p);
-EXPORT_SYMBOL(mmu_unlockarea);
-EXPORT_SYMBOL(mmu_lockarea);
-EXPORT_SYMBOL(mmu_get_scsi_sgl);
-EXPORT_SYMBOL(mmu_get_scsi_one);
-EXPORT_SYMBOL(mmu_release_scsi_sgl);
-EXPORT_SYMBOL(mmu_release_scsi_one);
+
+/* Btfixup stuff cannot have versions, it would be complicated too much */
+#ifndef __SMP__
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(___xchg32));
+#else
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(__smp_processor_id));
+#endif
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(enable_irq));
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(disable_irq));
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_v2p));
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_unlockarea));
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_lockarea));
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_get_scsi_sgl));
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_get_scsi_one));
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_sgl));
+EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_one));
+
 EXPORT_SYMBOL(_sparc_dvma_malloc);
 EXPORT_SYMBOL(sun4c_unmapioaddr);
 EXPORT_SYMBOL(srmmu_unmapioaddr);
@@ -272,7 +280,3 @@ EXPORT_SYMBOL_DOT(mul);
 EXPORT_SYMBOL_DOT(umul);
 EXPORT_SYMBOL_DOT(div);
 EXPORT_SYMBOL_DOT(udiv);
-
-#if CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
index bc95696883366e92935ffd64411d0f6f8d399b79..592d94856d693b2e690a5852cad2779f0d92db73 100644 (file)
@@ -9,6 +9,7 @@
  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
  */
 
+#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -30,6 +31,9 @@
 #include <asm/traps.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/sun4paddr.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
 
 /* Pointer to the interrupt enable byte
  *
@@ -128,7 +132,7 @@ __initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct
        /* Map the Timer chip, this is implemented in hardware inside
         * the cache chip on the sun4c.
         */
-       sun4c_timers = sparc_alloc_io (SUN4C_TIMER_PHYSADDR, 0,
+       sun4c_timers = sparc_alloc_io (SUN_TIMER_PHYSADDR, 0,
                                       sizeof(struct sun4c_timer_info),
                                       "timer", 0x0, 0x0);
     
@@ -160,30 +164,41 @@ __initfunc(void sun4c_init_IRQ(void))
 {
        struct linux_prom_registers int_regs[2];
        int ie_node;
+
+       if (ARCH_SUN4) {
+               interrupt_enable =
+                       (char *) sparc_alloc_io(SUN4_IE_PHYSADDR, 0,
+                                               PAGE_SIZE,
+                                               "sun4c_interrupts",
+                                               0x0, 0x0);
+       } else {
     
-       ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
-                                      "interrupt-enable");
-       if(ie_node == 0)
-               panic("Cannot find /interrupt-enable node");
-
-       /* Depending on the "address" property is bad news... */
-       prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
-       interrupt_enable = (char *) sparc_alloc_io(int_regs[0].phys_addr, 0,
-                                                  int_regs[0].reg_size,
-                                                  "sun4c_interrupts",
-                                                  int_regs[0].which_io, 0x0);
-       enable_irq = sun4c_enable_irq;
-       disable_irq = sun4c_disable_irq;
-       enable_pil_irq = sun4c_enable_irq;
-       disable_pil_irq = sun4c_disable_irq;
-       clear_clock_irq = sun4c_clear_clock_irq;
-       clear_profile_irq = sun4c_clear_profile_irq;
-       load_profile_irq = sun4c_load_profile_irq;
+               ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
+                                       "interrupt-enable");
+               if(ie_node == 0)
+                       panic("Cannot find /interrupt-enable node");
+
+               /* Depending on the "address" property is bad news... */
+               prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
+               interrupt_enable =
+                       (char *) sparc_alloc_io(int_regs[0].phys_addr, 0,
+                                               int_regs[0].reg_size,
+                                               "sun4c_interrupts",
+                                               int_regs[0].which_io, 0x0);
+       }
+
+       BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
        init_timers = sun4c_init_timers;
 #ifdef __SMP__
-       set_cpu_int = (void (*) (int, int))sun4c_nop;
-       clear_cpu_int = (void (*) (int, int))sun4c_nop;
-       set_irq_udt = (void (*) (int))sun4c_nop;
+       BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP);
 #endif
        *interrupt_enable = (SUN4C_INT_ENABLE);
        /* Cannot enable interrupts until OBP ticker is disabled. */
index f22fe1495fb53a2fbf7d81128ffcd8bfcb13657c..302df86f469711cb56d785a668685b620b045842 100644 (file)
@@ -1,8 +1,8 @@
-/*  $Id: sun4d_irq.c,v 1.3 1997/12/22 16:09:15 jj Exp $
- *  arch/sparc/kernel/sun4d_irq.c: 
+/*  $Id: sun4d_irq.c,v 1.12 1998/03/19 15:36:36 jj Exp $
+ *  arch/sparc/kernel/sun4d_irq.c:
  *                     SS1000/SC2000 interrupt handling.
  *
- *  Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *  Heavily based on arch/sparc/kernel/irq.c.
  */
 
 #include <asm/sbus.h>
 #include <asm/sbi.h>
 
+/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
+/* #define DISTRIBUTE_IRQS */
+
 struct sun4d_timer_regs *sun4d_timers;
 #define TIMER_IRQ      10
 
 #define MAX_STATIC_ALLOC       4
 extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 extern int static_irq_count;
+unsigned char cpu_leds[32];
+#ifdef __SMP__
+unsigned char sbus_tid[32];
+#endif
 
 extern struct irqaction *irq_action[];
 
 struct sbus_action {
        struct irqaction *action;
-       unsigned char   lock;
-       unsigned char   active;
-       unsigned char   disabled;
+       /* For SMP this needs to be extended */
 } *sbus_actions;
 
 static int pil_to_sbus[] = {
        0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
 };
 
+static int sbus_to_pil[] = {
+       0, 2, 3, 5, 7, 9, 11, 13,
+};
+
 static int nsbi;
+#ifdef __SMP__
+spinlock_t sun4d_imsk_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 int sun4d_get_irq_list(char *buf)
 {
        int i, j = 0, k = 0, len = 0, sbusl;
        struct irqaction * action;
+#ifdef __SMP__
+       int x;
+#endif
 
        for (i = 0 ; i < NR_IRQS ; i++) {
                sbusl = pil_to_sbus[i];
@@ -77,8 +92,15 @@ int sun4d_get_irq_list(char *buf)
                        }
                        continue;
                }
-found_it:      len += sprintf(buf+len, "%2d: %8d %c %s",
-                       i, kstat.interrupts[i],
+found_it:      len += sprintf(buf+len, "%3d: ", i);
+#ifndef __SMP__
+               len += sprintf(buf+len, "%10u ", kstat_irqs(i));
+#else
+               for (x = 0; x < smp_num_cpus; x++)
+                       len += sprintf(buf+len, "%10u ",
+                                      kstat.irqs[cpu_logical_map(x)][i]);
+#endif
+               len += sprintf(buf+len, "%c %s",
                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
                        action->name);
                action = action->next;
@@ -172,7 +194,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
        cc_set_iclr(1 << irq);
        
        irq_enter(cpu, irq, regs);
-       kstat.interrupts[irq]++;
+       kstat.irqs[cpu][irq]++;
        if (!sbusl) {
                action = *(irq + irq_action);
                if (!action)
@@ -183,7 +205,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
                } while (action);
        } else {
                int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
-               int lock;
                int sbino;
                struct sbus_action *actionp;
                unsigned mask, slot;
@@ -202,19 +223,13 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
                                        if (mask & slot) {
                                                mask &= ~slot;
                                                action = actionp->action;
-                                               __asm__ __volatile__ ("ldstub   [%1 + 4], %0"
-                                               : "=r" (lock) : "r" (actionp));
                                                
-                                               if (!lock) {
-                                                       if (!action)
-                                                               unexpected_irq(irq, 0, regs);
-                                                       do {
-                                                               action->handler(irq, action->dev_id, regs);
-                                                               action = action->next;
-                                                       } while (action);
-                                                       actionp->lock = 0;
-                                               } else
-                                                       actionp->active = 1;
+                                               if (!action)
+                                                       unexpected_irq(irq, 0, regs);
+                                               do {
+                                                       action->handler(irq, action->dev_id, regs);
+                                                       action = action->next;
+                                               } while (action);
                                                release_sbi(SBI2DEVID(sbino), slot);
                                        }
                        }
@@ -305,79 +320,49 @@ int sun4d_request_irq(unsigned int irq,
        else
                *actionp = action;
                
-       if (ret) irq = *ret;
-
-       if (irq > NR_IRQS) {
-               struct sbus_action *s = sbus_actions + irq - (1 << 5);
-       
-               if (s->disabled) {
-                       s->disabled = 0;
-                       s->active = 0;
-                       s->lock = 0;
-               }
-       }
-       
+       enable_irq(irq);
        restore_flags(flags);
        return 0;
 }
 
 static void sun4d_disable_irq(unsigned int irq)
 {
-       struct sbus_action *s;
-       
-       if (irq < NR_IRQS) {
-               /* FIXME */
-               printk ("Unable to disable IRQ %d\n", irq);
-               return;
-       }
-       s = sbus_actions + irq - (1 << 5);
+#ifdef __SMP__
+       int tid = sbus_tid[(irq >> 5) - 1];
+       unsigned long flags;
+#endif 
        
-       if (s->disabled) return;
-       s->disabled = 1;
-       __asm__ __volatile__ ("
-1:             ldstub  [%0 + 4], %%g1
-               orcc    %%g1, 0, %%g0
-               bne     1b"
-               : : "r" (s) : "g1", "cc");
+       if (irq < NR_IRQS) return;
+#ifdef __SMP__
+       spin_lock_irqsave(&sun4d_imsk_lock, flags);
+       cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
+       spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
+#else          
+       cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
+#endif
 }
 
 static void sun4d_enable_irq(unsigned int irq)
 {
-       struct sbus_action *s;
-       struct irqaction *action;
-       
-       if (irq < NR_IRQS)
-               /* FIXME */
-               return;
-       s = sbus_actions + irq - (1 << 5);
+#ifdef __SMP__
+       int tid = sbus_tid[(irq >> 5) - 1];
+       unsigned long flags;
+#endif 
        
-       if (!s->disabled) return;
-       action = s->action;
-       s->disabled = 0;
-       while (s->active) {
-               s->active = 0;
-               while (action) {
-                       /* FIXME: Hope no sbus intr handler uses regs */
-                       action->handler(irq, action->dev_id, NULL);
-                       action = action->next;
-               }
-       }
-       s->lock = 0;
+       if (irq < NR_IRQS) return;
+#ifdef __SMP__
+       spin_lock_irqsave(&sun4d_imsk_lock, flags);
+       cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
+       spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
+#else          
+       cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
+#endif
 }
 
 #ifdef __SMP__
-
-/* +-------+-------------+-----------+------------------------------------+
- * | bcast |  devid      |   sid     |              levels mask           |
- * +-------+-------------+-----------+------------------------------------+
- *  31      30         23 22       15 14                                 0
- */
-#define IGEN_MESSAGE(bcast, devid, sid, levels) \
-       (((bcast) << 31) | ((devid) << 23) | ((sid) << 15) | (levels))
-
-static void sun4d_send_ipi(int cpu, int level)
+static void sun4d_set_cpu_int(int cpu, int level)
 {
-       cc_set_igen(IGEN_MESSAGE(0, cpu << 3, 6 + ((level >> 1) & 7), 1 << (level - 1)));
+       sun4d_send_ipi(cpu, level);
 }
 
 static void sun4d_clear_ipi(int cpu, int level)
@@ -387,6 +372,55 @@ static void sun4d_clear_ipi(int cpu, int level)
 static void sun4d_set_udt(int cpu)
 {
 }
+
+/* Setup IRQ distribution scheme. */
+__initfunc(void sun4d_distribute_irqs(void))
+{
+#ifdef DISTRIBUTE_IRQS
+       struct linux_sbus *sbus;
+       unsigned long sbus_serving_map;
+
+       sbus_serving_map = cpu_present_map;
+       for_each_sbus(sbus) {
+               if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1))))
+                       sbus_tid[sbus->board] = (sbus->board * 2 + 1);
+               else if (cpu_present_map & (1 << (sbus->board * 2)))
+                       sbus_tid[sbus->board] = (sbus->board * 2);
+               else if (cpu_present_map & (1 << (sbus->board * 2 + 1)))
+                       sbus_tid[sbus->board] = (sbus->board * 2 + 1);
+               else
+                       sbus_tid[sbus->board] = 0xff;
+               if (sbus_tid[sbus->board] != 0xff)
+                       sbus_serving_map &= ~(1 << sbus_tid[sbus->board]);
+       }
+       for_each_sbus(sbus)
+               if (sbus_tid[sbus->board] == 0xff) {
+                       int i = 31;
+                               
+                       if (!sbus_serving_map)
+                               sbus_serving_map = cpu_present_map;
+                       while (!(sbus_serving_map & (1 << i)))
+                               i--;
+                       sbus_tid[sbus->board] = i;
+                       sbus_serving_map &= ~(1 << i);
+               }
+       for_each_sbus(sbus) {
+               printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]);
+               set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
+       }
+#else
+       struct linux_sbus *sbus;
+       int cpuid = cpu_logical_map(1);
+
+       if (cpuid == -1)
+               cpuid = cpu_logical_map(0);
+       for_each_sbus(sbus) {
+               sbus_tid[sbus->board] = cpuid;
+               set_sbi_tid(sbus->devid, cpuid << 3);
+       }
+       printk("All sbus IRQs directed to CPU%d\n", cpuid);
+#endif
+}
 #endif
  
 static void sun4d_clear_clock_irq(void)
@@ -408,7 +442,7 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
 __initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)))
 {
        int irq;
-       extern struct prom_cpuinfo linux_cpus[NCPUS];
+       extern struct prom_cpuinfo linux_cpus[NR_CPUS];
        int cpu;
 
        /* Map the User Timer registers. */
@@ -431,15 +465,39 @@ __initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct
        /* Enable user timer free run for CPU 0 in BW */
        /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
     
-       for(cpu = 0; cpu < NCPUS; cpu++)
-               sun4d_load_profile_irq(linux_cpus[cpu].mid, 0);
+       for(cpu = 0; cpu < linux_num_cpus; cpu++)
+               sun4d_load_profile_irq((linux_cpus[cpu].mid >> 3), 0);
+               
+#ifdef __SMP__
+       {
+               unsigned long flags;
+               extern unsigned long lvl14_save[4];
+               struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
+               extern unsigned int real_irq_entry[], smp4d_ticker[];
+               extern unsigned int patchme_maybe_smp_msg[];
+
+               /* Adjust so that we jump directly to smp4d_ticker */
+               lvl14_save[2] += smp4d_ticker - real_irq_entry;
+
+               /* For SMP we use the level 14 ticker, however the bootup code
+                * has copied the firmwares level 14 vector into boot cpu's
+                * trap table, we must fix this now or we get squashed.
+                */
+               __save_and_cli(flags);
+               patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+               trap_table->inst_one = lvl14_save[0];
+               trap_table->inst_two = lvl14_save[1];
+               trap_table->inst_three = lvl14_save[2];
+               trap_table->inst_four = lvl14_save[3];
+               local_flush_cache_all();
+               __restore_flags(flags);
+       }
+#endif
 }
 
 __initfunc(unsigned long sun4d_init_sbi_irq(unsigned long memory_start))
 {
        struct linux_sbus *sbus;
-       struct sbus_action *s;
-       int i;
        unsigned mask;
 
        nsbi = 0;
@@ -449,11 +507,13 @@ __initfunc(unsigned long sun4d_init_sbi_irq(unsigned long memory_start))
        sbus_actions = (struct sbus_action *)memory_start;
        memory_start += (nsbi * 8 * 4 * sizeof(struct sbus_action));
        memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action)));
-       for (i = 0, s = sbus_actions; i < nsbi * 8 * 4; i++, s++) {
-               s->lock = 0xff;
-               s->disabled = 1;
-       }
        for_each_sbus(sbus) {
+#ifdef __SMP__ 
+               extern unsigned char boot_cpu_id;
+               
+               set_sbi_tid(sbus->devid, boot_cpu_id << 3);
+               sbus_tid[sbus->board] = boot_cpu_id;
+#endif
                /* Get rid of pending irqs from PROM */
                mask = acquire_sbi(sbus->devid, 0xffffffff);
                if (mask) {
@@ -468,16 +528,16 @@ __initfunc(void sun4d_init_IRQ(void))
 {
        __cli();
 
-       enable_irq = sun4d_enable_irq;
-       disable_irq = sun4d_disable_irq;
-       clear_clock_irq = sun4d_clear_clock_irq;
-       clear_profile_irq = sun4d_clear_profile_irq;
-       load_profile_irq = sun4d_load_profile_irq;
+       BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
        init_timers = sun4d_init_timers;
 #ifdef __SMP__
-       set_cpu_int = (void (*) (int, int))sun4d_send_ipi;
-       clear_cpu_int = (void (*) (int, int))sun4d_clear_ipi;
-       set_irq_udt = (void (*) (int))sun4d_set_udt;
+       BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
 #endif
        /* Cannot enable interrupts until OBP ticker is disabled. */
 }
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
new file mode 100644 (file)
index 0000000..46ce7a8
--- /dev/null
@@ -0,0 +1,576 @@
+/* sun4d_smp.c: Sparc SS1000/SC2000 SMP support.
+ *
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on sun4m's smp.c, which is:
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h> /* for CONFIG_PROFILE */
+#include <asm/head.h>
+
+#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 <linux/init.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/atops.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+#include <asm/sbus.h>
+#include <asm/sbi.h>
+
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+#define IRQ_CROSS_CALL         15
+
+extern ctxd_t *srmmu_ctx_table_phys;
+extern int linux_num_cpus;
+
+extern void calibrate_delay(void);
+
+extern struct task_struct *current_set[NR_CPUS];
+extern volatile int smp_processors_ready;
+extern unsigned long cpu_present_map;
+extern int smp_num_cpus;
+static int smp_highest_cpu = 0;
+extern int smp_threads_ready;
+extern unsigned char mid_xlate[NR_CPUS];
+extern volatile unsigned long cpu_callin_map[NR_CPUS];
+extern unsigned long smp_proc_in_lock[NR_CPUS];
+extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+extern unsigned long cpu_offset[NR_CPUS];
+extern unsigned char boot_cpu_id;
+extern int smp_activated;
+extern volatile int cpu_number_map[NR_CPUS];
+extern volatile int __cpu_logical_map[NR_CPUS];
+extern struct klock_info klock_info;
+extern volatile unsigned long ipi_count;
+extern volatile int smp_process_available;
+extern volatile int smp_commenced;
+extern int __smp4d_processor_id(void);
+
+/* #define SMP_DEBUG */
+
+#ifdef SMP_DEBUG
+#define SMP_PRINTK(x)  printk x
+#else
+#define SMP_PRINTK(x)
+#endif
+
+int smp4d_bogo_info(char *buf)
+{
+       int len = 0, i;
+       
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_present_map & (1 << i))
+                       len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", 
+                                       i,
+                                       cpu_data[i].udelay_val/500000,
+                                       (cpu_data[i].udelay_val/5000)%100);
+       return len;
+}
+
+int smp4d_info(char *buf)
+{
+       int len = 0, i;
+       
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_present_map & (1 << i))
+                       len += sprintf(buf + len, "CPU%d\t\t: %s\n", 
+                                       i,
+                                       (klock_info.akp == i) ? "akp" : "online");
+       return len;
+}
+
+static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
+{
+       __asm__ __volatile__("swap [%1], %0\n\t" :
+                            "=&r" (val), "=&r" (ptr) :
+                            "0" (val), "1" (ptr));
+       return val;
+}
+
+static void smp_setup_percpu_timer(void);
+extern void cpu_probe(void);
+extern void sun4d_distribute_irqs(void);
+
+__initfunc(void smp4d_callin(void))
+{
+       int cpuid = hard_smp4d_processor_id();
+       extern spinlock_t sun4d_imsk_lock;
+       unsigned long flags;
+       
+       /* Show we are alive */
+       cpu_leds[cpuid] = 0x6;
+       show_leds(cpuid);
+
+       /* Enable level15 interrupt, disable level14 interrupt for now */
+       cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000);
+
+       local_flush_cache_all();
+       local_flush_tlb_all();
+
+       /* Get our local ticker going. */
+       smp_setup_percpu_timer();
+
+       calibrate_delay();
+       smp_store_cpu_info(cpuid);
+       local_flush_cache_all();
+       local_flush_tlb_all();
+
+       /* Allow master to continue. */
+       swap((unsigned long *)&cpu_callin_map[cpuid], 1);
+       local_flush_cache_all();
+       local_flush_tlb_all();
+       
+       cpu_probe();
+
+       while((unsigned long)current_set[cpuid] < PAGE_OFFSET)
+               barrier();
+               
+       while(current_set[cpuid]->processor != cpuid)
+               barrier();
+               
+       /* Fix idle thread fields. */
+       __asm__ __volatile__("ld [%0], %%g6\n\t"
+                            "sta %%g6, [%%g0] %1\n\t"
+                            : : "r" (&current_set[cpuid]), "i" (ASI_M_VIKING_TMP2)
+                            : "memory" /* paranoid */);
+
+       cpu_leds[cpuid] = 0x9;
+       show_leds(cpuid);
+       
+       current->mm->mmap->vm_page_prot = PAGE_SHARED;
+       current->mm->mmap->vm_start = PAGE_OFFSET;
+       current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+       
+       local_flush_cache_all();
+       local_flush_tlb_all();
+       
+       __sti();        /* We don't allow PIL 14 yet */
+       
+       while(!smp_commenced)
+               barrier();
+
+       spin_lock_irqsave(&sun4d_imsk_lock, flags);
+       cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
+       spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
+}
+
+extern int cpu_idle(void *unused);
+extern void init_IRQ(void);
+extern void cpu_panic(void);
+extern int start_secondary(void *unused);
+
+/*
+ *     Cycle through the processors asking the PROM to start each one.
+ */
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+extern struct linux_prom_registers smp_penguin_ctable;
+extern unsigned long trapbase_cpu1[];
+extern unsigned long trapbase_cpu2[];
+extern unsigned long trapbase_cpu3[];
+
+__initfunc(void smp4d_boot_cpus(void))
+{
+       int cpucount = 0;
+       int i = 0;
+
+       printk("Entering SMP Mode...\n");
+       
+       smp_penguin_ctable.which_io = 0;
+       smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+       smp_penguin_ctable.reg_size = 0;
+
+       for (i = 0; i < NR_CPUS; i++)
+               cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
+               
+       if (boot_cpu_id)
+               current_set[0] = NULL;
+
+       __sti();
+       cpu_present_map = 0;
+       for(i=0; i < linux_num_cpus; i++)
+               cpu_present_map |= (1<<linux_cpus[i].mid);
+       SMP_PRINTK(("cpu_present_map %08lx\n", cpu_present_map));
+       for(i=0; i < NR_CPUS; i++)
+               cpu_number_map[i] = -1;
+       for(i=0; i < NR_CPUS; i++)
+               __cpu_logical_map[i] = -1;
+       for(i=0; i < NR_CPUS; i++)
+               mid_xlate[i] = i;
+       cpu_number_map[boot_cpu_id] = 0;
+       __cpu_logical_map[0] = boot_cpu_id;
+       klock_info.akp = boot_cpu_id;
+       current->processor = boot_cpu_id;
+       smp_store_cpu_info(boot_cpu_id);
+       smp_setup_percpu_timer();
+       local_flush_cache_all();
+       if(linux_num_cpus == 1)
+               return;  /* Not an MP box. */
+       SMP_PRINTK(("Iterating over CPUs\n"));
+       for(i = 0; i < NR_CPUS; i++) {
+               if(i == boot_cpu_id)
+                       continue;
+
+               if(cpu_present_map & (1 << i)) {
+                       extern unsigned long sun4d_cpu_startup;
+                       unsigned long *entry = &sun4d_cpu_startup;
+                       struct task_struct *p;
+                       int timeout;
+                       int no;
+
+                       /* Cook up an idler for this guy. */
+                       kernel_thread(start_secondary, NULL, CLONE_PID);
+
+                       p = task[++cpucount];
+
+                       p->processor = i;
+                       current_set[i] = p;
+                       
+                       for (no = 0; no < linux_num_cpus; no++)
+                               if (linux_cpus[no].mid == i)
+                                       break;
+                       
+                       /* whirrr, whirrr, whirrrrrrrrr... */
+                       SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, linux_cpus[no].prom_node));
+                       local_flush_cache_all();
+                       prom_startcpu(linux_cpus[no].prom_node,
+                                     &smp_penguin_ctable, 0, (char *)entry);
+                                     
+                       SMP_PRINTK(("prom_startcpu returned :)\n"));
+
+                       /* wheee... it's going... */
+                       for(timeout = 0; timeout < 5000000; timeout++) {
+                               if(cpu_callin_map[i])
+                                       break;
+                               udelay(100);
+                       }
+                       
+                       if(cpu_callin_map[i]) {
+                               /* Another "Red Snapper". */
+                               cpu_number_map[i] = cpucount;
+                               __cpu_logical_map[cpucount] = i;
+                       } else {
+                               cpucount--;
+                               printk("Processor %d is stuck.\n", i);
+                       }
+               }
+               if(!(cpu_callin_map[i])) {
+                       cpu_present_map &= ~(1 << i);
+                       cpu_number_map[i] = -1;
+               }
+       }
+       local_flush_cache_all();
+       if(cpucount == 0) {
+               printk("Error: only one Processor found.\n");
+               cpu_present_map = (1 << hard_smp4d_processor_id());
+       } else {
+               unsigned long bogosum = 0;
+               
+               for(i = 0; i < NR_CPUS; i++) {
+                       if(cpu_present_map & (1 << i)) {
+                               bogosum += cpu_data[i].udelay_val;
+                               smp_highest_cpu = i;
+                       }
+               }
+               SMP_PRINTK(("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, (bogosum + 2500)/500000, ((bogosum + 2500)/5000)%100));
+               printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
+                      cpucount + 1,
+                      (bogosum + 2500)/500000,
+                      ((bogosum + 2500)/5000)%100);
+               smp_activated = 1;
+               smp_num_cpus = cpucount + 1;
+       }
+
+       /* Free unneeded trap tables */
+       
+       mem_map[MAP_NR((unsigned long)trapbase_cpu1)].flags &= ~(1 << PG_reserved);
+       free_page((unsigned long)trapbase_cpu1);
+       mem_map[MAP_NR((unsigned long)trapbase_cpu2)].flags &= ~(1 << PG_reserved);
+       free_page((unsigned long)trapbase_cpu2);
+       mem_map[MAP_NR((unsigned long)trapbase_cpu3)].flags &= ~(1 << PG_reserved);
+       free_page((unsigned long)trapbase_cpu3);
+
+       /* Ok, they are spinning and ready to go. */
+       smp_processors_ready = 1;
+       sun4d_distribute_irqs();
+}
+
+static struct smp_funcall {
+       smpfunc_t func;
+       unsigned long arg1;
+       unsigned long arg2;
+       unsigned long arg3;
+       unsigned long arg4;
+       unsigned long arg5;
+       unsigned char processors_in[NR_CPUS];  /* Set when ipi entered. */
+       unsigned char processors_out[NR_CPUS]; /* Set when ipi exited. */
+} ccall_info __attribute__((aligned(8)));
+
+static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED;
+
+/* Cross calls must be serialized, at least currently. */
+void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
+                   unsigned long arg3, unsigned long arg4, unsigned long arg5)
+{
+       if(smp_processors_ready) {
+               register int high = smp_highest_cpu;
+               unsigned long flags;
+
+               spin_lock_irqsave(&cross_call_lock, flags);
+
+               {
+                       /* If you make changes here, make sure gcc generates proper code... */
+                       smpfunc_t f asm("i0") = func;
+                       unsigned long a1 asm("i1") = arg1;
+                       unsigned long a2 asm("i2") = arg2;
+                       unsigned long a3 asm("i3") = arg3;
+                       unsigned long a4 asm("i4") = arg4;
+                       unsigned long a5 asm("i5") = arg5;
+                                       
+                       __asm__ __volatile__("
+                               std %0, [%6]
+                               std %2, [%6 + 8]
+                               std %4, [%6 + 16]" : : 
+                               "r"(f), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5),
+                               "r" (&ccall_info.func));
+               }
+
+               /* Init receive/complete mapping, plus fire the IPI's off. */
+               {
+                       register unsigned long mask;
+                       register int i;
+
+                       mask = (cpu_present_map & ~(1 << hard_smp4d_processor_id()));
+                       for(i = 0; i <= high; i++) {
+                               if(mask & (1 << i)) {
+                                       ccall_info.processors_in[i] = 0;
+                                       ccall_info.processors_out[i] = 0;
+                                       sun4d_send_ipi(i, IRQ_CROSS_CALL);
+                               }
+                       }
+               }
+
+               /* First, run local copy. */
+               func(arg1, arg2, arg3, arg4, arg5);
+
+               {
+                       register int i;
+
+                       i = 0;
+                       do {
+                               while(!ccall_info.processors_in[i])
+                                       barrier();
+                       } while(++i <= high);
+
+                       i = 0;
+                       do {
+                               while(!ccall_info.processors_out[i])
+                                       barrier();
+                       } while(++i <= high);
+               }
+
+               spin_unlock_irqrestore(&cross_call_lock, flags);
+       } else
+               func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
+}
+
+/* Running cross calls. */
+void smp4d_cross_call_irq(void)
+{
+       int i = hard_smp4d_processor_id();
+
+       ccall_info.processors_in[i] = 1;
+       ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
+                       ccall_info.arg4, ccall_info.arg5);
+       ccall_info.processors_out[i] = 1;
+}
+
+static int smp4d_stop_cpu_sender;
+
+static void smp4d_stop_cpu(void)
+{
+       int me = hard_smp4d_processor_id();
+       
+       if (me != smp4d_stop_cpu_sender)
+               while(1) barrier();
+}
+
+/* Cross calls, in order to work efficiently and atomically do all
+ * the message passing work themselves, only stopcpu and reschedule
+ * messages come through here.
+ */
+void smp4d_message_pass(int target, int msg, unsigned long data, int wait)
+{
+       int me = hard_smp4d_processor_id();
+
+       SMP_PRINTK(("smp4d_message_pass %d %d %08lx %d\n", target, msg, data, wait));
+       if (msg == MSG_STOP_CPU && target == MSG_ALL_BUT_SELF) {
+               unsigned long flags;
+               static spinlock_t stop_cpu_lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_irqsave(&stop_cpu_lock, flags);
+               smp4d_stop_cpu_sender = me;
+               smp4d_cross_call((smpfunc_t)smp4d_stop_cpu, 0, 0, 0, 0, 0);
+               spin_unlock_irqrestore(&stop_cpu_lock, flags);
+       }
+       printk("Yeeee, trying to send SMP msg(%d) to %d on cpu %d\n", msg, target, me);
+       panic("Bogon SMP message pass.");
+}
+
+/* Protects counters touched during level14 ticker */
+static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+
+#ifdef CONFIG_PROFILE
+
+/* 32-bit Sparc specific profiling function. */
+static inline void sparc_do_profile(unsigned long pc)
+{
+       if(prof_buffer && current->pid) {
+               extern int _stext;
+
+               pc -= (unsigned long) &_stext;
+               pc >>= prof_shift;
+
+               spin_lock(&ticker_lock);
+               if(pc < prof_len)
+                       prof_buffer[pc]++;
+               else
+                       prof_buffer[prof_len - 1]++;
+               spin_unlock(&ticker_lock);
+       }
+}
+
+#endif
+
+extern unsigned int prof_multiplier[NR_CPUS];
+extern unsigned int prof_counter[NR_CPUS];
+
+extern void update_one_process(struct task_struct *p, unsigned long ticks,
+                              unsigned long user, unsigned long system,
+                              int cpu);
+                              
+
+void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
+{
+       int cpu = hard_smp4d_processor_id();
+       static int cpu_tick[NR_CPUS];
+       static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd };
+
+       bw_get_prof_limit(cpu); 
+       bw_clear_intr_mask(0, 1);       /* INTR_TABLE[0] & 1 is Profile IRQ */
+
+       cpu_tick[cpu]++;
+       if (!(cpu_tick[cpu] & 15)) {
+               if (cpu_tick[cpu] == 0x60)
+                       cpu_tick[cpu] = 0;
+               cpu_leds[cpu] = led_mask[cpu_tick[cpu] >> 4];
+               show_leds(cpu);
+       }
+
+#ifdef CONFIG_PROFILE
+       if(!user_mode(regs))
+               sparc_do_profile(regs->pc);
+#endif
+       if(!--prof_counter[cpu]) {
+               int user = user_mode(regs);
+               if(current->pid) {
+                       update_one_process(current, 1, user, !user, cpu);
+
+                       if(--current->counter < 0) {
+                               current->counter = 0;
+                               need_resched = 1;
+                       }
+
+                       spin_lock(&ticker_lock);
+                       if(user) {
+                               if(current->priority < DEF_PRIORITY) {
+                                       kstat.cpu_nice++;
+                                       kstat.per_cpu_nice[cpu]++;
+                               } else {
+                                       kstat.cpu_user++;
+                                       kstat.per_cpu_user[cpu]++;
+                               }
+                       } else {
+                               kstat.cpu_system++;
+                               kstat.per_cpu_system[cpu]++;
+                       }
+                       spin_unlock(&ticker_lock);
+               }
+               prof_counter[cpu] = prof_multiplier[cpu];
+       }
+}
+
+extern unsigned int lvl14_resolution;
+
+__initfunc(static void smp_setup_percpu_timer(void))
+{
+       int cpu = hard_smp4d_processor_id();
+
+       prof_counter[cpu] = prof_multiplier[cpu] = 1;
+       load_profile_irq(cpu, lvl14_resolution);
+}
+
+__initfunc(void smp4d_blackbox_id(unsigned *addr))
+{
+       int rd = *addr & 0x3e000000;
+       
+       addr[0] = 0xc0800800 | rd;              /* lda [%g0] ASI_M_VIKING_TMP1, reg */
+       addr[1] = 0x01000000;                   /* nop */
+       addr[2] = 0x01000000;                   /* nop */
+}
+
+__initfunc(void smp4d_blackbox_current(unsigned *addr))
+{
+       /* We have a nice Linux current register :) */
+       int rd = addr[1] & 0x3e000000;
+       
+       addr[0] = 0x10800006;                   /* b .+24 */
+       addr[1] = 0xc0800820 | rd;              /* lda [%g0] ASI_M_VIKING_TMP2, reg */
+}
+
+__initfunc(void sun4d_init_smp(void))
+{
+       int i;
+       extern unsigned int patchme_store_new_current[];
+       extern unsigned int t_nmi[], linux_trap_ipi15_sun4d[], linux_trap_ipi15_sun4m[];
+
+       /* Store current into Linux current register :) */
+       __asm__ __volatile__("sta %%g6, [%%g0] %0" : : "i"(ASI_M_VIKING_TMP2));
+       
+       /* Patch switch_to */
+       patchme_store_new_current[0] = (patchme_store_new_current[0] & 0x3e000000) | 0xc0a00820;
+       
+       /* Patch ipi15 trap table */
+       t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m);
+       
+       /* And set btfixup... */
+       BTFIXUPSET_BLACKBOX(smp_processor_id, smp4d_blackbox_id);
+       BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
+       BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(smp_message_pass, smp4d_message_pass, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(smp_bogo_info, smp4d_bogo_info, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(smp_info, smp4d_info, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(__smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
+       
+       for (i = 0; i < NR_CPUS; i++) {
+               ccall_info.processors_in[i] = 1;
+               ccall_info.processors_out[i] = 1;
+       }
+}
index 81db1a4ce0dd7dfd8da5389b5138d6612fd964e4..e55839a7af4836336d88983caa4b46b997886dbc 100644 (file)
@@ -83,9 +83,9 @@ inline unsigned long sun4m_get_irqmask(unsigned int irq)
                if (!mask)
                        printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
        } else {
-               /* Soft Interrupts will come here
-                * Currently there is no way to trigger them but I'm sure something
-                * could be cooked up.
+               /* Soft Interrupts will come here.
+                * Currently there is no way to trigger them but I'm sure
+                * something could be cooked up.
                 */
                irq &= 0xf;
                mask = SUN4M_SOFT_INT(irq);
@@ -349,18 +349,18 @@ __initfunc(void sun4m_init_IRQ(void))
                                &sun4m_interrupts->undirected_target;
                sun4m_interrupts->undirected_target = 0;
        }
-       enable_irq = sun4m_enable_irq;
-       disable_irq = sun4m_disable_irq;
-       enable_pil_irq = sun4m_enable_pil_irq;
-       disable_pil_irq = sun4m_disable_pil_irq;
-       clear_clock_irq = sun4m_clear_clock_irq;
-       clear_profile_irq = sun4m_clear_profile_irq;
-       load_profile_irq = sun4m_load_profile_irq;
+       BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
        init_timers = sun4m_init_timers;
 #ifdef __SMP__
-       set_cpu_int = (void (*) (int, int))sun4m_send_ipi;
-       clear_cpu_int = (void (*) (int, int))sun4m_clear_ipi;
-       set_irq_udt = (void (*) (int))sun4m_set_udt;
+       BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
 #endif
        /* Cannot enable interrupts until OBP ticker is disabled. */
 }
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
new file mode 100644 (file)
index 0000000..ec1ef42
--- /dev/null
@@ -0,0 +1,545 @@
+/* sun4m_smp.c: Sparc SUN4M SMP support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h> /* for CONFIG_PROFILE */
+#include <asm/head.h>
+
+#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 <linux/init.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/atops.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+#define IRQ_RESCHEDULE         13
+#define IRQ_STOP_CPU           14
+#define IRQ_CROSS_CALL         15
+
+extern ctxd_t *srmmu_ctx_table_phys;
+extern int linux_num_cpus;
+
+extern void calibrate_delay(void);
+
+extern struct task_struct *current_set[NR_CPUS];
+extern volatile int smp_processors_ready;
+extern unsigned long cpu_present_map;
+extern int smp_num_cpus;
+extern int smp_threads_ready;
+extern unsigned char mid_xlate[NR_CPUS];
+extern volatile unsigned long cpu_callin_map[NR_CPUS];
+extern unsigned long smp_proc_in_lock[NR_CPUS];
+extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+extern unsigned long cpu_offset[NR_CPUS];
+extern unsigned char boot_cpu_id;
+extern int smp_activated;
+extern volatile int cpu_number_map[NR_CPUS];
+extern volatile int __cpu_logical_map[NR_CPUS];
+extern struct klock_info klock_info;
+extern volatile unsigned long ipi_count;
+extern volatile int smp_process_available;
+extern volatile int smp_commenced;
+extern int __smp4m_processor_id(void);
+
+/*#define SMP_DEBUG*/
+
+#ifdef SMP_DEBUG
+#define SMP_PRINTK(x)  printk x
+#else
+#define SMP_PRINTK(x)
+#endif
+
+int smp4m_bogo_info(char *buf)
+{
+       return sprintf(buf,
+            "Cpu0Bogo\t: %lu.%02lu\n"
+           "Cpu1Bogo\t: %lu.%02lu\n"
+           "Cpu2Bogo\t: %lu.%02lu\n"
+           "Cpu3Bogo\t: %lu.%02lu\n",
+           cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100,
+           cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100,
+           cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100,
+           cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100);
+}
+
+int smp4m_info(char *buf)
+{
+       return sprintf(buf,
+"        CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
+"State:  %s\t\t%s\t\t%s\t\t%s\n",
+(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline",
+(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline",
+(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline",
+(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline");
+}
+
+static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
+{
+       __asm__ __volatile__("swap [%1], %0\n\t" :
+                            "=&r" (val), "=&r" (ptr) :
+                            "0" (val), "1" (ptr));
+       return val;
+}
+
+static void smp_setup_percpu_timer(void);
+extern void cpu_probe(void);
+
+__initfunc(void smp4m_callin(void))
+{
+       int cpuid = hard_smp_processor_id();
+
+       local_flush_cache_all();
+       local_flush_tlb_all();
+       set_irq_udt(mid_xlate[boot_cpu_id]);
+
+       /* Get our local ticker going. */
+       smp_setup_percpu_timer();
+
+       calibrate_delay();
+       smp_store_cpu_info(cpuid);
+       local_flush_cache_all();
+       local_flush_tlb_all();
+
+       /* Allow master to continue. */
+       swap((unsigned long *)&cpu_callin_map[cpuid], 1);
+       local_flush_cache_all();
+       local_flush_tlb_all();
+       
+       cpu_probe();
+
+       while(!task[cpuid] || current_set[cpuid] != task[cpuid])
+               barrier();
+
+       /* Fix idle thread fields. */
+       __asm__ __volatile__("ld [%0], %%g6\n\t"
+                            : : "r" (&current_set[cpuid])
+                            : "memory" /* paranoid */);
+       current->mm->mmap->vm_page_prot = PAGE_SHARED;
+       current->mm->mmap->vm_start = PAGE_OFFSET;
+       current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+       
+       while(!smp_commenced)
+               barrier();
+
+       local_flush_cache_all();
+       local_flush_tlb_all();
+
+       __sti();
+}
+
+extern int cpu_idle(void *unused);
+extern void init_IRQ(void);
+extern void cpu_panic(void);
+extern int start_secondary(void *unused);
+
+/*
+ *     Cycle through the processors asking the PROM to start each one.
+ */
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+extern struct linux_prom_registers smp_penguin_ctable;
+extern unsigned long trapbase_cpu1[];
+extern unsigned long trapbase_cpu2[];
+extern unsigned long trapbase_cpu3[];
+
+__initfunc(void smp4m_boot_cpus(void))
+{
+       int cpucount = 0;
+       int i = 0;
+       int first, prev;
+
+       printk("Entering SMP Mode...\n");
+
+       smp_penguin_ctable.which_io = 0;
+       smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+       smp_penguin_ctable.reg_size = 0;
+
+       for (i = 0; i < NR_CPUS; i++)
+               cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
+
+       __sti();
+       cpu_present_map = 0;
+       for(i=0; i < linux_num_cpus; i++)
+               cpu_present_map |= (1<<i);
+       for(i=0; i < NR_CPUS; i++)
+               cpu_number_map[i] = -1;
+       for(i=0; i < NR_CPUS; i++)
+               __cpu_logical_map[i] = -1;
+       mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
+       cpu_number_map[boot_cpu_id] = 0;
+       __cpu_logical_map[0] = boot_cpu_id;
+       klock_info.akp = boot_cpu_id;
+       current->processor = boot_cpu_id;
+       smp_store_cpu_info(boot_cpu_id);
+       set_irq_udt(mid_xlate[boot_cpu_id]);
+       smp_setup_percpu_timer();
+       local_flush_cache_all();
+       if(linux_num_cpus == 1)
+               return;  /* Not an MP box. */
+       for(i = 0; i < NR_CPUS; i++) {
+               if(i == boot_cpu_id)
+                       continue;
+
+               if(cpu_present_map & (1 << i)) {
+                       extern unsigned long sun4m_cpu_startup;
+                       unsigned long *entry = &sun4m_cpu_startup;
+                       struct task_struct *p;
+                       int timeout;
+
+                       /* Cook up an idler for this guy. */
+                       kernel_thread(start_secondary, NULL, CLONE_PID);
+
+                       p = task[++cpucount];
+
+                       p->processor = i;
+                       current_set[i] = p;
+
+                       /* See trampoline.S for details... */
+                       entry += ((i-1) * 3);
+
+                       /* whirrr, whirrr, whirrrrrrrrr... */
+                       printk("Starting CPU %d at %p\n", i, entry);
+                       mid_xlate[i] = (linux_cpus[i].mid & ~8);
+                       local_flush_cache_all();
+                       prom_startcpu(linux_cpus[i].prom_node,
+                                     &smp_penguin_ctable, 0, (char *)entry);
+
+                       /* wheee... it's going... */
+                       for(timeout = 0; timeout < 5000000; timeout++) {
+                               if(cpu_callin_map[i])
+                                       break;
+                               udelay(100);
+                       }
+                       if(cpu_callin_map[i]) {
+                               /* Another "Red Snapper". */
+                               cpu_number_map[i] = i;
+                               __cpu_logical_map[i] = i;
+                       } else {
+                               cpucount--;
+                               printk("Processor %d is stuck.\n", i);
+                       }
+               }
+               if(!(cpu_callin_map[i])) {
+                       cpu_present_map &= ~(1 << i);
+                       cpu_number_map[i] = -1;
+               }
+       }
+       local_flush_cache_all();
+       if(cpucount == 0) {
+               printk("Error: only one Processor found.\n");
+               cpu_present_map = (1 << smp_processor_id());
+       } else {
+               unsigned long bogosum = 0;
+               for(i = 0; i < NR_CPUS; i++) {
+                       if(cpu_present_map & (1 << i))
+                               bogosum += cpu_data[i].udelay_val;
+               }
+               printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
+                      cpucount + 1,
+                      (bogosum + 2500)/500000,
+                      ((bogosum + 2500)/5000)%100);
+               smp_activated = 1;
+               smp_num_cpus = cpucount + 1;
+       }
+
+       /* Setup CPU list for IRQ distribution scheme. */
+       first = prev = -1;
+       for(i = 0; i < NR_CPUS; i++) {
+               if(cpu_present_map & (1 << i)) {
+                       if(first == -1)
+                               first = i;
+                       if(prev != -1)
+                               cpu_data[prev].next = i;
+                       cpu_data[i].mid = mid_xlate[i];
+                       prev = i;
+               }
+       }
+       cpu_data[prev].next = first;
+       
+       /* Free unneeded trap tables */
+       
+       if (!(cpu_present_map & (1 << 1))) {
+               mem_map[MAP_NR((unsigned long)trapbase_cpu1)].flags &= ~(1 << PG_reserved);
+               free_page((unsigned long)trapbase_cpu1);
+       }
+       if (!(cpu_present_map & (1 << 2))) {
+               mem_map[MAP_NR((unsigned long)trapbase_cpu2)].flags &= ~(1 << PG_reserved);
+               free_page((unsigned long)trapbase_cpu2);
+       }
+       if (!(cpu_present_map & (1 << 3))) {
+               mem_map[MAP_NR((unsigned long)trapbase_cpu3)].flags &= ~(1 << PG_reserved);
+               free_page((unsigned long)trapbase_cpu3);
+       }
+
+       /* Ok, they are spinning and ready to go. */
+       smp_processors_ready = 1;
+}
+
+/* At each hardware IRQ, we get this called to forward IRQ reception
+ * to the next processor.  The caller must disable the IRQ level being
+ * serviced globally so that there are no double interrupts received.
+ */
+void smp4m_irq_rotate(int cpu)
+{
+       if(smp_processors_ready)
+               set_irq_udt(cpu_data[cpu_data[cpu].next].mid);
+}
+
+/* Cross calls, in order to work efficiently and atomically do all
+ * the message passing work themselves, only stopcpu and reschedule
+ * messages come through here.
+ */
+void smp4m_message_pass(int target, int msg, unsigned long data, int wait)
+{
+       static unsigned long smp_cpu_in_msg[NR_CPUS];
+       unsigned long mask;
+       int me = smp_processor_id();
+       int irq, i;
+
+       if(msg == MSG_RESCHEDULE) {
+               irq = IRQ_RESCHEDULE;
+
+               if(smp_cpu_in_msg[me])
+                       return;
+       } else if(msg == MSG_STOP_CPU) {
+               irq = IRQ_STOP_CPU;
+       } else {
+               goto barf;
+       }
+
+       smp_cpu_in_msg[me]++;
+       if(target == MSG_ALL_BUT_SELF || target == MSG_ALL) {
+               mask = cpu_present_map;
+               if(target == MSG_ALL_BUT_SELF)
+                       mask &= ~(1 << me);
+               for(i = 0; i < 4; i++) {
+                       if(mask & (1 << i))
+                               set_cpu_int(mid_xlate[i], irq);
+               }
+       } else {
+               set_cpu_int(mid_xlate[target], irq);
+       }
+       smp_cpu_in_msg[me]--;
+
+       return;
+barf:
+       printk("Yeeee, trying to send SMP msg(%d) on cpu %d\n", msg, me);
+       panic("Bogon SMP message pass.");
+}
+
+static struct smp_funcall {
+       smpfunc_t func;
+       unsigned long arg1;
+       unsigned long arg2;
+       unsigned long arg3;
+       unsigned long arg4;
+       unsigned long arg5;
+       unsigned long processors_in[NR_CPUS];  /* Set when ipi entered. */
+       unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */
+} ccall_info;
+
+static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED;
+
+/* Cross calls must be serialized, at least currently. */
+void smp4m_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
+                   unsigned long arg3, unsigned long arg4, unsigned long arg5)
+{
+       if(smp_processors_ready) {
+               register int ncpus = smp_num_cpus;
+               unsigned long flags;
+
+               spin_lock_irqsave(&cross_call_lock, flags);
+
+               /* Init function glue. */
+               ccall_info.func = func;
+               ccall_info.arg1 = arg1;
+               ccall_info.arg2 = arg2;
+               ccall_info.arg3 = arg3;
+               ccall_info.arg4 = arg4;
+               ccall_info.arg5 = arg5;
+
+               /* Init receive/complete mapping, plus fire the IPI's off. */
+               {
+                       register unsigned long mask;
+                       register int i;
+
+                       mask = (cpu_present_map & ~(1 << smp_processor_id()));
+                       for(i = 0; i < ncpus; i++) {
+                               if(mask & (1 << i)) {
+                                       ccall_info.processors_in[i] = 0;
+                                       ccall_info.processors_out[i] = 0;
+                                       set_cpu_int(mid_xlate[i], IRQ_CROSS_CALL);
+                               } else {
+                                       ccall_info.processors_in[i] = 1;
+                                       ccall_info.processors_out[i] = 1;
+                               }
+                       }
+               }
+
+               /* First, run local copy. */
+               func(arg1, arg2, arg3, arg4, arg5);
+
+               {
+                       register int i;
+
+                       i = 0;
+                       do {
+                               while(!ccall_info.processors_in[i])
+                                       barrier();
+                       } while(++i < ncpus);
+
+                       i = 0;
+                       do {
+                               while(!ccall_info.processors_out[i])
+                                       barrier();
+                       } while(++i < ncpus);
+               }
+
+               spin_unlock_irqrestore(&cross_call_lock, flags);
+       } else
+               func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
+}
+
+/* Running cross calls. */
+void smp4m_cross_call_irq(void)
+{
+       int i = smp_processor_id();
+
+       ccall_info.processors_in[i] = 1;
+       ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
+                       ccall_info.arg4, ccall_info.arg5);
+       ccall_info.processors_out[i] = 1;
+}
+
+/* Protects counters touched during level14 ticker */
+static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+
+#ifdef CONFIG_PROFILE
+
+/* 32-bit Sparc specific profiling function. */
+static inline void sparc_do_profile(unsigned long pc)
+{
+       if(prof_buffer && current->pid) {
+               extern int _stext;
+
+               pc -= (unsigned long) &_stext;
+               pc >>= prof_shift;
+
+               spin_lock(&ticker_lock);
+               if(pc < prof_len)
+                       prof_buffer[pc]++;
+               else
+                       prof_buffer[prof_len - 1]++;
+               spin_unlock(&ticker_lock);
+       }
+}
+
+#endif
+
+extern unsigned int prof_multiplier[NR_CPUS];
+extern unsigned int prof_counter[NR_CPUS];
+
+extern void update_one_process(struct task_struct *p, unsigned long ticks,
+                              unsigned long user, unsigned long system,
+                              int cpu);
+
+void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       clear_profile_irq(mid_xlate[cpu]);
+#ifdef CONFIG_PROFILE
+       if(!user_mode(regs))
+               sparc_do_profile(regs->pc);
+#endif
+       if(!--prof_counter[cpu]) {
+               int user = user_mode(regs);
+               if(current->pid) {
+                       update_one_process(current, 1, user, !user, cpu);
+
+                       if(--current->counter < 0) {
+                               current->counter = 0;
+                               need_resched = 1;
+                       }
+
+                       spin_lock(&ticker_lock);
+                       if(user) {
+                               if(current->priority < DEF_PRIORITY) {
+                                       kstat.cpu_nice++;
+                                       kstat.per_cpu_nice[cpu]++;
+                               } else {
+                                       kstat.cpu_user++;
+                                       kstat.per_cpu_user[cpu]++;
+                               }
+                       } else {
+                               kstat.cpu_system++;
+                               kstat.per_cpu_system[cpu]++;
+                       }
+                       spin_unlock(&ticker_lock);
+               }
+               prof_counter[cpu] = prof_multiplier[cpu];
+       }
+}
+
+extern unsigned int lvl14_resolution;
+
+__initfunc(static void smp_setup_percpu_timer(void))
+{
+       int cpu = smp_processor_id();
+
+       prof_counter[cpu] = prof_multiplier[cpu] = 1;
+       load_profile_irq(mid_xlate[cpu], lvl14_resolution);
+
+       if(cpu == boot_cpu_id)
+               enable_pil_irq(14);
+}
+
+__initfunc(void smp4m_blackbox_id(unsigned *addr))
+{
+       int rd = *addr & 0x3e000000;
+       int rs1 = rd >> 11;
+       
+       addr[0] = 0x81580000 | rd;              /* rd %tbr, reg */
+       addr[1] = 0x8130200c | rd | rs1;        /* srl reg, 0xc, reg */
+       addr[2] = 0x80082003 | rd | rs1;        /* and reg, 3, reg */
+}
+
+__initfunc(void smp4m_blackbox_current(unsigned *addr))
+{
+       int rd = *addr & 0x3e000000;
+       int rs1 = rd >> 11;
+       
+       addr[0] = 0x81580000 | rd;              /* rd %tbr, reg */
+       addr[2] = 0x8130200a | rd | rs1;        /* srl reg, 0xa, reg */
+       addr[4] = 0x8008200c | rd | rs1;        /* and reg, 3, reg */
+}
+
+__initfunc(void sun4m_init_smp(void))
+{
+       BTFIXUPSET_BLACKBOX(smp_processor_id, smp4m_blackbox_id);
+       BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current);
+       BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(smp_message_pass, smp4m_message_pass, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(smp_bogo_info, smp4m_bogo_info, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(smp_info, smp4m_info, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(__smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM);
+}
index 4f6b2accc68a3642ceb1f1377caaa1637d439b64..deb1aa79ec4b307e8b50fcd645a39ca4e2cfc82f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.29 1997/09/18 10:37:31 rth Exp $
+/* $Id: sunos_ioctl.c,v 1.30 1998/01/21 06:17:32 ecd Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -114,7 +114,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
                ret = sys_ioctl(fd, SIOCGIFBRDADDR, arg);
                goto out;
        case _IOW('i', 24, struct ifreq):
-               ret = sys_ioctl(fd, SIOCGIFBRDADDR, arg);
+               ret = sys_ioctl(fd, SIOCSIFBRDADDR, arg);
                goto out;
        case _IOWR('i', 25, struct ifreq):
                ret = sys_ioctl(fd, SIOCGIFNETMASK, arg);
index 5b82aa8eb10a943090165c8c5f8b870e76bb7001..2fe56b344d1065d619c756103b7c9d21e9e88f34 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.38 1998/01/09 16:42:48 jj Exp $
+/* $Id: sys_sparc.c,v 1.40 1998/03/28 08:29:26 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -10,8 +10,9 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/config.h>
-#include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -39,7 +40,7 @@ asmlinkage unsigned long sparc_brk(unsigned long brk)
        unsigned long ret;
 
        lock_kernel();
-       if(sparc_cpu_model == sun4c) {
+       if(ARCH_SUN4C_SUN4) {
                if(brk >= 0x20000000 && brk < 0xe0000000) {
                        ret = current->mm->brk;
                        goto out;
@@ -192,31 +193,34 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
 
        lock_kernel();
        if (!(flags & MAP_ANONYMOUS)) {
-               if (fd >= NR_OPEN || !(file = current->files->fd[fd])){
+               file = fget(fd);
+               if (!file)
                        goto out;
-           }
        }
        retval = -ENOMEM;
        if(!(flags & MAP_FIXED) && !addr) {
                addr = get_unmapped_area(addr, len);
-               if(!addr){
-                       goto out;
-               }
+               if(!addr)
+                       goto out_putf;
        }
 
        /* See asm-sparc/uaccess.h */
        retval = -EINVAL;
        if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
-               goto out;
+               goto out_putf;
 
-       if(sparc_cpu_model == sun4c) {
+       if(ARCH_SUN4C_SUN4) {
                if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
                        retval = current->mm->brk;
-                       goto out;
+                       goto out_putf;
                }
        }
 
        retval = do_mmap(file, addr, len, prot, flags, off);
+
+out_putf:
+       if (file)
+               fput(file);
 out:
        unlock_kernel();
        return retval;
index 29f00f6b89dc1ac1e794402e3017baa81a2699e1..bd7bf5d7764d3534c010e3a83a28b62c32ff7458 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.83 1997/12/14 23:24:28 ecd Exp $
+/* $Id: sys_sunos.c,v 1.87 1998/03/29 03:48:16 shadow Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/resource.h>
 #include <linux/ipc.h>
 #include <linux/shm.h>
@@ -77,14 +78,19 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
                flags &= ~MAP_NORESERVE;
        }
        retval = -EBADF;
-       if(!(flags & MAP_ANONYMOUS))
-               if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+       if(!(flags & MAP_ANONYMOUS)) {
+               if (fd >= SUNOS_NR_OPEN)
                        goto out;
+               file = fget(fd);
+               if (!file)
+                       goto out;
+       }
+
        retval = -ENOMEM;
        if(!(flags & MAP_FIXED) && !addr) {
                addr = get_unmapped_area(addr, len);
                if(!addr)
-                       goto out;
+                       goto out_putf;
        }
        /* If this is ld.so or a shared library doing an mmap
         * of /dev/zero, transform it into an anonymous mapping.
@@ -105,18 +111,22 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
        /* See asm-sparc/uaccess.h */
        retval = -EINVAL;
        if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
-               goto out;
+               goto out_putf;
 
-       if(sparc_cpu_model == sun4c) {
+       if(ARCH_SUN4C_SUN4) {
                if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
                        retval = current->mm->brk;
-                       goto out;
+                       goto out_putf;
                }
        }
 
        retval = do_mmap(file, addr, len, prot, flags, off);
        if(!ret_type)
                retval = ((retval < PAGE_OFFSET) ? 0 : retval);
+
+out_putf:
+       if (file)
+               fput(file);
 out:
        unlock_kernel();
        return retval;
@@ -139,7 +149,7 @@ asmlinkage int sunos_brk(unsigned long brk)
        unsigned long newbrk, oldbrk;
 
        lock_kernel();
-       if(sparc_cpu_model == sun4c) {
+       if(ARCH_SUN4C_SUN4) {
                if(brk >= 0x20000000 && brk < 0xe0000000) {
                        goto out;
                }
@@ -423,39 +433,48 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
 asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
 {
        struct file * file;
+       struct inode * inode;
        struct sunos_dirent * lastdirent;
        struct sunos_dirent_callback buf;
        int error = -EBADF;
 
        lock_kernel();
-       if(fd >= SUNOS_NR_OPEN)
+       if (fd >= SUNOS_NR_OPEN)
                goto out;
 
-       file = current->files->fd[fd];
-       if(!file)
+       file = fget(fd);
+       if (!file)
                goto out;
 
        error = -ENOTDIR;
        if (!file->f_op || !file->f_op->readdir)
-               goto out;
+               goto out_putf;
 
        error = -EINVAL;
-       if(cnt < (sizeof(struct sunos_dirent) + 255))
-               goto out;
+       if (cnt < (sizeof(struct sunos_dirent) + 255))
+               goto out_putf;
 
        buf.curr = (struct sunos_dirent *) dirent;
        buf.previous = NULL;
        buf.count = cnt;
        buf.error = 0;
+
+       inode = file->f_dentry->d_inode;
+       down(&inode->i_sem);
        error = file->f_op->readdir(file, &buf, sunos_filldir);
+       up(&inode->i_sem);
        if (error < 0)
-               goto out;
+               goto out_putf;
+
        lastdirent = buf.previous;
        error = buf.error;
        if (lastdirent) {
                put_user(file->f_pos, &lastdirent->d_off);
                error = cnt - buf.count;
        }
+
+out_putf:
+       fput(file);
 out:
        unlock_kernel();
        return error;
@@ -503,39 +522,48 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
 asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep)
 {
        struct file * file;
+       struct inode * inode;
        struct sunos_direntry * lastdirent;
        struct sunos_direntry_callback buf;
        int error = -EBADF;
 
        lock_kernel();
-       if(fd >= SUNOS_NR_OPEN)
+       if (fd >= SUNOS_NR_OPEN)
                goto out;
 
-       file = current->files->fd[fd];
-       if(!file)
+       file = fget(fd);
+       if (!file)
                goto out;
 
        error = -ENOTDIR;
        if (!file->f_op || !file->f_op->readdir)
-               goto out;
+               goto out_putf;
 
        error = -EINVAL;
        if(cnt < (sizeof(struct sunos_direntry) + 255))
-               goto out;
+               goto out_putf;
 
        buf.curr = (struct sunos_direntry *) dirent;
        buf.previous = NULL;
        buf.count = cnt;
        buf.error = 0;
+
+       inode = file->f_dentry->d_inode;
+       down(&inode->i_sem);
        error = file->f_op->readdir(file, &buf, sunos_filldirentry);
+       up(&inode->i_sem);
        if (error < 0)
-               goto out;
+               goto out_putf;
+
        lastdirent = buf.previous;
        error = buf.error;
        if (lastdirent) {
                put_user(file->f_pos, basep);
                error = cnt - buf.count;
        }
+
+out_putf:
+       fput(file);
 out:
        unlock_kernel();
        return error;
@@ -669,6 +697,15 @@ asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, s
        lock_kernel();
        current->personality |= STICKY_TIMEOUTS;
        ret = sys_select (width, inp, outp, exp, tvp);
+       if (ret == -EINTR && tvp) {
+               time_t sec, usec;
+
+               __get_user(sec, &tvp->tv_sec);
+               __get_user(usec, &tvp->tv_usec);
+
+               if (sec == 0 && usec == 0)
+                       ret = 0;
+       }
        unlock_kernel();
        return ret;
 }
@@ -720,7 +757,7 @@ extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
 
 /* Bind the socket on a local reserved port and connect it to the
  * remote server.  This on Linux/i386 is done by the mount program,
- * not by the kernel. 
+ * not by the kernel.
  */
 static int
 sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
@@ -728,16 +765,16 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
        struct sockaddr_in local;
        struct sockaddr_in server;
        int    try_port;
-       int    ret;
        struct socket *socket;
-       struct dentry *dentry;
        struct inode  *inode;
        struct file   *file;
+       int    ret, result = 0;
 
-       file = current->files->fd [fd];
-       dentry = file->f_dentry;
-       if(!dentry || !(inode = dentry->d_inode))
-               return 0;
+       file = fget(fd);
+       if (!file)
+               goto out;
+       if (!file->f_dentry || !(inode = file->f_dentry->d_inode))
+               goto out_putf;
 
        socket = &inode->u.socket_i;
        local.sin_family = AF_INET;
@@ -752,7 +789,7 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
        } while (ret && try_port > (1024 / 2));
 
        if (ret)
-               return 0;
+               goto out_putf;
 
        server.sin_family = AF_INET;
        server.sin_addr = addr->sin_addr;
@@ -761,9 +798,13 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
        /* Call sys_connect */
        ret = socket->ops->connect (socket, (struct sockaddr *) &server,
                                    sizeof (server), file->f_flags);
-       if (ret < 0)
-               return 0;
-       return 1;
+       if (ret >= 0)
+               result = 1;
+
+out_putf:
+       fput(file);
+out:
+       return result;
 }
 
 static int get_default (int value, int def_value)
@@ -1139,10 +1180,13 @@ asmlinkage int sunos_open(const char *filename, int flags, int mode)
    file descriptors that have been set non-blocking 
    using 4.2BSD style calls. (tridge) */
 
-static inline int check_nonblock(int ret,int fd)
+static inline int check_nonblock(int ret, int fd)
 {
-       if (ret == -EAGAIN && (current->files->fd[fd]->f_flags & O_NDELAY))
-               return -SUNOS_EWOULDBLOCK;
+       if (ret == -EAGAIN) {
+               struct file * file = fcheck(fd);
+               if (file && (file->f_flags & O_NDELAY))
+                       ret = -SUNOS_EWOULDBLOCK;
+       }
        return ret;
 }
 
@@ -1215,12 +1259,41 @@ asmlinkage int sunos_send(int fd, void * buff, int len, unsigned flags)
        return ret;
 }
 
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+                                    char *optval, int optlen);
+
+asmlinkage int sunos_socket(int family, int type, int protocol)
+{
+       int ret, one = 1;
+
+       lock_kernel();
+       ret = sys_socket(family, type, protocol);
+       if (ret < 0)
+               goto out;
+
+       sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT,
+                      (char *)&one, sizeof(one));
+out:
+       unlock_kernel();
+       return ret;
+}
+
 asmlinkage int sunos_accept(int fd, struct sockaddr *sa, int *addrlen)
 {
-       int ret;
+       int ret, one = 1;
 
        lock_kernel();
-       ret = check_nonblock(sys_accept(fd,sa,addrlen),fd);     
+       while (1) {
+               ret = check_nonblock(sys_accept(fd,sa,addrlen),fd);     
+               if (ret != -ENETUNREACH && ret != -EHOSTUNREACH)
+                       break;
+       }
+       if (ret < 0)
+               goto out;
+
+       sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT,
+                      (char *)&one, sizeof(one));
+out:
        unlock_kernel();
        return ret;
 }
index 5ea64d2a476e10c9988ccc40b18c8c9c4c86f8ec..320264255c8075394e7568a70419f1f54d2625db 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.68 1997/12/24 17:26:38 ecd Exp $
+/* $Id: systbls.S,v 1.71 1998/03/24 06:25:06 ecd Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -23,9 +23,9 @@ C_LABEL(sys_call_table):
 /*5*/  .long C_LABEL(sys_open), C_LABEL(sys_close), C_LABEL(sys_wait4)
        .long C_LABEL(sys_creat), C_LABEL(sys_link)
 /*10*/  .long C_LABEL(sys_unlink), C_LABEL(sunos_execv), C_LABEL(sys_chdir)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_mknod)
-/*15*/ .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sparc_brk)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_lseek)
+       .long C_LABEL(sys_xstat), C_LABEL(sys_mknod)
+/*15*/ .long C_LABEL(sys_chmod), C_LABEL(sys_lchown), C_LABEL(sparc_brk)
+       .long C_LABEL(sys_xmknod), C_LABEL(sys_lseek)
 /*20*/ .long C_LABEL(sys_getpid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
        .long C_LABEL(sys_setuid), C_LABEL(sys_getuid)
 /*25*/ .long C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm)
@@ -137,7 +137,7 @@ C_LABEL(sunos_sys_table):
        .long C_LABEL(sys_close), C_LABEL(sunos_wait4), C_LABEL(sys_creat)
        .long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv)
        .long C_LABEL(sys_chdir), C_LABEL(sunos_nosys), C_LABEL(sys_mknod)
-       .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sunos_brk)
+       .long C_LABEL(sys_chmod), C_LABEL(sys_lchown), C_LABEL(sunos_brk)
        .long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), C_LABEL(sunos_getpid)
        .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
        .long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sys_ptrace)
@@ -164,7 +164,7 @@ C_LABEL(sunos_sys_table):
        .long C_LABEL(sys_getitimer), C_LABEL(sys_gethostname), C_LABEL(sys_sethostname)
        .long C_LABEL(sunos_getdtablesize), C_LABEL(sys_dup2), C_LABEL(sunos_nop)
        .long C_LABEL(sys_fcntl), C_LABEL(sunos_select), C_LABEL(sunos_nop)
-       .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_socket)
+       .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sunos_socket)
        .long C_LABEL(sys_connect), C_LABEL(sunos_accept)
 /*100*/        .long C_LABEL(sys_getpriority), C_LABEL(sunos_send), C_LABEL(sunos_recv)
        .long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sunos_setsockopt)
index 03fe3cff91079db12e26b6ebaca4f27c0f55363b..f618bf53be02fdcb80d8a343c26794d7d39cbf29 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/asi.h>
 #include <asm/oplib.h>
@@ -94,7 +95,7 @@ static void swift_clockstop(void)
        clk_ctrl[0] = 0;
 }
 
-void clock_stop_probe(void)
+__initfunc(void clock_stop_probe(void))
 {
        unsigned int node, clk_nd;
        char name[20];
index 77401391e1b8dd927521867d101f471c7ccfb499..5eb49e22cc9a2d05a8574aa49691ef9230d939ad 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.29 1997/04/18 09:48:44 davem Exp $
+/* $Id: time.c,v 1.32 1998/03/23 08:41:13 jj Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/sun4paddr.h>
+#include <asm/page.h>
 
 enum sparc_clock_type sp_clock_typ;
 struct mostek48t02 *mstk48t02_regs = 0;
@@ -88,7 +92,7 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon,
 }
 
 /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void kick_start_clock(void)
+__initfunc(static void kick_start_clock(void))
 {
        register struct mostek48t02 *regs = mstk48t02_regs;
        unsigned char sec;
@@ -137,7 +141,7 @@ static void kick_start_clock(void)
 }
 
 /* Return nonzero if the clock chip battery is low. */
-static int has_low_battery(void)
+static __inline__ int has_low_battery(void)
 {
        register struct mostek48t02 *regs = mstk48t02_regs;
        unsigned char data1, data2;
@@ -150,8 +154,24 @@ static int has_low_battery(void)
        return (data1 == data2);        /* Was the write blocked? */
 }
 
-/* Probe for the real time clock chip. */
-__initfunc(static void clock_probe(void))
+/* Probe for the real time clock chip on Sun4/300. */
+static __inline__ void sun4_clock_probe(void)
+{
+       sp_clock_typ = MSTK48T02;
+       mstk48t02_regs = (struct mostek48t02 *) 
+               sparc_alloc_io(SUN4_300_MOSTEK_PHYSADDR, 0,
+                              sizeof(*mstk48t02_regs),
+                              "clock", 0x0, 0x0);
+       mstk48t08_regs = 0;  /* To catch weirdness */
+       /* Kick start the clock if it is completely stopped. */
+       if (mstk48t02_regs->sec & MSTK_STOP) {
+               kick_start_clock();
+       }
+
+}
+
+/* Probe for the mostek real time clock chip. */
+static __inline__ void clock_probe(void)
 {
        struct linux_prom_registers clk_reg[2];
        char model[128];
@@ -247,7 +267,11 @@ __initfunc(void time_init(void))
         return;
 #endif
 
-       clock_probe();
+       if (ARCH_SUN4)
+               sun4_clock_probe();
+       else
+               clock_probe();
+
        init_timers(timer_interrupt);
 
        mregs = mstk48t02_regs;
index 9ee5bd14a38d5fb83dcf1d2dde716380fad63e80..3515e265d484f4a4a1a728acf6aa120a7b3a1fa3 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: trampoline.S,v 1.9 1997/05/01 08:53:34 davem Exp $
+/* $Id: trampoline.S,v 1.12 1998/03/19 15:36:38 jj Exp $
  * trampoline.S: SMP cpu boot-up trampoline code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 #include <asm/vaddrs.h>
 #include <asm/contregs.h>
+#include <asm/init.h>
 
+       .globl C_LABEL(sun4m_cpu_startup), C_LABEL(__smp4m_processor_id)
+       .globl C_LABEL(sun4d_cpu_startup), C_LABEL(__smp4d_processor_id)
 
-       .text
+       __INIT
        .align 4
 
 /* When we start up a cpu for the first time it enters this routine.
@@ -22,8 +26,7 @@
  * in and sets PIL in %psr to 15, no irqs.
  */
 
-       .globl C_LABEL(sparc_cpu_startup)
-C_LABEL(sparc_cpu_startup):
+C_LABEL(sun4m_cpu_startup):
 cpu1_startup:
        sethi   %hi(C_LABEL(trapbase_cpu1)), %g3
        b       1f
@@ -60,9 +63,8 @@ cpu3_startup:
        and     %g4, 0xc, %g4
        ld      [%g5 + %g4], %g6
 
-       mov     1, %sp
-       sll     %sp, (PAGE_SHIFT + 1), %sp
-       sub     %sp, REGWIN_SZ, %sp
+       sethi   %hi(TASK_UNION_SIZE - REGWIN_SZ), %sp
+       or      %sp, %lo(TASK_UNION_SIZE - REGWIN_SZ), %sp
        add     %g6, %sp, %sp
 
        /* Turn on traps (PSR_ET). */
@@ -77,11 +79,84 @@ cpu3_startup:
         nop
 
        /* Start this processor. */
-       call    C_LABEL(smp_callin)
+       call    C_LABEL(smp4m_callin)
         nop
 
+       b,a     smp_do_cpu_idle
+
+       .text
+       .align  4
+
+smp_do_cpu_idle:
        call    C_LABEL(cpu_idle)
         mov    0, %o0
 
        call    C_LABEL(cpu_panic)
         nop
+
+C_LABEL(__smp4m_processor_id):
+       rd      %tbr, %g2
+       srl     %g2, 12, %g2
+       and     %g2, 3, %g2
+       retl
+        mov    %g1, %o7
+
+C_LABEL(__smp4d_processor_id):
+       lda     [%g0] ASI_M_VIKING_TMP1, %g2
+       retl
+        mov    %g1, %o7
+
+/* CPUID in bootbus can be found at PA 0xff0140000 */
+#define SUN4D_BOOTBUS_CPUID    0xf0140000
+
+       __INIT
+       .align  4
+
+C_LABEL(sun4d_cpu_startup):
+       /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
+       set     (PSR_PIL | PSR_S | PSR_PS), %g1
+       wr      %g1, 0x0, %psr          ! traps off though
+       WRITE_PAUSE
+
+       /* Our %wim is one behind CWP */
+       mov     2, %g1
+       wr      %g1, 0x0, %wim
+       WRITE_PAUSE
+
+       /* Set tbr - we use just one trap table. */
+       set     C_LABEL(trapbase), %g1
+       wr      %g1, 0x0, %tbr
+       WRITE_PAUSE
+
+       /* Get our CPU id out of bootbus */
+       set     SUN4D_BOOTBUS_CPUID, %g3
+       lduba   [%g3] ASI_M_CTL, %g3
+       and     %g3, 0xf8, %g3
+       srl     %g3, 3, %g1
+       sta     %g1, [%g0] ASI_M_VIKING_TMP1
+
+       /* Give ourselves a stack and curptr. */
+       set     C_LABEL(current_set), %g5
+       srl     %g3, 1, %g4
+       ld      [%g5 + %g4], %g6
+
+       sethi   %hi(TASK_UNION_SIZE - REGWIN_SZ), %sp
+       or      %sp, %lo(TASK_UNION_SIZE - REGWIN_SZ), %sp
+       add     %g6, %sp, %sp
+
+       /* Turn on traps (PSR_ET). */
+       rd      %psr, %g1
+       wr      %g1, PSR_ET, %psr       ! traps on
+       WRITE_PAUSE
+
+       /* Init our caches, etc. */
+       set     C_LABEL(poke_srmmu), %g5
+       ld      [%g5], %g5
+       call    %g5
+        nop
+
+       /* Start this processor. */
+       call    C_LABEL(smp4d_callin)
+        nop
+
+       b,a     smp_do_cpu_idle
index 19a3afbd0b0c9a696a0d3523873ac6a9b8500f07..015d05357ef4ab380c436c8c388fe20b95596a57 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.53 1997/01/25 02:43:05 miguel Exp $
+/* $Id: traps.c,v 1.56 1998/04/06 16:08:32 jj Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -62,6 +62,14 @@ void sun4m_nmi(struct pt_regs *regs)
        prom_halt();
 }
 
+void sun4d_nmi(struct pt_regs *regs)
+{
+       printk("Aieee: sun4d NMI received!\n");
+       printk("you lose buddy boy...\n");
+       show_regs(regs);
+       prom_halt();
+}
+
 void instruction_dump (unsigned long *pc)
 {
        int i;
@@ -229,10 +237,13 @@ static unsigned long fake_fsr;
 static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
 static unsigned long fake_depth;
 
+extern int do_mathemu(struct pt_regs *, struct task_struct *);
+
 void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                 unsigned long psr)
 {
        static calls = 0;
+       int ret;
 #ifndef __SMP__
        struct task_struct *fpt = last_task_used_math;
 #else
@@ -255,6 +266,40 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
        }
        fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr,
               &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth);
+#ifdef DEBUG_FPU
+       printk("Hmm, FP exception, fsr was %016lx\n", fpt->tss.fsr);
+#endif
+
+       switch ((fpt->tss.fsr & 0x1c000)) {
+       /* switch on the contents of the ftt [floating point trap type] field */
+#ifdef DEBUG_FPU
+       case (1 << 14):
+               printk("IEEE_754_exception\n");
+               break;
+#endif
+       case (2 << 14):  /* unfinished_FPop (underflow & co) */
+       case (3 << 14):  /* unimplemented_FPop (quad stuff, maybe sqrt) */
+               ret = do_mathemu(regs, fpt);
+               break;
+#ifdef DEBUG_FPU
+       case (4 << 14):
+               printk("sequence_error (OS bug...)\n");
+               break;
+       case (5 << 14):
+               printk("hardware_error (uhoh!)\n");
+               break;
+       case (6 << 14):
+               printk("invalid_fp_register (user error)\n");
+               break;
+#endif /* DEBUG_FPU */
+       }
+       /* If we successfully emulated the FPop, we pretend the trap never happened :-> */
+       if (ret) {
+               fpload(&current->tss.float_regs[0], &current->tss.fsr);
+               return;
+       }
+       /* nope, better SIGFPE the offending process... */
+              
        fpt->tss.sig_address = pc;
        fpt->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */
 #ifdef __SMP__
@@ -331,19 +376,6 @@ void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long np
        unlock_kernel();
 }
 
-void handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-                     unsigned long psr)
-{
-       lock_kernel();
-#ifdef TRAP_DEBUG
-       printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n",
-              pc, npc, psr);
-#endif
-       printk("INSTRUCTION=%08lx\n", *((unsigned long *) regs->pc));
-       send_sig(SIGILL, current, 1);
-       unlock_kernel();
-}
-
 void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                         unsigned long psr)
 {
index 890676bfb1e239252bdc22492f947a8a0f0027e9..1d321d5214fbadf9b90799747060de5f3a3979ee 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.36 1997/05/01 08:53:35 davem Exp $
+/* $Id: wof.S,v 1.38 1998/02/06 14:14:22 jj Exp $
  * wof.S: Sparc window overflow handler.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -234,9 +234,10 @@ spwin_user_stack_is_bolixed:
 spnwin_patch3: and     %twin_tmp, 0xff, %twin_tmp      ! patched on 7win Sparcs
                st      %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask]
 
-       mov     1, %sp
-       sll     %sp, (PAGE_SHIFT + 1), %sp
-       sub     %sp, (TRACEREG_SZ + REGWIN_SZ), %sp
+#define STACK_OFFSET   (TASK_UNION_SIZE - TRACEREG_SZ - REGWIN_SZ)
+
+       sethi   %hi(STACK_OFFSET), %sp
+       or      %sp, %lo(STACK_OFFSET), %sp
        add     %curptr, %sp, %sp
 
        /* Restore the saved globals and build a pt_regs frame. */
@@ -244,9 +245,8 @@ spnwin_patch3:      and     %twin_tmp, 0xff, %twin_tmp      ! patched on 7win Sparcs
        mov     %saved_g6, %g6
        STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
 
-       mov     1, %g6
-       sll     %g6, (PAGE_SHIFT + 1), %g6
-       sub     %g6, (TRACEREG_SZ + REGWIN_SZ), %g6
+       sethi   %hi(STACK_OFFSET), %g6
+       or      %g6, %lo(STACK_OFFSET), %g6
        sub     %sp, %g6, %g6
 
        /* Turn on traps and call c-code to deal with it. */
@@ -394,9 +394,8 @@ C_LABEL(spwin_srmmu_stackchk):
         * kernel is page aligned, which should always be the case.
         */
        /* Check results of callers andcc %sp, 0x7, %g0 */
-       sethi   %hi(C_LABEL(page_offset)), %glob_tmp
        bne     spwin_user_stack_is_bolixed
-        ld     [%glob_tmp + %lo(C_LABEL(page_offset))], %glob_tmp
+        GET_PAGE_OFFSET(glob_tmp)
        cmp     %glob_tmp, %sp
        bleu    spwin_user_stack_is_bolixed
         mov    AC_M_SFSR, %glob_tmp
index cb407aa6922a6839ff2a9e4cbbb7ec38e5f48f34..bfa5b5191472a8160dabcd202cdeb400a3cd2924 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.34 1997/05/01 08:53:36 davem Exp $
+/* $Id: wuf.S,v 1.37 1998/02/19 21:25:50 ecd Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
@@ -138,6 +138,8 @@ fwin_from_user:
 C_LABEL(fwin_mmu_patchme):     b       C_LABEL(sun4c_fwin_stackchk)
                                 andcc  %sp, 0x7, %g0
 
+#define STACK_OFFSET (TASK_UNION_SIZE - TRACEREG_SZ - REGWIN_SZ)
+
 fwin_user_stack_is_bolixed:
        /* LOCATION: Window 'W' */
 
@@ -146,9 +148,8 @@ fwin_user_stack_is_bolixed:
         */
        LOAD_CURRENT(l4, l5)
 
-       mov     1, %l5
-       sll     %l5, (PAGE_SHIFT + 1), %l5
-       sub     %l5, (TRACEREG_SZ + REGWIN_SZ), %l5
+       sethi   %hi(STACK_OFFSET), %l5
+       or      %l5, %lo(STACK_OFFSET), %l5
        add     %l4, %l5, %l5
 
        /* Store globals into pt_regs frame. */
@@ -169,10 +170,9 @@ fwin_user_stack_is_bolixed:
 
        /* LOCATION: Window 'T' */
 
-       mov     1, %sp
-       sll     %sp, (PAGE_SHIFT + 1), %sp
-       sub     %sp, (TRACEREG_SZ + REGWIN_SZ), %sp
-       add     %curptr, %sp, %sp
+       sethi   %hi(STACK_OFFSET), %l5
+       or      %l5, %lo(STACK_OFFSET), %l5
+       add     %curptr, %l5, %sp
 
        /* Build rest of pt_regs. */
        STORE_PT_INS(sp)
@@ -299,9 +299,8 @@ C_LABEL(srmmu_fwin_stackchk):
        /* LOCATION: Window 'W' */
 
        /* Caller did 'andcc %sp, 0x7, %g0' */
-       sethi   %hi(C_LABEL(page_offset)), %l5
        bne     fwin_user_stack_is_bolixed
-        ld     [%l5 + %lo(C_LABEL(page_offset))], %l5
+        GET_PAGE_OFFSET(l5)
 
        /* Check if the users stack is in kernel vma, then our
         * trial and error technique below would succeed for
index cefe7a8514f2ac31f7e4efe4f60b0f85ec672434..6ec986c86bf4dbcb63a8350d29c69afe0289722e 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.24 1997/05/08 17:45:26 davem Exp $
+# $Id: Makefile,v 1.25 1998/01/30 10:58:43 jj Exp $
 # Makefile for Sparc library files..
 #
 
@@ -16,19 +16,19 @@ lib.a: $(OBJS)
        sync
 
 checksum.o: checksum.S
-       $(CC) -ansi -c -o checksum.o checksum.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o checksum.o checksum.S
 
 memcpy.o: memcpy.S
        $(CC) -D__ASSEMBLY__ -ansi -c -o memcpy.o memcpy.S
 
 memcmp.o: memcmp.S
-       $(CC) -ansi -c -o memcmp.o memcmp.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o memcmp.o memcmp.S
 
 memscan.o: memscan.S
-       $(CC) -ansi -c -o memscan.o memscan.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o memscan.o memscan.S
 
 strncmp.o: strncmp.S
-       $(CC) -ansi -c -o strncmp.o strncmp.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o strncmp.o strncmp.S
 
 strncpy_from_user.o: strncpy_from_user.S
        $(CC) -D__ASSEMBLY__ -ansi -c -o strncpy_from_user.o strncpy_from_user.S
@@ -40,7 +40,7 @@ copy_user.o: copy_user.S
        $(CC) -D__ASSEMBLY__ -ansi -c -o copy_user.o copy_user.S
 
 blockops.o: blockops.S
-       $(CC) -ansi -c -o blockops.o blockops.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o blockops.o blockops.S
 
 memset.o: memset.S
        $(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S
@@ -73,34 +73,34 @@ bitops.o: bitops.S
 endif
 
 strlen.o: strlen.S
-       $(CC) -ansi -c -o strlen.o strlen.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o strlen.o strlen.S
 
 divdi3.o: divdi3.S
-       $(CC) -ansi -c -o divdi3.o divdi3.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o divdi3.o divdi3.S
 
 udivdi3.o: udivdi3.S
-       $(CC) -ansi -c -o udivdi3.o udivdi3.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o udivdi3.o udivdi3.S
 
 mul.o: mul.S
-       $(CC) -c -o mul.o mul.S
+       $(CC) -D__ASSEMBLY__ -c -o mul.o mul.S
 
 rem.o: rem.S
-       $(CC) -DST_DIV0=0x2 -c -o rem.o rem.S
+       $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o rem.o rem.S
 
 sdiv.o: sdiv.S
-       $(CC) -DST_DIV0=0x2 -c -o sdiv.o sdiv.S
+       $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o sdiv.o sdiv.S
 
 udiv.o: udiv.S
-       $(CC) -DST_DIV0=0x2 -c -o udiv.o udiv.S
+       $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o udiv.o udiv.S
 
 umul.o: umul.S
-       $(CC) -c -o umul.o umul.S
+       $(CC) -D__ASSEMBLY__ -c -o umul.o umul.S
 
 urem.o: urem.S
-       $(CC) -DST_DIV0=0x2 -c -o urem.o urem.S
+       $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o urem.o urem.S
 
 ashrdi3.o: ashrdi3.S
-       $(CC) -c -o ashrdi3.o ashrdi3.S
+       $(CC) -D__ASSEMBLY__ -c -o ashrdi3.o ashrdi3.S
 
 dep:
 
index 89bf2c5fbf61c6df5485722e10c579651e0c031c..4e4aa064631cd34d3dfe053bb511e428b3a70a58 100644 (file)
@@ -10,8 +10,9 @@
        .text
        .align  4
 
-       .globl  ___xchg32
-___xchg32:
+#ifndef __SMP__
+       .globl  ___xchg32_sun4c
+___xchg32_sun4c:
        rd      %psr, %g3
        andcc   %g3, PSR_PIL, %g0
        bne     1f
@@ -27,9 +28,16 @@ ___xchg32:
        nop; nop; nop
 1:
        mov     %g7, %g2
-       jmpl    %o7, %g0                /* Note, not + 0x8, see call in system.h */
+       jmpl    %o7 + 8, %g0
         mov    %g4, %o7
 
+       .globl  ___xchg32_sun4md
+___xchg32_sun4md:
+       swap    [%g1], %g2
+       jmpl    %o7 + 8, %g0
+        mov    %g4, %o7
+#endif
+
        /* Read asm-sparc/atomic.h carefully to understand how this works for SMP.
         * Really, some things here for SMP are overly clever, go read the header.
         */
index a5a4bffadf1acd700627d0c8f91642163aec3d24..3f09ec1dbaaba2b26cac8e5b7f1fb75860ca7e75 100644 (file)
@@ -1,10 +1,11 @@
-/* $Id: blockops.S,v 1.7 1997/05/20 07:58:28 jj Exp $
+/* $Id: blockops.S,v 1.8 1998/01/30 10:58:44 jj Exp $
  * blockops.S: Common block zero optimized routines.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <asm/cprefix.h>
+#include <asm/page.h>
 
        /* Zero out 64 bytes of memory at (buf + offset).
         * Assumes %g1 contains zero.
@@ -53,7 +54,7 @@ C_LABEL(bzero_1page):
        /* %o0 = buf */
        or      %g0, %g0, %g1
        or      %o0, %g0, %o1
-       or      %g0, 0x10, %g2
+       or      %g0, (PAGE_SIZE >> 8), %g2
 1:
        BLAST_BLOCK(%o0, 0x00)
        BLAST_BLOCK(%o0, 0x40)
@@ -70,7 +71,7 @@ C_LABEL(__copy_1page):
 /* NOTE: If you change the number of insns of this routine, please check
  * arch/sparc/mm/hypersparc.S */
        /* %o0 = dst, %o1 = src */
-       or      %g0, 0x10, %g1
+       or      %g0, (PAGE_SIZE >> 8), %g1
 1:
        MIRROR_BLOCK(%o0, %o1, 0x00, %o2, %o3, %o4, %o5, %g2, %g3, %g4, %g5)
        MIRROR_BLOCK(%o0, %o1, 0x20, %o2, %o3, %o4, %o5, %g2, %g3, %g4, %g5)
diff --git a/arch/sparc/math-emu/Makefile b/arch/sparc/math-emu/Makefile
new file mode 100644 (file)
index 0000000..d7642b2
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# Makefile for the FPU instruction emulation.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := math-emu.o
+O_OBJS   := math.o ashldi3.o fabss.o faddd.o faddq.o fadds.o           \
+               fcmpd.o fcmped.o fcmpeq.o fcmpes.o fcmpq.o fcmps.o      \
+               fdivd.o fdivq.o fdivs.o fdmulq.o fdtoi.o fdtoq.o        \
+               fdtos.o fitoq.o fmovs.o fmuld.o fmulq.o fmuls.o         \
+               fnegs.o fqtod.o fqtoi.o fqtos.o fsmuld.o fsqrtd.o       \
+               fsqrtq.o fsqrts.o fstod.o fstoi.o fstoq.o fsubd.o       \
+               fsubq.o fsubs.o udivmodti4.o
+
+LINKS   := double.h faddd.c faddq.c fadds.c fdivd.c fdivq.c fdivs.c    \
+               fdtoi.c fitoq.c fmuld.c fmulq.c fmuls.c fqtoi.c         \
+               fsqrtd.c fsqrtq.c fsqrts.c fstoi.c fsubd.c              \
+               fsubq.c fsubs.c op-1.h op-2.h op-4.h op-common.h quad.h \
+               single.h soft-fp.h udivmodti4.c
+
+.S.s:
+       $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+
+.S.o:
+       $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+
+include $(TOPDIR)/Rules.make
+
+symlinks:
+       ln -sf $(patsubst %,../../sparc64/math-emu/%,$(LINKS)) .
+
+cleansymlinks:
+       rm -f $(LINKS)
diff --git a/arch/sparc/math-emu/ashldi3.S b/arch/sparc/math-emu/ashldi3.S
new file mode 100644 (file)
index 0000000..eab1d09
--- /dev/null
@@ -0,0 +1,36 @@
+/* $Id: ashldi3.S,v 1.1 1998/04/06 16:09:28 jj Exp $
+ * ashldi3.S:  Math-emu code creates all kinds of references to
+ *              this little routine on the sparc with gcc.
+ *
+ * Copyright (C) 1998 Jakub Jelinek(jj@ultra.linux.cz)
+ */
+
+#include <asm/cprefix.h>
+
+       .globl C_LABEL(__ashldi3)
+C_LABEL(__ashldi3):
+       tst     %o2
+       be      3f
+        mov    32, %g2
+
+       sub     %g2, %o2, %g2
+
+       tst     %g2
+       bg      1f
+        srl    %o1, %g2, %g3
+
+       clr     %o5
+       neg     %g2
+       ba      2f
+        sll    %o1, %g2, %o4
+
+1:
+       sll     %o1, %o2, %o5
+       srl     %o0, %o2, %g2
+       or      %g2, %g3, %o4
+2:
+       mov     %o4, %o0
+       mov     %o5, %o1
+3:
+       jmpl    %o7 + 8, %g0
+        nop
diff --git a/arch/sparc/math-emu/fabss.c b/arch/sparc/math-emu/fabss.c
new file mode 100644 (file)
index 0000000..accfd4f
--- /dev/null
@@ -0,0 +1,6 @@
+int FABSS(unsigned long *rd, unsigned long *rs2)
+{
+       /* Clear the sign bit (high bit of word 0) */
+       rd[0] = rs2[0] & 0x7fffffffUL;
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fcmpd.c b/arch/sparc/math-emu/fcmpd.c
new file mode 100644 (file)
index 0000000..3a99265
--- /dev/null
@@ -0,0 +1,18 @@
+#include "soft-fp.h"
+#include "double.h"
+
+int FCMPD(void *rd, void *rs2, void *rs1)
+{
+       FP_DECL_D(A); FP_DECL_D(B);
+       long ret;
+       unsigned long *fsr = rd;
+       
+       __FP_UNPACK_D(A, rs1);
+       __FP_UNPACK_D(B, rs2);
+       FP_CMP_D(ret, B, A, 2);
+       if (ret == -1)
+               ret = 2;
+
+       *fsr = (*fsr & ~0xc00) | (ret << 10); 
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fcmped.c b/arch/sparc/math-emu/fcmped.c
new file mode 100644 (file)
index 0000000..a8c1880
--- /dev/null
@@ -0,0 +1,18 @@
+#include "soft-fp.h"
+#include "double.h"
+
+int FCMPED(void *rd, void *rs2, void *rs1)
+{
+       FP_DECL_D(A); FP_DECL_D(B);
+       long ret;
+       unsigned long *fsr = rd;
+       
+       __FP_UNPACK_D(A, rs1);
+       __FP_UNPACK_D(B, rs2);
+       FP_CMP_D(ret, B, A, 2);
+       if (ret == -1)
+               ret = 2;
+
+       *fsr = (*fsr & ~0xc00) | (ret << 10); 
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fcmpeq.c b/arch/sparc/math-emu/fcmpeq.c
new file mode 100644 (file)
index 0000000..c109c51
--- /dev/null
@@ -0,0 +1,18 @@
+#include "soft-fp.h"
+#include "quad.h"
+
+int FCMPEQ(void *rd, void *rs2, void *rs1)
+{
+       FP_DECL_Q(A); FP_DECL_Q(B);
+       long ret;
+       unsigned long fsr;
+       
+       __FP_UNPACK_Q(A, rs1);
+       __FP_UNPACK_Q(B, rs2);
+       FP_CMP_Q(ret, B, A, 3);
+       if (ret == -1) ret = 2;
+       fsr = *(unsigned long *)rd;
+       fsr &= ~0xc00; fsr |= (ret << 10);
+       *(unsigned long *)rd = fsr;
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fcmpes.c b/arch/sparc/math-emu/fcmpes.c
new file mode 100644 (file)
index 0000000..e20884c
--- /dev/null
@@ -0,0 +1,18 @@
+#include "soft-fp.h"
+#include "single.h"
+
+int FCMPES(void *rd, void *rs2, void *rs1)
+{
+       FP_DECL_S(A); FP_DECL_S(B);
+       long ret;
+       unsigned long *fsr = rd;
+       
+       __FP_UNPACK_S(A, rs1);
+       __FP_UNPACK_S(B, rs2);
+       FP_CMP_S(ret, B, A, 1);
+       if (ret == -1)
+               ret = 2;
+
+       *fsr = (*fsr & ~0xc00) | (ret << 10); 
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fcmpq.c b/arch/sparc/math-emu/fcmpq.c
new file mode 100644 (file)
index 0000000..549f02c
--- /dev/null
@@ -0,0 +1,18 @@
+#include "soft-fp.h"
+#include "quad.h"
+
+int FCMPQ(void *rd, void *rs2, void *rs1)
+{
+       FP_DECL_Q(A); FP_DECL_Q(B);
+       long ret;
+       unsigned long fsr;
+       
+       __FP_UNPACK_Q(A, rs1);
+       __FP_UNPACK_Q(B, rs2);
+       FP_CMP_Q(ret, B, A, 3);
+       if (ret == -1) ret = 2;
+       fsr = *(unsigned long *)rd;
+       fsr &= ~0xc00; fsr |= (ret << 10);
+       *(unsigned long *)rd = fsr;
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fcmps.c b/arch/sparc/math-emu/fcmps.c
new file mode 100644 (file)
index 0000000..1b53312
--- /dev/null
@@ -0,0 +1,18 @@
+#include "soft-fp.h"
+#include "single.h"
+
+int FCMPS(void *rd, void *rs2, void *rs1)
+{
+       FP_DECL_S(A); FP_DECL_S(B);
+       long ret;
+       unsigned long *fsr = rd;
+       
+       __FP_UNPACK_S(A, rs1);
+       __FP_UNPACK_S(B, rs2);
+       FP_CMP_S(ret, B, A, 1);
+       if (ret == -1)
+               ret = 2;
+
+       *fsr = (*fsr & ~0xc00) | (ret << 10); 
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fdmulq.c b/arch/sparc/math-emu/fdmulq.c
new file mode 100644 (file)
index 0000000..1d5bc50
--- /dev/null
@@ -0,0 +1,16 @@
+#include "soft-fp.h"
+#include "quad.h"
+#include "double.h"
+
+int FDMULQ(void *rd, void *rs2, void *rs1)
+{
+       FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
+
+       __FP_UNPACK_D(IN, rs1);
+       FP_CONV(Q,D,4,2,A,IN);
+       __FP_UNPACK_D(IN, rs2);
+       FP_CONV(Q,D,4,2,B,IN);
+       FP_MUL_Q(R, A, B);
+       __FP_PACK_Q(rd, R);
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fdtoq.c b/arch/sparc/math-emu/fdtoq.c
new file mode 100644 (file)
index 0000000..84ebcf4
--- /dev/null
@@ -0,0 +1,13 @@
+#include "soft-fp.h"
+#include "quad.h"
+#include "double.h"
+
+int FDTOQ(void *rd, void *rs2)
+{
+       FP_DECL_D(A); FP_DECL_Q(R);
+
+       __FP_UNPACK_D(A, rs2);
+       FP_CONV(Q,D,4,2,R,A);
+       __FP_PACK_Q(rd, R);
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fdtos.c b/arch/sparc/math-emu/fdtos.c
new file mode 100644 (file)
index 0000000..83b8a14
--- /dev/null
@@ -0,0 +1,13 @@
+#include "soft-fp.h"
+#include "double.h"
+#include "single.h"
+
+int FDTOS(void *rd, void *rs2)
+{
+       FP_DECL_D(A); FP_DECL_S(R);
+
+       __FP_UNPACK_D(A, rs2);
+       FP_CONV(S,D,1,2,R,A);
+       __FP_PACK_S(rd, R);
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fmovs.c b/arch/sparc/math-emu/fmovs.c
new file mode 100644 (file)
index 0000000..f113c0b
--- /dev/null
@@ -0,0 +1,5 @@
+int FMOVS(unsigned long *rd, unsigned long *rs2)
+{
+       rd[0] = rs2[0];
+       return 0;
+}
diff --git a/arch/sparc/math-emu/fnegs.c b/arch/sparc/math-emu/fnegs.c
new file mode 100644 (file)
index 0000000..39188ee
--- /dev/null
@@ -0,0 +1,7 @@
+int FNEGS(unsigned long *rd, unsigned long *rs2)
+{
+       /* just change the sign bit */
+       rd[0] = rs2[0] ^ 0x80000000UL;
+       return 1;
+}
+                
diff --git a/arch/sparc/math-emu/fqtod.c b/arch/sparc/math-emu/fqtod.c
new file mode 100644 (file)
index 0000000..dc5b6f9
--- /dev/null
@@ -0,0 +1,13 @@
+#include "soft-fp.h"
+#include "quad.h"
+#include "double.h"
+
+int FQTOD(void *rd, void *rs2)
+{
+       FP_DECL_Q(A); FP_DECL_D(R);
+
+       __FP_UNPACK_Q(A, rs2);
+       FP_CONV(D,Q,2,4,R,A);
+       __FP_PACK_D(rd, R);
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fqtos.c b/arch/sparc/math-emu/fqtos.c
new file mode 100644 (file)
index 0000000..608f57b
--- /dev/null
@@ -0,0 +1,13 @@
+#include "soft-fp.h"
+#include "quad.h"
+#include "single.h"
+
+int FQTOS(void *rd, void *rs2)
+{
+       FP_DECL_Q(A); FP_DECL_S(R);
+
+       __FP_UNPACK_Q(A, rs2);
+       FP_CONV(S,Q,1,4,R,A);
+       __FP_PACK_S(rd, R);
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fsmuld.c b/arch/sparc/math-emu/fsmuld.c
new file mode 100644 (file)
index 0000000..dead5a0
--- /dev/null
@@ -0,0 +1,16 @@
+#include "soft-fp.h"
+#include "double.h"
+#include "single.h"
+
+int FSMULD(void *rd, void *rs2, void *rs1)
+{
+       FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
+
+       __FP_UNPACK_S(IN, rs1);
+       FP_CONV(D,S,2,1,A,IN);
+       __FP_UNPACK_S(IN, rs2);
+       FP_CONV(D,S,2,1,B,IN);
+       FP_MUL_D(R, A, B);
+       __FP_PACK_D(rd, R);
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fstod.c b/arch/sparc/math-emu/fstod.c
new file mode 100644 (file)
index 0000000..cb34329
--- /dev/null
@@ -0,0 +1,13 @@
+#include "soft-fp.h"
+#include "double.h"
+#include "single.h"
+
+int FSTOD(void *rd, void *rs2)
+{
+       FP_DECL_S(A); FP_DECL_D(R);
+
+       __FP_UNPACK_S(A, rs2);
+       FP_CONV(D,S,2,1,R,A);
+       __FP_PACK_D(rd, R);
+       return 1;
+}
diff --git a/arch/sparc/math-emu/fstoq.c b/arch/sparc/math-emu/fstoq.c
new file mode 100644 (file)
index 0000000..081c4d4
--- /dev/null
@@ -0,0 +1,13 @@
+#include "soft-fp.h"
+#include "quad.h"
+#include "single.h"
+
+int FSTOQ(void *rd, void *rs2)
+{
+       FP_DECL_S(A); FP_DECL_Q(R);
+
+       __FP_UNPACK_S(A, rs2);
+       FP_CONV(Q,S,4,1,R,A);
+       __FP_PACK_Q(rd, R);
+       return 1;
+}
diff --git a/arch/sparc/math-emu/math.c b/arch/sparc/math-emu/math.c
new file mode 100644 (file)
index 0000000..df5c879
--- /dev/null
@@ -0,0 +1,416 @@
+/* 
+ * arch/sparc/math-emu/math.c
+ *
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ * Based on the sparc64 code by Jakub Jelinek.
+ *
+ * This is a good place to start if you're trying to understand the
+ * emulation code, because it's pretty simple. What we do is 
+ * essentially analyse the instruction to work out what the operation
+ * is and which registers are involved. We then execute the appropriate
+ * FXXXX function. [The floating point queue introduces a minor wrinkle;
+ * see below...]
+ * The fxxxxx.c files each emulate a single insn. They look relatively
+ * simple because the complexity is hidden away in an unholy tangle
+ * of preprocessor macros. 
+ *
+ * WARNING : don't look at the macro definitions unless you 
+ * absolutely have to! They're extremely ugly, rather complicated
+ * and a single line in an fxxxx.c file can expand to the equivalent 
+ * of  30 lines or more of C. Of course, any error in those 30 lines 
+ * is reported by the compiler as an error in the single line with the
+ * macro usage...
+ * Question: should we replace them with inline functions?
+ *
+ * The first layer of macros is single.h, double.h, quad.h. Generally
+ * these files define macros for working with floating point numbers
+ * of the three IEEE formats. FP_ADD_D(R,A,B) is for adding doubles,
+ * for instance. These macros are usually defined as calls to more
+ * generic macros (in this case _FP_ADD(D,2,R,X,Y) where the number
+ * of machine words required to store the given IEEE format is passed
+ * as a parameter. [double.h and co check the number of bits in a word
+ * and define FP_ADD_D & co appropriately]. 
+ * The generic macros are defined in op-common.h. This is where all
+ * the grotty stuff like handling NaNs is coded. To handle the possible
+ * word sizes macros in op-common.h use macros like _FP_FRAC_SLL_##wc()
+ * where wc is the 'number of machine words' parameter (here 2). 
+ * These are defined in the third layer of macros: op-1.h, op-2.h
+ * and op-4.h. These handle operations on floating point numbers composed
+ * of 1,2 and 4 machine words respectively. [For example, on sparc64
+ * doubles are one machine word so macros in double.h eventually use
+ * constructs in op-1.h, but on sparc32 they use op-2.h definitions.]
+ * soft-fp.h is on the same level as op-common.h, and defines some
+ * macros which are independent of both word size and FP format.
+ * Finally, sfp-machine.h is the machine dependent part of the 
+ * code: it defines the word size and what type a word is. It also
+ * defines how _FP_MUL_MEAT_t() maps to _FP_MUL_MEAT_n_* : op-n.h
+ * provide several possible flavours of multiply algorithm, most
+ * of which require that you supply some form of asm or C primitive to
+ * do the actual multiply. (such asm primitives should be defined
+ * in sfp-machine.h too). udivmodti4.c is the same sort of thing.
+ *
+ * There may be some errors here because I'm working from a
+ * SPARC architecture manual V9, and what I really want is V8...
+ * Also, the insns which can generate exceptions seem to be a
+ * greater subset of the FPops than for V9 (for example, FCMPED
+ * has to be emulated on V8). So I think I'm going to have
+ * to emulate them all just to be on the safe side...
+ *
+ * Emulation routines originate from soft-fp package, which is
+ * part of glibc and has appropriate copyrights in it (allegedly).
+ *
+ * NB: on sparc int == long == 4 bytes, long long == 8 bytes.
+ * Most bits of the kernel seem to go for long rather than int,
+ * so we follow that practice...
+ */
+
+/* WISHLIST:
+ *
+ * + Replace all the macros with inline functions. These should
+ * have the same effect but be much easier to work with.
+ *
+ * + Emulate the IEEE exception flags. We don't currently do this
+ * because a) it would require significant alterations to
+ * the emulation macros [see the comments about _FP_NEG()
+ * in op-common.c and note that we'd need to invent a convention
+ * for passing in the flags to FXXXX fns and returning them] and 
+ * b) SPARClinux doesn't let users access the flags anyway 
+ * [contrast Solaris, which allows you to examine, clear or set
+ * the flags, and request that exceptions cause SIGFPE 
+ * [which you then set up a signal handler for, obviously...]].
+ * Erm, (b) may quite possibly be garbage. %fsr is user-writable
+ * so you don't need a syscall. There may or may not be library
+ * support.
+ *
+ * + Emulation of FMULQ, FDIVQ, FSQRTQ, FDMULQ needs to be 
+ * written!
+ * 
+ * + reindent code to conform to Linux kernel standard :->
+ *
+ * + work out whether all the compile-time warnings are bogus
+ *
+ * + check that conversion to/from integers works
+ * 
+ * + check with the SPARC architecture manual to see if we resolve
+ * the implementation-dependent bits of the IEEE spec in the
+ * same manner as the hardware.
+ *
+ * + more test cases for the test script always welcome!
+ *
+ * + illegal opcodes currently cause SIGFPEs. We should arrange
+ * to tell the traps.c code to SIGILL instead. Currently,
+ * everywhere that we return 0 should cause SIGILL, I think.
+ * SIGFPE should only be caused if we set an IEEE exception bit
+ * and the relevant trap bit is also set. (this means that 
+ * traps.c should do this; also it should handle the case of
+ * IEEE exception generated directly by the hardware.)
+ * Should illegal_fp_register (which is a flavour of fp exception)
+ * cause SIGFPE or  SIGILL?
+ *
+ * + the test script needs to be extended to handle the quadword
+ * and comparison insns.
+ *
+ * + _FP_DIV_MEAT_2_udiv_64() appears to work but it should be
+ * checked by somebody who understands the algorithm :->
+ * 
+ * + fpsave() saves the FP queue but fpload() doesn't reload it.
+ * Therefore when we context switch or change FPU ownership
+ * we have to check to see if the queue had anything in it and
+ * emulate it if it did. This is going to be a pain. 
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+
+
+#define FLOATFUNC(x) extern int x(void *,void *,void *)
+
+/* Current status: we don't properly emulate the difficult quadword
+ * insns (MUL, DIV, SQRT).
+ * There are also some ops involving the FP registers which we don't
+ * emulate: the branch on FP condition flags and the load/store to
+ * FP regs or FSR. I'm assuming that these will never generate traps
+ * (not unreasonable if there's an FPU at all; comments in the NetBSD
+ * kernel source agree on this point). If we wanted to allow
+ * purely software-emulation of the FPU with FPU totally disabled
+ * or non-existent, we'd have to emulate these as well. We'd also
+ * need to alter the fp_disabled trap handler to call the math-emu
+ * code appropriately. The structure of do_one_mathemu() is also
+ * inappropriate for these ops (as it has no way to alter the pc, 
+ * for a start) and it might be better to special-case them in do_mathemu().
+ * Oh, and you'd need to alter the traps.c code so it didn't try to
+ * fpsave() and fpload(). If there's genuinely no FPU then there's 
+ * probably bits of kernel stuff that just won't work anyway...
+ */
+
+/* The Vn labels indicate what version of the SPARC architecture gas thinks
+ * each insn is. This is from the binutils source :-> 
+ */
+/* quadword instructions */
+FLOATFUNC(FSQRTQ);                                /* v8 NYI */
+FLOATFUNC(FADDQ);                                 /* v8 */
+FLOATFUNC(FSUBQ);                                 /* v8 */
+FLOATFUNC(FMULQ);                                 /* v8 NYI */
+FLOATFUNC(FDIVQ);                                 /* v8 NYI */
+FLOATFUNC(FDMULQ);                                /* v8 NYI */
+FLOATFUNC(FQTOS);                                 /* v8 */
+FLOATFUNC(FQTOD);                                 /* v8 */
+FLOATFUNC(FITOQ);                                 /* v8 */
+FLOATFUNC(FSTOQ);                                 /* v8 */
+FLOATFUNC(FDTOQ);                                 /* v8 */
+FLOATFUNC(FQTOI);                                 /* v8 */
+FLOATFUNC(FCMPQ);                                 /* v8 */
+FLOATFUNC(FCMPEQ);                                /* v8 */
+/* single/double instructions (subnormal): should all work */
+FLOATFUNC(FSQRTS);                                /* v7 */
+FLOATFUNC(FSQRTD);                                /* v7 */
+FLOATFUNC(FADDS);                                 /* v6 */
+FLOATFUNC(FADDD);                                 /* v6 */
+FLOATFUNC(FSUBS);                                 /* v6 */
+FLOATFUNC(FSUBD);                                 /* v6 */
+FLOATFUNC(FMULS);                                 /* v6 */
+FLOATFUNC(FMULD);                                 /* v6 */
+FLOATFUNC(FDIVS);                                 /* v6 */
+FLOATFUNC(FDIVD);                                 /* v6 */
+FLOATFUNC(FSMULD);                                /* v8 */
+FLOATFUNC(FDTOS);                                 /* v6 */
+FLOATFUNC(FSTOD);                                 /* v6 */
+FLOATFUNC(FSTOI);                                 /* v6 */
+FLOATFUNC(FDTOI);                                 /* v6 */
+FLOATFUNC(FABSS);                                 /* v6 */
+FLOATFUNC(FCMPS);                                 /* v6 */
+FLOATFUNC(FCMPES);                                /* v6 */
+FLOATFUNC(FCMPD);                                 /* v6 */
+FLOATFUNC(FCMPED);                                /* v6 */
+FLOATFUNC(FMOVS);                                 /* v6 */
+FLOATFUNC(FNEGS);                                 /* v6 */
+FLOATFUNC(FITOS);                                 /* v6 */
+FLOATFUNC(FITOD);                                 /* v6 */
+
+static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs);   
+
+/* Unlike the Sparc64 version (which has a struct fpustate), we
+ * pass the taskstruct corresponding to the task which currently owns the
+ * FPU. This is partly because we don't have the fpustate struct and
+ * partly because the task owning the FPU isn't always current (as is
+ * the case for the Sparc64 port). This is probably SMP-related...
+ * This function returns 1 if all queued insns were emulated successfully.
+ * The test for unimplemented FPop in kernel mode has been moved into
+ * kernel/traps.c for simplicity.
+ */
+int do_mathemu(struct pt_regs *regs, struct task_struct *fpt)
+{
+   /* regs->pc isn't necessarily the PC at which the offending insn is sitting.
+    * The FPU maintains a queue of FPops which cause traps. 
+    * When it hits an instruction that requires that the trapped op succeeded
+    * (usually because it reads a reg. that the trapped op wrote) then it
+    * causes this exception. We need to emulate all the insns on the queue
+    * and then allow the op to proceed.
+    * This code should also handle the case where the trap was precise,
+    * in which case the queue length is zero and regs->pc points at the 
+    * single FPop to be emulated. (this case is untested, though :->) 
+    * You'll need this case if you want to be able to emulate all FPops
+    * because the FPU either doesn't exist or has been software-disabled.
+    * [The UltraSPARC makes FP a precise trap; this isn't as stupid as it 
+    * might sound because the Ultra does funky things with a superscalar
+    * architecture.]
+    */
+   
+   /* You wouldn't believe how often I typed 'ftp' when I meant 'fpt' :-> */
+
+   int i;
+   int retcode = 0;                               /* assume all succeed */
+   unsigned long insn;
+   
+#ifdef DEBUG_MATHEMU   
+   printk("In do_mathemu()... pc is %08lx\n", regs->pc);
+   printk("fpqdepth is %ld\n",fpt->tss.fpqdepth);
+   for (i = 0; i < fpt->tss.fpqdepth; i++)
+      printk("%d: %08lx at %08lx\n",i,fpt->tss.fpqueue[i].insn, (unsigned long)fpt->tss.fpqueue[i].insn_addr);
+#endif      
+
+   if (fpt->tss.fpqdepth == 0) {                   /* no queue, guilty insn is at regs->pc */
+#ifdef DEBUG_MATHEMU   
+      printk("precise trap at %08lx\n", regs->pc);
+#endif
+      if (!get_user(insn, (u32 *)regs->pc)) {
+         retcode = do_one_mathemu(insn, &fpt->tss.fsr, fpt->tss.float_regs);
+         if (retcode) {
+            /* in this case we need to fix up PC & nPC */
+            regs->pc = regs->npc;
+            regs->npc += 4;
+         }
+      }
+      return retcode;
+   }
+
+   /* Normal case: need to empty the queue... */
+   for (i = 0; i < fpt->tss.fpqdepth; i++)
+   {
+      retcode = do_one_mathemu(fpt->tss.fpqueue[i].insn, &(fpt->tss.fsr), fpt->tss.float_regs);
+      if (!retcode)                               /* insn failed, no point doing any more */
+         break;
+   }
+   /* Now empty the queue and clear the queue_not_empty flag */
+   fpt->tss.fsr &= ~0x3000;
+   fpt->tss.fpqdepth = 0;
+   
+   return retcode;
+}
+
+static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs)
+{
+   /* Emulate the given insn, updating fsr and fregs appropriately. */
+   int type = 0; 
+   /* 01 is single, 10 is double, 11 is quad, 
+    * 000011 is rs1, 001100 is rs2, 110000 is rd (00 in rd is fcc)
+    * 111100000000 tells which ftt that may happen in 
+    * (this field not used on sparc32 code, as we can't 
+    * extract trap type info for ops on the FP queue) 
+    */
+   int freg;
+   int (*func)(void *,void *,void *) = NULL;
+   void *rs1 = NULL, *rs2 = NULL, *rd = NULL;   
+
+#ifdef DEBUG_MATHEMU
+   printk("In do_mathemu(), emulating %08lx\n", insn);
+#endif   
+      
+   if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
+      switch ((insn >> 5) & 0x1ff) {
+         /* QUAD - ftt == 3 */
+         case 0x001: type = 0x314; func = FMOVS; break;
+         case 0x005: type = 0x314; func = FNEGS; break;
+         case 0x009: type = 0x314; func = FABSS; break;
+         case 0x02b: type = 0x33c; func = FSQRTQ; break;
+         case 0x043: type = 0x33f; func = FADDQ; break;
+         case 0x047: type = 0x33f; func = FSUBQ; break;
+         case 0x04b: type = 0x33f; func = FMULQ; break;
+         case 0x04f: type = 0x33f; func = FDIVQ; break;
+         case 0x06e: type = 0x33a; func = FDMULQ; break;
+         case 0x0c7: type = 0x31c; func = FQTOS; break;
+         case 0x0cb: type = 0x32c; func = FQTOD; break;
+         case 0x0cc: type = 0x334; func = FITOQ; break;
+         case 0x0cd: type = 0x334; func = FSTOQ; break;
+         case 0x0ce: type = 0x338; func = FDTOQ; break;
+         case 0x0d3: type = 0x31c; func = FQTOI; break;
+            /* SUBNORMAL - ftt == 2 */
+         case 0x029: type = 0x214; func = FSQRTS; break;
+         case 0x02a: type = 0x228; func = FSQRTD; break;
+         case 0x041: type = 0x215; func = FADDS; break;
+         case 0x042: type = 0x22a; func = FADDD; break;
+         case 0x045: type = 0x215; func = FSUBS; break;
+         case 0x046: type = 0x22a; func = FSUBD; break;
+         case 0x049: type = 0x215; func = FMULS; break;
+         case 0x04a: type = 0x22a; func = FMULD; break;
+         case 0x04d: type = 0x215; func = FDIVS; break;
+         case 0x04e: type = 0x22a; func = FDIVD; break;
+         case 0x069: type = 0x225; func = FSMULD; break;
+         case 0x0c6: type = 0x218; func = FDTOS; break;
+         case 0x0c9: type = 0x224; func = FSTOD; break;
+         case 0x0d1: type = 0x214; func = FSTOI; break;
+         case 0x0d2: type = 0x218; func = FDTOI; break;
+         default: 
+#ifdef DEBUG_MATHEMU         
+               printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff);
+#endif         
+      }
+   }
+   else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ {
+      switch ((insn >> 5) & 0x1ff) {
+         case 0x051: type = 0x305; func = FCMPS; break;
+         case 0x052: type = 0x30a; func = FCMPD; break;
+         case 0x053: type = 0x30f; func = FCMPQ; break;
+         case 0x055: type = 0x305; func = FCMPES; break;
+         case 0x056: type = 0x30a; func = FCMPED; break;
+         case 0x057: type = 0x30f; func = FCMPEQ; break;
+         default: 
+#ifdef DEBUG_MATHEMU         
+               printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff);
+#endif                 
+      }
+   }
+   
+   if (!type) { /* oops, didn't recognise that FPop */
+      printk("attempt to emulate unrecognised FPop!\n");
+      return 0;
+   }
+   
+   /* Decode the registers to be used */
+   freg = (*fsr >> 14) & 0xf;
+
+   *fsr &= ~0x1c000;                              /* clear the traptype bits */
+    
+   freg = ((insn >> 14) & 0x1f);
+   switch (type & 0x3)                            /* is rs1 single, double or quad? */
+   {
+      case 3:
+         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
+         {                                        /* encoded reg. number set to zero. */
+            *fsr |= (6 << 14);                  
+            return 0;                             /* simulate invalid_fp_register exception */
+         }
+         /* fall through */
+      case 2:
+         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
+         {
+            *fsr |= (6 << 14);
+            return 0;
+         }
+   }
+   rs1 = (void *)&fregs[freg];
+   freg = (insn & 0x1f);
+   switch ((type >> 2) & 0x3)
+   {                                              /* same again for rs2 */
+      case 3:
+         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
+         {                                        /* encoded reg. number set to zero. */
+            *fsr |= (6 << 14);                  
+            return 0;                             /* simulate invalid_fp_register exception */
+         }
+         /* fall through */
+      case 2:
+         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
+         {
+            *fsr |= (6 << 14);
+            return 0;
+         }
+   }
+   rs2 = (void *)&fregs[freg];
+   freg = ((insn >> 25) & 0x1f);
+   switch ((type >> 4) & 0x3)                     /* and finally rd. This one's a bit different */
+   {
+      case 0:                                     /* dest is fcc. (this must be FCMPQ or FCMPEQ) */
+         if (freg)                                /* V8 has only one set of condition codes, so */
+         {                                        /* anything but 0 in the rd field is an error */
+            *fsr |= (6 << 14);                    /* (should probably flag as invalid opcode */
+            return 0;                             /* but SIGFPE will do :-> ) */
+         }
+         rd = (void *)(fsr);                      /* FCMPQ and FCMPEQ are special and only  */
+         break;                                   /* set bits they're supposed to :-> */
+      case 3:
+         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
+         {                                        /* encoded reg. number set to zero. */
+            *fsr |= (6 << 14);
+            return 0;                             /* simulate invalid_fp_register exception */
+         }
+         /* fall through */
+      case 2:
+         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
+         {
+            *fsr |= (6 << 14);
+            return 0;
+         }
+         /* fall through */
+      case 1:
+         rd = (void *)&fregs[freg];
+         break;
+   }
+#ifdef DEBUG_MATHEMU   
+   printk("executing insn...\n");
+#endif   
+   func(rd, rs2, rs1);                            /* do the Right Thing */
+   return 1;                                      /* success! */
+}
diff --git a/arch/sparc/math-emu/sfp-machine.h b/arch/sparc/math-emu/sfp-machine.h
new file mode 100644 (file)
index 0000000..eafad42
--- /dev/null
@@ -0,0 +1,363 @@
+/* Machine-dependent software floating-point definitions.  Sparc version.
+   Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+   Actually, this is a sparc (32bit) version, written based on the
+   i386 and sparc64 versions, by me, 
+   Peter Maydell (pmaydell@chiark.greenend.org.uk).
+   Comments are by and large also mine, although they may be inaccurate.
+
+   In picking out asm fragments I've gone with the lowest common
+   denominator, which also happens to be the hardware I have :->
+   That is, a SPARC without hardware multiply and divide.
+ */
+
+
+/* basic word size definitions */
+#define _FP_W_TYPE_SIZE                32
+#define _FP_W_TYPE             unsigned long
+#define _FP_WS_TYPE            signed long
+#define _FP_I_TYPE             long
+
+/* You can optionally code some things like addition in asm. For
+ * example, i386 defines __FP_FRAC_ADD_2 as asm. If you don't
+ * then you get a fragment of C code [if you change an #ifdef 0
+ * in op-2.h] or a call to add_ssaaaa (see below).
+ * Good places to look for asm fragments to use are gcc and glibc.
+ * gcc's longlong.h is useful.
+ */
+
+/* We need to know how to multiply and divide. If the host word size
+ * is >= 2*fracbits you can use FP_MUL_MEAT_n_imm(t,R,X,Y) which
+ * codes the multiply with whatever gcc does to 'a * b'.
+ * _FP_MUL_MEAT_n_wide(t,R,X,Y,f) is used when you have an asm 
+ * function that can multiply two 1W values and get a 2W result. 
+ * Otherwise you're stuck with _FP_MUL_MEAT_n_hard(t,R,X,Y) which
+ * does bitshifting to avoid overflow.
+ * For division there is FP_DIV_MEAT_n_imm(t,R,X,Y,f) for word size
+ * >= 2*fracbits, where f is either _FP_DIV_HELP_imm or 
+ * _FP_DIV_HELP_ldiv (see op-1.h).
+ * _FP_DIV_MEAT_udiv() is if you have asm to do 2W/1W => (1W, 1W).
+ * [GCC and glibc have longlong.h which has the asm macro udiv_qrnnd
+ * to do this.]
+ * In general, 'n' is the number of words required to hold the type,
+ * and 't' is either S, D or Q for single/double/quad.
+ *           -- PMM
+ */
+/* Example: SPARC64:
+ * #define _FP_MUL_MEAT_S(R,X,Y)       _FP_MUL_MEAT_1_imm(S,R,X,Y)
+ * #define _FP_MUL_MEAT_D(R,X,Y)       _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm)
+ * #define _FP_MUL_MEAT_Q(R,X,Y)       _FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm)
+ *
+ * #define _FP_DIV_MEAT_S(R,X,Y)       _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
+ * #define _FP_DIV_MEAT_D(R,X,Y)       _FP_DIV_MEAT_1_udiv(D,R,X,Y)
+ * #define _FP_DIV_MEAT_Q(R,X,Y)       _FP_DIV_MEAT_2_udiv_64(Q,R,X,Y)
+ *
+ * Example: i386:
+ * #define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(S,R,X,Y,_i386_mul_32_64)
+ * #define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(D,R,X,Y,_i386_mul_32_64)
+ *
+ * #define _FP_DIV_MEAT_S(R,X,Y)   _FP_DIV_MEAT_1_udiv(S,R,X,Y,_i386_div_64_32)
+ * #define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
+ */
+#define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
+/* FIXME: This is not implemented, but should be soon */
+#define _FP_MUL_MEAT_Q(R,X,Y)   _FP_FRAC_SET_4(R, _FP_ZEROFRAC_4)
+#define _FP_DIV_MEAT_S(R,X,Y)   _FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
+/* FIXME: This is not implemented, but should be soon */
+#define _FP_DIV_MEAT_Q(R,X,Y)   _FP_FRAC_SET_4(R, _FP_ZEROFRAC_4)
+
+/* These macros define what NaN looks like. They're supposed to expand to 
+ * a comma-separated set of 32bit unsigned ints that encode NaN.
+ */
+#define _FP_NANFRAC_S          _FP_QNANBIT_S
+#define _FP_NANFRAC_D          _FP_QNANBIT_D, 0
+#define _FP_NANFRAC_Q           _FP_QNANBIT_Q, 0, 0, 0
+
+#define _FP_KEEPNANFRACP 1
+
+/* This macro appears to be called when both X and Y are NaNs, and 
+ * has to choose one and copy it to R. i386 goes for the larger of the
+ * two, sparc64 just picks Y. I don't understand this at all so I'll
+ * go with sparc64 because it's shorter :->   -- PMM 
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y)                         \
+  do {                                                         \
+    R##_s = Y##_s;                                             \
+    _FP_FRAC_COPY_##wc(R,Y);                                   \
+    R##_c = FP_CLS_NAN;                                                \
+  } while (0)
+  
+#define __FP_UNPACK_RAW_1(fs, X, val)                          \
+  do {                                                         \
+    union _FP_UNION_##fs *_flo =                               \
+       (union _FP_UNION_##fs *)val;                            \
+                                                               \
+    X##_f = _flo->bits.frac;                                   \
+    X##_e = _flo->bits.exp;                                    \
+    X##_s = _flo->bits.sign;                                   \
+  } while (0)
+
+#define __FP_PACK_RAW_1(fs, val, X)                            \
+  do {                                                         \
+    union _FP_UNION_##fs *_flo =                               \
+       (union _FP_UNION_##fs *)val;                            \
+                                                               \
+    _flo->bits.frac = X##_f;                                   \
+    _flo->bits.exp  = X##_e;                                   \
+    _flo->bits.sign = X##_s;                                   \
+  } while (0)
+  
+#define __FP_UNPACK_RAW_2(fs, X, val)                  \
+  do {                                                 \
+    union _FP_UNION_##fs *_flo =                       \
+       (union _FP_UNION_##fs *)val;                    \
+                                                       \
+    X##_f0 = _flo->bits.frac0;                         \
+    X##_f1 = _flo->bits.frac1;                         \
+    X##_e  = _flo->bits.exp;                           \
+    X##_s  = _flo->bits.sign;                          \
+  } while (0)
+
+#define __FP_PACK_RAW_2(fs, val, X)                    \
+  do {                                                 \
+    union _FP_UNION_##fs *_flo =                       \
+       (union _FP_UNION_##fs *)val;                    \
+                                                       \
+    _flo->bits.frac0 = X##_f0;                         \
+    _flo->bits.frac1 = X##_f1;                         \
+    _flo->bits.exp   = X##_e;                          \
+    _flo->bits.sign  = X##_s;                          \
+  } while (0)
+
+#define __FP_UNPACK_RAW_4(fs, X, val)                  \
+  do {                                                 \
+    union _FP_UNION_##fs *_flo =                       \
+       (union _FP_UNION_##fs *)val;                    \
+                                                       \
+    X##_f[0] = _flo->bits.frac0;                       \
+    X##_f[1] = _flo->bits.frac1;                       \
+    X##_f[2] = _flo->bits.frac2;                       \
+    X##_f[3] = _flo->bits.frac3;                       \
+    X##_e  = _flo->bits.exp;                           \
+    X##_s  = _flo->bits.sign;                          \
+  } while (0)
+
+#define __FP_PACK_RAW_4(fs, val, X)                    \
+  do {                                                 \
+    union _FP_UNION_##fs *_flo =                       \
+       (union _FP_UNION_##fs *)val;                    \
+                                                       \
+    _flo->bits.frac0 = X##_f[0];                       \
+    _flo->bits.frac1 = X##_f[1];                       \
+    _flo->bits.frac2 = X##_f[2];                       \
+    _flo->bits.frac3 = X##_f[3];                       \
+    _flo->bits.exp   = X##_e;                          \
+    _flo->bits.sign  = X##_s;                          \
+  } while (0)
+
+#define __FP_UNPACK_S(X,val)           \
+  do {                                 \
+    __FP_UNPACK_RAW_1(S,X,val);                \
+    _FP_UNPACK_CANONICAL(S,1,X);       \
+  } while (0)
+
+#define __FP_PACK_S(val,X)             \
+  do {                                 \
+    _FP_PACK_CANONICAL(S,1,X);         \
+    __FP_PACK_RAW_1(S,val,X);          \
+  } while (0)
+
+#define __FP_UNPACK_D(X,val)           \
+  do {                                 \
+    __FP_UNPACK_RAW_2(D,X,val);                \
+    _FP_UNPACK_CANONICAL(D,2,X);       \
+  } while (0)
+
+#define __FP_PACK_D(val,X)             \
+  do {                                 \
+    _FP_PACK_CANONICAL(D,2,X);         \
+    __FP_PACK_RAW_2(D,val,X);          \
+  } while (0)
+
+#define __FP_UNPACK_Q(X,val)           \
+  do {                                 \
+    __FP_UNPACK_RAW_4(Q,X,val);                \
+    _FP_UNPACK_CANONICAL(Q,4,X);       \
+  } while (0)
+
+#define __FP_PACK_Q(val,X)             \
+  do {                                 \
+    _FP_PACK_CANONICAL(Q,4,X);         \
+    __FP_PACK_RAW_4(Q,val,X);          \
+  } while (0)
+
+/* the asm fragments go here: all these are taken from glibc-2.0.5's stdlib/longlong.h */
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/* add_ssaaaa is used in op-2.h and should be equivalent to
+ * #define add_ssaaaa(sh,sl,ah,al,bh,bl) (sh = ah+bh+ (( sl = al+bl) < al))
+ * add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
+ * high_addend_2, low_addend_2) adds two UWtype integers, composed by
+ * HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
+ * respectively.  The result is placed in HIGH_SUM and LOW_SUM.  Overflow
+ * (i.e. carry out) is not stored anywhere, and is lost.
+ */
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addcc %r4,%5,%1
+        addx %r2,%3,%0"                                                 \
+           : "=r" ((USItype)(sh)),                                      \
+             "=&r" ((USItype)(sl))                                      \
+           : "%rJ" ((USItype)(ah)),                                     \
+             "rI" ((USItype)(bh)),                                      \
+             "%rJ" ((USItype)(al)),                                     \
+             "rI" ((USItype)(bl))                                       \
+           : "cc")
+
+
+/* sub_ddmmss is used in op-2.h and udivmodti4.c and should be equivalent to
+ * #define sub_ddmmss(sh, sl, ah, al, bh, bl) (sh = ah-bh - ((sl = al-bl) > al))
+ * sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
+ * high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
+ * composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
+ * LOW_SUBTRAHEND_2 respectively.  The result is placed in HIGH_DIFFERENCE
+ * and LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
+ * and is lost.
+ */
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subcc %r4,%5,%1
+        subx %r2,%3,%0"                                                 \
+           : "=r" ((USItype)(sh)),                                      \
+             "=&r" ((USItype)(sl))                                      \
+           : "rJ" ((USItype)(ah)),                                      \
+             "rI" ((USItype)(bh)),                                      \
+             "rJ" ((USItype)(al)),                                      \
+             "rI" ((USItype)(bl))                                       \
+           : "cc")
+
+
+/* asm fragments for mul and div */     
+/* umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two
+ * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
+ * word product in HIGH_PROD and LOW_PROD.
+ * These look ugly because the sun4/4c don't have umul/udiv/smul/sdiv in
+ * hardware. 
+ */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("! Inlined umul_ppmm
+        wr      %%g0,%2,%%y     ! SPARC has 0-3 delay insn after a wr
+        sra     %3,31,%%g2      ! Don't move this insn
+        and     %2,%%g2,%%g2    ! Don't move this insn
+        andcc   %%g0,0,%%g1     ! Don't move this insn
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,%3,%%g1
+        mulscc  %%g1,0,%%g1
+        add     %%g1,%%g2,%0
+        rd      %%y,%1"                                                 \
+           : "=r" ((USItype)(w1)),                                      \
+             "=r" ((USItype)(w0))                                       \
+           : "%rI" ((USItype)(u)),                                      \
+             "r" ((USItype)(v))                                         \
+           : "%g1", "%g2", "cc")
+
+/* udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+ * denominator) divides a UDWtype, composed by the UWtype integers
+ * HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
+ * in QUOTIENT and the remainder in REMAINDER.  HIGH_NUMERATOR must be less
+ * than DENOMINATOR for correct operation.  If, in addition, the most
+ * significant bit of DENOMINATOR must be 1, then the pre-processor symbol
+ * UDIV_NEEDS_NORMALIZATION is defined to 1.
+ */
+
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("! Inlined udiv_qrnnd
+        mov     32,%%g1
+        subcc   %1,%2,%%g0
+1:      bcs     5f
+         addxcc %0,%0,%0        ! shift n1n0 and a q-bit in lsb
+        sub     %1,%2,%1        ! this kills msb of n
+        addx    %1,%1,%1        ! so this can't give carry
+        subcc   %%g1,1,%%g1
+2:      bne     1b
+         subcc  %1,%2,%%g0
+        bcs     3f
+         addxcc %0,%0,%0        ! shift n1n0 and a q-bit in lsb
+        b       3f
+         sub    %1,%2,%1        ! this kills msb of n
+4:      sub     %1,%2,%1
+5:      addxcc  %1,%1,%1
+        bcc     2b
+         subcc  %%g1,1,%%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+        bne     4b
+         addcc  %0,%0,%0        ! shift n1n0 and a 0-bit in lsb
+        sub     %1,%2,%1
+3:      xnor    %0,0,%0
+        ! End of inline udiv_qrnnd"                                     \
+           : "=&r" ((USItype) (q)),                                     \
+             "=&r" ((USItype) (r))                                      \
+           : "r" ((USItype) (d)),                                       \
+             "1" ((USItype) (n1)),                                      \
+             "0" ((USItype) (n0)) : "%g1", "cc")
+
+#define UDIV_NEEDS_NORMALIZATION 0
+
+#define abort()                                                                \
+       return 0
+
+#ifdef __BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
index bae5d323a61b8362e0a5ee7347b12a785470ebee..18eeb1f52c3d1a703388c98f7ee5c0ab64decb8f 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.27 1997/11/07 15:01:27 jj Exp $
+# $Id: Makefile,v 1.30 1998/03/09 14:03:53 jj Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -8,9 +8,17 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS   := fault.o init.o sun4c.o srmmu.o hypersparc.o viking.o \
-           tsunami.o loadmmu.o generic.o asyncd.o extable.o \
-           turbosparc.o iommu.o io-unit.o
+O_OBJS   := fault.o init.o loadmmu.o generic.o asyncd.o extable.o btfixup.o
+ifeq ($(CONFIG_SUN4),y)
+O_OBJS  += nosrmmu.o
+else
+O_OBJS  += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o turbosparc.o
+endif
+ifdef SMP
+O_OBJS   += nosun4c.o
+else
+O_OBJS   += sun4c.o
+endif
 
 include $(TOPDIR)/Rules.make
 
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c
new file mode 100644 (file)
index 0000000..e61ccc1
--- /dev/null
@@ -0,0 +1,334 @@
+/* $Id: btfixup.c,v 1.7 1998/03/09 14:03:56 jj Exp $
+ * btfixup.c: Boot time code fixup and relocator, so that
+ * we can get rid of most indirect calls to achieve single
+ * image sun4c and srmmu kernel.
+ *
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/btfixup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+
+#define BTFIXUP_OPTIMIZE_NOP
+#define BTFIXUP_OPTIMIZE_OTHER
+
+extern char *srmmu_name;
+static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for ";
+#ifdef CONFIG_SUN4
+static char str_sun4c[] __initdata = "sun4\n";
+#else
+static char str_sun4c[] __initdata = "sun4c\n";
+#endif
+static char str_srmmu[] __initdata = "srmmu[%s]/";
+static char str_iommu[] __initdata = "iommu\n";
+static char str_iounit[] __initdata = "io-unit\n";
+
+static int visited __initdata = 0;
+extern unsigned int ___btfixup_start[], ___btfixup_end[], __init_begin[], __init_end[], __init_text_end[];
+extern unsigned int _stext[], _end[], __start___ksymtab[], __stop___ksymtab[];
+static char wrong_f[] __initdata = "Trying to set f fixup %p to invalid function %08x\n";
+static char wrong_b[] __initdata = "Trying to set b fixup %p to invalid function %08x\n";
+static char wrong_s[] __initdata = "Trying to set s fixup %p to invalid value %08x\n";
+static char wrong_h[] __initdata = "Trying to set h fixup %p to invalid value %08x\n";
+static char wrong_a[] __initdata = "Trying to set a fixup %p to invalid value %08x\n";
+static char wrong[] __initdata = "Wrong address for %c fixup %p\n";
+static char insn_f[] __initdata = "Fixup f %p refers to weird instructions at %p[%08x,%08x]\n";
+static char insn_b[] __initdata = "Fixup b %p doesn't refer to a SETHI at %p[%08x]\n";
+static char insn_s[] __initdata = "Fixup s %p doesn't refer to an OR at %p[%08x]\n";
+static char insn_h[] __initdata = "Fixup h %p doesn't refer to a SETHI at %p[%08x]\n";
+static char insn_a[] __initdata = "Fixup a %p doesn't refer to a SETHI nor OR at %p[%08x]\n";
+static char insn_i[] __initdata = "Fixup i %p doesn't refer to a valid instruction at %p[%08x]\n";
+static char fca_und[] __initdata = "flush_cache_all undefined in btfixup()\n";
+static char wrong_setaddr[] __initdata = "Garbled CALL/INT patch at %p[%08x,%08x,%08x]=%08x\n";
+
+#ifdef BTFIXUP_OPTIMIZE_OTHER
+__initfunc(static void set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value))
+{
+       if (!fmangled)
+               *addr = value;
+       else {
+               unsigned int *q = (unsigned int *)q1;
+               if (*addr == 0x01000000) {
+                       /* Noped */
+                       *q = value;
+               } else if (addr[-1] == *q) {
+                       /* Moved */
+                       addr[-1] = value;
+                       *q = value;
+               } else {
+                       prom_printf(wrong_setaddr, addr-1, addr[-1], *addr, *q, value);
+                       prom_halt();
+               }
+       }
+}
+#else
+static __inline__ void set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value)
+{
+       *addr = value;
+}
+#endif
+
+__initfunc(void btfixup(void))
+{
+       unsigned int *p, *q;
+       int type, count;
+       unsigned insn;
+       unsigned *addr;
+       int fmangled = 0;
+       void (*flush_cacheall)(void);
+       
+       if (!visited) {
+               visited++;
+               printk(version);
+               if (ARCH_SUN4C_SUN4)
+                       printk(str_sun4c);
+               else {
+                       printk(str_srmmu, srmmu_name);
+                       if (sparc_cpu_model == sun4d)
+                               printk(str_iounit);
+                       else
+                               printk(str_iommu);
+               }
+       }
+       for (p = ___btfixup_start; p < ___btfixup_end; ) {
+               count = p[2];
+               q = p + 3;
+               switch (type = *(unsigned char *)p) {
+               case 'f': 
+                       count = p[3];
+                       q = p + 4;
+                       if (((p[0] & 1) || p[1]) 
+                           && ((p[1] & 3) || (unsigned *)(p[1]) < _stext || (unsigned *)(p[1]) >= _end)) {
+                               prom_printf(wrong_f, p, p[1]);
+                               prom_halt();
+                       }
+                       break;
+               case 'b':
+                       if (p[1] < (unsigned long)__init_begin || p[1] >= (unsigned long)__init_text_end || (p[1] & 3)) {
+                               prom_printf(wrong_b, p, p[1]);
+                               prom_halt();
+                       }
+                       break;
+               case 's':
+                       if (p[1] + 0x1000 >= 0x2000) {
+                               prom_printf(wrong_s, p, p[1]);
+                               prom_halt();
+                       }
+                       break;
+               case 'h':
+                       if (p[1] & 0x3ff) {
+                               prom_printf(wrong_h, p, p[1]);
+                               prom_halt();
+                       }
+                       break;
+               case 'a':
+                       if (p[1] + 0x1000 >= 0x2000 && (p[1] & 0x3ff)) {
+                               prom_printf(wrong_a, p, p[1]);
+                               prom_halt();
+                       }
+                       break;
+               }
+               if (p[0] & 1) {
+                       p[0] &= ~1;
+                       while (count) {
+                               fmangled = 0;
+                               addr = (unsigned *)*q;
+                               if (addr < _stext || addr >= _end) {
+                                       prom_printf(wrong, type, p);
+                                       prom_halt();
+                               }
+                               insn = *addr;
+#ifdef BTFIXUP_OPTIMIZE_OTHER                          
+                               if (type != 'f' && q[1]) {
+                                       insn = *(unsigned int *)q[1];
+                                       if (!insn || insn == 1)
+                                               insn = *addr;
+                                       else
+                                               fmangled = 1;
+                               }
+#endif
+                               switch (type) {
+                               case 'f':       /* CALL */
+                                       if (addr >= __start___ksymtab && addr < __stop___ksymtab) {
+                                               *addr = p[1];
+                                               break;
+                                       } else if (!q[1]) {
+                                               if ((insn & 0xc1c00000) == 0x01000000) { /* SETHI */
+                                                       *addr = (insn & 0xffc00000) | (p[1] >> 10); break;
+                                               } else if ((insn & 0xc1f82000) == 0x80102000) { /* OR X, %LO(i), Y */
+                                                       *addr = (insn & 0xffffe000) | (p[1] & 0x3ff); break;
+                                               } else if ((insn & 0xc0000000) != 0x40000000) { /* !CALL */
+                               bad_f:
+                                                       prom_printf(insn_f, p, addr, insn, addr[1]);
+                                                       prom_halt();
+                                               }
+                                       } else if (q[1] != 1)
+                                               addr[1] = q[1];
+                                       if (p[2] == BTFIXUPCALL_NORM) {
+                               norm_f: 
+                                               *addr = 0x40000000 | ((p[1] - (unsigned)addr) >> 2);
+                                               q[1] = 0;
+                                               break;
+                                       }
+#ifndef BTFIXUP_OPTIMIZE_NOP
+                                       goto norm_f;
+#else
+                                       if (!(addr[1] & 0x80000000)) {
+                                               if ((addr[1] & 0xc1c00000) != 0x01000000)       /* !SETHI */
+                                                       goto bad_f; /* CALL, Bicc, FBfcc, CBccc are weird in delay slot, aren't they? */
+                                       } else {
+                                               if ((addr[1] & 0x01800000) == 0x01800000) {
+                                                       if ((addr[1] & 0x01f80000) == 0x01e80000) {
+                                                               /* RESTORE */
+                                                               goto norm_f; /* It is dangerous to patch that */
+                                                       }
+                                                       goto bad_f;
+                                               }
+                                               if ((addr[1] & 0xffffe003) == 0x9e03e000) {
+                                                       /* ADD %O7, XX, %o7 */
+                                                       int displac = (addr[1] << 19);
+                                                       
+                                                       displac = (displac >> 21) + 2;
+                                                       *addr = (0x10800000) + (displac & 0x3fffff);
+                                                       q[1] = addr[1];
+                                                       addr[1] = p[2];
+                                                       break;
+                                               }
+                                               if ((addr[1] & 0x201f) == 0x200f || (addr[1] & 0x7c000) == 0x3c000)
+                                                       goto norm_f; /* Someone is playing bad tricks with us: rs1 or rs2 is o7 */
+                                               if ((addr[1] & 0x3e000000) == 0x1e000000)
+                                                       goto norm_f; /* rd is %o7. We'd better take care. */
+                                       }
+                                       if (p[2] == BTFIXUPCALL_NOP) {
+                                               *addr = 0x01000000;
+                                               q[1] = 1;
+                                               break;
+                                       }
+#ifndef BTFIXUP_OPTIMIZE_OTHER
+                                       goto norm_f;
+#else
+                                       if (addr[1] == 0x01000000) {    /* NOP in the delay slot */
+                                               q[1] = addr[1];
+                                               *addr = p[2];
+                                               break;
+                                       }
+                                       if ((addr[1] & 0xc0000000) != 0xc0000000) {
+                                               /* Not a memory operation */
+                                               if ((addr[1] & 0x30000000) == 0x10000000) {
+                                                       /* Ok, non-memory op with rd %oX */
+                                                       if ((addr[1] & 0x3e000000) == 0x1c000000)
+                                                               goto bad_f; /* Aiee. Someone is playing strange %sp tricks */
+                                                       if ((addr[1] & 0x3e000000) > 0x12000000 ||
+                                                           ((addr[1] & 0x3e000000) == 0x12000000 &&
+                                                            p[2] != BTFIXUPCALL_STO1O0 && p[2] != BTFIXUPCALL_SWAPO0O1) ||
+                                                           ((p[2] & 0xffffe000) == BTFIXUPCALL_RETINT(0))) {
+                                                               /* Nobody uses the result. We can nop it out. */
+                                                               *addr = p[2];
+                                                               q[1] = addr[1];
+                                                               addr[1] = 0x01000000;
+                                                               break;
+                                                       }
+                                                       if ((addr[1] & 0xf1ffffe0) == 0x90100000) {
+                                                               /* MOV %reg, %Ox */
+                                                               if ((addr[1] & 0x3e000000) == 0x10000000 &&
+                                                                   (p[2] & 0x7c000) == 0x20000) {
+                                                                       /* Ok, it is call xx; mov reg, %o0 and call optimizes
+                                                                          to doing something on %o0. Patch the patch. */
+                                                                       *addr = (p[2] & ~0x7c000) | ((addr[1] & 0x1f) << 14);
+                                                                       q[1] = addr[1];
+                                                                       addr[1] = 0x01000000;
+                                                                       break;
+                                                               }
+                                                               if ((addr[1] & 0x3e000000) == 0x12000000 &&
+                                                                   p[2] == BTFIXUPCALL_STO1O0) {
+                                                                       *addr = (p[2] & ~0x3e000000) | ((addr[1] & 0x1f) << 25);
+                                                                       q[1] = addr[1];
+                                                                       addr[1] = 0x01000000;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       *addr = addr[1];
+                                       q[1] = addr[1];
+                                       addr[1] = p[2];
+                                       break;
+#endif /* BTFIXUP_OPTIMIZE_OTHER */
+#endif /* BTFIXUP_OPTIMIZE_NOP */
+                               case 'b':       /* BLACKBOX */
+                                       /* Has to be sethi i, xx */
+                                       if ((insn & 0xc1c00000) != 0x01000000) {
+                                               prom_printf(insn_b, p, addr, insn);
+                                               prom_halt();
+                                       } else {
+                                               void (*do_fixup)(unsigned *);
+                                               
+                                               do_fixup = (void (*)(unsigned *))p[1];
+                                               do_fixup(addr);
+                                       }
+                                       break;
+                               case 's':       /* SIMM13 */
+                                       /* Has to be or %g0, i, xx */
+                                       if ((insn & 0xc1ffe000) != 0x80102000) {
+                                               prom_printf(insn_s, p, addr, insn);
+                                               prom_halt();
+                                       }
+                                       set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x1fff));
+                                       break;
+                               case 'h':       /* SETHI */
+                                       /* Has to be sethi i, xx */
+                                       if ((insn & 0xc1c00000) != 0x01000000) {
+                                               prom_printf(insn_h, p, addr, insn);
+                                               prom_halt();
+                                       }
+                                       set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10));
+                                       break;
+                               case 'a':       /* HALF */
+                                       /* Has to be sethi i, xx or or %g0, i, xx */
+                                       if ((insn & 0xc1c00000) != 0x01000000 &&
+                                           (insn & 0xc1ffe000) != 0x80102000) {
+                                               prom_printf(insn_a, p, addr, insn);
+                                               prom_halt();
+                                       }
+                                       if (p[1] & 0x3ff)
+                                               set_addr(addr, q[1], fmangled, 
+                                                       (insn & 0x3e000000) | 0x80102000 | (p[1] & 0x1fff));
+                                       else
+                                               set_addr(addr, q[1], fmangled, 
+                                                       (insn & 0x3e000000) | 0x01000000 | (p[1] >> 10));
+                                       break;
+                               case 'i':       /* INT */
+                                       if ((insn & 0xc1c00000) == 0x01000000) /* %HI */
+                                               set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10));
+                                       else if ((insn & 0x80002000) == 0x80002000 &&
+                                                (insn & 0x01800000) != 0x01800000) /* %LO */
+                                               set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x3ff));
+                                       else {
+                                               prom_printf(insn_i, p, addr, insn);
+                                               prom_halt();
+                                       }
+                                       break;
+                               }
+                               count -= 2;
+                               q += 2;
+                       }
+               } else
+                       p = q + count;
+       }
+#ifdef __SMP__
+       flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(local_flush_cache_all);
+#else
+       flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(flush_cache_all);
+#endif
+       if (!flush_cacheall) {
+               prom_printf(fca_und);
+               prom_halt();
+       }
+       (*flush_cacheall)();
+}
index 0d6490860f59e413ec20ac997ec02a41904ecdd9..274b9eebf4b2d1419718767c9bb7ad12d1431139 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.92 1997/05/15 21:14:21 davem Exp $
+/* $Id: fault.c,v 1.93 1998/03/25 10:43:16 jj Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -271,7 +271,7 @@ bad_area:
 #endif
                tsk->tss.sig_address = address;
                tsk->tss.sig_desc = SUBSIG_NOMAPPING;
-               send_sig(SIGSEGV, tsk, 1);
+               force_sig(SIGSEGV, tsk);
                goto out;
        }
        unhandled_fault (address, tsk, regs);
index 2c27bfdabc6518328822a3490bfc4c82c61f080b..dcf3fd99085f24a7078b6dbbbfa169b01f238b24 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hypersparc.S,v 1.12 1997/11/27 15:42:30 jj Exp $
+/* $Id: hypersparc.S,v 1.13 1998/02/13 15:35:09 jj Exp $
  * hypersparc.S: High speed Hypersparc mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -301,14 +301,13 @@ hypersparc_flush_tlb_range:
        cmp     %o3, -1
        be      hypersparc_flush_tlb_range_out
 #endif
-        srl    %o1, SRMMU_PGDIR_SHIFT, %o1
+        sethi  %hi(~((1 << SRMMU_PGDIR_SHIFT) - 1)), %o4
        sta     %o3, [%g1] ASI_M_MMUREGS
-       sll     %o1, SRMMU_PGDIR_SHIFT, %o1
-       sethi   %hi(1 << SRMMU_PGDIR_SHIFT), %o4
+       and     %o1, %o4, %o1
        add     %o1, 0x200, %o1
        sta     %g0, [%o1] ASI_M_FLUSH_PROBE
 1:
-       add     %o1, %o4, %o1
+       sub     %o1, %o4, %o1
        cmp     %o1, %o2
        blu,a   1b
         sta    %g0, [%o1] ASI_M_FLUSH_PROBE
index aa85666c68d6457b3b600c71040f43cd640bd60e..db65592144168ba94414edfecfa46916a8380600 100644 (file)
@@ -1,8 +1,9 @@
-/*  $Id: init.c,v 1.50 1998/01/10 18:19:42 ecd Exp $
+/*  $Id: init.c,v 1.59 1998/03/27 06:59:57 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *  Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be)
+ *  Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/config.h>
 #include <asm/pgtable.h>
 #include <asm/vaddrs.h>
 
+/* Turn this off if you suspect some place in some physical memory hole
+   might get into page tables (something would be broken very much). */
+   
+#define FREE_UNUSED_MEM_MAP
+
 extern void show_net_buffers(void);
 
 struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 unsigned long sparc_unmapped_base;
 
+struct pgtable_cache_struct pgt_quicklists;
+
 /* References to section boundaries */
 extern char __init_begin, __init_end, etext;
 
@@ -65,26 +73,38 @@ pte_t __bad_page(void)
 
 void show_mem(void)
 {
-       int i,free = 0,total = 0,reserved = 0;
-       int shared = 0;
+       int free = 0,total = 0,reserved = 0;
+       int shared = 0, cached = 0;
+       struct page *page, *end;
 
        printk("\nMem-info:\n");
        show_free_areas();
        printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-       i = max_mapnr;
-       while (i-- > 0) {
+       for (page = mem_map, end = mem_map + max_mapnr;
+            page < end; page++) {
+               if (PageSkip(page)) {
+                       if (page->next_hash < page)
+                               break;
+                       page = page->next_hash;
+               }
                total++;
-               if (PageReserved(mem_map + i))
+               if (PageReserved(page))
                        reserved++;
-               else if (!atomic_read(&mem_map[i].count))
+               else if (PageSwapCache(page))
+                       cached++;
+               else if (!atomic_read(&page->count))
                        free++;
                else
-                       shared += atomic_read(&mem_map[i].count) - 1;
+                       shared += atomic_read(&page->count) - 1;
        }
        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);
+       printk("%d pages swap cached\n",cached);
+       printk("%ld page tables cached\n",pgtable_cache_size);
+       if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
+               printk("%ld page dirs cached\n", pgd_cache_size);
        show_buffers();
 #ifdef CONFIG_NET
        show_net_buffers();
@@ -128,19 +148,23 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        switch(sparc_cpu_model) {
        case sun4c:
        case sun4e:
+       case sun4:
                start_mem = sun4c_paging_init(start_mem, end_mem);
                sparc_unmapped_base = 0xe0000000;
+               BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000);
                break;
        case sun4m:
        case sun4d:
                start_mem = srmmu_paging_init(start_mem, end_mem);
                sparc_unmapped_base = 0x50000000;
+               BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
                break;
 
        case ap1000:
 #if CONFIG_AP1000
                start_mem = apmmu_paging_init(start_mem, end_mem);
                sparc_unmapped_base = 0x50000000;
+               BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
                break;
 #endif
 
@@ -168,6 +192,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        protection_map[13] = PAGE_READONLY;
        protection_map[14] = PAGE_SHARED;
        protection_map[15] = PAGE_SHARED;
+       btfixup();
        return device_scan(start_mem);
 }
 
@@ -175,7 +200,7 @@ struct cache_palias *sparc_aliases;
 
 extern void srmmu_frob_mem_map(unsigned long);
 
-int physmem_mapped_contig = 1;
+int physmem_mapped_contig __initdata = 1;
 
 __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
 {
@@ -210,7 +235,8 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
        int codepages = 0;
        int datapages = 0;
        int initpages = 0; 
-       unsigned long tmp2, addr;
+       unsigned long addr;
+       struct page *page, *end;
 
        /* Saves us work later. */
        memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
@@ -220,33 +246,60 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
        high_memory = (void *) end_mem;
 
        start_mem = PAGE_ALIGN(start_mem);
-       num_physpages = (start_mem - KERNBASE) >> PAGE_SHIFT;
+       num_physpages = 0;
 
        addr = KERNBASE;
        while(addr < start_mem) {
 #ifdef CONFIG_BLK_DEV_INITRD
-               if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) {
+               if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end)
                        mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
-                       num_physpages--;
-               } else
+               else
 #endif 
                        mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
                addr += PAGE_SIZE;
        }
 
        taint_real_pages(start_mem, end_mem);
+       
+#ifdef FREE_UNUSED_MEM_MAP
+       end = mem_map + max_mapnr;
+       for (page = mem_map; page < end; page++) {
+               if (PageSkip(page)) {
+                       unsigned long low, high;
+
+                       low = PAGE_ALIGN((unsigned long)(page+1));
+                       if (page->next_hash < page)
+                               high = ((unsigned long)end) & PAGE_MASK;
+                       else
+                               high = ((unsigned long)page->next_hash) & PAGE_MASK;
+                       while (low < high) {
+                               mem_map[MAP_NR(low)].flags &= ~(1<<PG_reserved);
+                               low += PAGE_SIZE;
+                       }
+               }
+       }
+#endif
+       
        for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
+               if (PageSkip(mem_map + MAP_NR(addr))) {
+                       unsigned long next = mem_map[MAP_NR(addr)].next_hash - mem_map;
+
+                       next = (next << PAGE_SHIFT) + PAGE_OFFSET;
+                       if (next < addr || next >= end_mem)
+                               break;
+                       addr = next;
+               }
+               num_physpages++;
                if(PageReserved(mem_map + MAP_NR(addr))) {
                        if ((addr < (unsigned long) &etext) && (addr >= KERNBASE))
                                codepages++;
-                        else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
-                                initpages++;
-                        else if((addr < start_mem) && (addr >= KERNBASE))
+                       else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+                               initpages++;
+                       else if((addr < start_mem) && (addr >= KERNBASE))
                                datapages++;
                        continue;
                }
                atomic_set(&mem_map[MAP_NR(addr)].count, 1);
-               num_physpages++;
 #ifdef CONFIG_BLK_DEV_INITRD
                if (!initrd_start ||
                    (addr < initrd_start || addr >= initrd_end))
@@ -254,14 +307,12 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
                        free_page(addr);
        }
 
-       tmp2 = nr_free_pages << PAGE_SHIFT;
-
-       printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
-              tmp2 >> 10,
+       printk("Memory: %dk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+              nr_free_pages << (PAGE_SHIFT-10),
               codepages << (PAGE_SHIFT-10),
               datapages << (PAGE_SHIFT-10), 
               initpages << (PAGE_SHIFT-10),
-              PAGE_OFFSET, end_mem);
+              (unsigned long)PAGE_OFFSET, end_mem);
 
        freepages.min = nr_free_pages >> 7;
        if(freepages.min < 16)
@@ -284,20 +335,25 @@ void free_initmem (void)
 
 void si_meminfo(struct sysinfo *val)
 {
-       int i;
+       struct page *page, *end;
 
-       i = MAP_NR(high_memory);
        val->totalram = 0;
        val->sharedram = 0;
        val->freeram = nr_free_pages << PAGE_SHIFT;
        val->bufferram = buffermem;
-       while (i-- > 0)  {
-               if (PageReserved(mem_map + i))
+       for (page = mem_map, end = mem_map + max_mapnr;
+            page < end; page++) {
+               if (PageSkip(page)) {
+                       if (page->next_hash < page)
+                               break;
+                       page = page->next_hash;
+               }
+               if (PageReserved(page))
                        continue;
                val->totalram++;
-               if (!atomic_read(&mem_map[i].count))
+               if (!atomic_read(&page->count))
                        continue;
-               val->sharedram += atomic_read(&mem_map[i].count) - 1;
+               val->sharedram += atomic_read(&page->count) - 1;
        }
        val->totalram <<= PAGE_SHIFT;
        val->sharedram <<= PAGE_SHIFT;
index 519c124c93d4b9319b850fbf32979eef9908a37f..d293fc71c7a5814941fd7ef730fc6fa1f558d17d 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: io-unit.c,v 1.5 1997/12/22 16:09:26 jj Exp $
+/* $Id: io-unit.c,v 1.10 1998/03/03 12:31:14 jj Exp $
  * io-unit.c:  IO-UNIT specific routines for memory management.
  *
- * Copyright (C) 1997 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
  */
  
 #include <linux/config.h>
 #include <asm/io.h>
 #include <asm/io-unit.h>
 #include <asm/mxcc.h>
+#include <asm/spinlock.h>
+#include <asm/bitops.h>
+
+/* #define IOUNIT_DEBUG */
+#ifdef IOUNIT_DEBUG
+#define IOD(x) printk(x)
+#else
+#define IOD(x) do { } while (0)
+#endif
 
 #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
 
 #define IOPERM        (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
-#define MKIOPTE(phys) ((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
+#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
 
-unsigned long sun4d_dma_base;
-unsigned long sun4d_dma_vbase;
-unsigned long sun4d_dma_size;
 __initfunc(unsigned long
 iounit_init(int sbi_node, int io_node, unsigned long memory_start,
            unsigned long memory_end, struct linux_sbus *sbus))
 {
        iopte_t *xpt, *xptend;
-       unsigned long paddr;
        struct iounit_struct *iounit;
        struct linux_prom_registers iommu_promregs[PROMREG_MAX];
        
        memory_start = LONG_ALIGN(memory_start);
        iounit = (struct iounit_struct *)memory_start;
-       memory_start += sizeof(struct iounit_struct);
-
+       memory_start = LONG_ALIGN(memory_start + sizeof(struct iounit_struct));
+       
+       memset(iounit, 0, sizeof(*iounit));
+       iounit->limit[0] = IOUNIT_BMAP1_START;
+       iounit->limit[1] = IOUNIT_BMAP2_START;
+       iounit->limit[2] = IOUNIT_BMAPM_START;
+       iounit->limit[3] = IOUNIT_BMAPM_END;
+       iounit->rotor[1] = IOUNIT_BMAP2_START;
+       iounit->rotor[2] = IOUNIT_BMAPM_START;
+       
        prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
                         sizeof(iommu_promregs));
        prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
@@ -46,11 +59,6 @@ iounit_init(int sbi_node, int io_node, unsigned long memory_start,
        sbus->iommu = (struct iommu_struct *)iounit;
        iounit->page_table = xpt;
        
-       /* Initialize new table. */
-       paddr = IOUNIT_DMA_BASE - sun4d_dma_base;
-       for (xptend = xpt + (sun4d_dma_size >> PAGE_SHIFT);
-            xpt < xptend; paddr++)
-               *xpt++ = MKIOPTE(paddr);
        for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t);
             xpt < xptend;)
                *xpt++ = 0;
@@ -58,36 +66,108 @@ iounit_init(int sbi_node, int io_node, unsigned long memory_start,
        return memory_start;
 }
 
+/* One has to hold iounit->lock to call this */
+static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
+{
+       int i, j, k, npages;
+       unsigned long rotor, scan, limit;
+       iopte_t iopte;
+
+        npages = ((vaddr & ~PAGE_MASK) + size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
+
+       /* A tiny bit of magic ingredience :) */
+       switch (npages) {
+       case 1: i = 0x0231; break;
+       case 2: i = 0x0132; break;
+       default: i = 0x0213; break;
+       }
+       
+       IOD(("iounit_get_area(%08lx,%d[%d])=", vaddr, size, npages));
+       
+next:  j = (i & 15);
+       rotor = iounit->rotor[j - 1];
+       limit = iounit->limit[j];
+       scan = rotor;
+nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
+       if (scan + npages > limit) {
+               if (limit != rotor) {
+                       limit = rotor;
+                       scan = iounit->limit[j - 1];
+                       goto nexti;
+               }
+               i >>= 4;
+               if (!(i & 15))
+                       panic("iounit_get_area: Couldn't find free iopte slots for (%08lx,%d)\n", vaddr, size);
+               goto next;
+       }
+       for (k = 1, scan++; k < npages; k++)
+               if (test_bit(scan++, iounit->bmap))
+                       goto nexti;
+       iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
+       scan -= npages;
+       iopte = MKIOPTE(mmu_v2p(vaddr & PAGE_MASK));
+       vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK);
+       for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) {
+               set_bit(scan, iounit->bmap);
+               iounit->page_table[scan] = iopte;
+       }
+       IOD(("%08lx\n", vaddr));
+       return vaddr;
+}
+
 static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
 {
-       /* Viking MXCC is IO coherent, just need to translate the address to DMA handle */
-#ifdef IOUNIT_DEBUG
-       if ((((unsigned long) vaddr) & PAGE_MASK) < sun4d_dma_vaddr || 
-           (((unsigned long) vaddr) & PAGE_MASK) + len > sun4d_dma_vbase + sun4d_dma_size)
-                       panic("Using non-DMA memory for iounit_get_scsi_one");
-#endif 
-       return (__u32)(sun4d_dma_base + mmu_v2p((long)vaddr));
+       unsigned long ret, flags;
+       struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+       
+       spin_lock_irqsave(&iounit->lock, flags);
+       ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
+       spin_unlock_irqrestore(&iounit->lock, flags);
+       return ret;
 }
 
 static void iounit_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
-       /* Viking MXCC is IO coherent, just need to translate the address to DMA handle */
+       unsigned long flags;
+       struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+
+       /* FIXME: Cache some resolved pages - often several sg entries are to the same page */
+       spin_lock_irqsave(&iounit->lock, flags);
        for (; sz >= 0; sz--) {
-#ifdef IOUNIT_DEBUG
-               unsigned long page = ((unsigned long) sg[sz].addr) & PAGE_MASK;
-               if (page < sun4d_dma_vbase || page + sg[sz].len > sun4d_dma_vbase + sun4d_dma_size)
-                       panic("Using non-DMA memory for iounit_get_scsi_sgl");
-#endif 
-               sg[sz].dvma_addr = (__u32) (sun4d_dma_base + mmu_v2p((long)sg[sz].addr));;
+               sg[sz].dvma_addr = iounit_get_area(iounit, (unsigned long)sg[sz].addr, sg[sz].len);
        }
+       spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
 static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus)
 {
+       unsigned long flags;
+       struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+       
+       spin_lock_irqsave(&iounit->lock, flags);
+       len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
+       vaddr = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
+       IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
+       for (len += vaddr; vaddr < len; vaddr++)
+               clear_bit(vaddr, iounit->bmap);
+       spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
 static void iounit_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
+       unsigned long flags;
+       unsigned long vaddr, len;
+       struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+       
+       spin_lock_irqsave(&iounit->lock, flags);
+       for (; sz >= 0; sz--) {
+               len = ((sg[sz].dvma_addr & ~PAGE_MASK) + sg[sz].len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
+               vaddr = (sg[sz].dvma_addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
+               IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
+               for (len += vaddr; vaddr < len; vaddr++)
+                       clear_bit(vaddr, iounit->bmap);
+       }
+       spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
 #ifdef CONFIG_SBUS
@@ -135,24 +215,26 @@ static void iounit_map_dma_area(unsigned long addr, int len)
 
 static char *iounit_lockarea(char *vaddr, unsigned long len)
 {
+/* FIXME: Write this */
        return vaddr;
 }
 
 static void iounit_unlockarea(char *vaddr, unsigned long len)
 {
+/* FIXME: Write this */
 }
 
 __initfunc(void ld_mmu_iounit(void))
 {
-       mmu_lockarea = iounit_lockarea;
-       mmu_unlockarea = iounit_unlockarea;
+       BTFIXUPSET_CALL(mmu_lockarea, iounit_lockarea, BTFIXUPCALL_RETO0);
+       BTFIXUPSET_CALL(mmu_unlockarea, iounit_unlockarea, BTFIXUPCALL_NOP);
 
-       mmu_get_scsi_one = iounit_get_scsi_one;
-       mmu_get_scsi_sgl = iounit_get_scsi_sgl;
-       mmu_release_scsi_one = iounit_release_scsi_one;
-       mmu_release_scsi_sgl = iounit_release_scsi_sgl;
+       BTFIXUPSET_CALL(mmu_get_scsi_one, iounit_get_scsi_one, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_get_scsi_sgl, iounit_get_scsi_sgl, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_release_scsi_one, iounit_release_scsi_one, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_release_scsi_sgl, iounit_release_scsi_sgl, BTFIXUPCALL_NORM);
 
 #ifdef CONFIG_SBUS
-       mmu_map_dma_area = iounit_map_dma_area;
+       BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
 #endif
 }
index 3019463261db3a677bad9acb108b35af2c5ec867..e46216233491b18fe18184b7e8e37de90b6912e4 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: iommu.c,v 1.4 1997/11/21 17:31:31 jj Exp $
+/* $Id: iommu.c,v 1.7 1998/02/22 10:32:26 ecd Exp $
  * iommu.c:  IOMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
  * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru)
  * Copyright (C) 1996 Eddie C. Dost    (ecd@skynet.be)
- * Copyright (C) 1997 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
  */
  
 #include <linux/config.h>
 
 /* srmmu.c */
 extern int viking_mxcc_present;
-extern void (*flush_page_for_dma)(unsigned long page);
+BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long)
+#define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page)
 extern int flush_page_for_dma_global;
+static int viking_flush = 0;
 /* viking.S */
 extern void viking_flush_page(unsigned long page);
 extern void viking_mxcc_flush_page(unsigned long page);
@@ -113,7 +115,7 @@ iommu_init(int iommund, unsigned long memory_start,
                        viking_mxcc_flush_page(start);
                        start += PAGE_SIZE;
                }
-       } else if(flush_page_for_dma == viking_flush_page) {
+       } else if (viking_flush) {
                unsigned long start = (unsigned long) iommu->page_table;
                unsigned long end = (start + ptsize);
                while(start < end) {
@@ -199,7 +201,7 @@ static void iommu_map_dma_area(unsigned long addr, int len)
        pgprot_t dvma_prot;
        struct iommu_struct *iommu = SBus_chain->iommu;
        iopte_t *iopte = iommu->page_table;
-       iopte_t *iopte_first = iopte;
+       iopte_t *first;
 
        if(viking_mxcc_present)
                dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
@@ -207,6 +209,7 @@ static void iommu_map_dma_area(unsigned long addr, int len)
                dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV);
 
        iopte += ((addr - iommu->start) >> PAGE_SHIFT);
+       first = iopte;
        end = PAGE_ALIGN((addr + len));
        while(addr < end) {
                page = get_free_page(GFP_KERNEL);
@@ -223,21 +226,20 @@ static void iommu_map_dma_area(unsigned long addr, int len)
                        ptep = pte_offset(pmdp, addr);
 
                        set_pte(ptep, pte_val(mk_pte(page, dvma_prot)));
-
                        iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
                }
                addr += PAGE_SIZE;
        }
        flush_cache_all();
        if(viking_mxcc_present) {
-               unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK;
+               unsigned long start = ((unsigned long) first) & PAGE_MASK;
                unsigned long end = PAGE_ALIGN(((unsigned long) iopte));
                while(start < end) {
                        viking_mxcc_flush_page(start);
                        start += PAGE_SIZE;
                }
-       } else if(flush_page_for_dma == viking_flush_page) {
-               unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK;
+       } else if(viking_flush) {
+               unsigned long start = ((unsigned long) first) & PAGE_MASK;
                unsigned long end = PAGE_ALIGN(((unsigned long) iopte));
                while(start < end) {
                        viking_flush_page(start);
@@ -260,25 +262,26 @@ static void iommu_unlockarea(char *vaddr, unsigned long len)
 
 __initfunc(void ld_mmu_iommu(void))
 {
-       mmu_lockarea = iommu_lockarea;
-       mmu_unlockarea = iommu_unlockarea;
+       viking_flush = (BTFIXUPVAL_CALL(flush_page_for_dma) == (unsigned long)viking_flush_page);
+       BTFIXUPSET_CALL(mmu_lockarea, iommu_lockarea, BTFIXUPCALL_RETO0);
+       BTFIXUPSET_CALL(mmu_unlockarea, iommu_unlockarea, BTFIXUPCALL_NOP);
 
-       if (!flush_page_for_dma) {
+       if (!BTFIXUPVAL_CALL(flush_page_for_dma)) {
                /* IO coherent chip */
-               mmu_get_scsi_one = iommu_get_scsi_one_noflush;
-               mmu_get_scsi_sgl = iommu_get_scsi_sgl_noflush;
+               BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_noflush, BTFIXUPCALL_RETO0);
+               BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_noflush, BTFIXUPCALL_NORM);
        } else if (flush_page_for_dma_global) {
                /* flush_page_for_dma flushes everything, no matter of what page is it */
-               mmu_get_scsi_one = iommu_get_scsi_one_gflush;
-               mmu_get_scsi_sgl = iommu_get_scsi_sgl_gflush;
+               BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_gflush, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_gflush, BTFIXUPCALL_NORM);
        } else {
-               mmu_get_scsi_one = iommu_get_scsi_one_pflush;
-               mmu_get_scsi_sgl = iommu_get_scsi_sgl_pflush;
+               BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_pflush, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_pflush, BTFIXUPCALL_NORM);
        }
-       mmu_release_scsi_one = iommu_release_scsi_one;
-       mmu_release_scsi_sgl = iommu_release_scsi_sgl;
+       BTFIXUPSET_CALL(mmu_release_scsi_one, iommu_release_scsi_one, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(mmu_release_scsi_sgl, iommu_release_scsi_sgl, BTFIXUPCALL_NOP);
 
 #ifdef CONFIG_SBUS
-       mmu_map_dma_area = iommu_map_dma_area;
+       BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM);
 #endif
 }
index 10eebecceeeedb3d6877db03b8fd9460245099ec..b38eea6d80e49ffe191cc8e976b60e8e28e584aa 100644 (file)
@@ -1,9 +1,10 @@
-/* $Id: loadmmu.c,v 1.46 1997/04/10 05:12:51 davem Exp $
+/* $Id: loadmmu.c,v 1.50 1998/02/05 14:19:02 jj Exp $
  * loadmmu.c:  This code loads up all the mm function pointers once the
  *             machine type has been determined.  It also sets the static
  *             mmu values such as PAGE_NONE, etc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/kernel.h>
@@ -16,6 +17,7 @@
 #include <asm/pgtable.h>
 #include <asm/a.out.h>
 #include <asm/mmu_context.h>
+#include <asm/oplib.h>
 
 unsigned long page_offset = 0xf0000000;
 unsigned long stack_top = 0xf0000000 - PAGE_SIZE;
@@ -24,132 +26,8 @@ struct ctx_list *ctx_list_pool;
 struct ctx_list ctx_free;
 struct ctx_list ctx_used;
 
-unsigned long (*alloc_kernel_stack)(struct task_struct *tsk);
-void (*free_kernel_stack)(unsigned long stack);
-struct task_struct *(*alloc_task_struct)(void);
-void (*free_task_struct)(struct task_struct *tsk);
-
-void (*quick_kernel_fault)(unsigned long);
-
-void (*init_new_context)(struct mm_struct *mm);
-void (*destroy_context)(struct mm_struct *mm);
-
-/* translate between physical and virtual addresses */
-unsigned long (*mmu_v2p)(unsigned long);
-unsigned long (*mmu_p2v)(unsigned long);
-
-char *(*mmu_lockarea)(char *, unsigned long);
-void  (*mmu_unlockarea)(char *, unsigned long);
-
-__u32 (*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus);
-void  (*mmu_get_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus);
-void  (*mmu_release_scsi_one)(__u32, unsigned long, struct linux_sbus *sbus);
-void  (*mmu_release_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus);
-
-void  (*mmu_map_dma_area)(unsigned long addr, int len);
-
-void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte);
-
-#ifdef __SMP__
-void (*local_flush_cache_all)(void);
-void (*local_flush_cache_mm)(struct mm_struct *);
-void (*local_flush_cache_range)(struct mm_struct *, unsigned long start,
-                               unsigned long end);
-void (*local_flush_cache_page)(struct vm_area_struct *, unsigned long address);
-
-void (*local_flush_tlb_all)(void);
-void (*local_flush_tlb_mm)(struct mm_struct *);
-void (*local_flush_tlb_range)(struct mm_struct *, unsigned long start,
-                             unsigned long end);
-void (*local_flush_tlb_page)(struct vm_area_struct *, unsigned long address);
-void (*local_flush_page_to_ram)(unsigned long address);
-void (*local_flush_sig_insns)(struct mm_struct *mm, unsigned long insn_addr);
-#endif
-
-void (*flush_cache_all)(void);
-void (*flush_cache_mm)(struct mm_struct *);
-void (*flush_cache_range)(struct mm_struct *, unsigned long start,
-                         unsigned long end);
-void (*flush_cache_page)(struct vm_area_struct *, unsigned long address);
-
-void (*flush_tlb_all)(void);
-void (*flush_tlb_mm)(struct mm_struct *);
-void (*flush_tlb_range)(struct mm_struct *, unsigned long start,
-                       unsigned long end);
-void (*flush_tlb_page)(struct vm_area_struct *, unsigned long address);
-
-void (*flush_page_to_ram)(unsigned long page);
-
-void (*flush_sig_insns)(struct mm_struct *mm, unsigned long insn_addr);
-
-void (*set_pte)(pte_t *pteptr, pte_t pteval);
-
-unsigned int pmd_shift, pmd_size, pmd_mask;
-unsigned int (*pmd_align)(unsigned int);
-unsigned int pgdir_shift, pgdir_size, pgdir_mask;
-unsigned int (*pgdir_align)(unsigned int);
-unsigned int ptrs_per_pte, ptrs_per_pmd, ptrs_per_pgd;
 unsigned int pg_iobits;
 
-pgprot_t page_none, page_shared, page_copy, page_readonly, page_kernel;
-
-unsigned long (*pte_page)(pte_t);
-unsigned long (*pmd_page)(pmd_t);
-unsigned long (*pgd_page)(pgd_t);
-
-void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
-unsigned long (*(vmalloc_start))(void);
-void (*switch_to_context)(struct task_struct *tsk);
-
-int (*pte_none)(pte_t);
-int (*pte_present)(pte_t);
-void (*pte_clear)(pte_t *);
-
-int (*pmd_none)(pmd_t);
-int (*pmd_bad)(pmd_t);
-int (*pmd_present)(pmd_t);
-void (*pmd_clear)(pmd_t *);
-
-int (*pgd_none)(pgd_t);
-int (*pgd_bad)(pgd_t);
-int (*pgd_present)(pgd_t);
-void (*pgd_clear)(pgd_t *);
-
-pte_t (*mk_pte)(unsigned long, pgprot_t);
-pte_t (*mk_pte_phys)(unsigned long, pgprot_t);
-pte_t (*mk_pte_io)(unsigned long, pgprot_t, int);
-void (*pgd_set)(pgd_t *, pmd_t *);
-pte_t (*pte_modify)(pte_t, pgprot_t);
-pgd_t * (*pgd_offset)(struct mm_struct *, unsigned long);
-pmd_t * (*pmd_offset)(pgd_t *, unsigned long);
-pte_t * (*pte_offset)(pmd_t *, unsigned long);
-void (*pte_free_kernel)(pte_t *);
-pte_t * (*pte_alloc_kernel)(pmd_t *, unsigned long);
-
-void (*pmd_free_kernel)(pmd_t *);
-pmd_t * (*pmd_alloc_kernel)(pgd_t *, unsigned long);
-void (*pte_free)(pte_t *);
-pte_t * (*pte_alloc)(pmd_t *, unsigned long);
-
-void (*pmd_free)(pmd_t *);
-pmd_t * (*pmd_alloc)(pgd_t *, unsigned long);
-void (*pgd_free)(pgd_t *);
-
-pgd_t * (*pgd_alloc)(void);
-
-int (*pte_write)(pte_t);
-int (*pte_dirty)(pte_t);
-int (*pte_young)(pte_t);
-
-pte_t (*pte_wrprotect)(pte_t);
-pte_t (*pte_mkclean)(pte_t);
-pte_t (*pte_mkold)(pte_t);
-pte_t (*pte_mkwrite)(pte_t);
-pte_t (*pte_mkdirty)(pte_t);
-pte_t (*pte_mkyoung)(pte_t);
-
-char *(*mmu_info)(void);
-
 extern void ld_mmu_sun4c(void);
 extern void ld_mmu_srmmu(void);
 
@@ -157,6 +35,7 @@ __initfunc(void load_mmu(void))
 {
        switch(sparc_cpu_model) {
        case sun4c:
+       case sun4:
                ld_mmu_sun4c();
                break;
        case sun4m:
@@ -169,9 +48,8 @@ __initfunc(void load_mmu(void))
                break;
 #endif
        default:
-               printk("load_mmu:MMU support not available for this architecture\n");
-               printk("load_mmu:sparc_cpu_model = %d\n", (int) sparc_cpu_model);
-               printk("load_mmu:Halting...\n");
-               panic("load_mmu()");
+               prom_printf("load_mmu: %d unsupported\n", (int)sparc_cpu_model);
+               prom_halt();
        }
+       btfixup();
 }
diff --git a/arch/sparc/mm/nosrmmu.c b/arch/sparc/mm/nosrmmu.c
new file mode 100644 (file)
index 0000000..f82599f
--- /dev/null
@@ -0,0 +1,50 @@
+/* $Id: nosrmmu.c,v 1.1 1998/03/09 14:04:15 jj Exp $
+ * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, 
+ *         so that it does not need srmmu and avoid ifdefs.
+ *
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <asm/mbus.h>
+
+static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
+
+enum mbus_module srmmu_modtype;
+
+__initfunc(static void should_not_happen(void))
+{
+       prom_printf(shouldnothappen);
+       prom_halt();
+}
+
+__initfunc(void srmmu_frob_mem_map(unsigned long start_mem))
+{
+       should_not_happen();
+}
+
+__initfunc(unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem))
+{
+       should_not_happen();
+       return 0;
+}
+
+__initfunc(void ld_mmu_srmmu(void))
+{
+       should_not_happen();
+}
+
+void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
+{
+}
+
+void srmmu_unmapioaddr(unsigned long virt_addr)
+{
+}
+
+__initfunc(void srmmu_end_memory(unsigned long memory_size, unsigned long *mem_end_p))
+{
+       return 0;
+}
diff --git a/arch/sparc/mm/nosun4c.c b/arch/sparc/mm/nosun4c.c
new file mode 100644 (file)
index 0000000..7da883a
--- /dev/null
@@ -0,0 +1,77 @@
+/* $Id: nosun4c.c,v 1.1 1998/03/09 14:04:16 jj Exp $
+ * nosun4c.c: This file is a bunch of dummies for SMP compiles, 
+ *         so that it does not need sun4c and avoid ifdefs.
+ *
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <asm/pgtable.h>
+
+static char shouldnothappen[] __initdata = "32bit SMP kernel only supports sun4m and sun4d\n";
+
+/* Dummies */
+struct sun4c_mmu_ring {
+       unsigned long xxx1[3];
+       unsigned char xxx2[2];
+       int xxx3;
+};
+struct sun4c_mmu_ring sun4c_kernel_ring;
+struct sun4c_mmu_ring sun4c_kfree_ring;
+unsigned long sun4c_kernel_faults;
+unsigned long *sun4c_memerr_reg;
+
+__initfunc(static void should_not_happen(void))
+{
+       prom_printf(shouldnothappen);
+       prom_halt();
+}
+
+__initfunc(unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem))
+{
+       should_not_happen();
+       return 0;
+}
+
+__initfunc(void ld_mmu_sun4c(void))
+{
+       should_not_happen();
+}
+
+void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
+{
+}
+
+void sun4c_unmapioaddr(unsigned long virt_addr)
+{
+}
+
+void sun4c_complete_all_stores(void)
+{
+}
+
+pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
+{
+       return NULL;
+}
+
+pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
+{
+       return NULL;
+}
+
+void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+}
+
+__initfunc(void sun4c_probe_vac(void))
+{
+       should_not_happen();
+}
+
+__initfunc(void sun4c_probe_memerr_reg(void))
+{
+       should_not_happen();
+}
index b16e3cc1e1b131a43f29c5f88ab3c97707580669..f9794125dcf84efae7181a5c106f6dabce8bbc1a 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: srmmu.c,v 1.156 1997/11/28 14:23:42 jj Exp $
+/* $Id: srmmu.c,v 1.170 1998/03/09 14:04:01 jj Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
  * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru)
  * Copyright (C) 1996 Eddie C. Dost    (ecd@skynet.be)
- * Copyright (C) 1997 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/config.h>
@@ -30,6 +30,7 @@
 #include <asm/a.out.h>
 #include <asm/mmu_context.h>
 #include <asm/io-unit.h>
+#include <asm/spinlock.h>
 
 /* Now the cpu specific definitions. */
 #include <asm/viking.h>
 #include <asm/swift.h>
 #include <asm/turbosparc.h>
 
+#include <asm/btfixup.h>
+
+/* #define DEBUG_MAP_KERNEL */
+/* #define PAGESKIP_DEBUG */
+
 enum mbus_module srmmu_modtype;
 unsigned int hwbug_bitmask;
 int vac_cache_size;
@@ -47,10 +53,6 @@ int vac_badbits;
 
 extern unsigned long sparc_iobase_vaddr;
 
-extern unsigned long sun4d_dma_base;
-extern unsigned long sun4d_dma_size;
-extern unsigned long sun4d_dma_vbase;
-
 #ifdef __SMP__
 #define FLUSH_BEGIN(mm)
 #define FLUSH_END
@@ -60,16 +62,24 @@ extern unsigned long sun4d_dma_vbase;
 #endif
 
 static int phys_mem_contig;
-long page_contig_offset;
+BTFIXUPDEF_SETHI(page_contig_offset)
+
+BTFIXUPDEF_CALL(void, ctxd_set, ctxd_t *, pgd_t *)
+BTFIXUPDEF_CALL(void, pmd_set, pmd_t *, pte_t *)
 
-static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp);
-static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep);
+#define ctxd_set(ctxp,pgdp) BTFIXUP_CALL(ctxd_set)(ctxp,pgdp)
+#define pmd_set(pmdp,ptep) BTFIXUP_CALL(pmd_set)(pmdp,ptep)
 
-void (*flush_page_for_dma)(unsigned long page);
+BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long)
+BTFIXUPDEF_CALL(void, flush_chunk, unsigned long)
+
+#define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page)
 int flush_page_for_dma_global = 1;
-static void (*flush_chunk)(unsigned long chunk);
+#define flush_chunk(chunk) BTFIXUP_CALL(flush_chunk)(chunk)
 #ifdef __SMP__
-static void (*local_flush_page_for_dma)(unsigned long page);
+BTFIXUPDEF_CALL(void, local_flush_page_for_dma, unsigned long)
+
+#define local_flush_page_for_dma(page) BTFIXUP_CALL(local_flush_page_for_dma)(page)
 #endif
 
 static struct srmmu_stats {
@@ -79,7 +89,7 @@ static struct srmmu_stats {
        int invmm;
 } module_stats;
 
-static char *srmmu_name;
+char *srmmu_name;
 
 ctxd_t *srmmu_ctx_table_phys;
 ctxd_t *srmmu_context_table;
@@ -96,8 +106,8 @@ static struct srmmu_trans {
 #define SRMMU_HASHSZ   256
 
 /* Not static, viking.S uses it. */
-struct srmmu_trans *srmmu_v2p_hash[SRMMU_HASHSZ];
-static struct srmmu_trans *srmmu_p2v_hash[SRMMU_HASHSZ];
+unsigned long srmmu_v2p_hash[SRMMU_HASHSZ];
+static unsigned long srmmu_p2v_hash[SRMMU_HASHSZ];
 
 #define srmmu_ahashfn(addr)    ((addr) >> 24)
 
@@ -111,20 +121,17 @@ int viking_mxcc_present = 0;
  */
 static inline unsigned long srmmu_v2p(unsigned long vaddr)
 {
-       struct srmmu_trans *tp = srmmu_v2p_hash[srmmu_ahashfn(vaddr)];
-
-       if(tp)
-               return (vaddr - tp->vbase + tp->pbase);
-       else
-               return 0xffffffffUL;
+       unsigned long off = srmmu_v2p_hash[srmmu_ahashfn(vaddr)];
+       
+       return (vaddr + off);
 }
 
 static inline unsigned long srmmu_p2v(unsigned long paddr)
 {
-       struct srmmu_trans *tp = srmmu_p2v_hash[srmmu_ahashfn(paddr)];
-
-       if(tp)
-               return (paddr - tp->pbase + tp->vbase);
+       unsigned long off = srmmu_p2v_hash[srmmu_ahashfn(paddr)];
+       
+       if (off != 0xffffffffUL)
+               return (paddr - off);
        else
                return 0xffffffffUL;
 }
@@ -132,16 +139,47 @@ static inline unsigned long srmmu_p2v(unsigned long paddr)
 /* Physical memory on most SS1000/SC2000 can be contiguous, so we handle that case
  * as a special case to make things faster.
  */
+/* FIXME: gcc is stupid here and generates very very bad code in this
+ * heavily used routine. So we help it a bit. */
 static inline unsigned long srmmu_c_v2p(unsigned long vaddr)
 {
+#if KERNBASE != 0xf0000000
        if (vaddr >= KERNBASE) return vaddr - KERNBASE;
-       return (vaddr - page_contig_offset);
+       return vaddr - BTFIXUP_SETHI(page_contig_offset);
+#else
+       register unsigned long kernbase;
+       
+       __asm__ ("sethi %%hi(0xf0000000), %0" : "=r"(kernbase));
+       return vaddr - ((vaddr >= kernbase) ? kernbase : BTFIXUP_SETHI(page_contig_offset));
+#endif
 }
 
 static inline unsigned long srmmu_c_p2v(unsigned long paddr)
 {
+#if KERNBASE != 0xf0000000
        if (paddr < (0xfd000000 - KERNBASE)) return paddr + KERNBASE;
-       return (paddr + page_contig_offset);
+       return (paddr + BTFIXUP_SETHI(page_contig_offset));
+#else
+       register unsigned long kernbase;
+       register unsigned long limit;
+       
+       __asm__ ("sethi %%hi(0x0d000000), %0" : "=r"(limit));
+       __asm__ ("sethi %%hi(0xf0000000), %0" : "=r"(kernbase));
+
+       return paddr + ((paddr < limit) ? kernbase : BTFIXUP_SETHI(page_contig_offset));
+#endif
+}
+
+/* On boxes where there is no lots_of_ram, KERNBASE is mapped to PA<0> and highest
+   PA is below 0x0d000000, we can optimize even more :) */
+static inline unsigned long srmmu_s_v2p(unsigned long vaddr)
+{
+       return vaddr - PAGE_OFFSET;
+}
+
+static inline unsigned long srmmu_s_p2v(unsigned long paddr)
+{
+       return paddr + PAGE_OFFSET;
 }
 
 /* In general all page table modifications should use the V8 atomic
@@ -157,19 +195,43 @@ static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value)
 /* Functions really use this, not srmmu_swap directly. */
 #define srmmu_set_entry(ptr, newentry) srmmu_swap((unsigned long *) (ptr), (newentry))
 
+#ifdef PAGESKIP_DEBUG
+#define PGSKIP_DEBUG(from,to) prom_printf("PG_skip %ld->%ld\n", (long)(from), (long)(to)); printk("PG_skip %ld->%ld\n", (long)(from), (long)(to))
+#else
+#define PGSKIP_DEBUG(from,to) do { } while (0)
+#endif
+
 __initfunc(void srmmu_frob_mem_map(unsigned long start_mem))
 {
-       unsigned long bank_start, bank_end;
+       unsigned long bank_start, bank_end = 0;
        unsigned long addr;
        int i;
 
        /* First, mark all pages as invalid. */
        for(addr = PAGE_OFFSET; MAP_NR(addr) < max_mapnr; addr += PAGE_SIZE)
                mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
+               
+       /* Next, pg[0-3] is sun4c cruft, so we can free it... */
+       mem_map[MAP_NR(pg0)].flags &= ~(1<<PG_reserved);
+       mem_map[MAP_NR(pg1)].flags &= ~(1<<PG_reserved);
+       mem_map[MAP_NR(pg2)].flags &= ~(1<<PG_reserved);
+       mem_map[MAP_NR(pg3)].flags &= ~(1<<PG_reserved);
 
        start_mem = PAGE_ALIGN(start_mem);
        for(i = 0; srmmu_map[i].size; i++) {
                bank_start = srmmu_map[i].vbase;
+               
+               if (i && bank_start - bank_end > 2 * PAGE_SIZE) {
+                       mem_map[MAP_NR(bank_end)].flags |= (1<<PG_skip);
+                       mem_map[MAP_NR(bank_end)].next_hash = mem_map + MAP_NR(bank_start);
+                       PGSKIP_DEBUG(MAP_NR(bank_end), MAP_NR(bank_start));
+                       if (bank_end > KERNBASE && bank_start < KERNBASE) {
+                               mem_map[0].flags |= (1<<PG_skip);
+                               mem_map[0].next_hash = mem_map + MAP_NR(bank_start);
+                               PGSKIP_DEBUG(0, MAP_NR(bank_start));
+                       }
+               }
+               
                bank_end = bank_start + srmmu_map[i].size;
                while(bank_start < bank_end) {
                        if((bank_start >= KERNBASE) &&
@@ -180,23 +242,28 @@ __initfunc(void srmmu_frob_mem_map(unsigned long start_mem))
                        mem_map[MAP_NR(bank_start)].flags &= ~(1<<PG_reserved);
                        bank_start += PAGE_SIZE;
                }
+               
+               if (bank_end == 0xfd000000)
+                       bank_end = PAGE_OFFSET;
        }
-       if (sparc_cpu_model == sun4d) {
-               for (addr = PAGE_OFFSET; MAP_NR(addr) < max_mapnr; addr += PAGE_SIZE)
-                       if (addr < sun4d_dma_vbase || addr >= sun4d_dma_vbase + sun4d_dma_size)
-                               clear_bit(PG_DMA, &mem_map[MAP_NR(addr)].flags);
+       
+       if (bank_end < KERNBASE) {
+               mem_map[MAP_NR(bank_end)].flags |= (1<<PG_skip);
+               mem_map[MAP_NR(bank_end)].next_hash = mem_map + MAP_NR(KERNBASE);
+               PGSKIP_DEBUG(MAP_NR(bank_end), MAP_NR(KERNBASE));
+       } else if (MAP_NR(bank_end) < max_mapnr) {
+               mem_map[MAP_NR(bank_end)].flags |= (1<<PG_skip);
+               if (mem_map[0].flags & (1 << PG_skip)) {
+                       mem_map[MAP_NR(bank_end)].next_hash = mem_map[0].next_hash;
+                       PGSKIP_DEBUG(MAP_NR(bank_end), mem_map[0].next_hash - mem_map);
+               } else {
+                       mem_map[MAP_NR(bank_end)].next_hash = mem_map;
+                       PGSKIP_DEBUG(MAP_NR(bank_end), 0);
+               }
        }
 }
 
 /* The very generic SRMMU page table operations. */
-static unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); }
-static unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); }
-
-static unsigned long srmmu_vmalloc_start(void)
-{
-       return SRMMU_VMALLOC_START;
-}
-
 static inline int srmmu_device_memory(unsigned long x) 
 {
        return ((x & 0xF0000000) != 0);
@@ -220,44 +287,53 @@ static unsigned long srmmu_c_pmd_page(pmd_t pmd)
 static unsigned long srmmu_c_pte_page(pte_t pte)
 { return srmmu_device_memory(pte_val(pte))?~0:srmmu_c_p2v((pte_val(pte) & SRMMU_PTE_PMASK) << 4); }
 
-static int srmmu_pte_none(pte_t pte)          
+static unsigned long srmmu_s_pgd_page(pgd_t pgd)
+{ return srmmu_device_memory(pgd_val(pgd))?~0:srmmu_s_p2v((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); }
+
+static unsigned long srmmu_s_pmd_page(pmd_t pmd)
+{ return srmmu_device_memory(pmd_val(pmd))?~0:srmmu_s_p2v((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); }
+
+static unsigned long srmmu_s_pte_page(pte_t pte)
+{ return srmmu_device_memory(pte_val(pte))?~0:srmmu_s_p2v((pte_val(pte) & SRMMU_PTE_PMASK) << 4); }
+
+static inline int srmmu_pte_none(pte_t pte)
 { return !(pte_val(pte) & 0xFFFFFFF); }
-static int srmmu_pte_present(pte_t pte)
+static inline int srmmu_pte_present(pte_t pte)
 { return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); }
 
-static void srmmu_pte_clear(pte_t *ptep)      { set_pte(ptep, __pte(0)); }
+static inline void srmmu_pte_clear(pte_t *ptep)      { set_pte(ptep, __pte(0)); }
 
-static int srmmu_pmd_none(pmd_t pmd)          
+static inline int srmmu_pmd_none(pmd_t pmd)
 { return !(pmd_val(pmd) & 0xFFFFFFF); }
-static int srmmu_pmd_bad(pmd_t pmd)
+static inline int srmmu_pmd_bad(pmd_t pmd)
 { return (pmd_val(pmd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }
 
-static int srmmu_pmd_present(pmd_t pmd)
+static inline int srmmu_pmd_present(pmd_t pmd)
 { return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
 
-static void srmmu_pmd_clear(pmd_t *pmdp)      { set_pte((pte_t *)pmdp, __pte(0)); }
+static inline void srmmu_pmd_clear(pmd_t *pmdp)      { set_pte((pte_t *)pmdp, __pte(0)); }
 
-static int srmmu_pgd_none(pgd_t pgd)          
+static inline int srmmu_pgd_none(pgd_t pgd)          
 { return !(pgd_val(pgd) & 0xFFFFFFF); }
 
-static int srmmu_pgd_bad(pgd_t pgd)
+static inline int srmmu_pgd_bad(pgd_t pgd)
 { return (pgd_val(pgd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }
 
-static int srmmu_pgd_present(pgd_t pgd)
+static inline int srmmu_pgd_present(pgd_t pgd)
 { return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
 
-static void srmmu_pgd_clear(pgd_t * pgdp)     { set_pte((pte_t *)pgdp, __pte(0)); }
+static inline void srmmu_pgd_clear(pgd_t * pgdp)     { set_pte((pte_t *)pgdp, __pte(0)); }
 
-static int srmmu_pte_write(pte_t pte)         { return pte_val(pte) & SRMMU_WRITE; }
-static int srmmu_pte_dirty(pte_t pte)         { return pte_val(pte) & SRMMU_DIRTY; }
-static int srmmu_pte_young(pte_t pte)         { return pte_val(pte) & SRMMU_REF; }
+static inline int srmmu_pte_write(pte_t pte)         { return pte_val(pte) & SRMMU_WRITE; }
+static inline int srmmu_pte_dirty(pte_t pte)         { return pte_val(pte) & SRMMU_DIRTY; }
+static inline int srmmu_pte_young(pte_t pte)         { return pte_val(pte) & SRMMU_REF; }
 
-static pte_t srmmu_pte_wrprotect(pte_t pte)   { return __pte(pte_val(pte) & ~SRMMU_WRITE);}
-static pte_t srmmu_pte_mkclean(pte_t pte)     { return __pte(pte_val(pte) & ~SRMMU_DIRTY);}
-static pte_t srmmu_pte_mkold(pte_t pte)       { return __pte(pte_val(pte) & ~SRMMU_REF);}
-static pte_t srmmu_pte_mkwrite(pte_t pte)     { return __pte(pte_val(pte) | SRMMU_WRITE);}
-static pte_t srmmu_pte_mkdirty(pte_t pte)     { return __pte(pte_val(pte) | SRMMU_DIRTY);}
-static pte_t srmmu_pte_mkyoung(pte_t pte)     { return __pte(pte_val(pte) | SRMMU_REF);}
+static inline pte_t srmmu_pte_wrprotect(pte_t pte)   { return __pte(pte_val(pte) & ~SRMMU_WRITE);}
+static inline pte_t srmmu_pte_mkclean(pte_t pte)     { return __pte(pte_val(pte) & ~SRMMU_DIRTY);}
+static inline pte_t srmmu_pte_mkold(pte_t pte)       { return __pte(pte_val(pte) & ~SRMMU_REF);}
+static inline pte_t srmmu_pte_mkwrite(pte_t pte)     { return __pte(pte_val(pte) | SRMMU_WRITE);}
+static inline pte_t srmmu_pte_mkdirty(pte_t pte)     { return __pte(pte_val(pte) | SRMMU_DIRTY);}
+static inline pte_t srmmu_pte_mkyoung(pte_t pte)     { return __pte(pte_val(pte) | SRMMU_REF);}
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -269,6 +345,9 @@ static pte_t srmmu_mk_pte(unsigned long page, pgprot_t pgprot)
 static pte_t srmmu_c_mk_pte(unsigned long page, pgprot_t pgprot)
 { return __pte(((srmmu_c_v2p(page)) >> 4) | pgprot_val(pgprot)); }
 
+static pte_t srmmu_s_mk_pte(unsigned long page, pgprot_t pgprot)
+{ return __pte(((srmmu_s_v2p(page)) >> 4) | pgprot_val(pgprot)); }
+
 static pte_t srmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot)
 { return __pte(((page) >> 4) | pgprot_val(pgprot)); }
 
@@ -307,41 +386,64 @@ static void srmmu_c_pmd_set(pmd_t * pmdp, pte_t * ptep)
        set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) ptep) >> 4)));
 }
 
-static pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot)
+static void srmmu_s_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
+{ 
+       set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (srmmu_s_v2p((unsigned long) pgdp) >> 4)));
+}
+
+static void srmmu_s_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{
+       set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (srmmu_s_v2p((unsigned long) pmdp) >> 4)));
+}
+
+static void srmmu_s_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+       set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_s_v2p((unsigned long) ptep) >> 4)));
+}
+
+static inline pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot)
 {
        return __pte((pte_val(pte) & SRMMU_CHG_MASK) | pgprot_val(newprot));
 }
 
 /* to find an entry in a top-level page table... */
-static pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
+static inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
 {
-       return mm->pgd + ((address >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1));
+       return mm->pgd + (address >> SRMMU_PGDIR_SHIFT);
 }
 
 /* Find an entry in the second-level page table.. */
-static pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address)
 {
        return (pmd_t *) srmmu_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
 }
 
 /* Find an entry in the third-level page table.. */ 
-static pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address)
+static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address)
 {
        return (pte_t *) srmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
 }
 
-/* Find an entry in the second-level page table.. */
-static pmd_t *srmmu_c_pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t *srmmu_c_pmd_offset(pgd_t * dir, unsigned long address)
 {
        return (pmd_t *) srmmu_c_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
 }
 
-/* Find an entry in the third-level page table.. */ 
-static pte_t *srmmu_c_pte_offset(pmd_t * dir, unsigned long address)
+static inline pte_t *srmmu_c_pte_offset(pmd_t * dir, unsigned long address)
 {
        return (pte_t *) srmmu_c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
 }
 
+static inline pmd_t *srmmu_s_pmd_offset(pgd_t * dir, unsigned long address)
+{
+       return (pmd_t *) srmmu_s_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
+}
+
+static inline pte_t *srmmu_s_pte_offset(pmd_t * dir, unsigned long address)
+{
+       return (pte_t *) srmmu_s_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+}
+
 /* This must update the context table entry for this process. */
 static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
 {
@@ -352,334 +454,146 @@ static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
        }
 }
 
-static inline void srmmu_putpage(unsigned long page)
-{
-       free_page(page);
-}
-
-#define LC_HIGH_WATER  128
-#define BC_HIGH_WATER  32
-
-static unsigned long *lcnks = 0;
-static unsigned long *bcnks = 0;
-static int lcwater = 0;
-static int bcwater = 0;
-static int chunk_pages = 0;
-static int clct_pages = 0;
-
-#define RELAX_JIFFIES  16
-
-static int lcjiffies;
-static int bcjiffies;
-
-struct chunk {
-       struct chunk *next;
-       struct chunk *prev;
-       struct chunk *npage;
-       struct chunk *ppage;
-       int count;
-};
-
-static int garbage_calls = 0;
-
-#define OTHER_PAGE(p,q)        (((unsigned long)(p) ^ (unsigned long)(q)) & PAGE_MASK)
-
-static int garbage_collect(unsigned long **cnks, int n, int cpp)
+static inline pte_t *srmmu_get_pte_fast(void)
 {
-       struct chunk *root = (struct chunk *)*cnks;
-       struct chunk *p, *q, *curr, *next;
-       int water = n;
-
-       next = root->next;
-       curr = root->prev = root->next = root->npage = root->ppage = root;
-       root->count = 1;
-
-       garbage_calls++;
-
-       while (--n) {
-               p = next;
-               next = next->next;
-
-               if (OTHER_PAGE(p, curr)) {
-
-                       q = curr->npage;
-                       while (q != curr) {
-                               if (!OTHER_PAGE(p, q))
-                                       break;
-                               q = q->npage;
-                       }
-
-                       if (q == curr) {
-
-                               (p->npage = curr->npage)->ppage = p;
-                               curr->npage = p;
-                               p->ppage = curr;
-
-                               p->next = p->prev = p;
-                               p->count = 1;
-
-                               curr = p;
-
-                               continue;
-                       }
-                       curr = q;
-               }
-
-               (p->next = curr->next)->prev = p;
-               curr->next = p;
-               p->prev = curr;
-
-               if (++curr->count == cpp) {
-
-                       q = curr->npage;
-                       if (curr == q) {
-
-                               srmmu_putpage((unsigned long)curr & PAGE_MASK);
-                               water -= cpp;
-
-                               clct_pages++;
-                               chunk_pages--;
-
-                               if (--n) {
-                                       p = next;
-                                       next = next->next;
-
-                                       curr = root->prev =
-                                               root->next = root->npage =
-                                               root->ppage = root = p;
-                                       root->count = 1;
-
-                                       continue;
-                               }
-                               return 0;
-                       }
-
-                       if (curr == root)
-                               root = q;
-
-                       curr->ppage->npage = q;
-                       q->ppage = curr->ppage;
-
-                       srmmu_putpage((unsigned long)curr & PAGE_MASK);
-                       water -= cpp;
-
-                       clct_pages++;
-                       chunk_pages--;
-
-                       curr = q;
-               }
-       }
-
-       p = root;
-       while (p->npage != root) {
-               p->prev->next = p->npage;
-               p = p->npage;
+       struct page *ret;
+       
+       spin_lock(&pte_spinlock);
+       if ((ret = (struct page *)pte_quicklist) != NULL) {
+               unsigned int mask = (unsigned int)ret->pprev_hash;
+               unsigned int tmp, off;
+               
+               if (mask & 0xff)
+                       for (tmp = 0x001, off = 0; (mask & tmp) == 0; tmp <<= 1, off += 256);
+               else
+                       for (tmp = 0x100, off = 2048; (mask & tmp) == 0; tmp <<= 1, off += 256);
+               (unsigned int)ret->pprev_hash = mask & ~tmp;
+               if (!(mask & ~tmp))
+                       pte_quicklist = (unsigned long *)ret->next_hash;
+               ret = (struct page *)(PAGE_OFFSET + (ret->map_nr << PAGE_SHIFT) + off);
+               pgtable_cache_size--;
        }
-
-       *cnks = (unsigned long *)root;
-       return water;
+       spin_unlock(&pte_spinlock);
+       return (pte_t *)ret;
 }
 
-static unsigned long *get_small_chunk(void)
+static inline pte_t *srmmu_get_pte_slow(void)
 {
-       unsigned long *rval;
-       unsigned long flags;
-
-       save_and_cli(flags);
-       if(lcwater) {
-               lcwater--;
-               rval = lcnks;
-               lcnks = (unsigned long *) *rval;
-       } else {
-               rval = (unsigned long *) __get_free_page(GFP_KERNEL);
-
-               if(!rval) {
-                       restore_flags(flags);
-                       return 0;
-               }
-               chunk_pages++;
-
-               lcnks = (rval + 64);
-
-               /* Cache stomping, I know... */
-               *(rval + 64) = (unsigned long) (rval + 128);
-               *(rval + 128) = (unsigned long) (rval + 192);
-               *(rval + 192) = (unsigned long) (rval + 256);
-               *(rval + 256) = (unsigned long) (rval + 320);
-               *(rval + 320) = (unsigned long) (rval + 384);
-               *(rval + 384) = (unsigned long) (rval + 448);
-               *(rval + 448) = (unsigned long) (rval + 512);
-               *(rval + 512) = (unsigned long) (rval + 576);
-               *(rval + 576) = (unsigned long) (rval + 640);
-               *(rval + 640) = (unsigned long) (rval + 704);
-               *(rval + 704) = (unsigned long) (rval + 768);
-               *(rval + 768) = (unsigned long) (rval + 832);
-               *(rval + 832) = (unsigned long) (rval + 896);
-               *(rval + 896) = (unsigned long) (rval + 960);
-               *(rval + 960) = 0;
-               lcwater = 15;
+       pte_t *ret;
+       struct page *page;
+       
+       ret = (pte_t *)get_free_page(GFP_KERNEL);
+       if (ret) {
+               page = mem_map + MAP_NR(ret);
+               flush_chunk((unsigned long)ret);
+               (unsigned int)page->pprev_hash = 0xfffe;
+               spin_lock(&pte_spinlock);
+               (unsigned long *)page->next_hash = pte_quicklist;
+               pte_quicklist = (unsigned long *)page;
+               pgtable_cache_size += 15;
        }
-       lcjiffies = jiffies;
-       restore_flags(flags);
-       memset(rval, 0, 256);
-       flush_chunk((unsigned long)rval);
-       return rval;
-}
-
-static inline void free_small_chunk(unsigned long *it)
-{
-       unsigned long flags;
-
-       save_and_cli(flags);
-       *it = (unsigned long) lcnks;
-       lcnks = it;
-       lcwater++;
-
-       if ((lcwater > LC_HIGH_WATER) &&
-           (jiffies > lcjiffies + RELAX_JIFFIES))
-               lcwater = garbage_collect(&lcnks, lcwater, 16);
-
-       restore_flags(flags);
+       return ret;
 }
 
-static unsigned long *get_big_chunk(void)
+static inline pgd_t *srmmu_get_pgd_fast(void)
 {
-       unsigned long *rval;
-       unsigned long flags;
-
-       save_and_cli(flags);
-       if(bcwater) {
-               bcwater--;
-               rval = bcnks;
-               bcnks = (unsigned long *) *rval;
-       } else {
-               rval = (unsigned long *) __get_free_page(GFP_KERNEL);
-
-               if(!rval) {
-                       restore_flags(flags);
-                       return 0;
-               }
-               chunk_pages++;
-
-               bcnks = (rval + 256);
+       struct page *ret;
 
-               /* Cache stomping, I know... */
-               *(rval + 256) = (unsigned long) (rval + 512);
-               *(rval + 512) = (unsigned long) (rval + 768);
-               *(rval + 768) = 0;
-               bcwater = 3;
+       spin_lock(&pgd_spinlock);       
+       if ((ret = (struct page *)pgd_quicklist) != NULL) {
+               unsigned int mask = (unsigned int)ret->pprev_hash;
+               unsigned int tmp, off;
+               
+               for (tmp = 0x001, off = 0; (mask & tmp) == 0; tmp <<= 1, off += 1024);
+               (unsigned int)ret->pprev_hash = mask & ~tmp;
+               if (!(mask & ~tmp))
+                       pgd_quicklist = (unsigned long *)ret->next_hash;
+               ret = (struct page *)(PAGE_OFFSET + (ret->map_nr << PAGE_SHIFT) + off);
+               pgd_cache_size--;
        }
-       bcjiffies = jiffies;
-       restore_flags(flags);
-       memset(rval, 0, 1024);
-       flush_chunk((unsigned long)rval);
-       return rval;
+       spin_unlock(&pgd_spinlock);
+       return (pte_t *)ret;
 }
 
-static inline void free_big_chunk(unsigned long *it)
+static inline pgd_t *srmmu_get_pgd_slow(void)
 {
-       unsigned long flags;
-
-       save_and_cli(flags);
-       *it = (unsigned long) bcnks;
-       bcnks = it;
-       bcwater++;
-
-       if ((bcwater > BC_HIGH_WATER) &&
-           (jiffies > bcjiffies + RELAX_JIFFIES))
-               bcwater = garbage_collect(&bcnks, bcwater, 4);
-
-       restore_flags(flags);
+       pgd_t *ret;
+       struct page *page;
+       
+       ret = (pgd_t *)__get_free_page(GFP_KERNEL);
+       if (ret) {
+               pgd_t *init = pgd_offset(&init_mm, 0);
+               memset(ret + (0 * PTRS_PER_PGD), 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+               memcpy(ret + (0 * PTRS_PER_PGD) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                                               (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+               memset(ret + (1 * PTRS_PER_PGD), 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+               memcpy(ret + (1 * PTRS_PER_PGD) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                                               (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+               memset(ret + (2 * PTRS_PER_PGD), 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+               memcpy(ret + (2 * PTRS_PER_PGD) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                                               (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+               memset(ret + (3 * PTRS_PER_PGD), 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+               memcpy(ret + (3 * PTRS_PER_PGD) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                                               (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+               page = mem_map + MAP_NR(ret);
+               flush_chunk((unsigned long)ret);
+               (unsigned int)page->pprev_hash = 0xe;
+               spin_lock(&pgd_spinlock);
+               (unsigned long *)page->next_hash = pgd_quicklist;
+               pgd_quicklist = (unsigned long *)page;
+               pgd_cache_size += 3;
+               spin_unlock(&pgd_spinlock);
+       }
+       return ret;
 }
 
-#define NEW_PGD() (pgd_t *) get_big_chunk()
-#define NEW_PMD() (pmd_t *) get_small_chunk()
-#define NEW_PTE() (pte_t *) get_small_chunk()
-#define FREE_PGD(chunk) free_big_chunk((unsigned long *)(chunk))
-#define FREE_PMD(chunk) free_small_chunk((unsigned long *)(chunk))
-#define FREE_PTE(chunk) free_small_chunk((unsigned long *)(chunk))
-
-/*
- * 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.
- */
-static void srmmu_pte_free_kernel(pte_t *pte)
+static void srmmu_free_pte_slow(pte_t *pte)
 {
-       FREE_PTE(pte);
 }
 
-static pte_t *srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+static void srmmu_free_pgd_slow(pgd_t *pgd)
 {
-       address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
-       if(srmmu_pmd_none(*pmd)) {
-               pte_t *page = NEW_PTE();
-               if(srmmu_pmd_none(*pmd)) {
-                       if(page) {
-                               pmd_set(pmd, page);
-                               return page + address;
-                       }
-                       pmd_set(pmd, BAD_PAGETABLE);
-                       return NULL;
-               }
-               FREE_PTE(page);
-       }
-       if(srmmu_pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_set(pmd, BAD_PAGETABLE);
-               return NULL;
-       }
-       return (pte_t *) pmd_page(*pmd) + address;
 }
 
-static void srmmu_pmd_free_kernel(pmd_t *pmd)
+static inline void srmmu_pte_free(pte_t *pte)
 {
-       FREE_PMD(pmd);
-}
+       struct page *page = mem_map + MAP_NR(pte);
 
-static pmd_t *srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
-{
-       address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
-       if(srmmu_pgd_none(*pgd)) {
-               pmd_t *page;
-               page = NEW_PMD();
-               if(srmmu_pgd_none(*pgd)) {
-                       if(page) {
-                               pgd_set(pgd, page);
-                               return page + address;
-                       }
-                       pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
-                       return NULL;
-               }
-               FREE_PMD(page);
+       spin_lock(&pte_spinlock);       
+       if (!page->pprev_hash) {
+               (unsigned long *)page->next_hash = pte_quicklist;
+               pte_quicklist = (unsigned long *)page;
        }
-       if(srmmu_pgd_bad(*pgd)) {
-               printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-               pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
-               return NULL;
-       }
-       return (pmd_t *) pgd_page(*pgd) + address;
-}
-
-static void srmmu_pte_free(pte_t *pte)
-{
-       FREE_PTE(pte);
+       (unsigned int)page->pprev_hash |= (1 << ((((unsigned long)pte) >> 8) & 15));
+       pgtable_cache_size++;
+       spin_unlock(&pte_spinlock);
 }
 
 static pte_t *srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
 {
        address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
        if(srmmu_pmd_none(*pmd)) {
-               pte_t *page = NEW_PTE();
+               pte_t *page = srmmu_get_pte_fast();
+               
+               if (page) {
+                       pmd_set(pmd, page);
+                       return page + address;
+               }
+               page = srmmu_get_pte_slow();
                if(srmmu_pmd_none(*pmd)) {
                        if(page) {
+                               spin_unlock(&pte_spinlock);
                                pmd_set(pmd, page);
                                return page + address;
                        }
                        pmd_set(pmd, BAD_PAGETABLE);
                        return NULL;
                }
-               FREE_PTE(page);
+               if (page) {
+                       (unsigned int)(((struct page *)pte_quicklist)->pprev_hash) = 0xffff;
+                       pgtable_cache_size++;
+                       spin_unlock(&pte_spinlock);
+               }
        }
        if(srmmu_pmd_bad(*pmd)) {
                printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
@@ -692,23 +606,34 @@ static pte_t *srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
 /* Real three-level page tables on SRMMU. */
 static void srmmu_pmd_free(pmd_t * pmd)
 {
-       FREE_PMD(pmd);
+       return srmmu_pte_free((pte_t *)pmd);
 }
 
 static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
 {
        address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
        if(srmmu_pgd_none(*pgd)) {
-               pmd_t *page = NEW_PMD();
+               pmd_t *page = (pmd_t *)srmmu_get_pte_fast();
+               
+               if (page) {
+                       pgd_set(pgd, page);
+                       return page + address;
+               }
+               page = (pmd_t *)srmmu_get_pte_slow();
                if(srmmu_pgd_none(*pgd)) {
                        if(page) {
+                               spin_unlock(&pte_spinlock);
                                pgd_set(pgd, page);
                                return page + address;
                        }
                        pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
                        return NULL;
                }
-               FREE_PMD(page);
+               if (page) {
+                       (unsigned int)(((struct page *)pte_quicklist)->pprev_hash) = 0xffff;
+                       pgtable_cache_size++;
+                       spin_unlock(&pte_spinlock);
+               }
        }
        if(srmmu_pgd_bad(*pgd)) {
                printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
@@ -720,12 +645,58 @@ static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
 
 static void srmmu_pgd_free(pgd_t *pgd)
 {
-       FREE_PGD(pgd);
+       struct page *page = mem_map + MAP_NR(pgd);
+
+       spin_lock(&pgd_spinlock);
+       if (!page->pprev_hash) {
+               (unsigned long *)page->next_hash = pgd_quicklist;
+               pgd_quicklist = (unsigned long *)page;
+       }
+       (unsigned int)page->pprev_hash |= (1 << ((((unsigned long)pgd) >> 10) & 3));
+       pgd_cache_size++;
+       spin_unlock(&pgd_spinlock);
 }
 
 static pgd_t *srmmu_pgd_alloc(void)
 {
-       return NEW_PGD();
+       pgd_t *ret;
+       
+       ret = srmmu_get_pgd_fast();
+       if (ret) return ret;
+       return srmmu_get_pgd_slow();
+}
+
+
+static void srmmu_set_pgdir(unsigned long address, pgd_t entry)
+{
+       struct task_struct * p;
+       struct page *page;
+
+       read_lock(&tasklist_lock);
+       for_each_task(p) {
+               if (!p->mm)
+                       continue;
+               *pgd_offset(p->mm,address) = entry;
+       }
+       read_unlock(&tasklist_lock);
+       spin_lock(&pgd_spinlock);
+       address >>= SRMMU_PGDIR_SHIFT;
+       for (page = (struct page *)pgd_quicklist; page; page = page->next_hash) {
+               pgd_t *pgd = (pgd_t *)(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+               unsigned int mask = (unsigned int)page->pprev_hash;
+               
+               if (mask & 1)
+                       pgd[address + 0 * SRMMU_PTRS_PER_PGD] = entry;
+               if (mask & 2)
+                       pgd[address + 1 * SRMMU_PTRS_PER_PGD] = entry;
+               if (mask & 4)
+                       pgd[address + 2 * SRMMU_PTRS_PER_PGD] = entry;
+               if (mask & 8)
+                       pgd[address + 3 * SRMMU_PTRS_PER_PGD] = entry;
+               if (mask)
+                       flush_chunk((unsigned long)pgd);
+       }
+       spin_unlock(&pgd_spinlock);
 }
 
 static void srmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval)
@@ -926,6 +897,19 @@ extern void tsunami_flush_tlb_mm(struct mm_struct *mm);
 extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
 extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
+/* Workaround, until we find what's going on with Swift. When low on memory, it sometimes
+ * loops in fault/handle_mm_fault incl. flush_tlb_page to find out it is already in page tables/
+ * fault again on the same instruction. I really don't understand it, have checked it and contexts
+ * are right, flush_tlb_all is done as well, and it faults again... Strange. -jj
+ */
+static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
+{
+       static unsigned long last;
+
+       if (last == address) viking_hwprobe(address);
+       last = address;
+}
+
 /* Swift flushes.  It has the recommended SRMMU specification flushing
  * facilities, so we can do things in a more fine grained fashion than we
  * could on the tsunami.  Let's watch out for HARDWARE BUGS...
@@ -1191,12 +1175,10 @@ static void cypress_flush_chunk(unsigned long chunk)
        cypress_flush_page_to_ram(chunk);
 }
 
-#if NOTUSED
 /* Cypress is also IO cache coherent. */
 static void cypress_flush_page_for_dma(unsigned long page)
 {
 }
-#endif
 
 /* Cypress has unified L2 VIPT, from which both instructions and data
  * are stored.  It does not have an onboard icache of any sort, therefore
@@ -1282,9 +1264,8 @@ extern void viking_flush_sig_insns(struct mm_struct *mm, unsigned long addr);
 extern void viking_flush_page(unsigned long page);
 extern void viking_mxcc_flush_page(unsigned long page);
 extern void viking_flush_chunk(unsigned long chunk);
-extern void viking_c_flush_page(unsigned long page);
-extern void viking_c_mxcc_flush_page(unsigned long page);
 extern void viking_c_flush_chunk(unsigned long chunk);
+extern void viking_s_flush_chunk(unsigned long chunk);
 extern void viking_mxcc_flush_chunk(unsigned long chunk);
 extern void viking_flush_tlb_all(void);
 extern void viking_flush_tlb_mm(struct mm_struct *mm);
@@ -1481,7 +1462,7 @@ static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned
  * looking at the prom's page table directly which is what most
  * other OS's do.  Yuck... this is much better.
  */
-void srmmu_inherit_prom_mappings(unsigned long start,unsigned long end)
+__initfunc(void srmmu_inherit_prom_mappings(unsigned long start,unsigned long end))
 {
        pgd_t *pgdp;
        pmd_t *pmdp;
@@ -1539,21 +1520,79 @@ void srmmu_inherit_prom_mappings(unsigned long start,unsigned long end)
        }
 }
 
-/* #define DEBUG_MAP_KERNEL */
-
 #ifdef DEBUG_MAP_KERNEL
 #define MKTRACE(foo) prom_printf foo
 #else
 #define MKTRACE(foo)
 #endif
 
-static int lots_of_ram = 0;
-static int large_pte_optimize = 1;
+static int lots_of_ram __initdata = 0;
+static int srmmu_low_pa __initdata = 0;
+static unsigned long end_of_phys_memory __initdata = 0;
+
+__initfunc(void srmmu_end_memory(unsigned long memory_size, unsigned long *end_mem_p))
+{
+       unsigned int sum = 0;
+       unsigned long last = 0xff000000;
+       long first, cur;
+       unsigned long pa;
+       unsigned long total = 0;
+       int i;
+
+       pa = srmmu_hwprobe(KERNBASE + PAGE_SIZE);
+       pa = (pa & SRMMU_PTE_PMASK) << 4;
+       if (!sp_banks[0].base_addr && pa == PAGE_SIZE) {
+               for(i = 0; sp_banks[i].num_bytes != 0; i++) {
+                       if (sp_banks[i].base_addr + sp_banks[i].num_bytes > 0x0d000000)
+                               break;
+               }
+               if (!sp_banks[i].num_bytes) {
+                       srmmu_low_pa = 1;
+                       end_of_phys_memory = SRMMU_PGDIR_ALIGN(sp_banks[i-1].base_addr + sp_banks[i-1].num_bytes);
+                       *end_mem_p = KERNBASE + end_of_phys_memory;
+                       if (sp_banks[0].num_bytes >= (6 * 1024 * 1024) || end_of_phys_memory <= 0x06000000) {
+                               /* Make sure there will be enough memory for the whole mem_map (even if sparse) */
+                               return;
+                       }
+               }
+       }
+       for(i = 0; sp_banks[i].num_bytes != 0; i++) {
+               pa = sp_banks[i].base_addr;
+               first = (pa & (~SRMMU_PGDIR_MASK));
+               cur = (sp_banks[i].num_bytes + first - SRMMU_PGDIR_SIZE);
+               if (cur < 0) cur = 0;
+               if (!first || last != (pa & SRMMU_PGDIR_MASK))
+                       total += SRMMU_PGDIR_SIZE;
+               sum += sp_banks[i].num_bytes;
+               if (memory_size) {
+                       if (sum > memory_size) {
+                               sp_banks[i].num_bytes -=
+                                       (sum - memory_size);
+                               cur = (sp_banks[i].num_bytes + first - SRMMU_PGDIR_SIZE);
+                               if (cur < 0) cur = 0;
+                               total += SRMMU_PGDIR_ALIGN(cur);
+                               sum = memory_size;
+                               sp_banks[++i].base_addr = 0xdeadbeef;
+                               sp_banks[i].num_bytes = 0;
+                               break;
+                       }
+               }
+               total += SRMMU_PGDIR_ALIGN(cur);
+               last = (sp_banks[i].base_addr + sp_banks[i].num_bytes - 1) & SRMMU_PGDIR_MASK;
+       }
+       if (total <= 0x0d000000)
+               *end_mem_p = KERNBASE + total;
+       else {
+               *end_mem_p = 0xfd000000;
+               lots_of_ram = 1;
+       }
+       end_of_phys_memory = total;
+}
 
 #define KERNEL_PTE(page_shifted) ((page_shifted)|SRMMU_CACHE|SRMMU_PRIV|SRMMU_VALID)
 
 /* Create a third-level SRMMU 16MB page mapping. */
-static inline void do_large_mapping(unsigned long vaddr, unsigned long phys_base)
+__initfunc(static void do_large_mapping(unsigned long vaddr, unsigned long phys_base))
 {
        pgd_t *pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
        unsigned long big_pte;
@@ -1563,47 +1602,6 @@ static inline void do_large_mapping(unsigned long vaddr, unsigned long phys_base
        *pgdp = __pgd(big_pte);
 }
 
-/* Create second-level SRMMU 256K medium sized page mappings. */
-static inline void do_medium_mapping(unsigned long vaddr, unsigned long vend,
-                                    unsigned long phys_base)
-{
-       pgd_t *pgdp;
-       pmd_t *pmdp;
-       unsigned long medium_pte;
-
-       MKTRACE(("dmm[v<%08lx,%08lx>-->p<%08lx>]", vaddr, vend, phys_base));
-       while(vaddr < vend) {
-               pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
-               pmdp = srmmu_early_pmd_offset(pgdp, vaddr);
-               medium_pte = KERNEL_PTE(phys_base >> 4);
-               *pmdp = __pmd(medium_pte);
-               phys_base += SRMMU_PMD_SIZE;
-               vaddr += SRMMU_PMD_SIZE;
-       }
-}
-
-/* Create a normal set of SRMMU page mappings for the virtual range
- * START to END, using physical pages beginning at PHYS_BASE.
- */
-static inline void do_small_mapping(unsigned long start, unsigned long end,
-                                    unsigned long phys_base)
-{
-       pgd_t *pgdp;
-       pmd_t *pmdp;
-       pte_t *ptep;
-
-       MKTRACE(("dsm[v<%08lx,%08lx>-->p<%08lx>]", start, end, phys_base));
-       while(start < end) {
-               pgdp = srmmu_pgd_offset(init_task.mm, start);
-               pmdp = srmmu_early_pmd_offset(pgdp, start);
-               ptep = srmmu_early_pte_offset(pmdp, start);
-
-               *ptep = __pte(KERNEL_PTE(phys_base >> 4));
-               phys_base += PAGE_SIZE;
-               start += PAGE_SIZE;
-       }
-}
-
 /* Look in the sp_bank for the given physical page, return the
  * index number the entry was found in, or -1 for not found.
  */
@@ -1625,7 +1623,7 @@ static inline int find_in_spbanks(unsigned long phys_page)
  * array of char's, each member indicating if that spbank is mapped
  * yet or not.
  */
-static inline int find_free_spbank(char *taken_vector)
+__initfunc(static int find_free_spbank(char *taken_vector))
 {
        int entry;
 
@@ -1635,78 +1633,28 @@ static inline int find_free_spbank(char *taken_vector)
        return entry;
 }
 
-/* Same as above, but with a given bank size limit BLIMIT. */
-static inline int find_free_spbank_limited(char *taken_vector, unsigned long limit)
-{
-       int entry;
-
-       for(entry = 0; sp_banks[entry].num_bytes; entry++)
-               if(!taken_vector[entry] &&
-                  (sp_banks[entry].num_bytes < limit))
-                       break;
-       return entry;
-}
+static unsigned long map_spbank_last_pa __initdata = 0xff000000;
 
 /* Map sp_bank entry SP_ENTRY, starting at virtual address VBASE.
- * This routine is expected to update the srmmu_map and try as
- * hard as possible to use 16MB level-one SRMMU pte's when at all
- * possible to get short termination and faster translations.
  */
-static inline unsigned long map_spbank(unsigned long vbase, int sp_entry)
+__initfunc(static unsigned long map_spbank(unsigned long vbase, int sp_entry))
 {
-       unsigned long pstart = sp_banks[sp_entry].base_addr;
-       unsigned long vstart = vbase;
-       unsigned long vend = vbase + sp_banks[sp_entry].num_bytes;
+       unsigned long pstart = (sp_banks[sp_entry].base_addr & SRMMU_PGDIR_MASK);
+       unsigned long vstart = (vbase & SRMMU_PGDIR_MASK);
+       unsigned long vend = SRMMU_PGDIR_ALIGN(vbase + sp_banks[sp_entry].num_bytes);
        static int srmmu_bank = 0;
 
-       /* If physically not aligned on 16MB boundry, just shortcut
-        * right here by mapping them with 4k normal pages, and bumping
-        * the next virtual address to the next 16MB boundry.  You can
-        * get this with various RAM configurations due to the way in
-        * which the PROM carves out it's own chunks of memory.
-        */
-       if(pstart & ~SRMMU_PGDIR_MASK) {
-               do_small_mapping(vstart, vend, pstart);
-               vstart = SRMMU_PGDIR_ALIGN(vend);
-               goto finish_up;
-       }
+       MKTRACE(("map_spbank %d[v<%08lx>p<%08lx>s<%08lx>]", sp_entry, vbase, sp_banks[sp_entry].base_addr, sp_banks[sp_entry].num_bytes));
+       MKTRACE(("map_spbank2 %d[p%08lx v%08lx-%08lx]", sp_entry, pstart, vstart, vend));
        while(vstart < vend) {
-               unsigned long coverage, next_aligned;
-               if(vstart & ~SRMMU_PMD_MASK) {
-                       next_aligned = SRMMU_PMD_ALIGN(vstart);
-                       if(next_aligned <= vend) {
-                               coverage = (next_aligned - vstart);
-                               do_small_mapping(vstart, next_aligned, pstart);
-                       } else {
-                               coverage = (vend - vstart);
-                               do_small_mapping(vstart, vend, pstart);
-                       }
-               } else if(vstart & ~SRMMU_PGDIR_MASK) {
-                       next_aligned = SRMMU_PGDIR_ALIGN(vstart);
-                       if(next_aligned <= vend) {
-                               coverage = (next_aligned - vstart);
-                               do_medium_mapping(vstart, next_aligned, pstart);
-                       } else {
-                               coverage = (vend - vstart);
-                               do_small_mapping(vstart, vend, pstart);
-                       }
-               } else {
-                       coverage = SRMMU_PGDIR_SIZE;
-                       if(large_pte_optimize || ((vstart+coverage)<=vend)) {
-                               do_large_mapping(vstart, pstart);
-                       } else {
-                               coverage = (vend - vstart);
-                               do_small_mapping(vstart, vend, pstart);
-                       }
-               }
-               vstart += coverage; pstart += coverage;
+               do_large_mapping(vstart, pstart);
+               vstart += SRMMU_PGDIR_SIZE; pstart += SRMMU_PGDIR_SIZE;
        }
-finish_up:
        srmmu_map[srmmu_bank].vbase = vbase;
        srmmu_map[srmmu_bank].pbase = sp_banks[sp_entry].base_addr;
        srmmu_map[srmmu_bank].size = sp_banks[sp_entry].num_bytes;
-       MKTRACE(("SRMMUBANK[v<%08lx>p<%08lx>s<%08lx>]", vbase, sp_banks[sp_entry].base_addr, sp_banks[sp_entry].num_bytes));
        srmmu_bank++;
+       map_spbank_last_pa = pstart - SRMMU_PGDIR_SIZE;
        return vstart;
 }
 
@@ -1721,10 +1669,10 @@ static inline void memprobe_error(char *msg)
  * is part of a full bank which is at least 4MB in size and begins at
  * 0xf0000000 (ie. KERNBASE).
  */
-static void map_kernel(void)
+static inline void map_kernel(void)
 {
        unsigned long raw_pte, physpage;
-       unsigned long vaddr, tally, low_base;
+       unsigned long vaddr, low_base;
        char etaken[SPARC_PHYS_BANKS];
        int entry;
 
@@ -1735,17 +1683,7 @@ static void map_kernel(void)
 
        low_base = KERNBASE;
 
-       /* Step 2: Calculate 'lots_of_ram'. */
-       tally = 0;
-       for(entry = 0; sp_banks[entry].num_bytes; entry++)
-               tally += sp_banks[entry].num_bytes;
-       if(tally > (0xfd000000 - KERNBASE))
-               lots_of_ram = 1;
-       else
-               lots_of_ram = 0;
-       MKTRACE(("tally=%08lx lots_of_ram<%d>\n", tally, lots_of_ram));
-
-       /* Step 3: Fill in KERNBASE base pgd.  Lots of sanity checking here. */
+       /* Step 2: Fill in KERNBASE base pgd.  Lots of sanity checking here. */
        raw_pte = srmmu_hwprobe(KERNBASE + PAGE_SIZE);
        if((raw_pte & SRMMU_ET_MASK) != SRMMU_ET_PTE)
                memprobe_error("Wheee, kernel not mapped at all by boot loader.\n");
@@ -1757,11 +1695,10 @@ static void map_kernel(void)
        if(entry == -1 || (sp_banks[entry].base_addr != physpage))
                memprobe_error("Kernel mapped in non-existant memory.\n");
        MKTRACE(("map_kernel: map_spbank(vbase=%08x, entry<%d>)[%08lx,%08lx]\n", KERNBASE, entry, sp_banks[entry].base_addr, sp_banks[entry].num_bytes));
-       if(((KERNBASE + (sp_banks[entry].num_bytes)) > 0xfd000000) ||
-          ((KERNBASE + (sp_banks[entry].num_bytes)) < KERNBASE)) {
+       if (sp_banks[entry].num_bytes > 0x0d000000) {
                unsigned long orig_base = sp_banks[entry].base_addr;
                unsigned long orig_len = sp_banks[entry].num_bytes;
-               unsigned long can_map = (0xfd000000 - KERNBASE);
+               unsigned long can_map = 0x0d000000;
                
                /* Map a partial bank in this case, adjust the base
                 * and the length, but don't mark it used.
@@ -1779,7 +1716,7 @@ static void map_kernel(void)
        vaddr = map_spbank(KERNBASE, entry);
        etaken[entry] = 1;
 
-       /* Step 4: Map what we can above KERNBASE. */
+       /* Step 3: Map what we can above KERNBASE. */
        MKTRACE(("map_kernel: vaddr=%08lx, entering first loop\n", vaddr));
        for(;;) {
                unsigned long bank_size;
@@ -1790,8 +1727,14 @@ static void map_kernel(void)
                MKTRACE(("<%d> base=%08lx bs=%08lx ", entry, sp_banks[entry].base_addr, bank_size));
                if(!bank_size)
                        break;
-               if(((vaddr + bank_size) > 0xfd000000) ||
-                  ((vaddr + bank_size) < KERNBASE)) {
+               if (srmmu_low_pa)
+                       vaddr = KERNBASE + sp_banks[entry].base_addr;
+               else if (sp_banks[entry].base_addr & (~SRMMU_PGDIR_MASK)) {
+                       if (map_spbank_last_pa == (sp_banks[entry].base_addr & SRMMU_PGDIR_MASK))
+                               vaddr -= SRMMU_PGDIR_SIZE;
+                       vaddr += (sp_banks[entry].base_addr & (~SRMMU_PGDIR_MASK));
+               }
+               if ((vaddr + bank_size - KERNBASE) > 0x0d000000) {
                        unsigned long orig_base = sp_banks[entry].base_addr;
                        unsigned long orig_len = sp_banks[entry].num_bytes;
                        unsigned long can_map = (0xfd000000 - vaddr);
@@ -1808,8 +1751,6 @@ static void map_kernel(void)
                        MKTRACE(("adjust[%08lx,%08lx]\n", (orig_base + can_map), (orig_len - can_map)));
                        break;
                }
-               if(!bank_size)
-                       break;
 
                /* Ok, we can map this one, do it. */
                MKTRACE(("map_spbank(%08lx,entry<%d>) ", vaddr, entry));
@@ -1823,22 +1764,16 @@ loop_skip:
        if(!lots_of_ram)
                goto check_and_return;
        
-       /* Step 5: Map the rest (if any) right below KERNBASE. */
+       /* Step 4: Map the rest (if any) right below KERNBASE. */
        MKTRACE(("map_kernel: doing low mappings... "));
-       tally = 0;
-       for(entry = 0; sp_banks[entry].num_bytes; entry++) {
-               if(!etaken[entry])
-                       tally += SRMMU_PGDIR_ALIGN(sp_banks[entry].num_bytes);
-       }
-       if(!tally)
-               memprobe_error("Whee, lots_of_ram yet no low pages to map.\n");
-       low_base = (KERNBASE - tally);
-       MKTRACE(("tally=%08lx low_base=%08lx\n", tally, low_base));
+       low_base = (KERNBASE - end_of_phys_memory + 0x0d000000);
+       MKTRACE(("end_of_phys_memory=%08lx low_base=%08lx\n", end_of_phys_memory, low_base));
 
        /* Ok, now map 'em. */
        MKTRACE(("map_kernel: Allocate pt skeleton (%08lx, %08x)\n",low_base,KERNBASE));
        srmmu_allocate_ptable_skeleton(low_base, KERNBASE);
        vaddr = low_base;
+       map_spbank_last_pa = 0xff000000;
        MKTRACE(("map_kernel: vaddr=%08lx Entering second loop for low maps.\n", vaddr));
        for(;;) {
                unsigned long bank_size;
@@ -1848,19 +1783,22 @@ loop_skip:
                MKTRACE(("map_kernel: e<%d> base=%08lx bs=%08lx ", entry, sp_banks[entry].base_addr, bank_size));
                if(!bank_size)
                        break;
+               if (sp_banks[entry].base_addr & (~SRMMU_PGDIR_MASK)) {
+                       if (map_spbank_last_pa == (sp_banks[entry].base_addr & SRMMU_PGDIR_MASK))
+                               vaddr -= SRMMU_PGDIR_SIZE;
+                       vaddr += (sp_banks[entry].base_addr & (~SRMMU_PGDIR_MASK));
+               }
                if((vaddr + bank_size) > KERNBASE)
                        memprobe_error("Wheee, kernel low mapping overflow.\n");
                MKTRACE(("map_spbank(%08lx, %d) ", vaddr, entry));
                vaddr = map_spbank(vaddr, entry);
                etaken[entry] = 1;
-               tally -= SRMMU_PGDIR_ALIGN(bank_size);
-               MKTRACE(("Now, vaddr=%08lx tally=%08lx\n", vaddr, tally));
+               MKTRACE(("Now, vaddr=%08lx end_of_phys_memory=%08lx\n", vaddr, end_of_phys_memory));
        }
        MKTRACE(("\n"));
-       if(tally)
-               memprobe_error("Wheee, did not map all of low mappings.\n");
+
 check_and_return:
-       /* Step 6: Sanity check, make sure we did it all. */
+       /* Step 5: Sanity check, make sure we did it all. */
        MKTRACE(("check_and_return: "));
        for(entry = 0; sp_banks[entry].num_bytes; entry++) {
                MKTRACE(("e[%d]=%d ", entry, etaken[entry]));
@@ -1872,6 +1810,10 @@ check_and_return:
        MKTRACE(("success\n"));
        init_task.mm->mmap->vm_start = page_offset = low_base;
        stack_top = page_offset - PAGE_SIZE;
+       BTFIXUPSET_SETHI(page_offset, low_base);
+       BTFIXUPSET_SETHI(stack_top, page_offset - PAGE_SIZE);
+       BTFIXUPSET_SIMM13(user_ptrs_per_pgd, page_offset / SRMMU_PGDIR_SIZE);
+       
 #if 1
        for(entry = 0; srmmu_map[entry].size; entry++) {
                printk("[%d]: v[%08lx,%08lx](%lx) p[%08lx]\n", entry,
@@ -1884,90 +1826,73 @@ check_and_return:
 
        /* Now setup the p2v/v2p hash tables. */
        for(entry = 0; entry < SRMMU_HASHSZ; entry++)
-               srmmu_v2p_hash[entry] = srmmu_p2v_hash[entry] = NULL;
+               srmmu_v2p_hash[entry] = ((0xff - entry) << 24);
+       for(entry = 0; entry < SRMMU_HASHSZ; entry++)
+               srmmu_p2v_hash[entry] = 0xffffffffUL;
        for(entry = 0; srmmu_map[entry].size; entry++) {
                unsigned long addr;
 
                for(addr = srmmu_map[entry].vbase;
                    addr < (srmmu_map[entry].vbase + srmmu_map[entry].size);
                    addr += (1 << 24))
-                       srmmu_v2p_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry];
+                       srmmu_v2p_hash[srmmu_ahashfn(addr)] =
+                               srmmu_map[entry].pbase - srmmu_map[entry].vbase;
                for(addr = srmmu_map[entry].pbase;
                    addr < (srmmu_map[entry].pbase + srmmu_map[entry].size);
                    addr += (1 << 24))
-                       srmmu_p2v_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry];
+                       srmmu_p2v_hash[srmmu_ahashfn(addr)] = 
+                               srmmu_map[entry].pbase - srmmu_map[entry].vbase;
        }
 
-       page_contig_offset = page_offset - (0xfd000000 - KERNBASE);
-       phys_mem_contig = 1;
-       for(entry = 0; srmmu_map[entry].size; entry++)
-               if (srmmu_map[entry].pbase != srmmu_c_v2p (srmmu_map[entry].vbase)) {
-                       phys_mem_contig = 0;
-                       break;
-               }
-       if (phys_mem_contig) {
-               printk ("SRMMU: Physical memory is contiguous, bypassing VA<->PA hashes\n");
-               pte_page = srmmu_c_pte_page;
-               pmd_page = srmmu_c_pmd_page;
-               pgd_page = srmmu_c_pgd_page;
-               mk_pte = srmmu_c_mk_pte;
-               pte_offset = srmmu_c_pte_offset;
-               pmd_offset = srmmu_c_pmd_offset;
-               if (ctxd_set == srmmu_ctxd_set)
-                       ctxd_set = srmmu_c_ctxd_set;
-               pgd_set = srmmu_c_pgd_set;
-               pmd_set = srmmu_c_pmd_set;
-               mmu_v2p = srmmu_c_v2p;
-               mmu_p2v = srmmu_c_p2v;
-               if (flush_chunk == viking_flush_chunk)
-                       flush_chunk = viking_c_flush_chunk;
-       }
-       
-       if (sparc_cpu_model == sun4d) {
-               int i, j = -1;
-               unsigned long bank_start, bank_end;
-               
-               sun4d_dma_vbase = 0;
-               sun4d_dma_size = IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE;
-               for (i = 0; srmmu_map[i].size; i++) {
-                       bank_start = srmmu_map[i].vbase;
-                       bank_end = bank_start + srmmu_map[i].size;
-                       if (bank_start <= KERNBASE && bank_end > KERNBASE)
-                               j = i;
-                       else if (srmmu_map[i].size >= sun4d_dma_size) {
-                               sun4d_dma_vbase = srmmu_map[i].vbase;
+       BTFIXUPSET_SETHI(page_contig_offset, page_offset - (0xfd000000 - KERNBASE));
+       if (srmmu_low_pa)
+               phys_mem_contig = 0;
+       else {
+               phys_mem_contig = 1;
+               for(entry = 0; srmmu_map[entry].size; entry++)
+                       if (srmmu_map[entry].pbase != srmmu_c_v2p (srmmu_map[entry].vbase)) {
+                               phys_mem_contig = 0;
                                break;
                        }
-               }
-               if (!sun4d_dma_vbase && j != -1) {
-                       if (srmmu_map[j].size >= sun4d_dma_size + 0x1000000)
-                               sun4d_dma_vbase = srmmu_map[j].vbase + 0x1000000;
-                       else {
-                               sun4d_dma_vbase = srmmu_map[j].vbase;
-                               if (srmmu_map[j].size < sun4d_dma_size)
-                                       sun4d_dma_size = srmmu_map[j].size;
-                       }
-               }
-               sun4d_dma_base = IOUNIT_DMA_BASE - srmmu_v2p(sun4d_dma_vbase);
        }
+       if (phys_mem_contig) {
+               printk ("SRMMU: Physical memory is contiguous, bypassing VA<->PA hashes.\n");
+               BTFIXUPSET_CALL(pte_page, srmmu_c_pte_page, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pmd_page, srmmu_c_pmd_page, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pgd_page, srmmu_c_pgd_page, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(mk_pte, srmmu_c_mk_pte, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pte_offset, srmmu_c_pte_offset, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pmd_offset, srmmu_c_pmd_offset, BTFIXUPCALL_NORM);
+               if (BTFIXUPVAL_CALL(ctxd_set) == (unsigned long)srmmu_ctxd_set)
+                       BTFIXUPSET_CALL(ctxd_set, srmmu_c_ctxd_set, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pgd_set, srmmu_c_pgd_set, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pmd_set, srmmu_c_pmd_set, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(mmu_v2p, srmmu_c_v2p, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(mmu_p2v, srmmu_c_p2v, BTFIXUPCALL_NORM);
+               if (BTFIXUPVAL_CALL(flush_chunk) == (unsigned long)viking_flush_chunk)
+                       BTFIXUPSET_CALL(flush_chunk, viking_c_flush_chunk, BTFIXUPCALL_NORM);
+       } else if (srmmu_low_pa) {
+               printk ("SRMMU: Compact physical memory. Using strightforward VA<->PA translations.\n");
+               BTFIXUPSET_CALL(pte_page, srmmu_s_pte_page, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pmd_page, srmmu_s_pmd_page, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pgd_page, srmmu_s_pgd_page, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(mk_pte, srmmu_s_mk_pte, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pte_offset, srmmu_s_pte_offset, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pmd_offset, srmmu_s_pmd_offset, BTFIXUPCALL_NORM);
+               if (BTFIXUPVAL_CALL(ctxd_set) == (unsigned long)srmmu_ctxd_set)
+                       BTFIXUPSET_CALL(ctxd_set, srmmu_s_ctxd_set, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pgd_set, srmmu_s_pgd_set, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pmd_set, srmmu_s_pmd_set, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(mmu_v2p, srmmu_s_v2p, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(mmu_p2v, srmmu_s_p2v, BTFIXUPCALL_NORM);
+               if (BTFIXUPVAL_CALL(flush_chunk) == (unsigned long)viking_flush_chunk)
+                       BTFIXUPSET_CALL(flush_chunk, viking_s_flush_chunk, BTFIXUPCALL_NORM);
+       }
+       btfixup();
 
        return; /* SUCCESS! */
 }
 
-unsigned long srmmu_endmem_fixup(unsigned long mem_end_now)
-{
-       unsigned long tally = 0;
-       int i;
-
-       for(i = 0; sp_banks[i].num_bytes; i++)
-               tally += SRMMU_PGDIR_ALIGN(sp_banks[i].num_bytes);
-       if(tally < (0x0d000000UL)) {
-               return KERNBASE + tally;
-       } else {
-               return 0xfd000000UL;
-       }
-}
-
 /* Paging initialization on the Sparc Reference MMU. */
 extern unsigned long free_area_init(unsigned long, unsigned long);
 extern unsigned long sparc_context_init(unsigned long, int);
@@ -1975,9 +1900,9 @@ extern unsigned long sparc_context_init(unsigned long, int);
 extern int physmem_mapped_contig;
 extern int linux_num_cpus;
 
-void (*poke_srmmu)(void);
+void (*poke_srmmu)(void) __initdata = NULL;
 
-unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem))
 {
        unsigned long ptables_start;
        int i, cpunode;
@@ -2029,7 +1954,7 @@ unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
        start_mem = PAGE_ALIGN(mempool);
 
        flush_cache_all();
-       if(flush_page_for_dma == viking_flush_page) {
+       if(BTFIXUPVAL_CALL(flush_page_for_dma) == (unsigned long)viking_flush_page) {
                unsigned long start = ptables_start;
                unsigned long end = start_mem;
 
@@ -2048,37 +1973,22 @@ unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
        return PAGE_ALIGN(start_mem);
 }
 
-static char srmmuinfo[512];
-
-static char *srmmu_mmu_info(void)
+static int srmmu_mmu_info(char *buf)
 {
-       sprintf(srmmuinfo, "MMU type\t: %s\n"
+       return sprintf(buf, 
+               "MMU type\t: %s\n"
                "invall\t\t: %d\n"
                "invmm\t\t: %d\n"
                "invrnge\t\t: %d\n"
                "invpg\t\t: %d\n"
                "contexts\t: %d\n"
-#ifdef USE_CHUNK_ALLOC
-               "big chunks\t: %d\n"
-               "little chunks\t: %d\n"
-               "chunk pages\t: %d\n"
-               "garbage\t\t: %d\n"
-               "garbage hits\t: %d\n"
-#endif
                , srmmu_name,
                module_stats.invall,
                module_stats.invmm,
                module_stats.invrnge,
                module_stats.invpg,
                num_contexts
-#ifdef USE_CHUNK_ALLOC
-               , bcwater, lcwater,
-               chunk_pages,
-               garbage_calls,
-               clct_pages
-#endif
-               );
-       return srmmuinfo;
+       );
 }
 
 static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
@@ -2242,7 +2152,7 @@ __initfunc(static void init_vac_layout(void))
               (int)vac_cache_size, (int)vac_line_size);
 }
 
-static void poke_hypersparc(void)
+__initfunc(static void poke_hypersparc(void))
 {
        volatile unsigned long clear;
        unsigned long mreg = srmmu_get_mmureg();
@@ -2271,35 +2181,38 @@ __initfunc(static void init_hypersparc(void))
 
        init_vac_layout();
 
-       set_pte = srmmu_set_pte_nocache_hyper;
-       flush_cache_all = hypersparc_flush_cache_all;
-       flush_cache_mm = hypersparc_flush_cache_mm;
-       flush_cache_range = hypersparc_flush_cache_range;
-       flush_cache_page = hypersparc_flush_cache_page;
-
-       flush_tlb_all = hypersparc_flush_tlb_all;
-       flush_tlb_mm = hypersparc_flush_tlb_mm;
-       flush_tlb_range = hypersparc_flush_tlb_range;
-       flush_tlb_page = hypersparc_flush_tlb_page;
-
-       flush_page_to_ram = hypersparc_flush_page_to_ram;
-       flush_sig_insns = hypersparc_flush_sig_insns;
-       flush_page_for_dma = NULL /* hypersparc_flush_page_for_dma */;
-
-       flush_chunk = hypersparc_flush_chunk; /* local flush _only_ */
-
-       ctxd_set = hypersparc_ctxd_set;
-       switch_to_context = hypersparc_switch_to_context;
-       init_new_context = hypersparc_init_new_context;
-       destroy_context = hypersparc_destroy_context;
-       update_mmu_cache = srmmu_vac_update_mmu_cache;
-       sparc_update_rootmmu_dir = hypersparc_update_rootmmu_dir;
+       BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_hyper, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_all, hypersparc_flush_cache_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_mm, hypersparc_flush_cache_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_range, hypersparc_flush_cache_range, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_page, hypersparc_flush_cache_page, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(flush_tlb_all, hypersparc_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, hypersparc_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, hypersparc_flush_tlb_range, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, hypersparc_flush_tlb_page, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_sig_insns, hypersparc_flush_sig_insns, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_page_for_dma, hypersparc_flush_page_for_dma, BTFIXUPCALL_NOP);
+
+       BTFIXUPSET_CALL(flush_chunk, hypersparc_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
+
+       BTFIXUPSET_CALL(ctxd_set, hypersparc_ctxd_set, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(switch_to_context, hypersparc_switch_to_context, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(init_new_context, hypersparc_init_new_context, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(destroy_context, hypersparc_destroy_context, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(sparc_update_rootmmu_dir, hypersparc_update_rootmmu_dir, BTFIXUPCALL_NORM);
        poke_srmmu = poke_hypersparc;
 
        hypersparc_setup_blockops();
 }
 
-static void poke_cypress(void)
+__initfunc(static void poke_cypress(void))
 {
        unsigned long mreg = srmmu_get_mmureg();
        unsigned long faddr, tagval;
@@ -2342,25 +2255,28 @@ __initfunc(static void init_cypress_common(void))
 {
        init_vac_layout();
 
-       set_pte = srmmu_set_pte_nocache_cypress;
-       flush_cache_all = cypress_flush_cache_all;
-       flush_cache_mm = cypress_flush_cache_mm;
-       flush_cache_range = cypress_flush_cache_range;
-       flush_cache_page = cypress_flush_cache_page;
+       BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_cypress, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_all, cypress_flush_cache_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_mm, cypress_flush_cache_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_range, cypress_flush_cache_range, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_page, cypress_flush_cache_page, BTFIXUPCALL_NORM);
 
-       flush_tlb_all = cypress_flush_tlb_all;
-       flush_tlb_mm = cypress_flush_tlb_mm;
-       flush_tlb_page = cypress_flush_tlb_page;
-       flush_tlb_range = cypress_flush_tlb_range;
+       BTFIXUPSET_CALL(flush_tlb_all, cypress_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, cypress_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, cypress_flush_tlb_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, cypress_flush_tlb_range, BTFIXUPCALL_NORM);
 
-       flush_chunk = cypress_flush_chunk; /* local flush _only_ */
+       BTFIXUPSET_CALL(flush_chunk, cypress_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
 
-       flush_page_to_ram = cypress_flush_page_to_ram;
-       flush_sig_insns = cypress_flush_sig_insns;
-       flush_page_for_dma = NULL /* cypress_flush_page_for_dma */;
-       sparc_update_rootmmu_dir = cypress_update_rootmmu_dir;
+       BTFIXUPSET_CALL(flush_page_to_ram, cypress_flush_page_to_ram, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_sig_insns, cypress_flush_sig_insns, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_page_for_dma, cypress_flush_page_for_dma, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(sparc_update_rootmmu_dir, cypress_update_rootmmu_dir, BTFIXUPCALL_NORM);
 
-       update_mmu_cache = srmmu_vac_update_mmu_cache;
+       BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM);
        poke_srmmu = poke_cypress;
 }
 
@@ -2388,7 +2304,7 @@ __initfunc(static void init_cypress_605(unsigned long mrev))
        init_cypress_common();
 }
 
-static void poke_swift(void)
+__initfunc(static void poke_swift(void))
 {
        unsigned long mreg = srmmu_get_mmureg();
 
@@ -2456,21 +2372,23 @@ __initfunc(static void init_swift(void))
                break;
        };
 
-       flush_cache_all = swift_flush_cache_all;
-       flush_cache_mm = swift_flush_cache_mm;
-       flush_cache_page = swift_flush_cache_page;
-       flush_cache_range = swift_flush_cache_range;
+       BTFIXUPSET_CALL(flush_cache_all, swift_flush_cache_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_mm, swift_flush_cache_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_page, swift_flush_cache_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_range, swift_flush_cache_range, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
 
-       flush_chunk = swift_flush_chunk; /* local flush _only_ */
+       BTFIXUPSET_CALL(flush_tlb_all, swift_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, swift_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, swift_flush_tlb_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, swift_flush_tlb_range, BTFIXUPCALL_NORM);
 
-       flush_tlb_all = swift_flush_tlb_all;
-       flush_tlb_mm = swift_flush_tlb_mm;
-       flush_tlb_page = swift_flush_tlb_page;
-       flush_tlb_range = swift_flush_tlb_range;
+       BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_sig_insns, swift_flush_sig_insns, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_page_for_dma, swift_flush_page_for_dma, BTFIXUPCALL_NORM);
 
-       flush_page_to_ram = swift_flush_page_to_ram;
-       flush_sig_insns = swift_flush_sig_insns;
-       flush_page_for_dma = swift_flush_page_for_dma;
+       BTFIXUPSET_CALL(update_mmu_cache, swift_update_mmu_cache, BTFIXUPCALL_NORM);
 
        /* Are you now convinced that the Swift is one of the
         * biggest VLSI abortions of all time?  Bravo Fujitsu!
@@ -2484,8 +2402,9 @@ __initfunc(static void init_swift(void))
 /* turbosparc.S */
 extern void turbosparc_flush_cache_all(void);
 extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
+extern void turbosparc_flush_page_for_dma(unsigned long page);
 
-static void poke_turbosparc(void)
+__initfunc(static void poke_turbosparc(void))
 {
        unsigned long mreg = srmmu_get_mmureg();
        unsigned long ccreg;
@@ -2529,31 +2448,31 @@ __initfunc(static void init_turbosparc(void))
        srmmu_name = "Fujitsu TurboSparc";
        srmmu_modtype = TurboSparc;
 
-       flush_cache_all = turbosparc_flush_cache_all;
-       flush_cache_mm = hypersparc_flush_cache_mm;
-       flush_cache_page = hypersparc_flush_cache_page;
-       flush_cache_range = hypersparc_flush_cache_range;
+       BTFIXUPSET_CALL(flush_cache_all, turbosparc_flush_cache_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_mm, hypersparc_flush_cache_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_page, hypersparc_flush_cache_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_range, hypersparc_flush_cache_range, BTFIXUPCALL_NORM);
 
-       flush_tlb_all = hypersparc_flush_tlb_all;
-       flush_tlb_mm = hypersparc_flush_tlb_mm;
-       flush_tlb_page = hypersparc_flush_tlb_page;
-       flush_tlb_range = hypersparc_flush_tlb_range;
+       BTFIXUPSET_CALL(flush_tlb_all, hypersparc_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, hypersparc_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, hypersparc_flush_tlb_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, hypersparc_flush_tlb_range, BTFIXUPCALL_NORM);
 
 #ifdef TURBOSPARC_WRITEBACK
-       flush_page_to_ram = hypersparc_flush_page_to_ram;
-       flush_chunk = hypersparc_flush_chunk;
+       BTFIXUPSET_CALL(flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_chunk, hypersparc_flush_chunk, BTFIXUPCALL_NORM);
 #else
-       flush_page_to_ram = swift_flush_page_to_ram;
-       flush_chunk = swift_flush_chunk;
+       BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP);
 #endif
 
-       flush_sig_insns = turbosparc_flush_sig_insns;
-       flush_page_for_dma = NULL /* turbosparc_flush_page_for_dma */;
+       BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NOP);
 
        poke_srmmu = poke_turbosparc;
 }
 
-static void poke_tsunami(void)
+__initfunc(static void poke_tsunami(void))
 {
        unsigned long mreg = srmmu_get_mmureg();
 
@@ -2574,26 +2493,26 @@ __initfunc(static void init_tsunami(void))
        srmmu_name = "TI Tsunami";
        srmmu_modtype = Tsunami;
 
-       flush_cache_all = tsunami_flush_cache_all;
-       flush_cache_mm = tsunami_flush_cache_mm;
-       flush_cache_page = tsunami_flush_cache_page;
-       flush_cache_range = tsunami_flush_cache_range;
+       BTFIXUPSET_CALL(flush_cache_all, tsunami_flush_cache_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_mm, tsunami_flush_cache_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_page, tsunami_flush_cache_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_range, tsunami_flush_cache_range, BTFIXUPCALL_NORM);
 
-       flush_chunk = tsunami_flush_chunk; /* local flush _only_ */
+       BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
 
-       flush_tlb_all = tsunami_flush_tlb_all;
-       flush_tlb_mm = tsunami_flush_tlb_mm;
-       flush_tlb_page = tsunami_flush_tlb_page;
-       flush_tlb_range = tsunami_flush_tlb_range;
+       BTFIXUPSET_CALL(flush_tlb_all, tsunami_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, tsunami_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, tsunami_flush_tlb_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, tsunami_flush_tlb_range, BTFIXUPCALL_NORM);
 
-       flush_page_to_ram = tsunami_flush_page_to_ram;
-       flush_sig_insns = tsunami_flush_sig_insns;
-       flush_page_for_dma = tsunami_flush_page_for_dma;
+       BTFIXUPSET_CALL(flush_page_to_ram, tsunami_flush_page_to_ram, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_sig_insns, tsunami_flush_sig_insns, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_page_for_dma, tsunami_flush_page_for_dma, BTFIXUPCALL_NORM);
 
        poke_srmmu = poke_tsunami;
 }
 
-static void poke_viking(void)
+__initfunc(static void poke_viking(void))
 {
        unsigned long mreg = srmmu_get_mmureg();
        static int smp_catch = 0;
@@ -2637,13 +2556,14 @@ static void poke_viking(void)
 
 #ifdef __SMP__
        /* Avoid unnecessary cross calls. */
-       flush_cache_all = local_flush_cache_all;
-       flush_cache_mm = local_flush_cache_mm;
-       flush_cache_range = local_flush_cache_range;
-       flush_cache_page = local_flush_cache_page;
-       flush_page_to_ram = local_flush_page_to_ram;
-       flush_sig_insns = local_flush_sig_insns;
-       flush_page_for_dma = local_flush_page_for_dma;
+       BTFIXUPCOPY_CALL(flush_cache_all, local_flush_cache_all);
+       BTFIXUPCOPY_CALL(flush_cache_mm, local_flush_cache_mm);
+       BTFIXUPCOPY_CALL(flush_cache_range, local_flush_cache_range);
+       BTFIXUPCOPY_CALL(flush_cache_page, local_flush_cache_page);
+       BTFIXUPCOPY_CALL(flush_page_to_ram, local_flush_page_to_ram);
+       BTFIXUPCOPY_CALL(flush_sig_insns, local_flush_sig_insns);
+       BTFIXUPCOPY_CALL(flush_page_for_dma, local_flush_page_for_dma);
+       btfixup();
 #endif
 }
 
@@ -2664,10 +2584,13 @@ __initfunc(static void init_viking(void))
 
                msi_set_sync();
 
-               set_pte = srmmu_set_pte_nocache_viking;
-               sparc_update_rootmmu_dir = viking_update_rootmmu_dir;
+               BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_viking, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(sparc_update_rootmmu_dir, viking_update_rootmmu_dir, BTFIXUPCALL_NORM);
 
-               flush_chunk = viking_flush_chunk; /* local flush _only_ */
+               BTFIXUPSET_CALL(flush_chunk, viking_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
 
                /* We need this to make sure old viking takes no hits
                 * on it's cache for dma snoops to workaround the
@@ -2675,7 +2598,7 @@ __initfunc(static void init_viking(void))
                 * This is only necessary because of the new way in
                 * which we use the IOMMU.
                 */
-               flush_page_for_dma = viking_flush_page;
+               BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page, BTFIXUPCALL_NORM);
                /* Also, this is so far the only chip which actually uses
                   the page argument to flush_page_for_dma */
                flush_page_for_dma_global = 0;
@@ -2683,24 +2606,25 @@ __initfunc(static void init_viking(void))
                srmmu_name = "TI Viking/MXCC";
                viking_mxcc_present = 1;
 
-               flush_chunk = viking_mxcc_flush_chunk; /* local flush _only_ */
+               BTFIXUPSET_CALL(flush_chunk, viking_mxcc_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
 
                /* MXCC vikings lack the DMA snooping bug. */
-               flush_page_for_dma = NULL /* viking_flush_page_for_dma */;
+               BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page_for_dma, BTFIXUPCALL_NOP);
        }
 
-       flush_cache_all = viking_flush_cache_all;
-       flush_cache_mm = viking_flush_cache_mm;
-       flush_cache_page = viking_flush_cache_page;
-       flush_cache_range = viking_flush_cache_range;
+       /* flush_cache_* are nops */
+       BTFIXUPSET_CALL(flush_cache_all, viking_flush_cache_all, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_cache_mm, viking_flush_cache_mm, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_cache_page, viking_flush_cache_page, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_cache_range, viking_flush_cache_range, BTFIXUPCALL_NOP);
 
-       flush_tlb_all = viking_flush_tlb_all;
-       flush_tlb_mm = viking_flush_tlb_mm;
-       flush_tlb_page = viking_flush_tlb_page;
-       flush_tlb_range = viking_flush_tlb_range;
+       BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM);
 
-       flush_page_to_ram = viking_flush_page_to_ram;
-       flush_sig_insns = viking_flush_sig_insns;
+       BTFIXUPSET_CALL(flush_page_to_ram, viking_flush_page_to_ram, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_sig_insns, viking_flush_sig_insns, BTFIXUPCALL_NOP);
 
        poke_srmmu = poke_viking;
 }
@@ -2798,6 +2722,67 @@ __initfunc(static void get_srmmu_type(void))
        srmmu_is_bad();
 }
 
+/* Low and high watermarks for page table cache.
+   The system should try to have pgt_water[0] <= cache elements <= pgt_water[1]
+ */
+extern int pgt_cache_water[2];
+
+void srmmu_check_pgt_cache(void)
+{
+       struct page *page, *page2;
+
+       if (pgtable_cache_size > pgt_cache_water[0]) {
+               spin_lock(&pte_spinlock);
+               for (page2 = NULL, page = (struct page *)pte_quicklist; page;) {
+                       if ((unsigned int)page->pprev_hash == 0xffff) {
+                               if (page2)
+                                       page2->next_hash = page->next_hash;
+                               else
+                                       (struct page *)pte_quicklist = page->next_hash;
+                               page->next_hash = NULL;
+                               page->pprev_hash = NULL;
+                               pgtable_cache_size -= 16;
+                               free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+                               if (page2)
+                                       page = page2->next_hash;
+                               else
+                                       page = (struct page *)pte_quicklist;
+                               if (pgtable_cache_size <= pgt_cache_water[1])
+                                       break;
+                               continue;
+                       }
+                       page2 = page;
+                       page = page->next_hash;
+               }
+               spin_unlock(&pte_spinlock);
+       }
+       if (pgd_cache_size > pgt_cache_water[0] / 4) {
+               spin_lock(&pgd_spinlock);
+               for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) {
+                       if ((unsigned int)page->pprev_hash == 0xf) {
+                               if (page2)
+                                       page2->next_hash = page->next_hash;
+                               else
+                                       (struct page *)pgd_quicklist = page->next_hash;
+                               page->next_hash = NULL;
+                               page->pprev_hash = NULL;
+                               pgd_cache_size -= 4;
+                               free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+                               if (page2)
+                                       page = page2->next_hash;
+                               else
+                                       page = (struct page *)pgd_quicklist;
+                               if (pgd_cache_size <= pgt_cache_water[1] / 4)
+                                       break;
+                               continue;
+                       }
+                       page2 = page;
+                       page = page->next_hash;
+               }
+               spin_unlock(&pgd_spinlock);
+       }
+}
+
 extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme,
        tsetup_mmu_patchme, rtrap_mmu_patchme;
 
@@ -2810,7 +2795,7 @@ extern unsigned long srmmu_fault;
                iaddr = &(insn); \
                daddr = &(dest); \
                *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
-        } while(0);
+       } while(0);
 
 __initfunc(static void patch_window_trap_handlers(void))
 {
@@ -2829,7 +2814,7 @@ __initfunc(static void patch_window_trap_handlers(void))
 /* Local cross-calls. */
 static void smp_flush_page_for_dma(unsigned long page)
 {
-       xc1((smpfunc_t) local_flush_page_for_dma, page);
+       xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_for_dma), page);
 }
 
 #endif
@@ -2839,98 +2824,107 @@ __initfunc(void ld_mmu_srmmu(void))
 {
        extern void ld_mmu_iommu(void);
        extern void ld_mmu_iounit(void);
+       extern void ___xchg32_sun4md(void);
        
        /* First the constants */
-       pmd_shift = SRMMU_PMD_SHIFT;
-       pmd_size = SRMMU_PMD_SIZE;
-       pmd_mask = SRMMU_PMD_MASK;
-       pgdir_shift = SRMMU_PGDIR_SHIFT;
-       pgdir_size = SRMMU_PGDIR_SIZE;
-       pgdir_mask = SRMMU_PGDIR_MASK;
-
-       ptrs_per_pte = SRMMU_PTRS_PER_PTE;
-       ptrs_per_pmd = SRMMU_PTRS_PER_PMD;
-       ptrs_per_pgd = SRMMU_PTRS_PER_PGD;
-
-       page_none = SRMMU_PAGE_NONE;
-       page_shared = SRMMU_PAGE_SHARED;
-       page_copy = SRMMU_PAGE_COPY;
-       page_readonly = SRMMU_PAGE_RDONLY;
-       page_kernel = SRMMU_PAGE_KERNEL;
+       BTFIXUPSET_SIMM13(pmd_shift, SRMMU_PMD_SHIFT);
+       BTFIXUPSET_SETHI(pmd_size, SRMMU_PMD_SIZE);
+       BTFIXUPSET_SETHI(pmd_mask, SRMMU_PMD_MASK);
+       BTFIXUPSET_SIMM13(pgdir_shift, SRMMU_PGDIR_SHIFT);
+       BTFIXUPSET_SETHI(pgdir_size, SRMMU_PGDIR_SIZE);
+       BTFIXUPSET_SETHI(pgdir_mask, SRMMU_PGDIR_MASK);
+
+       BTFIXUPSET_SIMM13(ptrs_per_pte, SRMMU_PTRS_PER_PTE);
+       BTFIXUPSET_SIMM13(ptrs_per_pmd, SRMMU_PTRS_PER_PMD);
+       BTFIXUPSET_SIMM13(ptrs_per_pgd, SRMMU_PTRS_PER_PGD);
+
+       BTFIXUPSET_INT(page_none, pgprot_val(SRMMU_PAGE_NONE));
+       BTFIXUPSET_INT(page_shared, pgprot_val(SRMMU_PAGE_SHARED));
+       BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY));
+       BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY));
+       BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL));
        pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF;
-           
+       
        /* Functions */
-       set_pte = srmmu_set_pte_cacheable;
-       init_new_context = srmmu_init_new_context;
-       switch_to_context = srmmu_switch_to_context;
-       pmd_align = srmmu_pmd_align;
-       pgdir_align = srmmu_pgdir_align;
-       vmalloc_start = srmmu_vmalloc_start;
-
-       pte_page = srmmu_pte_page;
-       pmd_page = srmmu_pmd_page;
-       pgd_page = srmmu_pgd_page;
-
-       sparc_update_rootmmu_dir = srmmu_update_rootmmu_dir;
-
-       pte_none = srmmu_pte_none;
-       pte_present = srmmu_pte_present;
-       pte_clear = srmmu_pte_clear;
-
-       pmd_none = srmmu_pmd_none;
-       pmd_bad = srmmu_pmd_bad;
-       pmd_present = srmmu_pmd_present;
-       pmd_clear = srmmu_pmd_clear;
-
-       pgd_none = srmmu_pgd_none;
-       pgd_bad = srmmu_pgd_bad;
-       pgd_present = srmmu_pgd_present;
-       pgd_clear = srmmu_pgd_clear;
-
-       mk_pte = srmmu_mk_pte;
-       mk_pte_phys = srmmu_mk_pte_phys;
-       pgd_set = srmmu_pgd_set;
-       mk_pte_io = srmmu_mk_pte_io;
-       pte_modify = srmmu_pte_modify;
-       pgd_offset = srmmu_pgd_offset;
-       pmd_offset = srmmu_pmd_offset;
-       pte_offset = srmmu_pte_offset;
-       pte_free_kernel = srmmu_pte_free_kernel;
-       pmd_free_kernel = srmmu_pmd_free_kernel;
-       pte_alloc_kernel = srmmu_pte_alloc_kernel;
-       pmd_alloc_kernel = srmmu_pmd_alloc_kernel;
-       pte_free = srmmu_pte_free;
-       pte_alloc = srmmu_pte_alloc;
-       pmd_free = srmmu_pmd_free;
-       pmd_alloc = srmmu_pmd_alloc;
-       pgd_free = srmmu_pgd_free;
-       pgd_alloc = srmmu_pgd_alloc;
-
-       pte_write = srmmu_pte_write;
-       pte_dirty = srmmu_pte_dirty;
-       pte_young = srmmu_pte_young;
-       pte_wrprotect = srmmu_pte_wrprotect;
-       pte_mkclean = srmmu_pte_mkclean;
-       pte_mkold = srmmu_pte_mkold;
-       pte_mkwrite = srmmu_pte_mkwrite;
-       pte_mkdirty = srmmu_pte_mkdirty;
-       pte_mkyoung = srmmu_pte_mkyoung;
-       update_mmu_cache = srmmu_update_mmu_cache;
-       destroy_context = srmmu_destroy_context;
+#ifndef __SMP__        
+       BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4md, BTFIXUPCALL_SWAPG1G2);
+#endif
+       BTFIXUPSET_CALL(get_pte_fast, srmmu_get_pte_fast, BTFIXUPCALL_RETINT(0));
+       BTFIXUPSET_CALL(get_pgd_fast, srmmu_get_pgd_fast, BTFIXUPCALL_RETINT(0));
+       BTFIXUPSET_CALL(free_pte_slow, srmmu_free_pte_slow, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(free_pgd_slow, srmmu_free_pgd_slow, BTFIXUPCALL_NOP);
+       
+       BTFIXUPSET_CALL(set_pgdir, srmmu_set_pgdir, BTFIXUPCALL_NORM);
+           
+       BTFIXUPSET_CALL(set_pte, srmmu_set_pte_cacheable, BTFIXUPCALL_SWAPO0O1);
+       BTFIXUPSET_CALL(init_new_context, srmmu_init_new_context, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(switch_to_context, srmmu_switch_to_context, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(pte_page, srmmu_pte_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_page, srmmu_pgd_page, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(sparc_update_rootmmu_dir, srmmu_update_rootmmu_dir, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_SETHI(none_mask, 0xF0000000);
+       
+       BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0);
+
+       BTFIXUPSET_CALL(pmd_bad, srmmu_pmd_bad, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_present, srmmu_pmd_present, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_SWAPO0G0);
+
+       BTFIXUPSET_CALL(pgd_none, srmmu_pgd_none, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_bad, srmmu_pgd_bad, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_present, srmmu_pgd_present, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_SWAPO0G0);
+
+       BTFIXUPSET_CALL(mk_pte, srmmu_mk_pte, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mk_pte_phys, srmmu_mk_pte_phys, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mk_pte_io, srmmu_mk_pte_io, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_set, srmmu_pgd_set, BTFIXUPCALL_NORM);
        
-       mmu_info = srmmu_mmu_info;
-        mmu_v2p = srmmu_v2p;
-        mmu_p2v = srmmu_p2v;
+       BTFIXUPSET_INT(pte_modify_mask, SRMMU_CHG_MASK);
+       BTFIXUPSET_CALL(pgd_offset, srmmu_pgd_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_offset, srmmu_pmd_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_offset, srmmu_pte_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_free_kernel, srmmu_pte_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_free_kernel, srmmu_pmd_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_alloc_kernel, srmmu_pte_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_alloc_kernel, srmmu_pmd_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_free, srmmu_pte_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_alloc, srmmu_pte_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_free, srmmu_pmd_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_alloc, srmmu_pmd_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_free, srmmu_pgd_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_alloc, srmmu_pgd_alloc, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_HALF(pte_writei, SRMMU_WRITE);
+       BTFIXUPSET_HALF(pte_dirtyi, SRMMU_DIRTY);
+       BTFIXUPSET_HALF(pte_youngi, SRMMU_REF);
+       BTFIXUPSET_HALF(pte_wrprotecti, SRMMU_WRITE);
+       BTFIXUPSET_HALF(pte_mkcleani, SRMMU_DIRTY);
+       BTFIXUPSET_HALF(pte_mkoldi, SRMMU_REF);
+       BTFIXUPSET_CALL(pte_mkwrite, srmmu_pte_mkwrite, BTFIXUPCALL_ORINT(SRMMU_WRITE));
+       BTFIXUPSET_CALL(pte_mkdirty, srmmu_pte_mkdirty, BTFIXUPCALL_ORINT(SRMMU_DIRTY));
+       BTFIXUPSET_CALL(pte_mkyoung, srmmu_pte_mkyoung, BTFIXUPCALL_ORINT(SRMMU_REF));
+       BTFIXUPSET_CALL(update_mmu_cache, srmmu_update_mmu_cache, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(destroy_context, srmmu_destroy_context, BTFIXUPCALL_NORM);
+       
+       BTFIXUPSET_CALL(mmu_info, srmmu_mmu_info, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_v2p, srmmu_v2p, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_p2v, srmmu_p2v, BTFIXUPCALL_NORM);
 
        /* Task struct and kernel stack allocating/freeing. */
-       alloc_task_struct = srmmu_alloc_task_struct;
-       free_task_struct = srmmu_free_task_struct;
+       BTFIXUPSET_CALL(alloc_task_struct, srmmu_alloc_task_struct, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(free_task_struct, srmmu_free_task_struct, BTFIXUPCALL_NORM);
 
-       quick_kernel_fault = srmmu_quick_kernel_fault;
+       BTFIXUPSET_CALL(quick_kernel_fault, srmmu_quick_kernel_fault, BTFIXUPCALL_NORM);
 
        /* SRMMU specific. */
-       ctxd_set = srmmu_ctxd_set;
-       pmd_set = srmmu_pmd_set;
+       BTFIXUPSET_CALL(ctxd_set, srmmu_ctxd_set, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_set, srmmu_pmd_set, BTFIXUPCALL_NORM);
 
        get_srmmu_type();
        patch_window_trap_handlers();
@@ -2938,33 +2932,38 @@ __initfunc(void ld_mmu_srmmu(void))
 #ifdef __SMP__
        /* El switcheroo... */
 
-       local_flush_cache_all = flush_cache_all;
-       local_flush_cache_mm = flush_cache_mm;
-       local_flush_cache_range = flush_cache_range;
-       local_flush_cache_page = flush_cache_page;
-       local_flush_tlb_all = flush_tlb_all;
-       local_flush_tlb_mm = flush_tlb_mm;
-       local_flush_tlb_range = flush_tlb_range;
-       local_flush_tlb_page = flush_tlb_page;
-       local_flush_page_to_ram = flush_page_to_ram;
-       local_flush_sig_insns = flush_sig_insns;
-       local_flush_page_for_dma = flush_page_for_dma;
-
-       flush_cache_all = smp_flush_cache_all;
-       flush_cache_mm = smp_flush_cache_mm;
-       flush_cache_range = smp_flush_cache_range;
-       flush_cache_page = smp_flush_cache_page;
-       flush_tlb_all = smp_flush_tlb_all;
-       flush_tlb_mm = smp_flush_tlb_mm;
-       flush_tlb_range = smp_flush_tlb_range;
-       flush_tlb_page = smp_flush_tlb_page;
-       flush_page_to_ram = smp_flush_page_to_ram;
-       flush_sig_insns = smp_flush_sig_insns;
-       if (flush_page_for_dma)
-               flush_page_for_dma = smp_flush_page_for_dma;
+       BTFIXUPCOPY_CALL(local_flush_cache_all, flush_cache_all);
+       BTFIXUPCOPY_CALL(local_flush_cache_mm, flush_cache_mm);
+       BTFIXUPCOPY_CALL(local_flush_cache_range, flush_cache_range);
+       BTFIXUPCOPY_CALL(local_flush_cache_page, flush_cache_page);
+       BTFIXUPCOPY_CALL(local_flush_tlb_all, flush_tlb_all);
+       BTFIXUPCOPY_CALL(local_flush_tlb_mm, flush_tlb_mm);
+       BTFIXUPCOPY_CALL(local_flush_tlb_range, flush_tlb_range);
+       BTFIXUPCOPY_CALL(local_flush_tlb_page, flush_tlb_page);
+       BTFIXUPCOPY_CALL(local_flush_page_to_ram, flush_page_to_ram);
+       BTFIXUPCOPY_CALL(local_flush_sig_insns, flush_sig_insns);
+       BTFIXUPCOPY_CALL(local_flush_page_for_dma, flush_page_for_dma);
+
+       BTFIXUPSET_CALL(flush_cache_all, smp_flush_cache_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, smp_flush_tlb_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_page_to_ram, smp_flush_page_to_ram, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_sig_insns, smp_flush_sig_insns, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_page_for_dma, smp_flush_page_for_dma, BTFIXUPCALL_NORM);
 #endif
        if (sparc_cpu_model == sun4d)
                ld_mmu_iounit();
        else
                ld_mmu_iommu();
+#ifdef __SMP__
+       if (sparc_cpu_model == sun4d)
+               sun4d_init_smp();
+       else
+               sun4m_init_smp();
+#endif
 }
index c70753fa4629056b546c247f3a7c8f3e621d0a5f..b6d6d4e564ff8fcdc3d2859aaac9768a337318b6 100644 (file)
@@ -1,9 +1,11 @@
-/* $Id: sun4c.c,v 1.149 1997/07/20 05:59:38 davem Exp $
+/* $Id: sun4c.c,v 1.163 1998/03/11 04:08:21 tdyas Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
  * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au)
+ * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/kernel.h>
@@ -22,6 +24,7 @@
 #include <asm/oplib.h>
 #include <asm/openprom.h>
 #include <asm/mmu_context.h>
+#include <asm/sun4paddr.h>
 
 /* TODO: Make it such that interrupt handlers cannot dick with
  *       the user segment lists, most of the cli/sti pairs can
@@ -59,11 +62,15 @@ extern int num_segmaps, num_contexts;
        : "g4", "cc");                                                  \
 } while(0);
 
-/* That's it, we prom_halt() if the cache size is something other than 65536.
+#ifdef CONFIG_SUN4
+#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
+#else
+/* That's it, we prom_halt() on sun4c if the cache size is something other than 65536.
  * So let's save some cycles and just use that everywhere except for that bootup
  * sanity check.
  */
-#define SUN4C_VAC_SIZE 65536
+#define SUN4C_VAC_SIZE 65536
+#endif
 
 #define SUN4C_KERNEL_BUCKETS 32
 
@@ -427,22 +434,76 @@ static inline void sun4c_init_clean_mmu(unsigned long kernel_end)
        sun4c_set_context(savectx);
 }
 
-void sun4c_probe_vac(void)
+__initfunc(void sun4c_probe_vac(void))
 {
        sun4c_disable_vac();
-       if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-          (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-               /* PROM on SS1 lacks this info, to be super safe we
-                * hard code it here since this arch is cast in stone.
-                */
-               sun4c_vacinfo.num_bytes = 65536;
-               sun4c_vacinfo.linesize = 16;
+
+       if (ARCH_SUN4) {
+               switch(idprom->id_machtype) {
+
+               case (SM_SUN4|SM_4_110):
+                       sun4c_vacinfo.type = NONE;
+                       sun4c_vacinfo.num_bytes = 0;
+                       sun4c_vacinfo.linesize = 0;
+                       sun4c_vacinfo.do_hwflushes = 0;
+                       prom_printf("No VAC. Get some bucks and buy a real computer.");
+                       prom_halt();
+                       break;
+
+               case (SM_SUN4|SM_4_260):
+                       sun4c_vacinfo.type = WRITE_BACK;
+                       sun4c_vacinfo.num_bytes = 128 * 1024;
+                       sun4c_vacinfo.linesize = 16;
+                       sun4c_vacinfo.do_hwflushes = 0;
+                       break;
+
+               case (SM_SUN4|SM_4_330):
+                       sun4c_vacinfo.type = WRITE_THROUGH;
+                       sun4c_vacinfo.num_bytes = 128 * 1024;
+                       sun4c_vacinfo.linesize = 16;
+                       sun4c_vacinfo.do_hwflushes = 0;
+                       break;
+
+               case (SM_SUN4|SM_4_470):
+                       sun4c_vacinfo.type = WRITE_BACK;
+                       sun4c_vacinfo.num_bytes = 128 * 1024;
+                       sun4c_vacinfo.linesize = 32;
+                       sun4c_vacinfo.do_hwflushes = 0;
+                       break;
+
+               default:
+                       prom_printf("Cannot initialize VAC - wierd sun4 model idprom->id_machtype = %d", idprom->id_machtype);
+                       prom_halt();
+               }
        } else {
-               sun4c_vacinfo.num_bytes = prom_getintdefault(prom_root_node,
-                                                            "vac-size", 65536);
-               sun4c_vacinfo.linesize = prom_getintdefault(prom_root_node,
-                                                           "vac-linesize", 16);
+               sun4c_vacinfo.type = WRITE_THROUGH;
+
+               if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+                  (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+                       /* PROM on SS1 lacks this info, to be super safe we
+                        * hard code it here since this arch is cast in stone.
+                        */
+                       sun4c_vacinfo.num_bytes = 65536;
+                       sun4c_vacinfo.linesize = 16;
+               } else {
+                       sun4c_vacinfo.num_bytes =
+                        prom_getintdefault(prom_root_node, "vac-size", 65536);
+                       sun4c_vacinfo.linesize =
+                        prom_getintdefault(prom_root_node, "vac-linesize", 16);
+               }
+               sun4c_vacinfo.do_hwflushes =
+                prom_getintdefault(prom_root_node, "vac-hwflush", 0);
+
+               if(sun4c_vacinfo.do_hwflushes == 0)
+                       sun4c_vacinfo.do_hwflushes =
+                        prom_getintdefault(prom_root_node, "vac_hwflush", 0);
+
+               if (sun4c_vacinfo.num_bytes != 65536) {
+                       prom_printf("WEIRD Sun4C VAC cache size, tell davem");
+                       prom_halt();
+               }
        }
+
        sun4c_vacinfo.num_lines =
                (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
        switch(sun4c_vacinfo.linesize) {
@@ -458,17 +519,6 @@ void sun4c_probe_vac(void)
                prom_halt();
        };
 
-       sun4c_vacinfo.do_hwflushes = prom_getintdefault(prom_root_node,
-                                                       "vac-hwflush", 0);
-       if(sun4c_vacinfo.do_hwflushes == 0)
-               sun4c_vacinfo.do_hwflushes = prom_getintdefault(prom_root_node,
-                                                               "vac_hwflush", 0);
-
-       if(sun4c_vacinfo.num_bytes != 65536) {
-               prom_printf("WEIRD Sun4C VAC cache size, tell davem");
-               prom_halt();
-       }
-
        sun4c_flush_all();
        sun4c_enable_vac();
 }
@@ -476,6 +526,7 @@ void sun4c_probe_vac(void)
 /* Patch instructions for the low level kernel fault handler. */
 extern unsigned long invalid_segment_patch1, invalid_segment_patch1_ff;
 extern unsigned long invalid_segment_patch2, invalid_segment_patch2_ff;
+extern unsigned long invalid_segment_patch1_1ff, invalid_segment_patch2_1ff;
 extern unsigned long num_context_patch1, num_context_patch1_16;
 extern unsigned long num_context_patch2, num_context_patch2_16;
 extern unsigned long vac_linesize_patch, vac_linesize_patch_32;
@@ -502,6 +553,12 @@ static void patch_kernel_fault_handler(void)
                        PATCH_INSN(invalid_segment_patch2_ff,
                                   invalid_segment_patch2);
                        break;
+               case 512:
+                       PATCH_INSN(invalid_segment_patch1_1ff,
+                                  invalid_segment_patch1);
+                       PATCH_INSN(invalid_segment_patch2_1ff,
+                                  invalid_segment_patch2);
+                       break;
                default:
                        prom_printf("Unhandled number of segmaps: %d\n",
                                    num_segmaps);
@@ -541,38 +598,80 @@ static void patch_kernel_fault_handler(void)
        }
 }
 
-static void sun4c_probe_mmu(void)
+__initfunc(static void sun4c_probe_mmu(void))
 {
-       if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-          (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-               /* Hardcode these just to be safe, PROM on SS1 does
-                * not have this info available in the root node.
-                */
-               num_segmaps = 128;
-               num_contexts = 8;
+       if (ARCH_SUN4) {
+               switch(idprom->id_machtype) {
+               case (SM_SUN4|SM_4_110):
+                       prom_printf("No support for 4100 yet\n");
+                       prom_halt();
+                       num_segmaps = 256;
+                       num_contexts = 8;
+                       break;
+
+               case (SM_SUN4|SM_4_260):
+                       prom_printf("No support for 4200 yet\n");
+                       prom_halt();
+                       num_segmaps = 512;
+                       num_contexts = 16;
+                       break;
+
+               case (SM_SUN4|SM_4_330):
+                       num_segmaps = 256;
+                       num_contexts = 16;
+                       break;
+
+               case (SM_SUN4|SM_4_470):
+                       prom_printf("No support for 4400 yet\n");
+                       prom_halt();
+                       num_segmaps = 1024;
+                       num_contexts = 64;
+                       break;
+               default:
+                       prom_printf("Invalid SUN4 model\n");
+                       prom_halt();
+               }
        } else {
-               num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
-               num_contexts = prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
+               if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+               (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+                       /* Hardcode these just to be safe, PROM on SS1 does
+                       * not have this info available in the root node.
+                       */
+                       num_segmaps = 128;
+                       num_contexts = 8;
+               } else {
+                       num_segmaps =
+                           prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+                       num_contexts =
+                           prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
+               }
        }
        patch_kernel_fault_handler();
 }
 
 volatile unsigned long *sun4c_memerr_reg = 0;
 
-void sun4c_probe_memerr_reg(void)
+__initfunc(void sun4c_probe_memerr_reg(void))
 {
        int node;
        struct linux_prom_registers regs[1];
 
-       node = prom_getchild(prom_root_node);
-       node = prom_searchsiblings(prom_root_node, "memory-error");
-       if (!node)
-               return;
-       prom_getproperty(node, "reg", (char *)regs, sizeof(regs));
-       sun4c_memerr_reg = sparc_alloc_io(regs[0].phys_addr, 0,
-                                         regs[0].reg_size,
-                                         "memory parity error",
-                                         regs[0].which_io, 0);
+       if (ARCH_SUN4) {
+               sun4c_memerr_reg = sparc_alloc_io(SUN4_MEMREG_PHYSADDR, 0,
+                                               PAGE_SIZE,
+                                               "memory parity error",
+                                               0x0, 0);
+       } else {
+               node = prom_getchild(prom_root_node);
+               node = prom_searchsiblings(prom_root_node, "memory-error");
+               if (!node)
+                       return;
+               prom_getproperty(node, "reg", (char *)regs, sizeof(regs));
+               sun4c_memerr_reg = sparc_alloc_io(regs[0].phys_addr, 0,
+                                               regs[0].reg_size,
+                                               "memory parity error",
+                                               regs[0].which_io, 0);
+       }
 }
 
 static inline void sun4c_init_ss2_cache_bug(void)
@@ -581,6 +680,7 @@ static inline void sun4c_init_ss2_cache_bug(void)
 
        if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
           (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
+          (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
           (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
                /* Whee.. */
                printk("SS2 cache bug detected, uncaching trap table page\n");
@@ -626,13 +726,14 @@ struct sun4c_mmu_entry {
        unsigned char pseg;
        unsigned char locked;
 };
-static struct sun4c_mmu_entry mmu_entry_pool[256];
+
+static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS];
 
 __initfunc(static void sun4c_init_mmu_entry_pool(void))
 {
        int i;
 
-       for(i=0; i < 256; i++) {
+       for(i=0; i < SUN4C_MAX_SEGMAPS; i++) {
                mmu_entry_pool[i].pseg = i;
                mmu_entry_pool[i].next = 0;
                mmu_entry_pool[i].prev = 0;
@@ -703,7 +804,8 @@ struct sun4c_mmu_ring {
        struct sun4c_mmu_entry ringhd;
        int num_entries;
 };
-static struct sun4c_mmu_ring sun4c_context_ring[16]; /* used user entries */
+
+static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */
 static struct sun4c_mmu_ring sun4c_ufree_ring;       /* free user entries */
 struct sun4c_mmu_ring sun4c_kernel_ring;      /* used kernel entries */
 struct sun4c_mmu_ring sun4c_kfree_ring;       /* free kernel entries */
@@ -711,7 +813,7 @@ struct sun4c_mmu_ring sun4c_kfree_ring;       /* free kernel entries */
 static inline void sun4c_init_rings(unsigned long *mempool)
 {
        int i;
-       for(i=0; i<16; i++) {
+       for(i=0; i<SUN4C_MAX_CONTEXTS; i++) {
                sun4c_context_ring[i].ringhd.next =
                        sun4c_context_ring[i].ringhd.prev =
                        &sun4c_context_ring[i].ringhd;
@@ -1120,7 +1222,7 @@ static int sun4c_lowbucket_avail;
 #define BUCKET_PTE(page)       \
         ((((page) - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL))
 #define BUCKET_PTE_PAGE(pte)   \
-        (PAGE_OFFSET + (((pte) & 0xffff) << PAGE_SHIFT))
+        (PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT))
 
 static inline void get_locked_segment(unsigned long addr)
 {
@@ -1180,12 +1282,18 @@ static inline void garbage_collect(int entry)
        free_locked_segment(BUCKET_ADDR(entry));
 }
 
+#ifdef CONFIG_SUN4
+#define TASK_STRUCT_ORDER      0
+#else
+#define TASK_STRUCT_ORDER      1
+#endif
+
 static struct task_struct *sun4c_alloc_task_struct(void)
 {
        unsigned long addr, pages;
        int entry;
 
-       pages = __get_free_pages(GFP_KERNEL, 1);
+       pages = __get_free_pages(GFP_KERNEL, TASK_STRUCT_ORDER);
        if(!pages)
                return (struct task_struct *) 0;
 
@@ -1193,7 +1301,7 @@ static struct task_struct *sun4c_alloc_task_struct(void)
                if(sun4c_bucket[entry] == BUCKET_EMPTY)
                        break;
        if(entry == NR_TASKS) {
-               free_pages(pages, 1);
+               free_pages(pages, TASK_STRUCT_ORDER);
                return (struct task_struct *) 0;
        }
        if(entry >= sun4c_lowbucket_avail)
@@ -1204,8 +1312,9 @@ static struct task_struct *sun4c_alloc_task_struct(void)
        if(sun4c_get_segmap(addr) == invalid_segment)
                get_locked_segment(addr);
        sun4c_put_pte(addr, BUCKET_PTE(pages));
+#ifndef CONFIG_SUN4    
        sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
-
+#endif
        return (struct task_struct *) addr;
 }
 
@@ -1217,15 +1326,18 @@ static void sun4c_free_task_struct_hw(struct task_struct *tsk)
 
        /* We are deleting a mapping, so the flush here is mandatory. */
        sun4c_flush_page_hw(tsaddr);
+#ifndef CONFIG_SUN4    
        sun4c_flush_page_hw(tsaddr + PAGE_SIZE);
-
+#endif
        sun4c_put_pte(tsaddr, 0);
+#ifndef CONFIG_SUN4    
        sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
+#endif
        sun4c_bucket[entry] = BUCKET_EMPTY;
        if(entry < sun4c_lowbucket_avail)
                sun4c_lowbucket_avail = entry;
 
-       free_pages(pages, 1);
+       free_pages(pages, TASK_STRUCT_ORDER);
        garbage_collect(entry);
 }
 
@@ -1237,15 +1349,18 @@ static void sun4c_free_task_struct_sw(struct task_struct *tsk)
 
        /* We are deleting a mapping, so the flush here is mandatory. */
        sun4c_flush_page_sw(tsaddr);
+#ifndef CONFIG_SUN4    
        sun4c_flush_page_sw(tsaddr + PAGE_SIZE);
-
+#endif
        sun4c_put_pte(tsaddr, 0);
+#ifndef CONFIG_SUN4    
        sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
+#endif
        sun4c_bucket[entry] = BUCKET_EMPTY;
        if(entry < sun4c_lowbucket_avail)
                sun4c_lowbucket_avail = entry;
 
-       free_pages(pages, 1);
+       free_pages(pages, TASK_STRUCT_ORDER);
        garbage_collect(entry);
 }
 
@@ -1253,9 +1368,8 @@ __initfunc(static void sun4c_init_buckets(void))
 {
        int entry;
 
-       if(sizeof(union task_union) != (PAGE_SIZE << 1)) {
-               prom_printf("task union not 2 pages!\n");
-               prom_halt();
+       if(sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
+               prom_printf("task union not %d page(s)!\n", 1 << TASK_STRUCT_ORDER);
        }
        for(entry = 0; entry < NR_TASKS; entry++)
                sun4c_bucket[entry] = BUCKET_EMPTY;
@@ -1949,12 +2063,17 @@ static void sun4c_set_pte(pte_t *ptep, pte_t pte)
        *ptep = pte;
 }
 
+static void sun4c_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{
+}
+
+
 void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
                     int bus_type, int rdonly)
 {
        unsigned long page_entry;
 
-       page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
+       page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK);
        page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT));
        if(rdonly)
                page_entry &= ~_SUN4C_WRITEABLE;
@@ -2092,21 +2211,17 @@ static void sun4c_destroy_context_sw(struct mm_struct *mm)
        }
 }
 
-#if KGPROF_PROFILING
-static char s4cinfo[10240];
-#else
-static char s4cinfo[512];
-#endif
-
-static char *sun4c_mmu_info(void)
+static int sun4c_mmu_info(char *buf)
 {
        int used_user_entries, i;
+       int len;
 
        used_user_entries = 0;
        for(i=0; i < num_contexts; i++)
                used_user_entries += sun4c_context_ring[i].num_entries;
 
-       sprintf(s4cinfo, "vacsize\t\t: %d bytes\n"
+       len = sprintf(buf, 
+               "vacsize\t\t: %d bytes\n"
                "vachwflush\t: %s\n"
                "vaclinesize\t: %d bytes\n"
                "mmuctxs\t\t: %d\n"
@@ -2135,29 +2250,31 @@ static char *sun4c_mmu_info(void)
 
 #if KGPROF_PROFILING
        {
-               char *p = s4cinfo + strlen(s4cinfo);
                int i,j;
-               sprintf(p,"kgprof profiling:\n"); p += strlen(p);
+               len += sprintf(buf + len,"kgprof profiling:\n");
                for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
-                       sprintf(p,"%5d  ",kgprof_counters[i].count); p += strlen(p);
+                       len += sprintf(buf + len,"%5d  ",kgprof_counters[i].count);
                        for (j=0;j<KGPROF_DEPTH;j++) {
-                               sprintf(p,"%08x ",kgprof_counters[i].addr[j]);
-                               p += strlen(p);
+                               len += sprintf(buf + len,"%08x ",kgprof_counters[i].addr[j]);
                        }
-                       sprintf(p,"\n"); p += strlen(p);
+                       len += sprintf(buf + len,"\n");
                }
        }
 #endif
 
-       return s4cinfo;
+       return len;
 }
 
 /* Nothing below here should touch the mmu hardware nor the mmu_entry
  * data structures.
  */
 
+#if 0 /* Not used due to BTFIXUPs */
 static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
+#endif
+#if 0 /* Not used due to BTFIXUPs */
 static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
+#endif
 
 /* First the functions which the mid-level code uses to directly
  * manipulate the software page tables.  Some defines since we are
@@ -2170,12 +2287,17 @@ static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_AL
 #define PGD_DIRTY    0x040
 #define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
 
+#if 0 /* Not used due to BTFIXUPs */
 static unsigned long sun4c_vmalloc_start(void)
 {
        return SUN4C_VMALLOC_START;
 }
+#endif
 
+#if 0 /* Not used due to BTFIXUPs */
 static int sun4c_pte_none(pte_t pte)           { return !pte_val(pte); }
+#endif
+
 static int sun4c_pte_present(pte_t pte)
 {
        return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);
@@ -2204,35 +2326,47 @@ static void sun4c_pgd_clear(pgd_t * pgdp)       { }
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
+#if 0 /* Not used due to BTFIXUPs */
 static int sun4c_pte_write(pte_t pte)
 {
        return pte_val(pte) & _SUN4C_PAGE_WRITE;
 }
+#endif
 
+#if 0 /* Not used due to BTFIXUPs */
 static int sun4c_pte_dirty(pte_t pte)
 {
        return pte_val(pte) & _SUN4C_PAGE_MODIFIED;
 }
+#endif
 
+#if 0 /* Not used due to BTFIXUPs */
 static int sun4c_pte_young(pte_t pte)
 {
        return pte_val(pte) & _SUN4C_PAGE_ACCESSED;
 }
+#endif
 
+#if 0 /* Not used due to BTFIXUPs */
 static pte_t sun4c_pte_wrprotect(pte_t pte)
 {
        return __pte(pte_val(pte) & ~(_SUN4C_PAGE_WRITE | _SUN4C_PAGE_SILENT_WRITE));
 }
+#endif
 
+#if 0 /* Not used due to BTFIXUPs */
 static pte_t sun4c_pte_mkclean(pte_t pte)
 {
        return __pte(pte_val(pte) & ~(_SUN4C_PAGE_MODIFIED | _SUN4C_PAGE_SILENT_WRITE));
 }
+#endif
 
+#if 0 /* Not used due to BTFIXUPs */
 static pte_t sun4c_pte_mkold(pte_t pte)
 {
        return __pte(pte_val(pte) & ~(_SUN4C_PAGE_ACCESSED | _SUN4C_PAGE_SILENT_READ));
 }
+#endif
 
 static pte_t sun4c_pte_mkwrite(pte_t pte)
 {
@@ -2277,22 +2411,29 @@ static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
        return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
 }
 
+#if 0 /* Not used due to BTFIXUPs */
 static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
 {
        return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) |
                     pgprot_val(newprot));
 }
+#endif
 
 static unsigned long sun4c_pte_page(pte_t pte)
 {
-       return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
+       return (PAGE_OFFSET + ((pte_val(pte) & SUN4C_PFN_MASK) << (PAGE_SHIFT)));
 }
 
-static unsigned long sun4c_pmd_page(pmd_t pmd)
+static inline unsigned long sun4c_pmd_page(pmd_t pmd)
 {
        return (pmd_val(pmd) & PAGE_MASK);
 }
 
+static unsigned long sun4c_pgd_page(pgd_t pgd)
+{
+       return 0;
+}
+
 /* to find an entry in a page-table-directory */
 pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
 {
@@ -2351,6 +2492,16 @@ static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
        return (pte_t *) sun4c_pmd_page(*pmd) + address;
 }
 
+static void sun4c_free_pte_slow(pte_t *pte)
+{
+       free_page((unsigned long)pte);
+}
+
+static void sun4c_free_pgd_slow(pgd_t *pgd)
+{
+       free_page((unsigned long)pgd);
+}
+
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
@@ -2364,16 +2515,73 @@ static pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
        return (pmd_t *) pgd;
 }
 
+extern __inline__ pgd_t *sun4c_get_pgd_fast(void)
+{
+       unsigned long *ret;
+
+       if((ret = pgd_quicklist) != NULL) {
+               pgd_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
+       } else {
+               pgd_t *init;
+               
+               ret = (unsigned long *)__get_free_page(GFP_KERNEL);
+               memset (ret, 0, (KERNBASE / SUN4C_PGDIR_SIZE) * sizeof(pgd_t));
+               init = pgd_offset(&init_mm, 0);
+               memcpy (((pgd_t *)ret) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+       }
+       return (pgd_t *)ret;
+}
+
+static void sun4c_set_pgdir(unsigned long address, pgd_t entry)
+{
+       /* Nothing to do */
+}
+
+extern __inline__ void sun4c_free_pgd_fast(pgd_t *pgd)
+{
+       *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+       pgd_quicklist = (unsigned long *) pgd;
+       pgtable_cache_size++;
+}
+
+extern __inline__ pte_t *sun4c_get_pte_fast(void)
+{
+       unsigned long *ret;
+
+       if((ret = (unsigned long *)pte_quicklist) != NULL) {
+               pte_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
+       }
+       return (pte_t *)ret;
+}
+
+extern __inline__ void sun4c_free_pte_fast(pte_t *pte)
+{
+       *(unsigned long *)pte = (unsigned long) pte_quicklist;
+       pte_quicklist = (unsigned long *) pte;
+       pgtable_cache_size++;
+}
+
 static void sun4c_pte_free(pte_t *pte)
 {
-       free_page((unsigned long) pte);
+       sun4c_free_pte_fast(pte);
 }
 
 static pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
 {
        address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
        if (sun4c_pmd_none(*pmd)) {
-               pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
+               pte_t *page = (pte_t *) sun4c_get_pte_fast();
+               
+               if (page) {
+                       *pmd = __pmd(PGD_TABLE | (unsigned long) page);
+                       return page + address;
+               }
+               page = (pte_t *) get_free_page(GFP_KERNEL);
                if (sun4c_pmd_none(*pmd)) {
                        if (page) {
                                *pmd = __pmd(PGD_TABLE | (unsigned long) page);
@@ -2392,13 +2600,17 @@ static pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
        return (pte_t *) sun4c_pmd_page(*pmd) + address;
 }
 
+static pte_t *sun4c_pte_get(void)
+{
+       return sun4c_get_pte_fast();
+}
+
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
 static void sun4c_pmd_free(pmd_t * pmd)
 {
-       *pmd = __pmd(0);
 }
 
 static pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
@@ -2408,12 +2620,12 @@ static pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
 
 static void sun4c_pgd_free(pgd_t *pgd)
 {
-       free_page((unsigned long) pgd);
+       sun4c_free_pgd_fast(pgd);
 }
 
 static pgd_t *sun4c_pgd_alloc(void)
 {
-       return (pgd_t *) get_free_page(GFP_KERNEL);
+       return sun4c_get_pgd_fast();
 }
 
 /* There are really two cases of aliases to watch out for, and these
@@ -2435,12 +2647,13 @@ 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 dentry *dentry;
+       struct dentry *dentry = NULL;
        struct inode *inode = NULL;
        pgd_t *pgdp;
        pte_t *ptep;
 
-       dentry = vma->vm_dentry;
+       if (vma->vm_file)
+               dentry = vma->vm_file->f_dentry;
        if(dentry)
                inode = dentry->d_inode;
        if(inode) {
@@ -2556,134 +2769,147 @@ __initfunc(unsigned long sun4c_paging_init(unsigned long start_mem, unsigned lon
 /* Load up routines and constants for sun4c mmu */
 __initfunc(void ld_mmu_sun4c(void))
 {
+       extern void ___xchg32_sun4c(void);
+       
        printk("Loading sun4c MMU routines\n");
 
        /* First the constants */
-       pmd_shift = SUN4C_PMD_SHIFT;
-       pmd_size = SUN4C_PMD_SIZE;
-       pmd_mask = SUN4C_PMD_MASK;
-       pgdir_shift = SUN4C_PGDIR_SHIFT;
-       pgdir_size = SUN4C_PGDIR_SIZE;
-       pgdir_mask = SUN4C_PGDIR_MASK;
-
-       ptrs_per_pte = SUN4C_PTRS_PER_PTE;
-       ptrs_per_pmd = SUN4C_PTRS_PER_PMD;
-       ptrs_per_pgd = SUN4C_PTRS_PER_PGD;
-
-       page_none = SUN4C_PAGE_NONE;
-       page_shared = SUN4C_PAGE_SHARED;
-       page_copy = SUN4C_PAGE_COPY;
-       page_readonly = SUN4C_PAGE_READONLY;
-       page_kernel = SUN4C_PAGE_KERNEL;
+       BTFIXUPSET_SIMM13(pmd_shift, SUN4C_PMD_SHIFT);
+       BTFIXUPSET_SETHI(pmd_size, SUN4C_PMD_SIZE);
+       BTFIXUPSET_SETHI(pmd_mask, SUN4C_PMD_MASK);
+       BTFIXUPSET_SIMM13(pgdir_shift, SUN4C_PGDIR_SHIFT);
+       BTFIXUPSET_SETHI(pgdir_size, SUN4C_PGDIR_SIZE);
+       BTFIXUPSET_SETHI(pgdir_mask, SUN4C_PGDIR_MASK);
+
+       BTFIXUPSET_SIMM13(ptrs_per_pte, SUN4C_PTRS_PER_PTE);
+       BTFIXUPSET_SIMM13(ptrs_per_pmd, SUN4C_PTRS_PER_PMD);
+       BTFIXUPSET_SIMM13(ptrs_per_pgd, SUN4C_PTRS_PER_PGD);
+       BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE);
+
+       BTFIXUPSET_INT(page_none, pgprot_val(SUN4C_PAGE_NONE));
+       BTFIXUPSET_INT(page_shared, pgprot_val(SUN4C_PAGE_SHARED));
+       BTFIXUPSET_INT(page_copy, pgprot_val(SUN4C_PAGE_COPY));
+       BTFIXUPSET_INT(page_readonly, pgprot_val(SUN4C_PAGE_READONLY));
+       BTFIXUPSET_INT(page_kernel, pgprot_val(SUN4C_PAGE_KERNEL));
        pg_iobits = _SUN4C_PAGE_PRESENT | _SUN4C_READABLE | _SUN4C_WRITEABLE |
                    _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE;
        
        /* Functions */
-       flush_cache_all = sun4c_flush_cache_all;
+#ifndef __SMP__
+       BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM);
+#endif
+       BTFIXUPSET_CALL(get_pte_fast, sun4c_pte_get, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(get_pgd_fast, sun4c_pgd_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(free_pte_slow, sun4c_free_pte_slow, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(free_pgd_slow, sun4c_free_pgd_slow, BTFIXUPCALL_NORM);
+       
+       BTFIXUPSET_CALL(set_pgdir, sun4c_set_pgdir, BTFIXUPCALL_NOP);
+
+       BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM);
 
        if(sun4c_vacinfo.do_hwflushes) {
-               flush_cache_mm = sun4c_flush_cache_mm_hw;
-               flush_cache_range = sun4c_flush_cache_range_hw;
-               flush_cache_page = sun4c_flush_cache_page_hw;
-               flush_page_to_ram = sun4c_flush_page_to_ram_hw;
-               flush_tlb_mm = sun4c_flush_tlb_mm_hw;
-               flush_tlb_range = sun4c_flush_tlb_range_hw;
-               flush_tlb_page = sun4c_flush_tlb_page_hw;
-               free_task_struct = sun4c_free_task_struct_hw;
-               switch_to_context = sun4c_switch_to_context_hw;
-               destroy_context = sun4c_destroy_context_hw;
-               init_new_context = sun4c_init_new_context_hw;
+               BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_page_to_ram, sun4c_flush_page_to_ram_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(switch_to_context, sun4c_switch_to_context_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_hw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(init_new_context, sun4c_init_new_context_hw, BTFIXUPCALL_NORM);
        } else {
-               flush_cache_mm = sun4c_flush_cache_mm_sw;
-               flush_cache_range = sun4c_flush_cache_range_sw;
-               flush_cache_page = sun4c_flush_cache_page_sw;
-               flush_page_to_ram = sun4c_flush_page_to_ram_sw;
-               flush_tlb_mm = sun4c_flush_tlb_mm_sw;
-               flush_tlb_range = sun4c_flush_tlb_range_sw;
-               flush_tlb_page = sun4c_flush_tlb_page_sw;
-               free_task_struct = sun4c_free_task_struct_sw;
-               switch_to_context = sun4c_switch_to_context_sw;
-               destroy_context = sun4c_destroy_context_sw;
-               init_new_context = sun4c_init_new_context_sw;
-       }
-
-       flush_tlb_all = sun4c_flush_tlb_all;
-
-       flush_sig_insns = sun4c_flush_sig_insns;
-
-       set_pte = sun4c_set_pte;
-       pmd_align = sun4c_pmd_align;
-       pgdir_align = sun4c_pgdir_align;
-       vmalloc_start = sun4c_vmalloc_start;
-
-       pte_page = sun4c_pte_page;
-       pmd_page = sun4c_pmd_page;
-
-       sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir;
-
-       pte_none = sun4c_pte_none;
-       pte_present = sun4c_pte_present;
-       pte_clear = sun4c_pte_clear;
-
-       pmd_none = sun4c_pmd_none;
-       pmd_bad = sun4c_pmd_bad;
-       pmd_present = sun4c_pmd_present;
-       pmd_clear = sun4c_pmd_clear;
-
-       pgd_none = sun4c_pgd_none;
-       pgd_bad = sun4c_pgd_bad;
-       pgd_present = sun4c_pgd_present;
-       pgd_clear = sun4c_pgd_clear;
-
-       mk_pte = sun4c_mk_pte;
-       mk_pte_phys = sun4c_mk_pte_phys;
-       mk_pte_io = sun4c_mk_pte_io;
-       pte_modify = sun4c_pte_modify;
-       pgd_offset = sun4c_pgd_offset;
-       pmd_offset = sun4c_pmd_offset;
-       pte_offset = sun4c_pte_offset;
-       pte_free_kernel = sun4c_pte_free_kernel;
-       pmd_free_kernel = sun4c_pmd_free_kernel;
-       pte_alloc_kernel = sun4c_pte_alloc_kernel;
-       pmd_alloc_kernel = sun4c_pmd_alloc_kernel;
-       pte_free = sun4c_pte_free;
-       pte_alloc = sun4c_pte_alloc;
-       pmd_free = sun4c_pmd_free;
-       pmd_alloc = sun4c_pmd_alloc;
-       pgd_free = sun4c_pgd_free;
-       pgd_alloc = sun4c_pgd_alloc;
-
-       pte_write = sun4c_pte_write;
-       pte_dirty = sun4c_pte_dirty;
-       pte_young = sun4c_pte_young;
-       pte_wrprotect = sun4c_pte_wrprotect;
-       pte_mkclean = sun4c_pte_mkclean;
-       pte_mkold = sun4c_pte_mkold;
-       pte_mkwrite = sun4c_pte_mkwrite;
-       pte_mkdirty = sun4c_pte_mkdirty;
-       pte_mkyoung = sun4c_pte_mkyoung;
-       update_mmu_cache = sun4c_update_mmu_cache;
-
-       mmu_lockarea = sun4c_lockarea;
-       mmu_unlockarea = sun4c_unlockarea;
-
-       mmu_get_scsi_one = sun4c_get_scsi_one;
-       mmu_get_scsi_sgl = sun4c_get_scsi_sgl;
-       mmu_release_scsi_one = sun4c_release_scsi_one;
-       mmu_release_scsi_sgl = sun4c_release_scsi_sgl;
-
-       mmu_map_dma_area = sun4c_map_dma_area;
-
-        mmu_v2p = sun4c_v2p;
-        mmu_p2v = sun4c_p2v;
+               BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_page_to_ram, sun4c_flush_page_to_ram_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(switch_to_context, sun4c_switch_to_context_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_sw, BTFIXUPCALL_NORM);
+               BTFIXUPSET_CALL(init_new_context, sun4c_init_new_context_sw, BTFIXUPCALL_NORM);
+       }
+
+       BTFIXUPSET_CALL(flush_tlb_all, sun4c_flush_tlb_all, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(flush_sig_insns, sun4c_flush_sig_insns, BTFIXUPCALL_NOP);
+
+       BTFIXUPSET_CALL(set_pte, sun4c_set_pte, BTFIXUPCALL_STO1O0);
+
+       BTFIXUPSET_CALL(pte_page, sun4c_pte_page, BTFIXUPCALL_NORM);
+#if PAGE_SHIFT <= 12   
+       BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_ANDNINT(PAGE_SIZE - 1));
+#else
+       BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_NORM);
+#endif
+
+       BTFIXUPSET_CALL(sparc_update_rootmmu_dir, sun4c_update_rootmmu_dir, BTFIXUPCALL_NOP);
+
+       BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0);
+
+       BTFIXUPSET_CALL(pmd_bad, sun4c_pmd_bad, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_present, sun4c_pmd_present, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_clear, sun4c_pmd_clear, BTFIXUPCALL_STG0O0);
+
+       BTFIXUPSET_CALL(pgd_none, sun4c_pgd_none, BTFIXUPCALL_RETINT(0));
+       BTFIXUPSET_CALL(pgd_bad, sun4c_pgd_bad, BTFIXUPCALL_RETINT(0));
+       BTFIXUPSET_CALL(pgd_present, sun4c_pgd_present, BTFIXUPCALL_RETINT(1));
+       BTFIXUPSET_CALL(pgd_clear, sun4c_pgd_clear, BTFIXUPCALL_NOP);
+
+       BTFIXUPSET_CALL(mk_pte, sun4c_mk_pte, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mk_pte_phys, sun4c_mk_pte_phys, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mk_pte_io, sun4c_mk_pte_io, BTFIXUPCALL_NORM);
+       
+       BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK);
+       BTFIXUPSET_CALL(pgd_offset, sun4c_pgd_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_offset, sun4c_pmd_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_offset, sun4c_pte_offset, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_free_kernel, sun4c_pte_free_kernel, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_free_kernel, sun4c_pmd_free_kernel, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(pte_alloc_kernel, sun4c_pte_alloc_kernel, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_alloc_kernel, sun4c_pmd_alloc_kernel, BTFIXUPCALL_RETO0);
+       BTFIXUPSET_CALL(pte_free, sun4c_pte_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_alloc, sun4c_pte_alloc, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pmd_free, sun4c_pmd_free, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(pmd_alloc, sun4c_pmd_alloc, BTFIXUPCALL_RETO0);
+       BTFIXUPSET_CALL(pgd_free, sun4c_pgd_free, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pgd_alloc, sun4c_pgd_alloc, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_HALF(pte_writei, _SUN4C_PAGE_WRITE);
+       BTFIXUPSET_HALF(pte_dirtyi, _SUN4C_PAGE_MODIFIED);
+       BTFIXUPSET_HALF(pte_youngi, _SUN4C_PAGE_ACCESSED);
+       BTFIXUPSET_HALF(pte_wrprotecti, _SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE);
+       BTFIXUPSET_HALF(pte_mkcleani, _SUN4C_PAGE_MODIFIED|_SUN4C_PAGE_SILENT_WRITE);
+       BTFIXUPSET_HALF(pte_mkoldi, _SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_SILENT_READ);
+       BTFIXUPSET_CALL(pte_mkwrite, sun4c_pte_mkwrite, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_mkdirty, sun4c_pte_mkdirty, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(pte_mkyoung, sun4c_pte_mkyoung, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(update_mmu_cache, sun4c_update_mmu_cache, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(mmu_lockarea, sun4c_lockarea, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_unlockarea, sun4c_unlockarea, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(mmu_get_scsi_one, sun4c_get_scsi_one, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_get_scsi_sgl, sun4c_get_scsi_sgl, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_release_scsi_one, sun4c_release_scsi_one, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_release_scsi_sgl, sun4c_release_scsi_sgl, BTFIXUPCALL_NORM);
+
+       BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM);
+
+        BTFIXUPSET_CALL(mmu_v2p, sun4c_v2p, BTFIXUPCALL_NORM);
+        BTFIXUPSET_CALL(mmu_p2v, sun4c_p2v, BTFIXUPCALL_NORM);
        
        /* Task struct and kernel stack allocating/freeing. */
-       alloc_task_struct = sun4c_alloc_task_struct;
+       BTFIXUPSET_CALL(alloc_task_struct, sun4c_alloc_task_struct, BTFIXUPCALL_NORM);
 
-       quick_kernel_fault = sun4c_quick_kernel_fault;
-       mmu_info = sun4c_mmu_info;
+       BTFIXUPSET_CALL(quick_kernel_fault, sun4c_quick_kernel_fault, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(mmu_info, sun4c_mmu_info, BTFIXUPCALL_NORM);
 
        /* These should _never_ get called with two level tables. */
-       pgd_set = 0;
-       pgd_page = 0;
+       BTFIXUPSET_CALL(pgd_set, sun4c_pgd_set, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(pgd_page, sun4c_pgd_page, BTFIXUPCALL_RETO0);
 }
index 7cf925c5456e11479c90d588b2af01de04458d59..731de271ced2c3fccf4a5892c3b767167e466bae 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: turbosparc.S,v 1.2 1997/11/26 13:27:59 jj Exp $
+/* $Id: turbosparc.S,v 1.3 1998/02/05 14:19:04 jj Exp $
  * turbosparc.S: High speed TurboSparc mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -27,6 +27,7 @@
 
        .globl  turbosparc_flush_cache_all
        .globl  turbosparc_flush_sig_insns
+       .globl  turbosparc_flush_page_for_dma
 
 turbosparc_flush_cache_all:
        WINDOW_FLUSH(%g4, %g5)
@@ -42,5 +43,6 @@ turbosparc_flush_cache_all:
         sta    %g0, [%g0] ASI_M_IC_FLCLEAR
 
 turbosparc_flush_sig_insns:
+turbosparc_flush_page_for_dma:
        retl
         nop
index b05b7b416f8edf3ff757b29dbc3dd07e3c584042..c65f72007cef05b9c9e419cec320c63942f0d176 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: viking.S,v 1.6 1997/11/27 15:42:32 jj Exp $
+/* $Id: viking.S,v 1.11 1998/02/20 18:07:50 jj Exp $
  * viking.S: High speed Viking cache/mmu operations
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
  */
 
 #include <asm/ptrace.h>
@@ -13,6 +13,7 @@
 #include <asm/pgtsrmmu.h>
 #include <asm/viking.h>
 #include <asm/cprefix.h>
+#include <asm/btfixup.h>
 
 #define WINDOW_FLUSH(tmp1, tmp2)                                       \
        mov     0, tmp1;                                                \
        .globl  viking_flush_tlb_all, viking_flush_tlb_mm
        .globl  viking_flush_tlb_range, viking_flush_tlb_page
 
-       .globl  viking_c_mxcc_flush_page
-       .globl  viking_c_flush_page, viking_c_flush_chunk
+       .globl  viking_c_flush_chunk, viking_s_flush_chunk
+
+viking_s_flush_chunk:
+       sethi   %hi(KERNBASE), %g2
+       ba      2f
+        sub    %o0, %g2, %g3
 
-viking_c_flush_page:
 viking_c_flush_chunk:
        sethi   %hi(KERNBASE), %g2
        cmp     %o0, %g2
        bgeu    2f
         sub    %o0, %g2, %g3
-       sethi   %hi(C_LABEL(page_contig_offset)), %g2
-       ld      [%g2 + %lo(C_LABEL(page_contig_offset))], %g2
+       sethi   BTFIXUP_SETHI(page_contig_offset), %g2
        ba      2f
         sub    %o0, %g2, %g3
 
 viking_flush_page:
 viking_flush_chunk:
        sethi   %hi(C_LABEL(srmmu_v2p_hash)), %g2
-       or      %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2
        srl     %o0, 24, %o1
+       or      %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2
        sll     %o1, 2, %o1
-
        ld      [%g2 + %o1], %g3
-       cmp     %g3, 0
-       bne     1f
-        and    %o0, PAGE_MASK, %o0
-
-       retl
-        nop
-
-1:
-       ld      [%g3], %o1
-       sub     %o0, %o1, %g2
-       ld      [%g3 + 4], %o0
-       add     %g2, %o0, %g3
+       and     %o0, PAGE_MASK, %o0
+       cmp     %g3, -1
+       be      9f
+        add    %o0, %g3, %g3
 2:     srl     %g3, 12, %g1            ! ppage >> 12
 
        clr     %o1                     ! set counter, 0 - 127
@@ -124,41 +118,22 @@ viking_flush_chunk:
        ble     5b
         clr    %o2
 
-       retl
+9:     retl
         nop
 
-viking_c_mxcc_flush_page:
-       sethi   %hi(KERNBASE), %g2
-       cmp     %o0, %g2
-       bgeu    2f
-        sub    %o0, %g2, %g3
-       sethi   %hi(C_LABEL(page_contig_offset)), %g2
-       ld      [%g2 + %lo(C_LABEL(page_contig_offset))], %g2
-       ba      2f
-        sub    %o0, %g2, %g3
-
 viking_mxcc_flush_page:
        sethi   %hi(C_LABEL(srmmu_v2p_hash)), %g2
-       or      %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2
        srl     %o0, 24, %o1
+       or      %g2, %lo(C_LABEL(srmmu_v2p_hash)), %g2
        sll     %o1, 2, %o1
-
        ld      [%g2 + %o1], %g3
-       cmp     %g3, 0
-       bne     1f
-        and    %o0, PAGE_MASK, %o0
-
-       retl
-        nop
-
-1:
-       ld      [%g3], %o1
-       sub     %o0, %o1, %g2
-       ld      [%g3 + 4], %o0
-       add     %g2, %o0, %g3
+       and     %o0, PAGE_MASK, %o0
+       cmp     %g3, -1
+       be      9f
+        add    %o0, %g3, %g3
 2:     sub     %g3, -PAGE_SIZE, %g3            ! ppage + PAGE_SIZE
-       mov     0x10, %g2                       ! set cacheable bit
        sethi   %hi(MXCC_SRCSTREAM), %o3        ! assume %hi(MXCC_SRCSTREAM) == %hi(MXCC_DESTSTREAM)
+       mov     0x10, %g2                       ! set cacheable bit
        or      %o3, %lo(MXCC_SRCSTREAM), %o2
        or      %o3, %lo(MXCC_DESSTREAM), %o3
        sub     %g3, MXCC_STREAM_SIZE, %g3
@@ -169,7 +144,7 @@ viking_mxcc_flush_page:
        bne     6b
         sub    %g3, MXCC_STREAM_SIZE, %g3
 
-       retl
+9:     retl
         nop
 
 viking_mxcc_flush_chunk:
@@ -212,13 +187,12 @@ viking_flush_tlb_range:
        cmp     %o3, -1
        be      2f
 #endif
-       srl     %o1, SRMMU_PGDIR_SHIFT, %o1
+       sethi   %hi(~((1 << SRMMU_PGDIR_SHIFT) - 1)), %o4
        sta     %o3, [%g1] ASI_M_MMUREGS
-       sll     %o1, SRMMU_PGDIR_SHIFT, %o1
-       sethi   %hi(1 << SRMMU_PGDIR_SHIFT), %o4
+       and     %o1, %o4, %o1
        add     %o1, 0x200, %o1
        sta     %g0, [%o1] ASI_M_FLUSH_PROBE
-1:     add     %o1, %o4, %o1
+1:     sub     %o1, %o4, %o1
        cmp     %o1, %o2
        blu,a   1b
         sta    %g0, [%o1] ASI_M_FLUSH_PROBE
index 9c820a006431f532a677ba10813a9b5d39c5a4c7..917aa9ad72cfc23b3bc5b29fbaf569a1c50ecc7d 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 1995/11/25 00:59:48 davem Exp $
+# $Id: Makefile,v 1.6 1998/01/30 10:58:59 jj Exp $
 # Makefile for the Sun Boot PROM interface library under
 # Linux.
 #
@@ -9,7 +9,11 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 OBJS  = bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
-        palloc.o ranges.o segment.o tree.o console.o printf.o
+       palloc.o ranges.o segment.o console.o printf.o tree.o
+
+ifeq ($(CONFIG_SUN4),y)
+OBJS += sun4prom.o
+endif
 
 all: promlib.a
 
index e7bd9b06d8528db1f4ddb7ba5c6720edf89d51b8..10a603455e3c1bc8c25db4c05c64366b1998f1b5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bootstr.c,v 1.14 1997/06/19 16:28:49 jj Exp $
+/* $Id: bootstr.c,v 1.17 1998/02/09 13:26:21 jj Exp $
  * bootstr.c:  Boot string/argument acquisition from the PROM.
  *
  * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,12 +7,15 @@
 #include <linux/config.h>
 #include <linux/string.h>
 #include <asm/oplib.h>
+#include <asm/sun4prom.h>
 #include <linux/init.h>
 
 #define BARG_LEN  256
-static char barg_buf[BARG_LEN] __initdata = { 0 };
+static char barg_buf[BARG_LEN] = { 0 };
 static char fetched __initdata = 0;
 
+extern linux_sun4_romvec *sun4_romvec;
+
 __initfunc(char *
 prom_getbootargs(void))
 {
@@ -26,6 +29,7 @@ prom_getbootargs(void))
 
        switch(prom_vers) {
        case PROM_V0:
+       case PROM_SUN4:
                cp = barg_buf;
                /* Start from 1 and go over fd(0,0,0)kernel */
                for(iter = 1; iter < 8; iter++) {
index 4c999477bfd812d1c0254fab248d9d1d0c7c4aec..3bbc7ade02a96afd1e8e34983f35cedc6f409b7d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.14 1997/05/14 20:44:58 davem Exp $
+/* $Id: console.c,v 1.17 1998/03/09 14:04:21 jj Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <asm/openprom.h>
+#include <asm/sun4prom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
 #include <linux/string.h>
 
-/* XXX Let's get rid of this thing if we can... */
-extern struct task_struct *current_set[NR_CPUS];
+extern void restore_current(void);
 
 /* Non blocking get character from console input device, returns -1
  * if no input was taken.  This can be used for polling.
@@ -30,6 +30,7 @@ prom_nbgetchar(void)
        save_flags(flags); cli();
        switch(prom_vers) {
        case PROM_V0:
+       case PROM_SUN4:
                i = (*(romvec->pv_nbgetchar))();
                break;
        case PROM_V2:
@@ -45,9 +46,7 @@ prom_nbgetchar(void)
                i = -1;
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
        return i; /* Ugh, we could spin forever on unsupported proms ;( */
 }
@@ -65,6 +64,7 @@ prom_nbputchar(char c)
        save_flags(flags); cli();
        switch(prom_vers) {
        case PROM_V0:
+       case PROM_SUN4:
                i = (*(romvec->pv_nbputchar))(c);
                break;
        case PROM_V2:
@@ -89,9 +89,7 @@ prom_nbputchar(char c)
                i = -1;
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
        return i; /* Ugh, we could spin forever on unsupported proms ;( */
 }
@@ -125,6 +123,7 @@ prom_query_input_device()
        switch(prom_vers) {
        case PROM_V0:
        case PROM_V2:
+       case PROM_SUN4:
        default:
                switch(*romvec->pv_stdin) {
                case PROMDEV_KBD:       return PROMDEV_IKBD;
@@ -136,9 +135,7 @@ prom_query_input_device()
        case PROM_V3:
                save_flags(flags); cli();
                st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
-               __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                                    "r" (&current_set[hard_smp_processor_id()]) :
-                                    "memory");
+               restore_current();
                restore_flags(flags);
                if(prom_node_has_property(st_p, "keyboard"))
                        return PROMDEV_IKBD;
@@ -173,6 +170,7 @@ prom_query_output_device()
 
        switch(prom_vers) {
        case PROM_V0:
+       case PROM_SUN4:
                switch(*romvec->pv_stdin) {
                case PROMDEV_SCREEN:    return PROMDEV_OSCREEN;
                case PROMDEV_TTYA:      return PROMDEV_OTTYA;
@@ -183,9 +181,7 @@ prom_query_output_device()
        case PROM_V3:
                save_flags(flags); cli();
                st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
-               __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                                    "r" (&current_set[hard_smp_processor_id()]) :
-                                    "memory");
+               restore_current();
                restore_flags(flags);
                propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
                if (propl >= 0 && propl == sizeof("display") &&
index cd99ac3d65efb18c721fd9e4560b67fccd251ca5..463b07527acccb53cf962ad12b8070811ebc2334 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: devmap.c,v 1.5 1997/05/14 20:44:59 davem Exp $
+/* $Id: devmap.c,v 1.6 1998/03/09 14:04:23 jj Exp $
  * promdevmap.c:  Map device/IO areas to virtual addresses.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -11,8 +11,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-/* XXX Let's get rid of this thing if we can... */
-extern struct task_struct *current_set[NR_CPUS];
+extern void restore_current(void);
 
 /* Just like the routines in palloc.c, these should not be used
  * by the kernel at all.  Bootloader facility mainly.  And again,
@@ -35,9 +34,7 @@ prom_mapio(char *vhint, int ios, unsigned int paddr, unsigned int num_bytes)
        else
        ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr,
                                                    num_bytes);
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
        return ret;
 }
@@ -51,9 +48,7 @@ prom_unmapio(char *vaddr, unsigned int num_bytes)
        if(num_bytes == 0x0) return;
        save_flags(flags); cli();
        (*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes);
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
        return;
 }
index f7feb0815e7768cf1042ab525f3f1a331dcba53a..c273b9922f1e0ea82efc2287edcbf8bb2ff38964 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: devops.c,v 1.10 1997/05/14 20:44:59 davem Exp $
+/* $Id: devops.c,v 1.11 1998/03/09 14:04:24 jj Exp $
  * devops.c:  Device operations using the PROM.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -10,8 +10,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-/* XXX Let's get rid of this thing if we can... */
-extern struct task_struct *current_set[NR_CPUS];
+extern void restore_current(void);
 
 /* Open the device described by the string 'dstr'.  Returns the handle
  * to that device used for subsequent operations on that device.
@@ -37,9 +36,7 @@ prom_devopen(char *dstr)
                handle = -1;
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
 
        return handle;
@@ -63,9 +60,7 @@ prom_devclose(int dhandle)
        default:
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
        return 0;
 }
@@ -90,9 +85,7 @@ prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
        default:
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
 
        return;
index 6f691464aae1610bde99345c1322fb01af313031..2c70dd95ac5362e1f21b642e1ffb533ce9364730 100644 (file)
@@ -1,8 +1,9 @@
-/* $Id: init.c,v 1.11 1997/03/18 17:58:24 jj Exp $
+/* $Id: init.c,v 1.12 1998/01/30 10:59:02 jj Exp $
  * init.c:  Initialize internal variables used by the PROM
  *          library functions.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/config.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
+#include <asm/sun4prom.h>
 
 struct linux_romvec *romvec;
 enum prom_major_version prom_vers;
 unsigned int prom_rev, prom_prev;
+linux_sun4_romvec *sun4_romvec;
 
 /* The root node of the prom device tree. */
 int prom_root_node;
@@ -34,11 +37,14 @@ extern void prom_ranges_init(void);
 
 __initfunc(void prom_init(struct linux_romvec *rp))
 {
+#ifdef CONFIG_SUN4
+       extern struct linux_romvec *sun4_prom_init(void);
+       rp = sun4_prom_init();
+#endif
 #if CONFIG_AP1000
        extern struct linux_romvec *ap_prom_init(void);
        rp = ap_prom_init();
 #endif
-
        romvec = rp;
 
        switch(romvec->pv_romvers) {
@@ -51,6 +57,9 @@ __initfunc(void prom_init(struct linux_romvec *rp))
        case 3:
                prom_vers = PROM_V3;
                break;
+       case 40:
+               prom_vers = PROM_SUN4;
+               break;
        case 42: /* why not :-) */
                prom_vers = PROM_AP1000;
                break;
@@ -83,8 +92,11 @@ __initfunc(void prom_init(struct linux_romvec *rp))
 
        prom_ranges_init();
 
+#ifndef CONFIG_SUN4
+       /* SUN4 prints this in sun4_prom_init */
        printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
               romvec->pv_romvers, prom_rev);
+#endif
 
        /* Initialization successful. */
        return;
index b53bd17ea664c559b7d2c2a2c08cf2bfa6ff0383..af5019eb88d25ed9b4093d24738a7fa9a7b2af2a 100644 (file)
@@ -1,8 +1,9 @@
-/* $Id: memory.c,v 1.12 1997/05/27 06:45:57 davem Exp $
+/* $Id: memory.c,v 1.13 1998/01/30 10:59:03 jj Exp $
  * memory.c: Prom routine for acquiring various bits of information
  *           about RAM on the machine, both virtual and physical.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
  */
 
 #include <linux/config.h>
@@ -10,6 +11,7 @@
 #include <linux/init.h>
 
 #include <asm/openprom.h>
+#include <asm/sun4prom.h>
 #include <asm/oplib.h>
 
 /* This routine, for consistency, returns the ram parameters in the
@@ -177,6 +179,21 @@ __initfunc(void prom_meminit(void))
                prom_sortmemlist(prom_phys_avail);
                break;
 
+       case PROM_SUN4:
+#ifdef CONFIG_SUN4     
+               /* how simple :) */
+               prom_phys_total[0].start_adr = 0x0;
+               prom_phys_total[0].num_bytes = *(sun4_romvec->memorysize);
+               prom_phys_total[0].theres_more = 0x0;
+               prom_prom_taken[0].start_adr = 0x0; 
+               prom_prom_taken[0].num_bytes = 0x0;
+               prom_prom_taken[0].theres_more = 0x0;
+               prom_phys_avail[0].start_adr = 0x0;
+               prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail);
+               prom_phys_avail[0].theres_more = 0x0;
+#endif
+               break;
+
         case PROM_AP1000:
 #if CONFIG_AP1000
                /* really simple memory map */
@@ -189,9 +206,6 @@ __initfunc(void prom_meminit(void))
                prom_phys_avail[0].start_adr = 0x00000000;
                prom_phys_avail[0].num_bytes = prom_phys_total[0].num_bytes;
                prom_phys_avail[0].theres_more = 0x0;
-               prom_sortmemlist(prom_phys_total);
-               prom_sortmemlist(prom_prom_taken);
-               prom_sortmemlist(prom_phys_avail);
 #endif
        default:
                break;
index fede033ddf19b3d41f419918474e56ff91651277..d2ec600e12950752bec24e02e8d6f223c57a1969 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.15 1997/05/14 20:45:00 davem Exp $
+/* $Id: misc.c,v 1.16 1998/03/09 14:04:25 jj Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -13,8 +13,7 @@
 #include <asm/oplib.h>
 #include <asm/auxio.h>
 
-/* XXX Let's get rid of this thing if we can... */
-extern struct task_struct *current_set[NR_CPUS];
+extern void restore_current(void);
 
 /* Reset and reboot the machine with the command 'bcommand'. */
 void
@@ -24,9 +23,7 @@ prom_reboot(char *bcommand)
        save_flags(flags); cli();
        (*(romvec->pv_reboot))(bcommand);
        /* Never get here. */
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
 }
 
@@ -42,9 +39,7 @@ prom_feval(char *fstring)
                (*(romvec->pv_fortheval.v0_eval))(strlen(fstring), fstring);
        else
                (*(romvec->pv_fortheval.v2_eval))(fstring);
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
 }
 
@@ -74,9 +69,7 @@ prom_cmdline(void)
        install_obp_ticker();
        save_flags(flags); cli();
        (*(romvec->pv_abort))();
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
        install_linux_ticker();
 #ifdef CONFIG_SUN_AUXIO
@@ -99,9 +92,7 @@ again:
        save_flags(flags); cli();
        (*(romvec->pv_halt))();
        /* Never get here. */
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
        goto again; /* PROM is out to get me -DaveM */
 }
index 8f07f9d40502fba554be40ba8724d54cd087e52a..2346e35640ff3dbf46eb095d58025fefe70b4341 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mp.c,v 1.9 1997/05/14 20:45:01 davem Exp $
+/* $Id: mp.c,v 1.10 1998/03/09 14:04:26 jj Exp $
  * mp.c:  OpenBoot Prom Multiprocessor support routines.  Don't call
  *        these on a UP or else you will halt and catch fire. ;)
  *
@@ -12,8 +12,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-/* XXX Let's get rid of this thing if we can... */
-extern struct task_struct *current_set[NR_CPUS];
+extern void restore_current(void);
 
 /* Start cpu with prom-tree node 'cpunode' using context described
  * by 'ctable_reg' in context 'ctx' at program counter 'pc'.
@@ -38,9 +37,7 @@ prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, cha
                ret = (*(romvec->v3_cpustart))(cpunode, (int) ctable_reg, ctx, pc);
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
 
        return ret;
@@ -67,9 +64,7 @@ prom_stopcpu(int cpunode)
                ret = (*(romvec->v3_cpustop))(cpunode);
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
 
        return ret;
@@ -96,9 +91,7 @@ prom_idlecpu(int cpunode)
                ret = (*(romvec->v3_cpuidle))(cpunode);
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
 
        return ret;
@@ -125,9 +118,7 @@ prom_restartcpu(int cpunode)
                ret = (*(romvec->v3_cpuresume))(cpunode);
                break;
        };
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
 
        return ret;
index 7f7b1da543c2e3df4bc30463ba924289dc379cd7..b4fd3989e853c85a7a7196501ce277ce5431dbea 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ranges.c,v 1.10 1997/12/19 12:37:18 jj Exp $
+/* $Id: ranges.c,v 1.11 1998/01/30 10:59:05 jj Exp $
  * ranges.c: Handle ranges in newer proms for obio/sbus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -68,7 +68,7 @@ prom_apply_obio_ranges(struct linux_prom_registers *regs, int nregs)
 void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs,
                            int nregs, struct linux_sbus_device *sdev)
 {
-       if(sbus->num_sbus_ranges) {
+       if(sbus && sbus->num_sbus_ranges) {
                if(sdev && (sdev->ranges_applied == 0)) {
                        sdev->ranges_applied = 1;
                        prom_adjust_regs(regs, nregs, sbus->sbus_ranges,
index 96b543727a9333e63d7a4d9424a82f3edfad4ca6..62b3f85425ecc839d4827c8381b3bab86efc551b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: segment.c,v 1.5 1997/05/14 20:45:02 davem Exp $
+/* $Id: segment.c,v 1.6 1998/03/09 14:04:27 jj Exp $
  * segment.c:  Prom routine to map segments in other contexts before
  *             a standalone is completely mapped.  This is for sun4 and
  *             sun4c architectures only.
@@ -12,8 +12,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-/* XXX Let's get rid of this thing if we can... */
-extern struct task_struct *current_set[NR_CPUS];
+extern void restore_current(void);
 
 /* Set physical segment 'segment' at virtual address 'vaddr' in
  * context 'ctx'.
@@ -24,9 +23,7 @@ prom_putsegment(int ctx, unsigned long vaddr, int segment)
        unsigned long flags;
        save_flags(flags); cli();
        (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment);
-       __asm__ __volatile__("ld [%0], %%g6\n\t" : :
-                            "r" (&current_set[hard_smp_processor_id()]) :
-                            "memory");
+       restore_current();
        restore_flags(flags);
        return;
 }
diff --git a/arch/sparc/prom/sun4prom.c b/arch/sparc/prom/sun4prom.c
new file mode 100644 (file)
index 0000000..ce15ebb
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1996 The Australian National University.
+ * Copyright (C) 1996 Fujitsu Laboratories Limited
+ * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
+ * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * 
+ * This software may be distributed under the terms of the Gnu
+ * Public License version 2 or later
+ *
+ * fake a really simple Sun prom for the SUN4
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/oplib.h>
+#include <asm/idprom.h> 
+#include <asm/machines.h> 
+#include <asm/sun4prom.h>
+#include <asm/asi.h>
+#include <asm/contregs.h>
+#include <linux/init.h>
+
+static struct linux_romvec sun4romvec;
+static struct idprom sun4_idprom;
+
+struct property {
+       char *name;
+       char *value;
+       int length;
+};
+
+struct node {
+       int level;
+       struct property *properties;
+};
+
+struct property null_properties = { NULL, NULL, -1 };
+
+struct property root_properties[] = {
+       {"device_type", "cpu", 4},
+       {"idprom", (char *)&sun4_idprom, sizeof(struct idprom)},
+       {NULL, NULL, -1}
+};
+
+struct node nodes[] = {
+       { 0, &null_properties }, 
+       { 0, root_properties },
+       { -1,&null_properties }
+};
+
+
+static int no_nextnode(int node)
+{
+       if (nodes[node].level == nodes[node+1].level)
+               return node+1;
+       return -1;
+}
+
+static int no_child(int node)
+{
+       if (nodes[node].level == nodes[node+1].level-1)
+               return node+1;
+       return -1;
+}
+
+static struct property *find_property(int node,char *name)
+{
+       struct property *prop = &nodes[node].properties[0];
+       while (prop && prop->name) {
+               if (strcmp(prop->name,name) == 0) return prop;
+               prop++;
+       }
+       return NULL;
+}
+
+static int no_proplen(int node,char *name)
+{
+       struct property *prop = find_property(node,name);
+       if (prop) return prop->length;
+       return -1;
+}
+
+static int no_getprop(int node,char *name,char *value)
+{
+       struct property *prop = find_property(node,name);
+       if (prop) {
+               memcpy(value,prop->value,prop->length);
+               return 1;
+       }
+       return -1;
+}
+
+static int no_setprop(int node,char *name,char *value,int len)
+{
+       return -1;
+}
+
+static char *no_nextprop(int node,char *name)
+{
+       struct property *prop = find_property(node,name);
+       if (prop) return prop[1].name;
+       return NULL;
+}
+
+static struct linux_nodeops sun4_nodeops = {
+       no_nextnode,
+       no_child,
+       no_proplen,
+       no_getprop,
+       no_setprop,
+       no_nextprop
+};
+       
+static int synch_hook;
+
+__initfunc(struct linux_romvec *sun4_prom_init(void))
+{
+       int i;
+       unsigned char x;
+       char *p;
+                                
+       p = (char *)&sun4_idprom;
+       for (i = 0; i < sizeof(sun4_idprom); i++) {
+               __asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) :
+                                     "r" (AC_IDPROM + i), "i" (ASI_CONTROL));
+               *p++ = x;
+       }
+
+       memset(&sun4romvec,0,sizeof(sun4romvec));
+
+       sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR;
+
+       sun4romvec.pv_romvers = 40;
+       sun4romvec.pv_nodeops = &sun4_nodeops;
+       sun4romvec.pv_reboot = sun4_romvec->reboot;
+       sun4romvec.pv_abort = sun4_romvec->abortentry;
+       sun4romvec.pv_halt = sun4_romvec->exittomon;
+       sun4romvec.pv_synchook = (void (**)(void))&synch_hook;
+       sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap;
+       sun4romvec.pv_v0bootargs = sun4_romvec->bootParam;
+       sun4romvec.pv_nbgetchar = sun4_romvec->mayget;
+       sun4romvec.pv_nbputchar = sun4_romvec->mayput;
+       sun4romvec.pv_stdin = sun4_romvec->insource;
+       sun4romvec.pv_stdout = sun4_romvec->outsink;
+       
+       /*
+        * We turn on the LEDs to let folks without monitors or
+        * terminals know we booted.   Nothing too fancy now.  They
+        * are all on, except for LED 5, which blinks.   When we
+        * have more time, we can teach the penguin to say "By your
+        * command" or "Activating turbo boost, Michael". :-)
+        */
+       sun4_romvec->setLEDs(0x0);
+       
+       printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n",
+               sun4_romvec->monid,
+               sun4_romvec->romvecversion);
+
+       return &sun4romvec;
+}
index 616180e81ee6424657bad50e36e7bbb214196f77..1256aacecc37763ae449b03b18ec65ae311ee97f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.22 1997/09/25 02:19:22 davem Exp $
+/* $Id: tree.c,v 1.24 1998/03/09 14:04:29 jj Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-/* XXX Let's get rid of this thing if we can... */
-extern struct task_struct *current_set[NR_CPUS];
-
-/* Macro to restore "current" to the g6 register. */
-#define restore_current() __asm__ __volatile__("ld [%0], %%g6\n\t" : : \
-                         "r" (&current_set[hard_smp_processor_id()]) : \
-                         "memory")
+extern void restore_current(void);
 
 static char promlib_buf[128];
 
@@ -95,12 +89,11 @@ int prom_getproplen(int node, char *prop)
        int ret;
        unsigned long flags;
 
-       save_flags(flags); cli();
-
        if((!node) || (!prop))
-               ret = -1;
-       else
-               ret = prom_nodeops->no_proplen(node, prop);
+               return -1;
+               
+       save_flags(flags); cli();
+       ret = prom_nodeops->no_proplen(node, prop);
        restore_current();
        restore_flags(flags);
        return ret;
@@ -115,15 +108,12 @@ int prom_getproperty(int node, char *prop, char *buffer, int bufsize)
        int plen, ret;
        unsigned long flags;
 
-       save_flags(flags); cli();
-
        plen = prom_getproplen(node, prop);
        if((plen > bufsize) || (plen == 0) || (plen == -1))
-               ret = -1;
-       else {
-               /* Ok, things seem all right. */
-               ret = prom_nodeops->no_getprop(node, prop, buffer);
-       }
+               return -1;
+       /* Ok, things seem all right. */
+       save_flags(flags); cli();
+       ret = prom_nodeops->no_getprop(node, prop, buffer);
        restore_current();
        restore_flags(flags);
        return ret;
index 8141f5755f8cf8219086a0883a406ef05373b192..cbfc9fb3c3db10204dc778e2e82d2ecca2983deb 100644 (file)
@@ -32,6 +32,7 @@ SECTIONS
   . = ALIGN(4096);
   __init_begin = .;
   .text.init : { *(.text.init) }
+  __init_text_end = .;
   .data.init : { *(.data.init) }
   . = ALIGN(4096);
   __init_end = .;
index 9e8b0b862ac79cadb6b38a2cba90fae9db45f3b3..e004359c37f39fdf021017e144a9beb8ab951cfc 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.24 1997/10/02 16:31:16 jj Exp $
+# $Id: Makefile,v 1.25 1998/04/06 16:10:31 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -38,9 +38,7 @@ ifneq ($(CONFIG_SOLARIS_EMUL),n)
   SUBDIRS += arch/sparc64/solaris
 endif
 
-ifneq ($(CONFIG_MATHEMU),n)
-  SUBDIRS += arch/sparc64/math-emu
-endif
+SUBDIRS += arch/sparc64/math-emu
 
 CORE_FILES := arch/sparc64/kernel/kernel.o arch/sparc64/mm/mm.o $(CORE_FILES)
 
@@ -48,9 +46,7 @@ ifeq ($(CONFIG_SOLARIS_EMUL),y)
   CORE_FILES += arch/sparc64/solaris/solaris.o
 endif
 
-ifeq ($(CONFIG_MATHEMU),y)
-  CORE_FILES += arch/sparc64/math-emu/math-emu.o
-endif
+CORE_FILES += arch/sparc64/math-emu/math-emu.o
 
 LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \
        $(TOPDIR)/arch/sparc64/lib/lib.a
index 4af9da2e5f70eb12ee3b79b31b3e6d5ded9c18bb..8cd86f9db8258addb816ed60b1453b46d9a350ee 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.36 1998/01/10 19:04:30 ecd Exp $
+# $Id: config.in,v 1.44 1998/04/06 16:10:35 jj Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -67,9 +67,6 @@ fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL
 fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel Quad FPU (long double) and subnormal float/double emulation' CONFIG_MATHEMU
-fi
 endmenu
 
 if [ "$CONFIG_PCI" = "y" ]; then
@@ -84,6 +81,7 @@ if [ "$CONFIG_PCI" = "y" ]; then
       bool '    Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
     fi
   fi
+  tristate 'SUNW,envctrl support' CONFIG_ENVCTRL
 fi
 
 mainmenu_option next_comment
@@ -109,14 +107,16 @@ tristate 'Network block device support' CONFIG_BLK_DEV_NBD
 
 if [ "$CONFIG_PCI" = "y" ]; then
        tristate 'Ultra/PCI IDE disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
-       if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
+       if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
          dep_tristate '   Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
          dep_tristate '   Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
          dep_tristate '   Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
          dep_tristate '   Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
          dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
-         define_bool CONFIG_IDE_CHIPSETS y
-         define_bool CONFIG_BLK_DEV_NS87415_AX y
+         define_bool CONFIG_BLK_DEV_IDEPCI y
+         define_bool CONFIG_BLK_DEV_IDEDMA y
+         define_bool CONFIG_BLK_DEV_NS87415 y
+         define_bool CONFIG_BLK_DEV_CMD646 y
        fi
 fi
 
index 740fd68e31dbb764d8b836ebc8c36f26da973583..0a76f100f33bcd8909d6fbe5fb0754f590656f90 100644 (file)
@@ -25,12 +25,12 @@ CONFIG_SBUSCHAR=y
 CONFIG_SUN_MOUSE=y
 CONFIG_SERIAL=y
 CONFIG_SUN_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
 CONFIG_SUN_KEYBOARD=y
 CONFIG_SUN_CONSOLE=y
 CONFIG_SUN_AUXIO=y
 CONFIG_SUN_IO=y
 CONFIG_PCI=y
-CONFIG_PCI_OLD_PROC=y
 
 #
 # SBUS Frame Buffer support
@@ -52,10 +52,11 @@ SUN_FB_CREATOR=y
 CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
 CONFIG_SAB82532=y
-# CONFIG_OBP_FLASH is not set
+CONFIG_OBP_FLASH=m
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
 CONFIG_SUN_OPENPROMFS=m
+CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
@@ -67,11 +68,12 @@ CONFIG_BINFMT_AOUT32=y
 CONFIG_BINFMT_MISC=m
 CONFIG_BINFMT_JAVA=m
 CONFIG_SOLARIS_EMUL=m
-CONFIG_MATHEMU=m
 CONFIG_PARPORT=y
 CONFIG_PARPORT_AX=y
+# CONFIG_PARPORT_OTHER is not set
 CONFIG_PRINTER=y
 CONFIG_PRINTER_READBACK=y
+CONFIG_ENVCTRL=y
 
 #
 # Floppy, IDE, and other block devices
@@ -92,8 +94,10 @@ CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=m
 # CONFIG_BLK_DEV_IDESCSI is not set
-CONFIG_IDE_CHIPSETS=y
-CONFIG_BLK_DEV_NS87415_AX=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_BLK_DEV_NS87415=y
+CONFIG_BLK_DEV_CMD646=y
 
 #
 # Networking options
@@ -101,18 +105,18 @@ CONFIG_BLK_DEV_NS87415_AX=y
 CONFIG_PACKET=y
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
+CONFIG_NET_ALIAS=y
+# CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
 # CONFIG_IP_ACCT is not set
-# CONFIG_IP_MASQUERADE is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
+CONFIG_IP_ALIAS=y
 # CONFIG_SYN_COOKIES is not set
 
 #
@@ -123,30 +127,34 @@ CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 CONFIG_IPV6=m
 # CONFIG_IPV6_EUI64 is not set
-# CONFIG_IPV6_NO_PB is not set
 
 #
 #  
 #
 CONFIG_IPX=m
+
+#
+# IPX options
+#
 # CONFIG_IPX_INTERN is not set
 CONFIG_ATALK=m
-# CONFIG_AX25 is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_CBQ=y
 CONFIG_NET_SCH_CSZ=y
-CONFIG_NET_SCH_HFQ=y
 CONFIG_NET_SCH_RED=y
 CONFIG_NET_SCH_SFQ=y
 CONFIG_NET_SCH_TBF=y
 CONFIG_NET_SCH_PFIFO=y
 CONFIG_NET_SCH_PRIO=y
+# CONFIG_NET_PROFILE is not set
 
 #
 # SCSI support
@@ -186,6 +194,21 @@ CONFIG_SCSI_NCR53C8XX_MAX_TAGS=12
 CONFIG_SCSI_NCR53C8XX_SYNC=10
 # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 
+#
+# Fibre Channel support
+#
+CONFIG_FC4=m
+
+#
+# FC4 drivers
+#
+CONFIG_FC4_SOC=m
+
+#
+# FC4 targets
+#
+CONFIG_SCSI_PLUTO=m
+
 #
 # Network device support
 #
@@ -227,21 +250,31 @@ CONFIG_LOCKD=y
 CONFIG_SMB_FS=m
 CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
 CONFIG_HPFS_FS=m
+# CONFIG_NTFS_FS is not set
 CONFIG_SYSV_FS=m
 CONFIG_AFFS_FS=m
+# CONFIG_HFS_FS is not set
 CONFIG_ROMFS_FS=m
 CONFIG_AUTOFS_FS=m
 CONFIG_AMIGA_PARTITION=y
 CONFIG_UFS_FS=m
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
+CONFIG_SOLARIS_X86_PARTITION=y
+# CONFIG_ADFS_FS is not set
 # CONFIG_MAC_PARTITION is not set
+CONFIG_NLS=y
 
 #
 # Native Language Support
 #
-CONFIG_NLS=y
 # CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
index 7889c84a4ecf2d41ef7b70e97bed9cf5e3375370..1c3f459bc5c201bb9d70540ab913dff531599a5a 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.35 1997/09/20 21:48:58 davem Exp $
+# $Id: Makefile,v 1.36 1998/02/01 11:15:55 ecd Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -61,13 +61,24 @@ head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
 binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
 
 check_asm: dummy
+       @echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
+       @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
+       @echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#ifndef __SMP__" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
        @echo "#include <linux/sched.h>" > tmp.c
        $(CC) -E tmp.c -o tmp.i
-       @echo "/* Automatically generated. Do not edit. */" > check_asm.c; echo "#include <linux/sched.h>" >> check_asm.c; echo 'struct task_struct _task; struct mm_struct _mm; struct thread_struct _thread; int main(void) { printf ("/* Automatically generated. Do not edit. */\n#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n\n");' >> check_asm.c
+       @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/sched.h>" >> check_asm.c
+       @echo 'struct task_struct _task;' >> check_asm.c
+       @echo 'struct mm_struct _mm;' >> check_asm.c
+       @echo 'struct thread_struct _thread;' >> check_asm.c
+       @echo 'int main(void) {' >> check_asm.c
        $(SH) ./check_asm.sh task tmp.i check_asm.c
        $(SH) ./check_asm.sh mm tmp.i check_asm.c
        $(SH) ./check_asm.sh thread tmp.i check_asm.c
-       @echo 'printf ("\n#endif /* __ASM_OFFSETS_H__ */\n"); return 0; }' >> check_asm.c
+       @echo 'return 0; }' >> check_asm.c
        @rm -f tmp.[ci]
        #$(CC) -o check_asm check_asm.c
        # <hack> Until we can do this natively, a hack has to take place
@@ -75,9 +86,46 @@ check_asm: dummy
        $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
        @rm -f check_asm.s
        # </hack>
-       ./check_asm > asm_offsets.h
-       @if test -r $(HPATH)/asm/asm_offsets.h; then if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then echo $(HPATH)/asm/asm_offsets.h is unchanged; rm -f asm_offsets.h; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi
+       ./check_asm >> asm_offsets.h
        @rm -f check_asm check_asm.c
+       @echo "" >> asm_offsets.h
+       @echo "#else /* __SMP__ */" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#include <linux/sched.h>" > tmp.c
+       $(CC) -D__SMP__ -E tmp.c -o tmp.i
+       @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+       @echo "#include <linux/sched.h>" >> check_asm.c
+       @echo 'struct task_struct _task;' >> check_asm.c
+       @echo 'struct mm_struct _mm;' >> check_asm.c
+       @echo 'struct thread_struct _thread;' >> check_asm.c
+       @echo 'int main(void) {' >> check_asm.c
+       $(SH) ./check_asm.sh task tmp.i check_asm.c
+       $(SH) ./check_asm.sh mm tmp.i check_asm.c
+       $(SH) ./check_asm.sh thread tmp.i check_asm.c
+       @echo 'return 0; }' >> check_asm.c
+       @rm -f tmp.[ci]
+       #$(CC) -D__SMP__ -o check_asm check_asm.c
+       # <hack> Until we can do this natively, a hack has to take place
+       $(CC) -D__SMP__ -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c
+       $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
+       @rm -f check_asm.s
+       # </hack>
+       ./check_asm >> asm_offsets.h
+       @rm -f check_asm check_asm.c
+       @echo "" >> asm_offsets.h
+       @echo "#endif /* __SMP__ */" >> asm_offsets.h
+       @echo "" >> asm_offsets.h
+       @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
+       @if test -r $(HPATH)/asm/asm_offsets.h; then \
+         if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \
+           echo $(HPATH)/asm/asm_offsets.h is unchanged; \
+           rm -f asm_offsets.h; \
+         else \
+           mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
+         fi; \
+       else \
+         mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
+       fi
 
 
 include $(TOPDIR)/Rules.make
index 55ccbc2033d4df90aeaa7853be41f26babda5fc9..b0dd675b05b011d9b4d214abc38e6b7952bb20a8 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
+#include <linux/file.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/malloc.h>
@@ -257,7 +258,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
        unsigned long p = bprm->p;
        unsigned long fd_offset;
        unsigned long rlim;
-int retval;
+       int retval;
 
        ex = *((struct exec *) bprm->buf);              /* exec-header */
        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
@@ -326,10 +327,10 @@ int retval;
                        printk(KERN_NOTICE "executable not page aligned\n");
 
                fd = open_dentry(bprm->dentry, O_RDONLY);
-
                if (fd < 0)
                        return fd;
-               file = current->files->fd[fd];
+               file = fcheck(fd);
+
                if (!file->f_op || !file->f_op->mmap) {
                        sys_close(fd);
                        do_mmap(NULL, 0, ex.a_text+ex.a_data,
@@ -397,6 +398,7 @@ load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        return retval;
 }
 
+/* N.B. Move to .h file and use code in fs/binfmt_aout.c? */
 static inline int
 do_load_aout32_library(int fd)
 {
@@ -409,7 +411,7 @@ do_load_aout32_library(int fd)
        unsigned int start_addr;
        unsigned long error;
 
-       file = current->files->fd[fd];
+       file = fcheck(fd);
 
        if (!file || !file->f_op)
                return -EACCES;
index 817a8ecd304632eaa8d9d241c697e13d24e0efbc..a54e89f2daf94c2a24020ae423cbb9994df517a5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: central.c,v 1.4 1997/08/19 14:17:49 jj Exp $
+/* $Id: central.c,v 1.5 1998/02/12 15:57:59 jj Exp $
  * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -35,22 +35,18 @@ unsigned long central_probe(unsigned long memory_start)
                printk("no central found.\n");
                return memory_start;
        }
-       prom_printf("CENTRAL: found central PROM node.\n");
        printk("found central PROM node.\n");
 
        /* Ok we got one, grab some memory for software state. */
        memory_start = long_align(memory_start);
        central_bus = (struct linux_central *) (memory_start);
 
-       prom_printf("CENTRAL: central_bus[%p] ", central_bus);
        memory_start += sizeof(struct linux_central);
        memory_start = long_align(memory_start);
        fhc = (struct linux_fhc *)(memory_start);
        memory_start += sizeof(struct linux_fhc);
        memory_start = long_align(memory_start);
 
-       prom_printf("fhc[%p] ", fhc);
-
        /* First init central. */
        central_bus->child = fhc;
        central_bus->prom_node = cnode;
@@ -58,7 +54,6 @@ unsigned long central_probe(unsigned long memory_start)
        prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
        strcpy(central_bus->prom_name, namebuf);
 
-       prom_printf("init_central_ranges ");
        prom_central_ranges_init(cnode, central_bus);
 
        /* And then central's FHC. */
@@ -73,27 +68,15 @@ unsigned long central_probe(unsigned long memory_start)
        prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
        strcpy(fhc->prom_name, namebuf);
 
-       prom_printf("cnode[%x] fnode[%x] init_fhc_ranges\n", cnode, fnode);
        prom_fhc_ranges_init(fnode, fhc);
 
-       /* Finally, map in FHC register set.  (From the prtconf dumps
-        * I have seen on Ex000 boxes only the central ranges need to
-        * be applied to the fhc internal register set) -DaveM
-        */
-       err = prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs));
-       if(err == -1) {
+       /* Finally, map in FHC register set. */
+       if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) {
                prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n");
                prom_halt();
        }
        prom_apply_central_ranges(central_bus, &fpregs[0], 6);
-       prom_printf("CENTRAL: FHC_REGS[(%08x,%08x) (%08x,%08x) "
-                   "(%08x,%08x) (%08x,%08x) (%08x,%08x) (%08x,%08x)]\n",
-                   fpregs[0].which_io, fpregs[0].phys_addr,
-                   fpregs[1].which_io, fpregs[1].phys_addr,
-                   fpregs[2].which_io, fpregs[2].phys_addr,
-                   fpregs[3].which_io, fpregs[3].phys_addr,
-                   fpregs[4].which_io, fpregs[4].phys_addr,
-                   fpregs[5].which_io, fpregs[5].phys_addr);
+       
        fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
                __va((((unsigned long)fpregs[0].which_io)<<32) |
                     (((unsigned long)fpregs[0].phys_addr)));
@@ -112,14 +95,8 @@ unsigned long central_probe(unsigned long memory_start)
        fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
                __va((((unsigned long)fpregs[5].which_io)<<32) |
                     (((unsigned long)fpregs[5].phys_addr)));
-       prom_printf("CENTRAL: FHC_REGS[%p %p %p %p %p %p]\n",
-                   fhc->fhc_regs.pregs, fhc->fhc_regs.ireg,
-                   fhc->fhc_regs.ffregs, fhc->fhc_regs.sregs,
-                   fhc->fhc_regs.uregs, fhc->fhc_regs.tregs);
 
-       prom_printf("CENTRAL: reading FHC_ID register... ");
        err = fhc->fhc_regs.pregs->fhc_id;
-       prom_printf("VALUE[%x]\n", err);
        printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n",
               ((err & FHC_ID_VERS) >> 28),
               ((err & FHC_ID_PARTID) >> 12),
index d009f39d8051554452a493535a8745edcc48e532..86efc4bb7dd20180650a7131594b2702e132b30b 100644 (file)
@@ -32,7 +32,8 @@ struct cpu_fp_info linux_sparc_fpu[] = {
   { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
   { 0x22, 0x10, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
-  { 0x17, 0x12, 0, "UltraSparc III integrated FPU"},
+  { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
+  { 0x17, 0x13, 0, "UltraSparc III integrated FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -41,7 +42,8 @@ struct cpu_iu_info linux_sparc_chips[] = {
   { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
   { 0x22, 0x10, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
-  { 0x17, 0x12, "TI UltraSparc III (Cheetah)"},  /* A guess... */
+  { 0x17, 0x12, "TI UltraSparc IIi"},
+  { 0x17, 0x13, "TI UltraSparc III (Cheetah)"},  /* A guess... */
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
index 24ca3ff100ac65021fc64e57a92c3ddbb73ae157..8d3aca325f5d9ca1cab071a08a67f81a929255cc 100644 (file)
@@ -13,7 +13,8 @@
 #include <asm/system.h>
 #include <asm/smp.h>
 
-struct prom_cpuinfo linux_cpus[NR_CPUS];
+struct prom_cpuinfo linux_cpus[NR_CPUS] __initdata = { { 0 } };
+unsigned prom_cpu_nodes[NR_CPUS];
 int linux_num_cpus = 0;
 
 extern void cpu_probe(void);
@@ -64,6 +65,8 @@ device_scan(unsigned long mem_start))
        prom_node_cpu = cpu_nds[0];
 
        linux_num_cpus = cpu_ctr;
+       
+       prom_cpu_nodes[0] = prom_node_cpu;
 
        cpu_probe();
        return central_probe(mem_start);
index 4d71d967c83b73e1b194284cac6c27250b6ab19d..e5606cf33a6c3b3c9f929ef18722c05edc43ef0d 100644 (file)
@@ -1,9 +1,9 @@
-/* $Id: dtlb_miss.S,v 1.14 1997/10/14 01:48:28 davem Exp $
+/* $Id: dtlb_miss.S,v 1.15 1998/01/14 17:14:44 jj Exp $
  * dtlb_miss.S:        Data TLB miss code, this is included directly
  *              into the trap table.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 /* The basic algorithm is:
 
 #define KERN_HIGHBITS  ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
 #define KERN_LOWBITS   (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#define KERN_LOWBITS_IO        ((_PAGE_E | _PAGE_P | _PAGE_W) ^ KERN_LOWBITS)
+#define KERN_LOWBITS_IO        (_PAGE_E | _PAGE_P | _PAGE_W)
 
                                /* ICACHE line 1 */
   /*0x00*/     ldxa            [%g0] ASI_DMMU, %g1             ! Get TAG_TARGET
-  /*0x04*/     srlx            %g1, 8, %g3                     ! Position PGD offset
-  /*0x08*/     srlx            %g1, 48, %g5                    ! Shift down CONTEXT bits
-  /*0x0c*/     and             %g3, %g2, %g3                   ! Mask PGD offset
-  /*0x10*/     sllx            %g1, 2, %g4                     ! Position PMD offset
-  /*0x14*/     brz,pn          %g5, 3f                         ! Context 0 == kernel
-  /*0x18*/      and            %g4, %g2, %g4                   ! Mask PMD offset
+  /*0x04*/     srlx            %g1, 10, %g3                    ! Position PGD offset
+  /*0x08*/     andcc           %g1, %g2, %g0                   ! Test CONTEXT bits
+  /*0x0c*/     and             %g3, 0xffc, %g3                 ! Mask PGD offset
+  /*0x18*/     and             %g1, 0xffe, %g4                 ! Mask PMD offset
+  /*0x14*/     be,pn           %xcc, 3f                        ! Context 0 == kernel
+  /*0x10*/      add            %g4, %g4, %g4                   ! Position PMD offset
   /*0x1c*/     ldxa            [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
 
                                /* ICACHE line 2 */
-  /*0x20*/     ldxa            [%g7 + %g3] ASI_PHYS_USE_EC, %g5        ! Load PGD
+  /*0x20*/     lduwa           [%g7 + %g3] ASI_PHYS_USE_EC, %g5        ! Load PGD
   /*0x24*/     srlx            %g1, 1, %g1                             ! PTE offset
-2:/*0x28*/     ldxa            [%g5 + %g4] ASI_PHYS_USE_EC, %g3        ! Load PMD
+2:/*0x28*/     lduwa           [%g5 + %g4] ASI_PHYS_USE_EC, %g3        ! Load PMD
   /*0x2c*/     ldxa            [%g3 + %g1] ASI_PHYS_USE_EC, %g5        ! Load PTE
   /*0x30*/     brgez,pn        %g5, sparc64_dtlb_refbit_catch          ! Valid set?
   /*0x34*/      nop                                                    ! delay
 3:                             /* ICACHE line 3 */
   /*0x40*/     sllx            %g1, 22, %g5                    ! This is now physical page + PAGE_OFFSET
   /*0x44*/     brgez,pn        %g5, 4f                         ! If >= 0, then walk down page tables
-  /*0x48*/      sethi          %uhi(KERN_HIGHBITS), %g1        ! Construct PTE ^ PAGE_OFFSET
-  /*0x4c*/     andcc           %g3, 0x400, %g0                 ! Slick trick...
-  /*0x50*/     sllx            %g1, 32, %g1                    ! Move high bits up
-  /*0x54*/     or              %g1, (KERN_LOWBITS), %g1        ! Assume not IO
-  /*0x58*/     bne,a,pn        %icc, 5f                        ! Is it an IO page?
-  /*0x5c*/      xor            %g1, (KERN_LOWBITS_IO), %g1     ! Aha, it is IO...
+  /*0x48*/      or             %g2, (KERN_LOWBITS), %g1        ! Construct PTE ^ PAGE_OFFSET
+  /*0x4c*/     andcc           %g3, 0x100, %g0                 ! Slick trick...
+  /*0x50*/     bne,a,pn        %icc, 5f                        ! Is it an IO page?
+  /*0x54*/      or             %g2, (KERN_LOWBITS_IO), %g1     ! Aha, it is IO...
+5:/*0x58*/     xor             %g1, %g5, %g1                   ! Slick trick II...
+  /*0x5c*/     stxa            %g1, [%g0] ASI_DTLB_DATA_IN     ! TLB load
 
                                /* ICACHE line 4 */
-5:/*0x60*/     xor             %g1, %g5, %g1                   ! Slick trick II...
-  /*0x64*/     stxa            %g1, [%g0] ASI_DTLB_DATA_IN     ! TLB load
-  /*0x68*/     retry                                           ! Trap return
-4:/*0x6c*/     ldxa            [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
-  /*0x70*/     ldxa            [%g6 + %g3] ASI_PHYS_USE_EC, %g5        ! Load kern PGD
-  /*0x74*/     ba,pt           %xcc, 2b                        ! Go back up top
-  /*0x78*/      srlx           %g1, 1, %g1
-  /*0x7c*/     nop
+  /*0x60*/     retry                                           ! Trap return
+  /*0x64*/     nop
+  /*0x68*/     nop
+  /*0x6c*/     nop
+4:/*0x70*/     ldxa            [%g0] ASI_DMMU_TSB_8KB_PTR, %g1         ! For PTE offset
+  /*0x74*/     lduwa           [%g6 + %g3] ASI_PHYS_USE_EC, %g5        ! Load kern PGD
+  /*0x78*/     ba,pt           %xcc, 2b                                ! Go back up top
+  /*0x7c*/      srlx           %g1, 1, %g1
 
 #undef KERN_HIGHBITS
 #undef KERN_LOWBITS
index 55e86c887a677c00008af7bb9e15fb29305e701b..86cbfdc52b72b8cc5e6d6138969c0f86d90773b9 100644 (file)
@@ -1,9 +1,9 @@
-/* $Id: dtlb_prot.S,v 1.14 1997/08/03 09:07:00 davem Exp $
+/* $Id: dtlb_prot.S,v 1.15 1998/01/14 17:14:46 jj Exp $
  * dtlb_prot.S:        Data TLB protection code, this is included directly
  *              into the trap table.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
        /* We know kernel never takes protection trap,
 
                                /* ICACHE line 1 */
   /*0x00*/     ldxa            [%g0] ASI_DMMU, %g1             ! Get TAG_TARGET
-  /*0x04*/     srlx            %g1, 8, %g3                     ! Position PGD offset
-  /*0x08*/     sllx            %g1, 2, %g4                     ! Position PMD offset
-  /*0x0c*/     and             %g3, %g2, %g3                   ! Mask PGD offset
-  /*0x10*/     and             %g4, %g2, %g4                   ! Mask PMD offset
-  /*0x14*/     ldxa            [%g7 + %g3] ASI_PHYS_USE_EC, %g5        ! Load PGD
-  /*0x18*/     ldxa            [%g5 + %g4] ASI_PHYS_USE_EC, %g4        ! Load PMD
+  /*0x04*/     srlx            %g1, 10, %g3                    ! Position PGD offset
+  /*0x08*/     and             %g1, 0xffe, %g4                 ! Mask PMD offset
+  /*0x0c*/     and             %g3, 0xffc, %g3                 ! Mask PGD offset
+  /*0x10*/     add             %g4, %g4, %g4                   ! Position PMD offset
+  /*0x14*/     lduwa           [%g7 + %g3] ASI_PHYS_USE_EC, %g5        ! Load PGD
+  /*0x18*/     lduwa           [%g5 + %g4] ASI_PHYS_USE_EC, %g4        ! Load PMD
   /*0x1c*/     ldxa            [%g0] ASI_DMMU_TSB_8KB_PTR, %g1         ! For PTE offset
 
                                /* ICACHE line 2 */
   /*0x3c*/     ldxa            [%g5] ASI_DMMU, %g4                     ! From MMU
 
                                /* ICACHE line 3 */
-  /*0x40*/     add             %g2, 7, %g5                             ! Compute mask
-  /*0x44*/     andn            %g4, %g5, %g4                           ! Mask page
-  /*0x48*/     mov             TLB_SFSR, %g5                           ! read SFSR
-  /*0x4c*/     ldxa            [%g5] ASI_DMMU, %g5                     ! from DMMU for
+  /*0x40*/     mov             TLB_SFSR, %g5                           ! read SFSR
+  /*0x44*/     srlx            %g4, 13, %g4                            !   Prepare...
+  /*0x48*/     ldxa            [%g5] ASI_DMMU, %g5                     ! from DMMU for
+  /*0x4c*/     sllx            %g4, 13, %g4                            !   ...and mask page
   /*0x50*/     and             %g5, 0x10, %g5                          ! context bit
   /*0x54*/     or              %g4, %g5, %g4                           ! for prot trap
 1:/*0x58*/     stxa            %g0, [%g4] ASI_DMMU_DEMAP               ! TLB flush page
index 02faf4e3cf4fb82681ffa2100172b7bced79d18b..954cfd4bc3c1c708f4d18da898d639c2f5c85bc3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.17 1998/01/10 18:26:13 ecd Exp $
+/* $Id: ebus.c,v 1.23 1998/03/29 16:27:24 ecd Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
 struct linux_ebus *ebus_chain = 0;
 
 extern void prom_ebus_ranges_init(struct linux_ebus *);
+extern void prom_ebus_intmap_init(struct linux_ebus *);
 extern unsigned long pci_console_init(unsigned long memory_start);
 
 #ifdef CONFIG_SUN_OPENPROMIO
 extern int openprom_init(void);
 #endif
-#ifdef CONFIG_SUN_MOSTEK_RTC
-extern int rtc_init(void);
-#endif
 #ifdef CONFIG_SPARCAUDIO
 extern int sparcaudio_init(void);
 #endif
@@ -46,6 +44,9 @@ extern void auxio_probe(void);
 #ifdef CONFIG_OBP_FLASH
 extern int flash_init(void);
 #endif
+#ifdef CONFIG_ENVCTRL
+extern int envctrl_init(void);
+#endif
 
 extern unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
                                     unsigned int full_ino);
@@ -62,7 +63,35 @@ ebus_alloc(unsigned long *memory_start, size_t size)
        return mem;
 }
 
-__initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
+__initfunc(void ebus_intmap_match(struct linux_ebus *ebus,
+                                 struct linux_prom_registers *reg,
+                                 int *interrupt))
+{
+       unsigned int hi, lo, irq;
+       int i;
+
+       if (!ebus->num_ebus_intmap)
+               return;
+
+       hi = reg->which_io & ebus->ebus_intmask.phys_hi;
+       lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
+       irq = *interrupt & ebus->ebus_intmask.interrupt;
+       for (i = 0; i < ebus->num_ebus_intmap; i++) {
+               if ((ebus->ebus_intmap[i].phys_hi == hi) &&
+                   (ebus->ebus_intmap[i].phys_lo == lo) &&
+                   (ebus->ebus_intmap[i].interrupt == irq)) {
+                       *interrupt = ebus->ebus_intmap[i].cinterrupt;
+                       return;
+               }
+       }
+
+       prom_printf("ebus: IRQ [%08x.%08x.%08x] not found in interrupt-map\n",
+                   reg->which_io, reg->phys_addr, *interrupt);
+       prom_halt();
+}
+
+__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
+                               struct linux_ebus_child *dev))
 {
        int regs[PROMREG_MAX];
        int irqs[PROMREG_MAX];
@@ -90,8 +119,10 @@ __initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
                dev->num_irqs = 0;
        } else {
                dev->num_irqs = len / sizeof(irqs[0]);
-               for (i = 0; i < dev->num_irqs; i++)
+               for (i = 0; i < dev->num_irqs; i++) {
+                       ebus_intmap_match(dev->bus, preg, &irqs[i]);
                        dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]);
+               }
        }
 
 #ifdef DEBUG_FILL_EBUS_DEV
@@ -108,7 +139,8 @@ __initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
 #endif
 }
 
-__initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *dev,
+__initfunc(unsigned long fill_ebus_device(int node,
+                                         struct linux_ebus_device *dev,
                                          unsigned long memory_start))
 {
        struct linux_prom_registers regs[PROMREG_MAX];
@@ -142,8 +174,10 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
                dev->num_irqs = 0;
        } else {
                dev->num_irqs = len / sizeof(irqs[0]);
-               for (i = 0; i < dev->num_irqs; i++)
+               for (i = 0; i < dev->num_irqs; i++) {
+                       ebus_intmap_match(dev->bus, &regs[0], &irqs[i]);
                        dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]);
+               }
        }
 
 #ifdef DEBUG_FILL_EBUS_DEV
@@ -166,7 +200,7 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
                child->next = 0;
                child->parent = dev;
                child->bus = dev->bus;
-               fill_ebus_child(node, child);
+               fill_ebus_child(node, &regs[0], child);
 
                while ((node = prom_getsibling(node))) {
                        child->next = (struct linux_ebus_child *)
@@ -176,13 +210,16 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
                        child->next = 0;
                        child->parent = dev;
                        child->bus = dev->bus;
-                       fill_ebus_child(node, child);
+                       fill_ebus_child(node, &regs[0], child);
                }
        }
 
        return memory_start;
 }
 
+extern void sun4u_start_timers(void);
+extern void clock_probe(void);
+
 __initfunc(unsigned long ebus_init(unsigned long memory_start,
                                   unsigned long memory_end))
 {
@@ -199,14 +236,10 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
        int reg, rng, nreg;
        int num_ebus = 0;
 
-       if (!pcibios_present())
+       if (!pci_present())
                return memory_start;
 
-       for (pdev = pci_devices; pdev; pdev = pdev->next) {
-               if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
-                   (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
-                       break;
-       }
+       pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
        if (!pdev) {
                printk("ebus: No EBus's found.\n");
 #ifdef PROM_DEBUG
@@ -236,11 +269,9 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
                ebus->parent = pbm = cookie->pbm;
 
                /* Enable BUS Master. */
-               pcibios_read_config_word(pdev->bus->number, pdev->devfn,
-                                        PCI_COMMAND, &pci_command);
+               pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
                pci_command |= PCI_COMMAND_MASTER;
-               pcibios_write_config_word(pdev->bus->number, pdev->devfn,
-                                         PCI_COMMAND, pci_command);
+               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
 
                len = prom_getproperty(ebusnd, "reg", (void *)regs,
                                       sizeof(regs));
@@ -285,6 +316,7 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
 #endif
 
                prom_ebus_ranges_init(ebus);
+               prom_ebus_intmap_init(ebus);
 
                nd = prom_getchild(ebusnd);
                if (!nd)
@@ -312,11 +344,8 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
                }
 
        next_ebus:
-               for (pdev = pdev->next; pdev; pdev = pdev->next) {
-                       if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
-                           (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
-                               break;
-               }
+               pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+                                      PCI_DEVICE_ID_SUN_EBUS, pdev);
                if (!pdev)
                        break;
 
@@ -335,9 +364,6 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
 #ifdef CONFIG_SUN_OPENPROMIO
        openprom_init();
 #endif
-#ifdef CONFIG_SUN_MOSTEK_RTC
-       rtc_init();
-#endif
 #ifdef CONFIG_SPARCAUDIO
        sparcaudio_init();
 #endif
@@ -345,20 +371,15 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
        bpp_init();
 #endif
 #ifdef CONFIG_SUN_AUXIO
-       if (sparc_cpu_model == sun4u)
-               auxio_probe();
+       auxio_probe();
+#endif
+#ifdef CONFIG_ENVCTRL
+       envctrl_init();
 #endif
 #ifdef CONFIG_OBP_FLASH
        flash_init();
 #endif
-#ifdef __sparc_v9__
-       if (sparc_cpu_model == sun4u) {
-               extern void sun4u_start_timers(void);
-               extern void clock_probe(void);
-
-               sun4u_start_timers();
-               clock_probe();
-       }
-#endif
+       sun4u_start_timers();
+       clock_probe();
        return memory_start;
 }
index 43f950b2523119b34f3943d838cb9412d3fd1d64..c0531f30a376e7ad5531653a873933e96e74d006 100644 (file)
@@ -1,9 +1,9 @@
-/* $Id: head.S,v 1.46 1997/08/08 08:33:30 jj Exp $
+/* $Id: head.S,v 1.49 1998/03/03 12:31:17 jj Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
  */
 
@@ -26,7 +26,7 @@
 /* This section from from _start to sparc64_boot_end should fit into
  * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
  * with bootup_user_stack, which is from 0x0000.0000.0040.4000 to
- * 0x0000.0000.0040.6000 and bootup_kernel_stack, which is from
+ * 0x0000.0000.0040.6000 and empty_bad_page, which is from
  * 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000. 
  */
 
@@ -326,6 +326,8 @@ sun4u_init:
         nop
        /* Not reached... */
 
+/* IMPORTANT NOTE: Whenever making changes here, check
+ * trampoline.S as well. -jj */
        .globl  setup_tba
 setup_tba:
        save    %sp, -160, %sp
@@ -346,9 +348,11 @@ setup_tba:
        /* Set up MMU globals */
        wrpr    %o1, (PSTATE_MG|PSTATE_IE), %pstate
 
-       /* PGD/PMD offset mask, used by TLB miss handlers. */
-       sethi   %hi(0x1ff8), %g2
-       or      %g2, %lo(0x1ff8), %g2
+       /* Set KERN_HIGHBITS used by dTLB miss handler. */
+#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+       sethi   %uhi(KERN_HIGHBITS), %g2
+       sllx    %g2, 32, %g2
+#undef KERN_HIGHBITS
 
        /* Kernel PGDIR used by TLB miss handlers. */
        mov     %i0, %g6
@@ -391,7 +395,8 @@ sparc64_boot_end:
        .skip   0x2000 + _start - sparc64_boot_end
 bootup_user_stack_end:
 
-bootup_kernel_stack:
+       .globl  empty_bad_page
+empty_bad_page:
        .skip   0x2000
 
 ! 0x0000000000408000
index 1829daeea8fe41e214ec6cc64b960095d6ab3460..86b6c3dd60fc379f62467e57c633dddd13877965 100644 (file)
@@ -6,7 +6,7 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM;
index 64465663dfb9c33616ceeb6e6f5a52c19c32f608..17e904f251709380b085f3d51b0e605b42214584 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.26 1997/12/15 15:11:02 jj Exp $
+/* $Id: ioctl32.c,v 1.35 1998/04/10 02:01:46 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 #include <linux/netlink.h>
 #include <linux/vt.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/fd.h>
 #include <linux/if_ppp.h>
 #include <linux/mtio.h>
+#include <linux/cdrom.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -64,6 +66,30 @@ static int w_long(unsigned int fd, unsigned int cmd, u32 arg)
        return err;
 }
  
+struct timeval32 {
+       int tv_sec;
+       int tv_usec;
+};
+
+static int do_siocgstamp(unsigned int fd, unsigned int cmd, u32 arg)
+{
+       struct timeval32 *up = (struct timeval32 *)A(arg);
+       struct timeval ktv;
+       mm_segment_t old_fs = get_fs();
+       int err;
+
+       set_fs(KERNEL_DS);
+       err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+       set_fs(old_fs);
+       if(!err) {
+               if(!access_ok(VERIFY_WRITE, up, sizeof(*up))    ||
+                  __put_user(ktv.tv_sec, &up->tv_sec)          ||
+                  __put_user(ktv.tv_usec, &up->tv_usec))
+                       err = -EFAULT;
+       }
+       return err;
+}
+
 struct ifmap32 {
        u32 mem_start;
        u32 mem_end;
@@ -948,6 +974,90 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
        return 0;
 }
 
+struct cdrom_read32 {
+       int                     cdread_lba;
+       __kernel_caddr_t32      cdread_bufaddr;
+       int                     cdread_buflen;
+};
+
+struct cdrom_read_audio32 {
+       union cdrom_addr        addr;
+       u_char                  addr_format;
+       int                     nframes;
+       __kernel_caddr_t32      buf;
+};
+
+static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+{
+       mm_segment_t old_fs = get_fs();
+       struct cdrom_read cdread;
+       struct cdrom_read_audio cdreadaudio;
+       __kernel_caddr_t32 addr;
+       char *data = 0;
+       void *karg;
+       int err = 0;
+
+       switch(cmd) {
+       case CDROMREADMODE2:
+       case CDROMREADMODE1:
+       case CDROMREADRAW:
+       case CDROMREADCOOKED:
+               karg = &cdread;
+               if (__get_user(cdread.cdread_lba, &((struct cdrom_read32 *)A(arg))->cdread_lba) ||
+                   __get_user(addr, &((struct cdrom_read32 *)A(arg))->cdread_bufaddr) ||
+                   __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)A(arg))->cdread_buflen))
+                       return -EFAULT;
+               data = kmalloc(cdread.cdread_buflen, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+               cdread.cdread_bufaddr = data;
+               break;
+       case CDROMREADAUDIO:
+               karg = &cdreadaudio;
+               if (copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)A(arg))->addr, sizeof(cdreadaudio.addr)) ||
+                   __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)A(arg))->addr_format) ||
+                   __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)A(arg))->nframes) || 
+                   __get_user(addr, &((struct cdrom_read_audio32 *)A(arg))->buf))
+                       return -EFAULT;
+               data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+               cdreadaudio.buf = data;
+               break;
+       default:
+               printk("cdrom_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
+                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               return -EINVAL;
+       }
+       set_fs (KERNEL_DS);
+       err = sys_ioctl (fd, cmd, (unsigned long)karg);
+       set_fs (old_fs);
+       if (err) {
+               if (data) kfree(data);
+               return err;
+       }
+       switch (cmd) {
+       case CDROMREADMODE2:
+       case CDROMREADMODE1:
+       case CDROMREADRAW:
+       case CDROMREADCOOKED:
+               if (copy_to_user((char *)A(addr), data, cdread.cdread_buflen)) {
+                       kfree(data);
+                       return -EFAULT;
+               }
+               break;
+       case CDROMREADAUDIO:
+               if (copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352)) {
+                       kfree(data);
+                       return -EFAULT;
+               }
+               break;
+       default:
+               break;
+       }
+       if (data) kfree(data);
+       return 0;
+}
 
 asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
 {
@@ -955,10 +1065,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        int error = -EBADF;
 
        lock_kernel();
-       if(fd >= NR_OPEN)
-               goto out;
-
-       filp = current->files->fd[fd];
+       filp = fcheck(fd);
        if(!filp)
                goto out;
 
@@ -966,7 +1073,6 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
                error = sys_ioctl (fd, cmd, (unsigned long)arg);
                goto out;
        }
-       error = -EFAULT;
        switch (cmd) {
        case SIOCGIFCONF:
                error = dev_ifconf(fd, arg);
@@ -1014,6 +1120,11 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
                error = -EINVAL;
                goto out;
 
+       case SIOCGSTAMP:
+               /* Sorry, timeval in the kernel is different now. */
+               error = do_siocgstamp(fd, cmd, arg);
+               goto out;
+
        case HDIO_GETGEO:
                error = hdio_getgeo(fd, arg);
                goto out;
@@ -1066,6 +1177,15 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
                error = mt_ioctl_trans(fd, cmd, arg);
                goto out;
 
+       case CDROMREADMODE2:
+       case CDROMREADMODE1:
+       case CDROMREADRAW:
+       case CDROMREADCOOKED:
+       case CDROMREADAUDIO:
+       case CDROMREADALL:
+               error = cdrom_ioctl_trans(fd, cmd, arg);
+               goto out;
+
        /* List here exlicitly which ioctl's are known to have
         * compatable types passed or none at all...
         */
@@ -1170,6 +1290,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        
        /* 0x09 */
        case REGISTER_DEV:
+       case REGISTER_DEV_NEW:
        case START_MD:
        case STOP_MD:
        
@@ -1219,6 +1340,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        case SCSI_IOCTL_TAGGED_ENABLE:
        case SCSI_IOCTL_TAGGED_DISABLE:
        case SCSI_IOCTL_GET_BUS_NUMBER:
+       case SCSI_IOCTL_SEND_COMMAND:
        
        /* Big V */
        case VT_SETMODE:
@@ -1267,7 +1389,6 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        case FIOGETOWN:
        case SIOCGPGRP:
        case SIOCATMARK:
-       case SIOCGSTAMP:
        case SIOCSIFLINK:
        case SIOCSIFENCAP:
        case SIOCGIFENCAP:
@@ -1305,6 +1426,36 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        case PPPIOCSNPMODE:
        case PPPIOCGDEBUG:
        case PPPIOCSDEBUG:
+
+       /* CDROM stuff */
+       case CDROMPAUSE:
+       case CDROMRESUME:
+       case CDROMPLAYMSF:
+       case CDROMPLAYTRKIND:
+       case CDROMREADTOCHDR:
+       case CDROMREADTOCENTRY:
+       case CDROMSTOP:
+       case CDROMSTART:
+       case CDROMEJECT:
+       case CDROMVOLCTRL:
+       case CDROMSUBCHNL:
+       case CDROMEJECT_SW:
+       case CDROMMULTISESSION:
+       case CDROM_GET_MCN:
+       case CDROMRESET:
+       case CDROMVOLREAD:
+       case CDROMSEEK:
+       case CDROMPLAYBLK:
+       case CDROMCLOSETRAY:
+       case CDROM_SET_OPTIONS:
+       case CDROM_CLEAR_OPTIONS:
+       case CDROM_SELECT_SPEED:
+       case CDROM_SELECT_DISC:
+       case CDROM_MEDIA_CHANGED:
+       case CDROM_DRIVE_STATUS:
+       case CDROM_DISC_STATUS:
+       case CDROM_CHANGER_NSLOTS:
+
                error = sys_ioctl (fd, cmd, (unsigned long)arg);
                goto out;
 
@@ -1312,7 +1463,6 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
                printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
                       (int)fd, (unsigned int)cmd, (unsigned int)arg);
                error = -EINVAL;
-               goto out;
                break;
        }
 out:
index a84fe8eaa50b0232c5e3d47618708cb7ce4e87fb..176079643aa191cc1fa90325dd845060ee1a08a8 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: irq.c,v 1.47 1998/01/10 18:26:17 ecd Exp $
+/* $Id: irq.c,v 1.52 1998/03/19 00:22:54 ecd Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
+ * Copyright (C) 1998  Eddie C. Dost    (ecd@skynet.be)
  */
 
 #include <linux/config.h>
@@ -98,12 +99,22 @@ int get_irq_list(char *buf)
 {
        int i, len = 0;
        struct irqaction *action;
+#ifdef __SMP__
+       int j;
+#endif
 
        for(i = 0; i < (NR_IRQS + 1); i++) {
                if(!(action = *(i + irq_action)))
                        continue;
-               len += sprintf(buf + len, "%2d: %8d %c %s",
-                              i, kstat.interrupts[i],
+               len += sprintf(buf + len, "%3d: ", i);
+#ifndef __SMP__
+               len += sprintf(buf + len, "%10u ", kstat_irqs(i));
+#else
+               for (j = 0; j < smp_num_cpus; j++)
+                       len += sprintf(buf + len, "%10u ",
+                               kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+               len += sprintf(buf + len, "%c %s",
                               (action->flags & SA_INTERRUPT) ? '+' : ' ',
                               action->name);
                for(action = action->next; action; action = action->next) {
@@ -113,19 +124,6 @@ int get_irq_list(char *buf)
                }
                len += sprintf(buf + len, "\n");
        }
-#if 0
-#ifdef CONFIG_PCI
-       {
-               struct linux_psycho *p;
-               for (p = psycho_root; p; p = p->next)
-                       len += sprintf(buf + len,
-                                      "ISTAT[%d]: PCI[%016lx] OBIO[%016lx]\n",
-                                      p->index,
-                                      p->psycho_regs->pci_istate,
-                                      p->psycho_regs->obio_istate);
-       }
-#endif
-#endif
        return len;
 }
 
@@ -197,8 +195,7 @@ static unsigned int *sysio_irq_to_imap(unsigned int irq)
        unsigned long offset;
        struct sysio_regs *sregs;
 
-       if((irq == 14) ||
-          (irq >= NUM_SYSIO_OFFSETS) ||
+       if((irq >= NUM_SYSIO_OFFSETS) ||
           ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
                return NULL;
        sregs = SBus_chain->iommu->sysio_regs;
@@ -224,8 +221,8 @@ static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
 unsigned char psycho_ino_to_pil[] = {
        7, 5, 5, 2,                     /* PCI A slot 0  Int A, B, C, D */
        7, 5, 5, 2,                     /* PCI A slot 1  Int A, B, C, D */
-       0, 0, 0, 0,
-       0, 0, 0, 0,
+       7, 5, 5, 2,                     /* PCI A slot 2  Int A, B, C, D */
+       7, 5, 5, 2,                     /* PCI A slot 3  Int A, B, C, D */
        6, 4, 3, 1,                     /* PCI B slot 0  Int A, B, C, D */
        6, 4, 3, 1,                     /* PCI B slot 1  Int A, B, C, D */
        6, 4, 3, 1,                     /* PCI B slot 2  Int A, B, C, D */
@@ -255,13 +252,13 @@ unsigned char psycho_ino_to_pil[] = {
  */
 #define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
 
-#define psycho_imap_offset(ino)                                                        \
-       ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) :    \
+#define psycho_imap_offset(ino)                                                      \
+       ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) :  \
                        (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1)))
 
-#define psycho_iclr_offset(ino)                                                        \
-       ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) :    \
-                       (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3)))
+#define psycho_iclr_offset(ino)                                                      \
+       ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) :  \
+                       (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f)<<3)))
 
 #endif
 
@@ -529,7 +526,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
        unsigned long flags;
        unsigned int *imap, *iclr;
        void *bus_id = NULL;
-       int ivindex, ivindex_fixup, cpu_irq = -1, pending;
+       int ivindex = -1, ivindex_fixup, cpu_irq = -1, pending = 0;
        
        if(!handler)
            return -EINVAL;
@@ -537,43 +534,47 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
        imap = iclr = NULL;
 
        ivindex_fixup = 0;
+
+       if (irq == 0) {
+               cpu_irq = irq;
+               irqflags &= ~(SA_IMAP_MASKED);
+       } else {
+               irqflags |= SA_IMAP_MASKED;
 #ifdef CONFIG_PCI
-       if(PCI_IRQ_P(irq)) {
-               pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
-       } else
+               if(PCI_IRQ_P(irq)) {
+                       pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
+               } else
 #endif
-       if(irqflags & SA_DCOOKIE) {
-               if(!dev_id) {
-                       printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
-                       panic("Bogus irq registry.");
-               }
-               dcookie         = dev_id;
-               dev_id          = dcookie->real_dev_id;
-               cpu_irq         = dcookie->pil;
-               imap            = dcookie->imap;
-               iclr            = dcookie->iclr;
-               bus_id          = dcookie->bus_cookie;
-               get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
-                                    &iclr, bus_id, irqflags, irq);
-       } else {
-               /* XXX NOTE: This code is maintained for compatability until I can
-                * XXX       verify that all drivers sparc64 will use are updated
-                * XXX       to use the new IRQ registry dcookie interface.  -DaveM
-                */
-               if(irq == 14)
-                       cpu_irq = irq;
-               else
+               if(irqflags & SA_DCOOKIE) {
+                       if(!dev_id) {
+                               printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
+                               panic("Bogus irq registry.");
+                       }
+                       dcookie         = dev_id;
+                       dev_id          = dcookie->real_dev_id;
+                       cpu_irq         = dcookie->pil;
+                       imap            = dcookie->imap;
+                       iclr            = dcookie->iclr;
+                       bus_id          = dcookie->bus_cookie;
+                       get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
+                                            &iclr, bus_id, irqflags, irq);
+               } else {
+                       /* XXX NOTE: This code is maintained for compatability until I can
+                        * XXX       verify that all drivers sparc64 will use are updated
+                        * XXX       to use the new IRQ registry dcookie interface.  -DaveM
+                        */
                        cpu_irq = sysio_ino_to_pil[irq];
-               imap = sysio_irq_to_imap(irq);
-               if(!imap) {
-                       printk("request_irq: BAD, null imap for old style "
-                              "irq registry IRQ[%x].\n", irq);
-                       panic("Bad IRQ registery...");
+                       imap = sysio_irq_to_imap(irq);
+                       if(!imap) {
+                               printk("request_irq: BAD, null imap for old style "
+                                      "irq registry IRQ[%x].\n", irq);
+                               panic("Bad IRQ registery...");
+                       }
+                       iclr = sysio_imap_to_iclr(imap);
                }
-               iclr = sysio_imap_to_iclr(imap);
+               ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+               ivindex += ivindex_fixup;
        }
-       ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
-       ivindex += ivindex_fixup;
 
        action = *(cpu_irq + irq_action);
        if(action) {
@@ -612,26 +613,28 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
                return -ENOMEM;
        }
 
-       bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
-       if(!bucket) {
-               kfree(action);
-               restore_flags(flags);
-               return -ENOMEM;
-       }
+       if (irqflags & SA_IMAP_MASKED) {
+               bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
+               if(!bucket) {
+                       kfree(action);
+                       restore_flags(flags);
+                       return -ENOMEM;
+               }
 
-       pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0);
-       ivector_to_mask[ivindex] = (1 << cpu_irq);
-       if(pending)
-               ivector_to_mask[ivindex] |= 0x80000000;
+               pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0);
+               ivector_to_mask[ivindex] = (1 << cpu_irq);
+               if(pending)
+                       ivector_to_mask[ivindex] |= 0x80000000;
 
-       if(dcookie) {
-               dcookie->ret_ino = ivindex;
-               dcookie->ret_pil = cpu_irq;
+               if(dcookie) {
+                       dcookie->ret_ino = ivindex;
+                       dcookie->ret_pil = cpu_irq;
+               }
        }
 
        action->mask = (unsigned long) bucket;
        action->handler = handler;
-       action->flags = irqflags | SA_IMAP_MASKED;
+       action->flags = irqflags;
        action->name = name;
        action->next = NULL;
        action->dev_id = dev_id;
@@ -664,7 +667,7 @@ void free_irq(unsigned int irq, void *dev_id)
        unsigned int cpu_irq;
        int ivindex = -1;
 
-       if(irq == 14) {
+       if(irq == 0) {
                cpu_irq = irq;
        } else {
 #ifdef CONFIG_PCI
@@ -951,34 +954,43 @@ void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
 void handler_irq(int irq, struct pt_regs *regs)
 {
        struct ino_bucket *bucket = NULL;
-       struct irqaction *action;
+       struct irqaction *action, *act;
        int cpu = smp_processor_id();
 
+#ifndef __SMP__
+       /*
+        * Check for TICK_INT on level 14 softint.
+        */
+       if ((irq == 14) && get_softint() & (1UL << 0))
+               irq = 0;
+#endif
        clear_softint(1 << irq);
 
        irq_enter(cpu, irq);
        action = *(irq + irq_action);
-       kstat.interrupts[irq]++;
+       kstat.irqs[cpu][irq]++;
        if(!action) {
                unexpected_irq(irq, 0, regs);
        } else {
+               act = action;
                do {
-                       unsigned long *swmask = NULL;
-
-                       if(action->flags & SA_IMAP_MASKED) {
-                               bucket = (struct ino_bucket *)action->mask;
-
-                               swmask = &ivector_to_mask[bucket->ino];
-                               if(!(*swmask & 0x80000000))
+                       if(act->flags & SA_IMAP_MASKED) {
+                               bucket = (struct ino_bucket *)act->mask;
+                               if(!(ivector_to_mask[bucket->ino] & 0x80000000))
                                        continue;
                        }
-
-                       action->handler(irq, action->dev_id, regs);
-                       if(swmask) {
-                               *swmask &= ~(0x80000000);
+                       act->handler(irq, act->dev_id, regs);
+               } while((act = act->next) != NULL);
+               act = action;
+               do {
+                       if(act->flags & SA_IMAP_MASKED) {
+                               bucket = (struct ino_bucket *)act->mask;
+                               if(!(ivector_to_mask[bucket->ino] & 0x80000000))
+                                       continue;
+                               ivector_to_mask[bucket->ino] &= ~(0x80000000);
                                *(bucket->iclr) = SYSIO_ICLR_IDLE;
                        }
-               } while((action = action->next) != NULL);
+               } while((act = act->next) != NULL);
        }
        irq_exit(cpu, irq);
 }
@@ -993,6 +1005,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
        int cpu = smp_processor_id();
 
        irq_enter(cpu, irq);
+       kstat.irqs[cpu][irq]++;
        bucket = (struct ino_bucket *)action->mask;
        floppy_interrupt(irq, dev_cookie, regs);
        ivector_to_mask[bucket->ino] &= ~(0x80000000);
@@ -1036,13 +1049,19 @@ int request_fast_irq(unsigned int irq,
        unsigned long flags;
        unsigned int *imap, *iclr;
        void *bus_id = NULL;
-       int ivindex, ivindex_fixup, cpu_irq = -1;
+       int ivindex = -1, ivindex_fixup, cpu_irq = -1;
 
        if(!handler)
                return -EINVAL;
 
        imap = iclr = NULL;
        ivindex_fixup = 0;
+
+       if ((irq == 0) || (irq == 14)) {
+               printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n");
+               return -EBUSY;
+       }
+
 #ifdef CONFIG_PCI
        if(PCI_IRQ_P(irq)) {
                pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
@@ -1066,10 +1085,7 @@ int request_fast_irq(unsigned int irq,
                 * XXX       verify that all drivers sparc64 will use are updated
                 * XXX       to use the new IRQ registry dcookie interface.  -DaveM
                 */
-               if(irq == 14)
-                       cpu_irq = irq;
-               else
-                       cpu_irq = sysio_ino_to_pil[irq];
+               cpu_irq = sysio_ino_to_pil[irq];
                imap = sysio_irq_to_imap(irq);
                if(!imap) {
                        printk("request_irq: BAD, null imap for old style "
@@ -1153,85 +1169,100 @@ int probe_irq_off(unsigned long mask)
        return 0;
 }
 
-struct sun5_timer *linux_timers = NULL;
-
-/* This is gets the master level10 timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
+/* This is gets the master TICK_INT timer going. */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
+                unsigned long *clock)
 {
-       struct linux_prom64_registers pregs[3];
-       struct devid_cookie dcookie;
-       unsigned int *imap, *iclr;
-       u32 pirqs[2];
+       unsigned long flags;
+       unsigned long timer_tick_offset;
        int node, err;
 
-       node = prom_finddevice("/counter-timer");
-       if(node == 0 || node == -1) {
-               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);
-       iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1);
-       imap = (((unsigned int *)__va(pregs[2].phys_addr))+1);
-
-       /* Shut it up first. */
-       linux_timers->limit0 = 0;
+       node = linux_cpus[0].prom_node;
+       *clock = prom_getint(node, "clock-frequency");
+       timer_tick_offset = *clock / HZ;
 
        /* Register IRQ handler. */
-       dcookie.real_dev_id = NULL;
-       dcookie.imap = imap;
-       dcookie.iclr = iclr;
-       dcookie.pil = 10;
-       dcookie.bus_cookie = NULL;
-
-       err = request_irq(pirqs[0], cfunc,
-                         (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC),
-                         "timer", &dcookie);
+       err = request_irq(0, cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC),
+                         "timer", NULL);
 
        if(err) {
-               prom_printf("Serious problem, cannot register timer interrupt\n");
+               prom_printf("Serious problem, cannot register TICK_INT\n");
                prom_halt();
-       } else {
-               unsigned long flags;
+       }
 
-               save_and_cli(flags);
+       save_and_cli(flags);
 
-               /* 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));
+       /* 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");
 
-               restore_flags(flags);
-       }
+       __asm__ __volatile__("
+               rd      %%tick, %%g1
+               add     %%g1, %0, %%g1
+               wr      %%g1, 0x0, %%tick_cmpr"
+       : /* no outputs */
+       : "r" (timer_tick_offset)
+       : "g1");
 
+       restore_flags(flags);
        sti();
 }
 
-struct sun5_timer *prom_timers;
+#ifdef __SMP__
+/* Called from smp_commence, when we know how many cpus are in the system
+ * and can have device IRQ's directed at them.
+ */
+void distribute_irqs(void)
+{
+       unsigned long flags;
+       int cpu, level;
+
+       printk("SMP: redistributing interrupts...\n");
+       save_and_cli(flags);
+       cpu = 0;
+       for(level = 0; level < NR_IRQS; level++) {
+               struct irqaction *p = irq_action[level];
+
+               while(p) {
+                       if(p->flags & SA_IMAP_MASKED) {
+                               struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
+                               unsigned int *imap = bucket->imap;
+                               unsigned int val;
+                               unsigned long tid = __cpu_logical_map[cpu] << 9;
+
+                               val = *imap;
+                               *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
 
+                               printk("SMP: Redirecting IGN[%x] INO[%x] "
+                                      "to cpu %d [%s]\n",
+                                      (val & SYSIO_IMAP_IGN) >> 6,
+                                      (val & SYSIO_IMAP_INO), cpu,
+                                      p->name);
+
+                               cpu++;
+                               if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1)
+                                       cpu = 0;
+                       }
+                       p = p->next;
+               }
+       }
+       restore_flags(flags);
+       irqs_have_been_distributed = 1;
+}
+#endif
+
+
+struct sun5_timer *prom_timers;
 static u64 prom_limit0, prom_limit1;
 
 static void map_prom_timers(void)
@@ -1245,9 +1276,8 @@ static void map_prom_timers(void)
        /* Assume if node is not present, PROM uses different tick mechanism
         * which we should not care about.
         */
-       if(tnode == 0) {
+       if(tnode == 0 || tnode == -1) {
                prom_timers = (struct sun5_timer *) 0;
-               prom_printf("AIEEE, no timers\n");
                return;
        }
 
@@ -1300,52 +1330,6 @@ void enable_prom_timer(void)
        prom_timers->count0 = 0;
 }
 
-#ifdef __SMP__
-/* Called from smp_commence, when we know how many cpus are in the system
- * and can have device IRQ's directed at them.
- */
-void distribute_irqs(void)
-{
-       unsigned long flags;
-       int cpu, level;
-
-       printk("SMP: redistributing interrupts...\n");
-       save_and_cli(flags);
-       cpu = 0;
-       for(level = 0; level < NR_IRQS; level++) {
-               struct irqaction *p = irq_action[level];
-
-               while(p) {
-                       if(p->flags & SA_IMAP_MASKED) {
-                               struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
-                               unsigned int *imap = bucket->imap;
-                               unsigned int val;
-                               unsigned long tid = linux_cpus[cpu].mid << 9;
-
-                               val = *imap;
-                               *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
-
-                               printk("SMP: Redirecting IGN[%x] INO[%x] "
-                                      "to cpu %d [%s]\n",
-                                      (val & SYSIO_IMAP_IGN) >> 6,
-                                      (val & SYSIO_IMAP_INO), cpu,
-                                      p->name);
-
-                               cpu += 1;
-                               while(!(cpu_present_map & (1UL << cpu))) {
-                                       cpu += 1;
-                                       if(cpu >= smp_num_cpus)
-                                               cpu = 0;
-                               }
-                       }
-                       p = p->next;
-               }
-       }
-       restore_flags(flags);
-       irqs_have_been_distributed = 1;
-}
-#endif
-
 __initfunc(void init_IRQ(void))
 {
        int i;
index 9317587a72026b6012826753a568e6786f1647fa..94e3f44f653f793c7940ece45bf8dab4557daab8 100644 (file)
@@ -1,42 +1,42 @@
-/* $Id: itlb_miss.S,v 1.11 1997/10/14 01:48:25 davem Exp $
+/* $Id: itlb_miss.S,v 1.12 1998/01/14 17:14:47 jj Exp $
  * itlb_miss.S:        Instruction TLB miss code, this is included directly
  *              into the trap table.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 /* Gratuitous comment. */
 
                                /* ICACHE line 1 */
   /*0x00*/     ldxa            [%g0] ASI_IMMU, %g1             ! Get TAG_TARGET
-  /*0x04*/     srlx            %g1, 8, %g3                     ! Position PGD offset
-  /*0x08*/     srlx            %g1, 48, %g5                    ! Shift down CONTEXT bits
-  /*0x0c*/     and             %g3, %g2, %g3                   ! Mask PGD offset
-  /*0x10*/     sllx            %g1, 2, %g4                     ! Position PMD offset
+  /*0x04*/     srlx            %g1, 10, %g3                    ! Position PGD offset
+  /*0x08*/     andcc           %g1, %g2, %g0                   ! Test CONTEXT bits
+  /*0x0c*/     and             %g3, 0xffc, %g3                 ! Mask PGD offset
+  /*0x10*/     and             %g1, 0xffe, %g4                 ! Mask PMD offset
   /*0x14*/     ldxa            [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! For PTE offset
-  /*0x18*/     brz,pn          %g5, 3f                         ! Context 0 == kernel
-  /*0x1c*/      and            %g4, %g2, %g4                   ! Mask PMD offset
+  /*0x18*/     be,pn           %xcc, 3f                        ! Context 0 == kernel
+  /*0x1c*/      add            %g4, %g4, %g4                   ! Position PMD offset
 
                                /* ICACHE line 2 */
-  /*0x20*/     ldxa            [%g7 + %g3] ASI_PHYS_USE_EC, %g5        ! Load user PGD
+  /*0x20*/     lduwa           [%g7 + %g3] ASI_PHYS_USE_EC, %g5        ! Load user PGD
   /*0x24*/     srlx            %g1, 1, %g1                             ! PTE offset
-  /*0x28*/     ldxa            [%g5 + %g4] ASI_PHYS_USE_EC, %g3        ! Load PMD
-2:/*0x2c*/     ldxa            [%g3 + %g1] ASI_PHYS_USE_EC, %g5        ! Load PTE
+  /*0x28*/     lduwa           [%g5 + %g4] ASI_PHYS_USE_EC, %g3        ! Load PMD
+  /*0x2c*/     ldxa            [%g3 + %g1] ASI_PHYS_USE_EC, %g5        ! Load PTE
   /*0x30*/     brgez,pn        %g5, sparc64_itlb_refbit_catch          ! Valid set?
   /*0x34*/      nop                                                    ! delay
   /*0x38*/     stxa            %g5, [%g0] ASI_ITLB_DATA_IN             ! TLB load
   /*0x3c*/     retry                                                   ! Trap return
 
 3:                             /* ICACHE line 3 */
-  /*0x40*/     ldxa            [%g6 + %g3] ASI_PHYS_USE_EC, %g5        ! Load kern PGD
+  /*0x40*/     lduwa           [%g6 + %g3] ASI_PHYS_USE_EC, %g5        ! Load kern PGD
   /*0x44*/     srlx            %g1, 1, %g1                             ! PTE offset
-  /*0x48*/     ba,pt           %xcc, 2b                                ! Continue above
-  /*0x4c*/      ldxa           [%g5 + %g4] ASI_PHYS_USE_EC, %g3        ! Load PMD
-  /*0x50*/     nop
-  /*0x54*/     nop
-  /*0x58*/     nop
-  /*0x5c*/     nop
+  /*0x48*/     lduwa           [%g5 + %g4] ASI_PHYS_USE_EC, %g3        ! Load PMD
+  /*0x4c*/     ldxa            [%g3 + %g1] ASI_PHYS_USE_EC, %g5        ! Load PTE
+  /*0x50*/     brgez,pn        %g5, sparc64_itlb_refbit_catch          ! Valid set?
+  /*0x54*/      nop                                                    ! delay
+  /*0x58*/     stxa            %g5, [%g0] ASI_ITLB_DATA_IN             ! TLB load
+  /*0x5c*/     retry                                                   ! Trap return
 
                                /* ICACHE line 4 */
   /*0x60*/     nop
index 4e5ead9821bf1e3ceb91e9e00c5c776c5bd55317..c0058afd90a09078cb4a524a10383d2cdb03fb35 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.50 1998/01/09 16:39:33 jj Exp $
+/*  $Id: process.c,v 1.52 1998/03/29 12:57:53 ecd Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -41,9 +41,6 @@
 
 /* #define VERBOSE_SHOWREGS */
 
-#define PGTCACHE_HIGH_WATER            50
-#define PGTCACHE_LOW_WATER             25
-
 #ifndef __SMP__
 
 /*
@@ -58,16 +55,7 @@ asmlinkage int sys_idle(void)
        current->priority = -100;
        current->counter = -100;
        for (;;) {
-               if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
-                       do {
-                               if(pgd_quicklist)
-                                       free_page((unsigned long) get_pgd_fast());
-                               if(pmd_quicklist)
-                                       free_page((unsigned long) get_pmd_fast());
-                               if(pte_quicklist)
-                                       free_page((unsigned long) get_pte_fast());
-                       } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
-               }
+               check_pgt_cache();
                run_task_queue(&tq_scheduler);
                schedule();
        }
@@ -83,16 +71,7 @@ asmlinkage int cpu_idle(void)
 {
        current->priority = -100;
        while(1) {
-               if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
-                       do {
-                               if(pgd_quicklist)
-                                       free_page((unsigned long) get_pgd_fast());
-                               if(pmd_quicklist)
-                                       free_page((unsigned long) get_pmd_fast());
-                               if(pte_quicklist)
-                                       free_page((unsigned long) get_pte_fast());
-                       } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
-               }
+               check_pgt_cache();
                if(tq_scheduler) {
                        lock_kernel();
                        run_task_queue(&tq_scheduler);
@@ -592,6 +571,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                p->tss.flags |= SPARC_FLAG_KTHREAD;
                p->tss.current_ds = KERNEL_DS;
                p->tss.ctx = 0;
+               __asm__ __volatile__("flushw");
+               memcpy((void *)(p->tss.ksp + STACK_BIAS),
+                      (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
+                      sizeof(struct reg_window));
                p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
        } else {
                if(current->tss.flags & SPARC_FLAG_32BIT) {
index b3b403e33959f8c625d548231f6a8250b7940547..78a69e8df70e14210fd1c4c55e3baf93c9533fb2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.31 1998/01/10 18:26:15 ecd Exp $
+/* $Id: psycho.c,v 1.50 1998/04/10 12:29:47 ecd Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -8,6 +8,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/init.h>
 
 #include <asm/ebus.h>
 #include <asm/sbus.h> /* for sanity check... */
@@ -15,6 +16,7 @@
 #undef PROM_DEBUG
 #undef FIXUP_REGS_DEBUG
 #undef FIXUP_IRQ_DEBUG
+#undef FIXUP_VMA_DEBUG
 
 #ifdef PROM_DEBUG
 #define dprintf        prom_printf
@@ -22,6 +24,9 @@
 #define dprintf printk
 #endif
 
+unsigned long pci_dvma_offset = 0x00000000UL;
+unsigned long pci_dvma_mask   = 0xffffffffUL;
+
 #ifndef CONFIG_PCI
 
 int pcibios_present(void)
@@ -51,12 +56,12 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
 
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/bios32.h>
 #include <linux/pci.h>
 
 #include <asm/io.h>
 #include <asm/oplib.h>
 #include <asm/pbm.h>
+#include <asm/apb.h>
 #include <asm/uaccess.h>
 
 struct linux_psycho *psycho_root = NULL;
@@ -95,8 +100,9 @@ static inline unsigned long long_align(unsigned long addr)
                ~(sizeof(unsigned long) - 1));
 }
 
-static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
-                                      unsigned long memory_start)
+__initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
+                                                 int tsbsize,
+                                                 unsigned long memory_start))
 {
        unsigned long tsbbase = PAGE_ALIGN(memory_start);
        unsigned long control, i;
@@ -114,10 +120,10 @@ static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
        control &= ~(IOMMU_CTRL_DENAB);
        psycho->psycho_regs->iommu_control = control;
 
-       memory_start = (tsbbase + ((32 * 1024) * 8));
+       memory_start = (tsbbase + ((tsbsize * 1024) * 8));
        iopte = (unsigned long *)tsbbase;
 
-       for(i = 0; i < (32 * 1024); i++) {
+       for(i = 0; i < (tsbsize * 1024); i++) {
                *iopte = (IOPTE_VALID | IOPTE_64K |
                          IOPTE_CACHE | IOPTE_WRITE);
                *iopte |= (i << 16);
@@ -128,15 +134,215 @@ static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
 
        control = psycho->psycho_regs->iommu_control;
        control &= ~(IOMMU_CTRL_TSBSZ);
-       control |= (IOMMU_TSBSZ_32K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+       control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+       switch(tsbsize) {
+       case 8:
+               pci_dvma_mask   = 0x1fffffffUL;
+               control |= IOMMU_TSBSZ_8K;
+               break;
+       case 16:
+               pci_dvma_mask   = 0x3fffffffUL;
+               control |= IOMMU_TSBSZ_16K;
+               break;
+       case 32:
+               pci_dvma_mask   = 0x7fffffffUL;
+               control |= IOMMU_TSBSZ_32K;
+               break;
+       default:
+               prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
+               prom_halt();
+               break;
+       }
        psycho->psycho_regs->iommu_control = control;
 
        return memory_start;
 }
 
 extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
+extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm);
+
+/*
+ * Poor man's PCI...
+ */
+__initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start))
+{
+       struct linux_prom64_registers pr_regs[2];
+       struct linux_psycho *sabre;
+       unsigned long ctrl;
+       int tsbsize, node, err;
+       u32 busrange[2];
+       u32 vdma[2];
+       u32 portid;
+       int bus;
+
+       sabre = (struct linux_psycho *)memory_start;
+       memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+
+       portid = prom_getintdefault(pnode, "upa-portid", 0xff);
+
+       memset(sabre, 0, sizeof(*sabre));
+
+       sabre->next = psycho_root;
+       psycho_root = sabre;
+
+       sabre->upa_portid = portid;
+       sabre->index = linux_num_psycho++;
+
+       /*
+        * Map in SABRE register set and report the presence of this SABRE.
+        */
+       err = prom_getproperty(pnode, "reg",
+                              (char *)&pr_regs[0], sizeof(pr_regs));
+       if(err == 0 || err == -1) {
+               prom_printf("SABRE: Error, cannot get U2P registers "
+                           "from PROM.\n");
+               prom_halt();
+       }
+
+       /*
+        * First REG in property is base of entire SABRE register space.
+        */
+       sabre->psycho_regs =
+                       sparc_alloc_io((pr_regs[0].phys_addr & 0xffffffff),
+                                      NULL, sizeof(struct psycho_regs),
+                                      "SABRE Registers",
+                                      (pr_regs[0].phys_addr >> 32), 0);
+       if(sabre->psycho_regs == NULL) {
+               prom_printf("SABRE: Error, cannot map SABRE main registers.\n");
+               prom_halt();
+       }
+
+       printk("PCI: Found SABRE, main regs at %p\n", sabre->psycho_regs);
+#ifdef PROM_DEBUG
+       dprintf("PCI: Found SABRE, main regs at %p\n", sabre->psycho_regs);
+#endif
+
+       ctrl = sabre->psycho_regs->pci_a_control;
+       ctrl = (1UL << 36) | (1UL << 34) | (1UL << 21) | (1UL << 8) | 0x0fUL;
+       sabre->psycho_regs->pci_a_control = ctrl;
+
+       /* Now map in PCI config space for entire SABRE. */
+       sabre->pci_config_space =
+                       sparc_alloc_io(((pr_regs[0].phys_addr & 0xffffffff)
+                                                               + 0x01000000),
+                                      NULL, 0x01000000,
+                                      "PCI Config Space",
+                                      (pr_regs[0].phys_addr >> 32), 0);
+       if(sabre->pci_config_space == NULL) {
+               prom_printf("SABRE: Error, cannot map PCI config space.\n");
+               prom_halt();
+       }
+
+       /* Report some more info. */
+       printk("SABRE: PCI config space at %p\n", sabre->pci_config_space);
+#ifdef PROM_DEBUG
+       dprintf("SABRE: PCI config space at %p\n", sabre->pci_config_space);
+#endif
+
+       err = prom_getproperty(pnode, "virtual-dma",
+                              (char *)&vdma[0], sizeof(vdma));
+       if(err == 0 || err == -1) {
+               prom_printf("SABRE: Error, cannot get virtual-dma property "
+                           "from PROM.\n");
+               prom_halt();
+       }
+
+       switch(vdma[1]) {
+               case 0x20000000:
+                       tsbsize = 8;
+                       break;
+               case 0x40000000:
+                       tsbsize = 16;
+                       break;
+               case 0x80000000:
+                       tsbsize = 32;
+                       break;
+               default:
+                       prom_printf("SABRE: strange virtual-dma size.\n");
+                       prom_halt();
+       }
+
+       memory_start = psycho_iommu_init(sabre, tsbsize, memory_start);
+       pci_dvma_offset = vdma[0];
+
+       printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
+#ifdef PROM_DEBUG
+       dprintf("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
+#endif
+
+       err = prom_getproperty(pnode, "bus-range",
+                                      (char *)&busrange[0], sizeof(busrange));
+       if(err == 0 || err == -1) {
+               prom_printf("SIMBA: Error, cannot get PCI bus-range "
+                           " from PROM.\n");
+               prom_halt();
+       }
+
+       sabre->pci_first_busno = busrange[0];
+       sabre->pci_last_busno = busrange[1];
+       sabre->pci_bus = &pci_root;
+
+       /*
+        * Handle config space reads through any Simba on APB.
+        */
+       for (bus = sabre->pci_first_busno; bus <= sabre->pci_last_busno; bus++)
+               bus2pbm[bus] = &sabre->pbm_A;
+
+       /*
+        * Look for APB underneath.
+        */
+       node = prom_getchild(pnode);
+       while ((node = prom_searchsiblings(node, "pci"))) {
+               struct linux_pbm_info *pbm;
+               char namebuf[128];
+
+               err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
+               if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))
+                       goto next_pci;
+
+               err = prom_getproperty(node, "bus-range",
+                                      (char *)&busrange[0], sizeof(busrange));
+               if(err == 0 || err == -1) {
+                       prom_printf("SIMBA: Error, cannot get PCI bus-range "
+                                   " from PROM.\n");
+                       prom_halt();
+               }
+
+               if (busrange[0] == 1)
+                       pbm = &sabre->pbm_B;
+               else
+                       pbm = &sabre->pbm_A;
+
+               pbm->parent = sabre;
+               pbm->IO_assignments = NULL;
+               pbm->MEM_assignments = NULL;
+               pbm->prom_node = node;
+
+               prom_getstring(node, "name", namebuf, sizeof(namebuf));
+               strcpy(pbm->prom_name, namebuf);
+
+               /* Now the ranges. */
+               prom_pbm_ranges_init(pnode, pbm);
+               prom_pbm_intmap_init(node, pbm);
+
+               pbm->pci_first_busno = busrange[0];
+               pbm->pci_last_busno = busrange[1];
+               memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
+
+               for (bus = pbm->pci_first_busno;
+                    bus <= pbm->pci_last_busno; bus++)
+                       bus2pbm[bus] = pbm;
 
-unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+       next_pci:
+               node = prom_getsibling(node);
+               if (!node)
+                       break;
+       }
+
+       return memory_start;
+}
+
+__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
 {
        struct linux_prom64_registers pr_regs[3];
        struct linux_psycho *psycho;
@@ -144,9 +350,9 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
        u32 portid;
        int node;
 
-       printk("PSYCHO: Probing for controllers.\n");
+       printk("PCI: Probing for controllers.\n");
 #ifdef PROM_DEBUG
-       dprintf("PSYCHO: Probing for controllers.\n");
+       dprintf("PCI: Probing for controllers.\n");
 #endif
 
        memory_start = long_align(memory_start);
@@ -157,6 +363,12 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
                u32 busrange[2];
                int err, is_pbm_a;
 
+               err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
+               if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) {
+                       memory_start = sabre_init(node, memory_start);
+                       goto next_pci;
+               }
+
                psycho = (struct linux_psycho *)memory_start;
 
                portid = prom_getintdefault(node, "upa-portid", 0xff);
@@ -200,34 +412,30 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
                 * Third REG in property is base of entire PSYCHO
                 * register space.
                 */
-               psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
-                                                    NULL, sizeof(struct psycho_regs),
-                                                    "PSYCHO Registers",
-                                                    (pr_regs[2].phys_addr >> 32), 0);
+               psycho->psycho_regs =
+                       sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
+                                      NULL, sizeof(struct psycho_regs),
+                                      "PSYCHO Registers",
+                                      (pr_regs[2].phys_addr >> 32), 0);
                if(psycho->psycho_regs == NULL) {
                        prom_printf("PSYCHO: Error, cannot map PSYCHO "
                                    "main registers.\n");
                        prom_halt();
                }
 
-               printk("PSYCHO: Found controller, main regs at %p\n",
+               printk("PCI: Found PSYCHO, main regs at %p\n",
                       psycho->psycho_regs);
 #ifdef PROM_DEBUG
-               dprintf("PSYCHO: Found controller, main regs at %p\n",
+               dprintf("PCI: Found PSYCHO, main regs at %p\n",
                        psycho->psycho_regs);
 #endif
 
                psycho->psycho_regs->irq_retry = 0xff;
 
-#if 0
-               psycho->psycho_regs->ecc_control |= 1;
-               psycho->psycho_regs->sbuf_a_control = 0;
-               psycho->psycho_regs->sbuf_b_control = 0;
-#endif
-
                /* Now map in PCI config space for entire PSYCHO. */
                psycho->pci_config_space =
-                       sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000),
+                       sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)
+                                                               + 0x01000000),
                                       NULL, 0x01000000,
                                       "PCI Config Space",
                                       (pr_regs[2].phys_addr >> 32), 0);
@@ -244,7 +452,8 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
                        psycho->pci_config_space);
 #endif
 
-               memory_start = psycho_iommu_init(psycho, memory_start);
+               memory_start = psycho_iommu_init(psycho, 32, memory_start);
+               pci_dvma_offset = 0x80000000UL;
 
                is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
 
@@ -268,6 +477,7 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
 
                /* Now the ranges. */
                prom_pbm_ranges_init(node, pbm);
+               prom_pbm_intmap_init(node, pbm);
 
                /* Finally grab the pci bus root array for this pbm after
                 * having found the bus range existing under it.
@@ -282,6 +492,7 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
                pbm->pci_last_busno = busrange[1];
                memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
 
+       next_pci:
                node = prom_getsibling(node);
                if(!node)
                        break;
@@ -308,54 +519,18 @@ int pcibios_present(void)
        return psycho_root != NULL;
 }
 
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
-                        unsigned short index, unsigned char *bus,
-                        unsigned char *devfn)
-{
-       unsigned int curr = 0;
-       struct pci_dev *dev;
-
-       for (dev = pci_devices; dev; dev = dev->next) {
-               if (dev->vendor == vendor && dev->device == device_id) {
-                       if (curr == index) {
-                               *devfn = dev->devfn;
-                               *bus = dev->bus->number;
-                               return PCIBIOS_SUCCESSFUL;
-                       }
-                       ++curr;
-               }
-       }
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int pcibios_find_class (unsigned int class_code, unsigned short index,
-                       unsigned char *bus, unsigned char *devfn)
-{
-       unsigned int curr = 0;
-       struct pci_dev *dev;
-
-       for (dev = pci_devices; dev; dev = dev->next) {
-               if (dev->class == class_code) {
-                       if (curr == index) {
-                               *devfn = dev->devfn;
-                               *bus = dev->bus->number;
-                               return PCIBIOS_SUCCESSFUL;
-                       }
-                       ++curr;
-               }
-       }
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
 static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm,
                                           unsigned long start,
-                                          int io)
+                                          unsigned int offset, int io)
 {
        struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
 
-       while(vp) {
-               if(vp->end > start)
+       while (vp) {
+               if (offset && (vp->offset != offset))
+                       goto next;
+               if (vp->end >= start)
                        break;
+       next:
                vp = vp->next;
        }
        return vp;
@@ -391,7 +566,7 @@ static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new,
                /* Check for programming errors. */
                if(vp &&
                   ((vp->start >= new->start && vp->start < new->end) ||
-                   ((vp->end - 1) >= new->start && (vp->end - 1) < new->end))) {
+                   (vp->end >= new->start && vp->end < new->end))) {
                        prom_printf("pci_add_vma: Wheee, overlapping %s PCI vma's\n",
                                    io ? "IO" : "MEM");
                        prom_printf("pci_add_vma: vp[%016lx:%016lx] "
@@ -414,7 +589,7 @@ static inline void pci_init_alloc_fini(void)
        pci_alloc_arena = NULL;
 }
 
-static void *pci_init_alloc(int size)
+__initfunc(static void *pci_init_alloc(int size))
 {
        unsigned long start = long_align(*pci_alloc_arena);
        void *mp = (void *)start;
@@ -439,8 +614,8 @@ static inline struct pcidev_cookie *pci_devcookie_alloc(void)
 }
 
 
-static void
-pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)
+__initfunc(static void
+pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus))
 {
        unsigned int devfn, l, class;
        unsigned char hdr_type = 0;
@@ -487,7 +662,7 @@ pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)
        }
 }
 
-static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)
+__initfunc(static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus))
 {
        unsigned int nbus;
 
@@ -513,7 +688,79 @@ static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)
 }
 
 
-static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
+__initfunc(static void apb_init(struct linux_psycho *sabre))
+{
+       struct pci_dev *pdev;
+       unsigned short stmp;
+       unsigned int itmp;
+
+       for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
+               if (pdev->vendor == PCI_VENDOR_ID_SUN &&
+                   pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
+
+                       pci_read_config_word(pdev, PCI_COMMAND, &stmp);
+                       stmp |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
+                               PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
+                               PCI_COMMAND_IO;
+                       pci_write_config_word(pdev, PCI_COMMAND, stmp);
+
+                       pci_write_config_word(pdev, PCI_STATUS, 0xffff);
+                       pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
+
+                       pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &stmp);
+                       stmp = PCI_BRIDGE_CTL_MASTER_ABORT |
+                              PCI_BRIDGE_CTL_SERR |
+                              PCI_BRIDGE_CTL_PARITY;
+                       pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, stmp);
+
+                       pci_read_config_dword(pdev, APB_PCI_CONTROL_HIGH, &itmp);
+                       itmp = APB_PCI_CTL_HIGH_SERR |
+                              APB_PCI_CTL_HIGH_ARBITER_EN;
+                       pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp);
+
+                       pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
+                       itmp = APB_PCI_CTL_LOW_ARB_PARK |
+                              APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
+                       pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
+
+                       /*
+                        * Setup Registers for Guaranteed Completion.
+                        */
+                       pci_write_config_byte(pdev, APB_PRIMARY_MASTER_RETRY_LIMIT, 0);
+                       pci_write_config_byte(pdev, APB_SECONDARY_MASTER_RETRY_LIMIT, 0);
+                       pci_write_config_byte(pdev, APB_PIO_TARGET_RETRY_LIMIT, 0x80);
+                       pci_write_config_byte(pdev, APB_PIO_TARGET_LATENCY_TIMER, 0);
+                       pci_write_config_byte(pdev, APB_DMA_TARGET_RETRY_LIMIT, 0x80);
+                       pci_write_config_byte(pdev, APB_DMA_TARGET_LATENCY_TIMER, 0);
+               }
+       }
+}
+
+__initfunc(static void sabre_probe(struct linux_psycho *sabre,
+                                  unsigned long *mstart))
+{
+       struct pci_bus *pbus = sabre->pci_bus;
+       static unsigned char busno = 0;
+
+       pbus->number = pbus->secondary = busno;
+       pbus->sysdata = sabre;
+
+       pbus->subordinate = pci_scan_bus(pbus, mstart);
+       busno = pbus->subordinate + 1;
+
+       for(pbus = pbus->children; pbus; pbus = pbus->next) {
+               if (pbus->number == sabre->pbm_A.pci_first_busno)
+                       memcpy(&sabre->pbm_A.pci_bus, pbus, sizeof(*pbus));
+               if (pbus->number == sabre->pbm_B.pci_first_busno)
+                       memcpy(&sabre->pbm_B.pci_bus, pbus, sizeof(*pbus));
+       }
+
+       apb_init(sabre);
+}
+
+
+__initfunc(static void pbm_probe(struct linux_pbm_info *pbm,
+                                unsigned long *mstart))
 {
        static struct pci_bus *pchain = NULL;
        struct pci_bus *pbus = &pbm->pci_bus;
@@ -552,9 +799,9 @@ static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
        }
 }
 
-static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
-                                    struct pci_dev *pdev,
-                                    int node)
+__initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
+                                               struct pci_dev *pdev,
+                                               int node))
 {
        struct linux_prom_pci_registers pregs[PROMREG_MAX];
        int err;
@@ -583,7 +830,7 @@ static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
        return 0;
 }
 
-static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev)
+__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev))
 {
        struct pcidev_cookie *pcp;
        int node = prom_getchild(pbm->prom_node);
@@ -597,24 +844,37 @@ static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev)
        pdev->sysdata = pcp;
 }
 
-static void fill_in_pbm_cookies(struct linux_pbm_info *pbm)
+__initfunc(static void fill_in_pbm_cookies(struct pci_bus *pbus,
+                                          struct linux_pbm_info *pbm))
 {
-       struct pci_bus *pbtmp, *pbus = &pbm->pci_bus;
        struct pci_dev *pdev;
 
-       for(pbtmp = pbus->children; pbtmp; pbtmp = pbtmp->children)
-               pbtmp->sysdata = pbm;
+       pbus->sysdata = pbm;
+
+       for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+               pdev_cookie_fillin(pbm, pdev);
+
+       for(pbus = pbus->children; pbus; pbus = pbus->next)
+               fill_in_pbm_cookies(pbus, pbm);
+}
+
+__initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre))
+{
+       struct pci_bus *pbus = sabre->pci_bus;
 
-       for( ; pbus; pbus = pbus->children)
-               for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
-                       pdev_cookie_fillin(pbm, pdev);
+       for(pbus = pbus->children; pbus; pbus = pbus->next) {
+               if (pbus->number == sabre->pbm_A.pci_first_busno)
+                       pdev_cookie_fillin(&sabre->pbm_A, pbus->self);
+               else if (pbus->number == sabre->pbm_B.pci_first_busno)
+                       pdev_cookie_fillin(&sabre->pbm_B, pbus->self);
+       }
 }
 
 /* Walk PROM device tree under PBM, looking for 'assigned-address'
  * properties, and recording them in pci_vma's linked in via
  * PBM->assignments.
  */
-static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs)
+__initfunc(static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs))
 {
        struct linux_prom_ebus_ranges erng[PROMREG_MAX];
        int err, iter;
@@ -632,18 +892,26 @@ static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *are
                ap->phys_hi = ep->parent_phys_hi;
                ap->phys_mid = ep->parent_phys_mid;
                ap->phys_lo = ep->parent_phys_lo;
+
+               ap->size_hi = 0;
+               ap->size_lo = ep->size;
        }
        return err;
 }
 
-static void assignment_process(struct linux_pbm_info *pbm, int node)
+__initfunc(static void assignment_process(struct linux_pbm_info *pbm, int node))
 {
        struct linux_prom_pci_registers aregs[PROMREG_MAX];
        char pname[256];
        int err, iter, numa;
 
        err = prom_getproperty(node, "name", (char *)&pname[0], sizeof(pname));
-       if(strncmp(pname, "ebus", 4) == 0) {
+       if (err > 0)
+               pname[err] = 0;
+#ifdef FIXUP_VMA_DEBUG
+       dprintf("%s: %s\n", __FUNCTION__, err > 0 ? pname : "???");
+#endif
+       if(strcmp(pname, "ebus") == 0) {
                numa = gimme_ebus_assignments(node, &aregs[0]);
        } else {
                err = prom_getproperty(node, "assigned-addresses",
@@ -653,7 +921,7 @@ static void assignment_process(struct linux_pbm_info *pbm, int node)
                if(err == 0 || err == -1)
                        return;
 
-               numa = (err / sizeof(struct linux_prom_pci_ranges));
+               numa = (err / sizeof(struct linux_prom_pci_registers));
        }
 
        for(iter = 0; iter < numa; iter++) {
@@ -667,8 +935,6 @@ static void assignment_process(struct linux_pbm_info *pbm, int node)
                io = (space == 1);
 
                breg = (ap->phys_hi & 0xff);
-               if(breg == PCI_ROM_ADDRESS)
-                       continue;
 
                vp = pci_vma_alloc();
 
@@ -677,21 +943,20 @@ static void assignment_process(struct linux_pbm_info *pbm, int node)
                 * XXX either due to it's layout so...
                 */
                vp->start = ap->phys_lo;
-               vp->end = vp->start + ap->size_lo;
-               vp->base_reg = breg;
-
-               /* Sanity */
-               if(io && (vp->end & ~(0xffff))) {
-                       prom_printf("assignment_process: Out of range PCI I/O "
-                                   "[%08lx:%08lx]\n", vp->start, vp->end);
-                       prom_halt();
-               }
+               vp->end = vp->start + ap->size_lo - 1;
+               vp->offset = (ap->phys_hi & 0xffffff);
 
                pci_add_vma(pbm, vp, io);
+
+#ifdef FIXUP_VMA_DEBUG
+               dprintf("%s: BaseReg %02x", pname, breg);
+               dprintf(" %s vma [%08x,%08x]\n",
+                       io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end);
+#endif
        }
 }
 
-static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
+__initfunc(static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node))
 {
        while(node) {
                int child = prom_getchild(node);
@@ -704,17 +969,112 @@ static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
        }
 }
 
-static void record_assignments(struct linux_pbm_info *pbm)
+static inline void record_assignments(struct linux_pbm_info *pbm)
 {
+       struct pci_vma *vp;
+
+       if (pbm->parent->pci_bus) {
+               /*
+                * Disallow anything that is not in our IO/MEM map on SIMBA.
+                */
+               struct pci_bus *pbus = pbm->parent->pci_bus;
+               struct pci_dev *pdev;
+               unsigned char map;
+               int bit;
+
+               for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
+                       struct pcidev_cookie *pcp = pdev->sysdata;
+                       if (!pcp) {
+                               prom_printf("record_assignments: "
+                                       "no pcidev_cookie for pdev %02x\n",
+                                       pdev->devfn);
+                               prom_halt();
+                       }
+                       if (pcp->pbm == pbm)
+                               break;
+               }
+
+               if (!pdev) {
+                       prom_printf("record_assignments: no pdev for PBM\n");
+                       prom_halt();
+               }
+
+               pci_read_config_byte(pdev, APB_IO_ADDRESS_MAP, &map);
+#ifdef FIXUP_VMA_DEBUG
+               dprintf("%s: IO   %02x\n", __FUNCTION__, map);
+#endif
+               for (bit = 0; bit < 8; bit++) {
+                       if (!(map & (1 << bit))) {
+                               vp = pci_vma_alloc();
+                               vp->start = (bit << 21);
+                               vp->end = vp->start + (1 << 21) - 1;
+                               vp->offset = 0;
+                               pci_add_vma(pbm, vp, 1);
+#ifdef FIXUP_VMA_DEBUG
+                               dprintf("%s: IO   prealloc vma [%08x,%08x]\n",
+                                       __FUNCTION__, vp->start, vp->end);
+#endif
+                       }
+               }
+               pci_read_config_byte(pdev, APB_MEM_ADDRESS_MAP, &map);
+#ifdef FIXUP_VMA_DEBUG
+               dprintf("%s: MEM  %02x\n", __FUNCTION__, map);
+#endif
+               for (bit = 0; bit < 8; bit++) {
+                       if (!(map & (1 << bit))) {
+                               vp = pci_vma_alloc();
+                               vp->start = (bit << 29);
+                               vp->end = vp->start + (1 << 29) - 1;
+                               vp->offset = 0;
+                               pci_add_vma(pbm, vp, 0);
+#ifdef FIXUP_VMA_DEBUG
+                               dprintf("%s: MEM  prealloc vma [%08x,%08x]\n",
+                                       __FUNCTION__, vp->start, vp->end);
+#endif
+                       }
+               }
+       }
+
        assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node));
+
+       /*
+        * Protect ISA IO space from being used.
+        */
+       vp = pci_find_vma(pbm, 0, 0, 1);
+       if (!vp || 0x400 <= vp->start) {
+               vp = pci_vma_alloc();
+               vp->start = 0;
+               vp->end = vp->start + 0x400 - 1;
+               vp->offset = 0;
+               pci_add_vma(pbm, vp, 1);
+       }
+
+#ifdef FIXUP_VMA_DEBUG
+       dprintf("PROM IO assignments for PBM %s:\n",
+               pbm == &pbm->parent->pbm_A ? "A" : "B");
+       vp = pbm->IO_assignments;
+       while (vp) {
+               dprintf("  [%08x,%08x] (%s)\n", vp->start, vp->end,
+                       vp->offset ? "Register" : "Unmapped");
+               vp = vp->next;
+       }
+       dprintf("PROM MEM assignments for PBM %s:\n",
+               pbm == &pbm->parent->pbm_A ? "A" : "B");
+       vp = pbm->MEM_assignments;
+       while (vp) {
+               dprintf("  [%08x,%08x] (%s)\n", vp->start, vp->end,
+                       vp->offset ? "Register" : "Unmapped");
+               vp = vp->next;
+       }
+#endif
 }
 
-static void fixup_regs(struct pci_dev *pdev,
-                      struct linux_pbm_info *pbm,
-                      struct linux_prom_pci_registers *pregs,
-                      int nregs,
-                      struct linux_prom_pci_registers *assigned,
-                      int numaa)
+__initfunc(static void fixup_regs(struct pci_dev *pdev,
+                                 struct linux_pbm_info *pbm,
+                                 struct linux_prom_pci_registers *pregs,
+                                 int nregs,
+                                 struct linux_prom_pci_registers *assigned,
+                                 int numaa))
 {
        int preg, rng;
        int IO_seen = 0;
@@ -724,34 +1084,39 @@ static void fixup_regs(struct pci_dev *pdev,
                struct linux_prom_pci_registers *ap = NULL;
                int bustype = (pregs[preg].phys_hi >> 24) & 0x3;
                int bsreg, brindex;
+               unsigned int rtmp;
                u64 pci_addr;
 
                if(bustype == 0) {
                        /* Config space cookie, nothing to do. */
                        if(preg != 0)
-                               printk("%s: strange, config space not 0\n",
-                                      __FUNCTION__);
+                               printk("%s %02x.%02x [%04x,%04x]: "
+                                      "strange, config space not 0\n",
+                                      __FUNCTION__,
+                                      pdev->bus->number, pdev->devfn,
+                                      pdev->vendor, pdev->device);
                        continue;
                } else if(bustype == 3) {
                        /* XXX add support for this... */
-                       printk("%s: Warning, ignoring 64-bit PCI memory space, "
+                       printk("%s %02x.%02x [%04x,%04x]: "
+                              "Warning, ignoring 64-bit PCI memory space, "
                               "tell Eddie C. Dost (ecd@skynet.be).\n",
-                              __FUNCTION__);
+                              __FUNCTION__,
+                              pdev->bus->number, pdev->devfn,
+                              pdev->vendor, pdev->device);
                        continue;
                }
-               bsreg = (pregs[preg].phys_hi & 0xff);
 
-               /* We can safely ignore these. */
-               if(bsreg == PCI_ROM_ADDRESS)
-                       continue;
+               bsreg = (pregs[preg].phys_hi & 0xff);
 
                /* Sanity */
                if((bsreg < PCI_BASE_ADDRESS_0) ||
-                  (bsreg > (PCI_BASE_ADDRESS_5 + 4)) ||
+                  ((bsreg > (PCI_BASE_ADDRESS_5 + 4)) && (bsreg != PCI_ROM_ADDRESS)) ||
                   (bsreg & 3)) {
-                       printk("%s: [%04x:%04x]: "
+                       printk("%s %02x.%02x [%04x:%04x]: "
                               "Warning, ignoring bogus basereg [%x]\n",
-                              __FUNCTION__, pdev->vendor, pdev->device, bsreg);
+                              __FUNCTION__, pdev->bus->number, pdev->devfn,
+                              pdev->vendor, pdev->device, bsreg);
                        printk("  PROM reg: %08x.%08x.%08x %08x.%08x\n",
                               pregs[preg].phys_hi, pregs[preg].phys_mid,
                               pregs[preg].phys_lo, pregs[preg].size_hi,
@@ -798,7 +1163,16 @@ static void fixup_regs(struct pci_dev *pdev,
                        /* AIEEE */
                        prom_printf("fixup_doit: YIEEE, cannot find PBM ranges\n");
                }
-               pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
+               if (bsreg == PCI_ROM_ADDRESS) {
+                       pdev->rom_address = (unsigned long)__va(pci_addr);
+                       pdev->rom_address |= 1;
+                       /*
+                        * Enable access to the ROM.
+                        */
+                       pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp);
+                       pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp | 1);
+               } else
+                       pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
 
                /* Preserve I/O space bit. */
                if(bustype == 0x1) {
@@ -811,15 +1185,18 @@ static void fixup_regs(struct pci_dev *pdev,
 
        /* Now handle assignments PROM did not take care of. */
        if(nregs) {
+               unsigned int rtmp, ridx;
+               unsigned int offset, base;
+               struct pci_vma *vp;
+               u64 pci_addr;
                int breg;
 
                for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) {
-                       unsigned int rtmp, ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
-                       unsigned int base = (unsigned int)pdev->base_address[ridx];
-                       struct pci_vma *vp;
-                       u64 pci_addr;
                        int io;
 
+                       ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
+                       base = (unsigned int)pdev->base_address[ridx];
+
                        if(pdev->base_address[ridx] > PAGE_OFFSET)
                                continue;
 
@@ -827,19 +1204,14 @@ static void fixup_regs(struct pci_dev *pdev,
                        base &= ~((io ?
                                   PCI_BASE_ADDRESS_IO_MASK :
                                   PCI_BASE_ADDRESS_MEM_MASK));
-                       vp = pci_find_vma(pbm, base, io);
+                       offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
+                       vp = pci_find_vma(pbm, base, offset, io);
                        if(!vp || vp->start > base) {
                                unsigned int size, new_base;
 
-                               pcibios_read_config_dword(pdev->bus->number,
-                                                         pdev->devfn,
-                                                         breg, &rtmp);
-                               pcibios_write_config_dword(pdev->bus->number,
-                                                          pdev->devfn,
-                                                          breg, 0xffffffff);
-                               pcibios_read_config_dword(pdev->bus->number,
-                                                         pdev->devfn,
-                                                         breg, &size);
+                               pci_read_config_dword(pdev, breg, &rtmp);
+                               pci_write_config_dword(pdev, breg, 0xffffffff);
+                               pci_read_config_dword(pdev, breg, &size);
                                if(io)
                                        size &= ~1;
                                size = (~(size) + 1);
@@ -847,7 +1219,8 @@ static void fixup_regs(struct pci_dev *pdev,
                                        continue;
 
                                new_base = 0;
-                               for(vp=pci_find_vma(pbm,new_base,io); ; vp=vp->next) {
+                               for(vp = pci_find_vma(pbm, new_base, 0, io); ;
+                                   vp = vp->next) {
                                        if(!vp || new_base + size <= vp->start)
                                                break;
                                        new_base = (vp->end + (size - 1)) & ~(size-1);
@@ -859,26 +1232,27 @@ static void fixup_regs(struct pci_dev *pdev,
                                }
                                vp = pci_vma_alloc();
                                vp->start = new_base;
-                               vp->end = vp->start + size;
-                               vp->base_reg = breg;
-
-                               /* Sanity */
-                               if(io && vp->end & ~(0xffff)) {
-                                       prom_printf("PCI: Out of range PCI I/O "
-                                                   "[%08lx:%08lx] during fixup\n",
-                                                   vp->start, vp->end);
-                                       prom_halt();
-                               }
+                               vp->end = vp->start + size - 1;
+                               vp->offset = offset;
+
                                pci_add_vma(pbm, vp, io);
 
+#ifdef FIXUP_VMA_DEBUG
+                               dprintf("%02x.%02x.%x: BaseReg %02x",
+                                       pdev->bus->number,
+                                       PCI_SLOT(pdev->devfn),
+                                       PCI_FUNC(pdev->devfn),
+                                       breg);
+                               dprintf(" %s vma [%08x,%08x]\n",
+                                       io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end);
+#endif
                                rtmp = new_base;
+                               pci_read_config_dword(pdev, breg, &base);
                                if(io)
-                                       rtmp |= (rtmp & PCI_BASE_ADDRESS_IO_MASK);
+                                       rtmp |= (base & ~PCI_BASE_ADDRESS_IO_MASK);
                                else
-                                       rtmp |= (rtmp & PCI_BASE_ADDRESS_MEM_MASK);
-                               pcibios_write_config_dword(pdev->bus->number,
-                                                          pdev->devfn,
-                                                          breg, rtmp);
+                                       rtmp |= (base & ~PCI_BASE_ADDRESS_MEM_MASK);
+                               pci_write_config_dword(pdev, breg, rtmp);
 
                                /* Apply PBM ranges and update pci_dev. */
                                pci_addr = new_base;
@@ -912,13 +1286,93 @@ static void fixup_regs(struct pci_dev *pdev,
                                }
                        }
                }
+
+               /*
+                * Handle PCI_ROM_ADDRESS.
+                */
+               breg = PCI_ROM_ADDRESS;
+               base = (unsigned int)pdev->rom_address;
+
+               if(pdev->rom_address > PAGE_OFFSET)
+                       goto rom_address_done;
+
+               base &= PCI_ROM_ADDRESS_MASK;
+               offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
+               vp = pci_find_vma(pbm, base, offset, 0);
+               if(!vp || vp->start > base) {
+                       unsigned int size, new_base;
+
+                       pci_read_config_dword(pdev, breg, &rtmp);
+                       pci_write_config_dword(pdev, breg, 0xffffffff);
+                       pci_read_config_dword(pdev, breg, &size);
+                       size &= ~1;
+                       size = (~(size) + 1);
+                       if(!size)
+                               goto rom_address_done;
+
+                       new_base = 0;
+                       for(vp = pci_find_vma(pbm, new_base, 0, 0); ; vp = vp->next) {
+                               if(!vp || new_base + size <= vp->start)
+                                       break;
+                               new_base = (vp->end + (size - 1)) & ~(size-1);
+                       }
+                       if(vp && (new_base + size > vp->start)) {
+                               prom_printf("PCI: Impossible full MEM space.\n");
+                               prom_halt();
+                       }
+                       vp = pci_vma_alloc();
+                       vp->start = new_base;
+                       vp->end = vp->start + size - 1;
+                       vp->offset = offset;
+
+                       pci_add_vma(pbm, vp, 0);
+
+#ifdef FIXUP_VMA_DEBUG
+                       dprintf("%02x.%02x.%x: BaseReg %02x",
+                               pdev->bus->number,
+                               PCI_SLOT(pdev->devfn),
+                               PCI_FUNC(pdev->devfn),
+                               breg);
+                       dprintf(" %s vma [%08x,%08x]\n",
+                               "ROM", vp->start, vp->end);
+#endif
+
+                       rtmp = new_base;
+                       pci_read_config_dword(pdev, breg, &base);
+                       rtmp |= (base & ~PCI_ROM_ADDRESS_MASK);
+                       pci_write_config_dword(pdev, breg, rtmp);
+
+                       /* Apply PBM ranges and update pci_dev. */
+                       pci_addr = new_base;
+                       for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+                               struct linux_prom_pci_ranges *rp;
+                               int rspace;
+
+                               rp = &pbm->pbm_ranges[rng];
+                               rspace = (rp->child_phys_hi >> 24) & 3;
+                               if(rspace != 2)
+                                       continue;
+                               pci_addr += ((u64)rp->parent_phys_lo);
+                               pci_addr += (((u64)rp->parent_phys_hi)<<32UL);
+                               break;
+                       }
+                       if(rng == pbm->num_pbm_ranges) {
+                               /* AIEEE */
+                               prom_printf("fixup_doit: YIEEE, cannot find "
+                                           "PBM ranges\n");
+                       }
+                       pdev->rom_address = (unsigned long)__va(pci_addr);
+
+                       pdev->rom_address |= (base & ~PCI_ROM_ADDRESS_MASK);
+                       MEM_seen = 1;
+               }
+       rom_address_done:
+
        }
        if(IO_seen || MEM_seen) {
                unsigned int l;
 
-               pcibios_read_config_dword(pdev->bus->number,
-                                         pdev->devfn,
-                                         PCI_COMMAND, &l);
+               pci_read_config_dword(pdev, PCI_COMMAND, &l);
 #ifdef FIXUP_REGS_DEBUG
                dprintf("[");
 #endif
@@ -937,9 +1391,7 @@ static void fixup_regs(struct pci_dev *pdev,
 #ifdef FIXUP_REGS_DEBUG
                dprintf("]");
 #endif
-               pcibios_write_config_dword(pdev->bus->number,
-                                          pdev->devfn,
-                                          PCI_COMMAND, l);
+               pci_write_config_dword(pdev, PCI_COMMAND, l);
        }
 
 #ifdef FIXUP_REGS_DEBUG
@@ -955,7 +1407,7 @@ static void fixup_regs(struct pci_dev *pdev,
 #define imap_offset(__member) \
        ((unsigned long)(&(((struct psycho_regs *)0)->__member)))
 
-static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
+__initfunc(static unsigned long psycho_pcislot_imap_offset(unsigned long ino))
 {
        unsigned int bus, slot;
 
@@ -963,17 +1415,20 @@ static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
        slot = (ino & 0x0c) >> 2;
 
        if(bus == 0) {
-               /* Perform a sanity check, we might as well.
-                * PBM A only has 2 PCI slots.
-                */
-               if(slot > 1) {
-                       prom_printf("pcislot_imap: Bogus slot on PBM A (%ld)\n", slot);
-                       prom_halt();
-               }
-               if(slot == 0)
+               switch(slot) {
+               case 0:
                        return imap_offset(imap_a_slot0);
-               else
+               case 1:
                        return imap_offset(imap_a_slot1);
+               case 2:
+                       return imap_offset(imap_a_slot2);
+               case 3:
+                       return imap_offset(imap_a_slot3);
+               default:
+                       prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n",
+                                   bus, slot);
+                       prom_halt();
+               }
        } else {
                switch(slot) {
                case 0:
@@ -988,13 +1443,12 @@ static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
                        prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n",
                                    bus, slot);
                        prom_halt();
-                       return 0; /* Make gcc happy */
-               };
+               }
        }
 }
 
 /* Exported for EBUS probing layer. */
-unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino)
+__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino))
 {
        unsigned long imap_off, ign, ino;
 
@@ -1089,9 +1543,62 @@ unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino)
        return pci_irq_encode(imap_off, pbm->parent->index, ign, ino);
 }
 
-static void fixup_irq(struct pci_dev *pdev,
-                     struct linux_pbm_info *pbm,
-                     int node)
+__initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm,
+                                      struct pci_dev *pdev,
+                                      struct linux_prom_pci_registers *preg,
+                                      unsigned int *interrupt))
+{
+       struct linux_prom_pci_registers ppreg;
+       unsigned int hi, mid, lo, irq;
+       int i;
+
+       if (!pbm->num_pbm_intmap)
+               return 0;
+
+       /*
+        * Underneath a bridge, use register of parent bridge.
+        */
+       if (pdev->bus->number != pbm->pci_first_busno) {
+               struct pcidev_cookie *pcp = pdev->bus->self->sysdata;
+               int node;
+
+               if (!pcp)
+                       goto out;
+
+               node = pcp->prom_node;
+
+               i = prom_getproperty(node, "reg", (char*)&ppreg, sizeof(ppreg));
+               if(i == 0 || i == -1)
+                       goto out;
+
+               preg = &ppreg;
+       }
+
+       hi = preg->phys_hi & pbm->pbm_intmask.phys_hi;
+       mid = preg->phys_mid & pbm->pbm_intmask.phys_mid;
+       lo = preg->phys_lo & pbm->pbm_intmask.phys_lo;
+       irq = *interrupt & pbm->pbm_intmask.interrupt;
+       for (i = 0; i < pbm->num_pbm_intmap; i++) {
+               if ((pbm->pbm_intmap[i].phys_hi == hi) &&
+                   (pbm->pbm_intmap[i].phys_mid == mid) &&
+                   (pbm->pbm_intmap[i].phys_lo == lo) &&
+                   (pbm->pbm_intmap[i].interrupt == irq)) {
+                       *interrupt = pbm->pbm_intmap[i].cinterrupt;
+                       return *interrupt;
+               }
+       }
+
+out:
+       prom_printf("pbm_intmap_match: IRQ [%08x.%08x.%08x.%08x] "
+                   "not found in interrupt-map\n", preg->phys_hi,
+                   preg->phys_mid, preg->phys_lo, *interrupt);
+       prom_halt();
+}
+
+__initfunc(static void fixup_irq(struct pci_dev *pdev,
+                                struct linux_pbm_info *pbm,
+                                struct linux_prom_pci_registers *preg,
+                                int node))
 {
        unsigned int prom_irq, portid = pbm->parent->upa_portid;
        unsigned char pci_irq_line = pdev->irq;
@@ -1102,13 +1609,24 @@ static void fixup_irq(struct pci_dev *pdev,
 #endif
        err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq));
        if(err == 0 || err == -1) {
-               prom_printf("fixup_irq: No interrupts property for dev[%04x:%04x]\n",
-                           pdev->vendor, pdev->device);
-               prom_halt();
+#ifdef FIXUP_IRQ_DEBUG
+               dprintf("No interrupts property.\n");
+#endif
+               pdev->irq = 0;
+               return;
        }
 
+       /* See if we find a matching interrupt-map entry. */
+       if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
+               pdev->irq = psycho_irq_build(pbm,
+                                            (pbm->parent->upa_portid << 6)
+                                            | prom_irq);
+#ifdef FIXUP_IRQ_DEBUG
+               dprintf("interrupt-map specified prom_irq[%x] pdev->irq[%x]",
+                       prom_irq, pdev->irq);
+#endif
        /* See if fully specified already (ie. for onboard devices like hme) */
-       if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
+       } else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
                pdev->irq = psycho_irq_build(pbm, prom_irq);
 #ifdef FIXUP_IRQ_DEBUG
                dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
@@ -1147,7 +1665,7 @@ static void fixup_irq(struct pci_dev *pdev,
                                slot = (pdev->bus->self->devfn >> 3) - 2;
 
                        /* Use low slot number bits of child as IRQ line. */
-                       line = (line + ((pdev->devfn >> 3) - 4)) % 4;
+                       line = (pdev->devfn >> 3) & 0x03;
                }
                slot = (slot << 2);
 
@@ -1159,16 +1677,10 @@ static void fixup_irq(struct pci_dev *pdev,
                do {
                        unsigned char iline, ipin;
 
-                       (void)pcibios_read_config_byte(pdev->bus->number,
-                                                      pdev->devfn,
-                                                      PCI_INTERRUPT_PIN,
-                                                      &ipin);
-                       (void)pcibios_read_config_byte(pdev->bus->number,
-                                                      pdev->devfn,
-                                                      PCI_INTERRUPT_LINE,
-                                                      &iline);
-                       dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] "
-                               "iline[%x] ipin[%x] prom_irq[%x]",
+                       pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &ipin);
+                       pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &iline);
+                       dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] "
+                               "irq[%x] iline[%x] ipin[%x] prom_irq[%x]",
                                portid, bus>>4, slot>>2, line, pdev->irq,
                                iline, ipin, prom_irq);
                } while(0);
@@ -1178,21 +1690,19 @@ static void fixup_irq(struct pci_dev *pdev,
        /*
         * Write the INO to config space PCI_INTERRUPT_LINE.
         */
-       (void)pcibios_write_config_byte(pdev->bus->number,
-                                       pdev->devfn,
-                                       PCI_INTERRUPT_LINE,
-                                       pdev->irq & PCI_IRQ_INO);
+       pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
+                             pdev->irq & PCI_IRQ_INO);
 
 #ifdef FIXUP_IRQ_DEBUG
        dprintf("\n");
 #endif
 }
 
-static void fixup_doit(struct pci_dev *pdev,
-                      struct linux_pbm_info *pbm,
-                      struct linux_prom_pci_registers *pregs,
-                      int nregs,
-                      int node)
+__initfunc(static void fixup_doit(struct pci_dev *pdev,
+                                 struct linux_pbm_info *pbm,
+                                 struct linux_prom_pci_registers *pregs,
+                                 int nregs,
+                                 int node))
 {
        struct linux_prom_pci_registers assigned[PROMREG_MAX];
        int numaa, err;
@@ -1209,12 +1719,12 @@ static void fixup_doit(struct pci_dev *pdev,
        fixup_regs(pdev, pbm, pregs, nregs, &assigned[0], numaa);
 
        /* Next, fixup interrupt numbers. */
-       fixup_irq(pdev, pbm, node);
+       fixup_irq(pdev, pbm, &pregs[0], node);
 }
 
-static void fixup_pci_dev(struct pci_dev *pdev,
-                         struct pci_bus *pbus,
-                         struct linux_pbm_info *pbm)
+__initfunc(static void fixup_pci_dev(struct pci_dev *pdev,
+                                    struct pci_bus *pbus,
+                                    struct linux_pbm_info *pbm))
 {
        struct linux_prom_pci_registers pregs[PROMREG_MAX];
        struct pcidev_cookie *pcp = pdev->sysdata;
@@ -1225,18 +1735,12 @@ static void fixup_pci_dev(struct pci_dev *pdev,
                unsigned short cmd;
 
                /* First, enable bus mastering. */
-               pcibios_read_config_word(pdev->bus->number,
-                                        pdev->devfn,
-                                        PCI_COMMAND, &cmd);
+               pci_read_config_word(pdev, PCI_COMMAND, &cmd);
                cmd |= PCI_COMMAND_MASTER;
-               pcibios_write_config_word(pdev->bus->number,
-                                         pdev->devfn,
-                                         PCI_COMMAND, cmd);
+               pci_write_config_word(pdev, PCI_COMMAND, cmd);
 
                /* Now, set cache line size to 64-bytes. */
-               pcibios_write_config_byte(pdev->bus->number,
-                                         pdev->devfn,
-                                         PCI_CACHE_LINE_SIZE, 64);
+               pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64);
        }
 
        /* Ignore if this is one of the PBM's, EBUS, or a
@@ -1246,8 +1750,17 @@ static void fixup_pci_dev(struct pci_dev *pdev,
        if((pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) ||
           (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) ||
           (pdev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) ||
-          (pcp == NULL))
+          (pcp == NULL)) {
+               /*
+                * Prevent access to PCI_ROM_ADDRESS, in case present
+                * as we don't fixup the address.
+                */
+               if (pdev->rom_address) {
+                       pci_write_config_dword(pdev, PCI_ROM_ADDRESS, 0);
+                       pdev->rom_address = 0;
+               }
                return;
+       }
 
        node = pcp->prom_node;
 
@@ -1260,20 +1773,30 @@ static void fixup_pci_dev(struct pci_dev *pdev,
        nregs = (err / sizeof(pregs[0]));
 
        fixup_doit(pdev, pbm, &pregs[0], nregs, node);
+
+       /* Enable bus mastering on IDE interfaces. */
+       if ((pdev->class >> 8 == PCI_CLASS_STORAGE_IDE)
+           && (pdev->class & 0x80)) {
+               unsigned short cmd;
+
+               pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+               cmd |= PCI_COMMAND_MASTER;
+               pci_write_config_word(pdev, PCI_COMMAND, cmd);
+       }
 }
 
-static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
+__initfunc(static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm))
 {
        struct pci_dev *pdev;
 
        for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
                fixup_pci_dev(pdev, pbus, pbm);
 
-       for(pbus = pbus->children; pbus; pbus = pbus->children)
+       for(pbus = pbus->children; pbus; pbus = pbus->next)
                fixup_pci_bus(pbus, pbm);
 }
 
-static void fixup_addr_irq(struct linux_pbm_info *pbm)
+__initfunc(static void fixup_addr_irq(struct linux_pbm_info *pbm))
 {
        struct pci_bus *pbus = &pbm->pci_bus;
 
@@ -1286,14 +1809,16 @@ static void fixup_addr_irq(struct linux_pbm_info *pbm)
 /* Walk all PCI devices probes, fixing up base registers and IRQ registers.
  * We use OBP for most of this work.
  */
-static void psycho_final_fixup(struct linux_psycho *psycho)
+__initfunc(static void psycho_final_fixup(struct linux_psycho *psycho))
 {
        /* Second, fixup base address registers and IRQ lines... */
-       fixup_addr_irq(&psycho->pbm_A);
-       fixup_addr_irq(&psycho->pbm_B);
+       if (psycho->pbm_A.parent)
+               fixup_addr_irq(&psycho->pbm_A);
+       if (psycho->pbm_B.parent)
+               fixup_addr_irq(&psycho->pbm_B);
 }
 
-unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end))
 {
        struct linux_psycho *psycho;
 
@@ -1312,11 +1837,16 @@ unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end
         */
 
        for (psycho = psycho_root; psycho; psycho = psycho->next) {
-               /* Probe busses under PBM B. */
-               pbm_probe(&psycho->pbm_B, &memory_start);
-
-               /* Probe busses under PBM A. */
-               pbm_probe(&psycho->pbm_A, &memory_start);
+               /* Probe bus on builtin PCI. */
+               if (psycho->pci_bus)
+                       sabre_probe(psycho, &memory_start);
+               else {
+                       /* Probe busses under PBM B. */
+                       pbm_probe(&psycho->pbm_B, &memory_start);
+
+                       /* Probe busses under PBM A. */
+                       pbm_probe(&psycho->pbm_A, &memory_start);
+               }
        }
 
        pci_init_alloc_init(&memory_start);
@@ -1327,8 +1857,13 @@ unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end
         * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's).
         */
        for (psycho = psycho_root; psycho; psycho = psycho->next) {
-               fill_in_pbm_cookies(&psycho->pbm_A);
-               fill_in_pbm_cookies(&psycho->pbm_B);
+               if (psycho->pci_bus)
+                       sabre_cookie_fillin(psycho);
+
+               fill_in_pbm_cookies(&psycho->pbm_A.pci_bus,
+                                   &psycho->pbm_A);
+               fill_in_pbm_cookies(&psycho->pbm_B.pci_bus,
+                                   &psycho->pbm_B);
 
                /* See what OBP has taken care of already. */
                record_assignments(&psycho->pbm_A);
@@ -1373,11 +1908,157 @@ pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus,
 static inline int
 out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn)
 {
-       return (((pbm == &pbm->parent->pbm_B) && PCI_SLOT(devfn) > 4) ||
-               ((pbm == &pbm->parent->pbm_A) && PCI_SLOT(devfn) > 6) ||
+       return ((pbm->parent == 0) ||
+               ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 4) ||
+               ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 6) ||
                (pci_probe_enable == 0));
 }
 
+static inline int
+sabre_out_of_range(unsigned char devfn)
+{
+       return ((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
+              ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
+              (PCI_SLOT(devfn) > 1);
+}
+
+static int
+sabre_read_config_byte(struct linux_pbm_info *pbm,
+                      unsigned char bus, unsigned char devfn,
+                      unsigned char where, unsigned char *value)
+{
+       if (bus)
+               return pbm_read_config_byte(pbm, bus, devfn, where, value);
+
+       if (sabre_out_of_range(devfn)) {
+               *value = 0xff;
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       if (where < 8) {
+               unsigned short tmp;
+
+               pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp);
+               if (where & 1)
+                       *value = tmp >> 8;
+               else
+                       *value = tmp & 0xff;
+               return PCIBIOS_SUCCESSFUL;
+       } else
+               return pbm_read_config_byte(pbm, bus, devfn, where, value);
+}
+
+static int
+sabre_read_config_word(struct linux_pbm_info *pbm,
+                      unsigned char bus, unsigned char devfn,
+                      unsigned char where, unsigned short *value)
+{
+       if (bus)
+               return pbm_read_config_word(pbm, bus, devfn, where, value);
+
+       if (sabre_out_of_range(devfn)) {
+               *value = 0xffff;
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       if (where < 8)
+               return pbm_read_config_word(pbm, bus, devfn, where, value);
+       else {
+               unsigned char tmp;
+
+               pbm_read_config_byte(pbm, bus, devfn, where, &tmp);
+               *value = tmp;
+               pbm_read_config_byte(pbm, bus, devfn, where + 1, &tmp);
+               *value |= tmp << 8;
+               return PCIBIOS_SUCCESSFUL;
+       }
+}
+
+static int
+sabre_read_config_dword(struct linux_pbm_info *pbm,
+                       unsigned char bus, unsigned char devfn,
+                       unsigned char where, unsigned int *value)
+{
+       unsigned short tmp;
+
+       if (bus)
+               return pbm_read_config_dword(pbm, bus, devfn, where, value);
+
+       if (sabre_out_of_range(devfn)) {
+               *value = 0xffffffff;
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       sabre_read_config_word(pbm, bus, devfn, where, &tmp);
+       *value = tmp;
+       sabre_read_config_word(pbm, bus, devfn, where + 2, &tmp);
+       *value |= tmp << 16;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+sabre_write_config_byte(struct linux_pbm_info *pbm,
+                       unsigned char bus, unsigned char devfn,
+                       unsigned char where, unsigned char value)
+{
+       if (bus)
+               return pbm_write_config_byte(pbm, bus, devfn, where, value);
+
+       if (sabre_out_of_range(devfn))
+               return PCIBIOS_SUCCESSFUL;
+
+       if (where < 8) {
+               unsigned short tmp;
+
+               pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp);
+               if (where & 1) {
+                       value &= 0x00ff;
+                       value |= tmp << 8;
+               } else {
+                       value &= 0xff00;
+                       value |= tmp;
+               }
+               return pbm_write_config_word(pbm, bus, devfn, where & ~1, tmp);
+       } else
+               return pbm_write_config_byte(pbm, bus, devfn, where, value);
+}
+
+static int
+sabre_write_config_word(struct linux_pbm_info *pbm,
+                       unsigned char bus, unsigned char devfn,
+                       unsigned char where, unsigned short value)
+{
+       if (bus)
+               return pbm_write_config_word(pbm, bus, devfn, where, value);
+
+       if (sabre_out_of_range(devfn))
+               return PCIBIOS_SUCCESSFUL;
+
+       if (where < 8)
+               return pbm_write_config_word(pbm, bus, devfn, where, value);
+       else {
+               pbm_write_config_byte(pbm, bus, devfn, where, value & 0xff);
+               pbm_write_config_byte(pbm, bus, devfn, where + 1, value >> 8);
+               return PCIBIOS_SUCCESSFUL;
+       }
+}
+
+static int
+sabre_write_config_dword(struct linux_pbm_info *pbm,
+                        unsigned char bus, unsigned char devfn,
+                        unsigned char where, unsigned int value)
+{
+       if (bus)
+               return pbm_write_config_dword(pbm, bus, devfn, where, value);
+
+       if (sabre_out_of_range(devfn))
+               return PCIBIOS_SUCCESSFUL;
+
+       sabre_write_config_word(pbm, bus, devfn, where, value & 0xffff);
+       sabre_write_config_word(pbm, bus, devfn, where + 2, value >> 16);
+       return PCIBIOS_SUCCESSFUL;
+}
+
 static int
 pbm_read_config_byte(struct linux_pbm_info *pbm,
                     unsigned char bus, unsigned char devfn,
@@ -1574,36 +2255,60 @@ pbm_write_config_dword(struct linux_pbm_info *pbm,
 int pcibios_read_config_byte (unsigned char bus, unsigned char devfn,
                              unsigned char where, unsigned char *value)
 {
-       return pbm_read_config_byte(bus2pbm[bus], bus, devfn, where, value);
+       struct linux_pbm_info *pbm = bus2pbm[bus];
+
+       if (pbm && pbm->parent && pbm->parent->pci_bus)
+               return sabre_read_config_byte(pbm, bus, devfn, where, value);
+       return pbm_read_config_byte(pbm, bus, devfn, where, value);
 }
 
 int pcibios_read_config_word (unsigned char bus, unsigned char devfn,
                              unsigned char where, unsigned short *value)
 {
-       return pbm_read_config_word(bus2pbm[bus], bus, devfn, where, value);
+       struct linux_pbm_info *pbm = bus2pbm[bus];
+
+       if (pbm && pbm->parent && pbm->parent->pci_bus)
+               return sabre_read_config_word(pbm, bus, devfn, where, value);
+       return pbm_read_config_word(pbm, bus, devfn, where, value);
 }
 
 int pcibios_read_config_dword (unsigned char bus, unsigned char devfn,
                               unsigned char where, unsigned int *value)
 {
-       return pbm_read_config_dword(bus2pbm[bus], bus, devfn, where, value);
+       struct linux_pbm_info *pbm = bus2pbm[bus];
+
+       if (pbm && pbm->parent && pbm->parent->pci_bus)
+               return sabre_read_config_dword(pbm, bus, devfn, where, value);
+       return pbm_read_config_dword(pbm, bus, devfn, where, value);
 }
 
 int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
                               unsigned char where, unsigned char value)
 {
-       return pbm_write_config_byte(bus2pbm[bus], bus, devfn, where, value);
+       struct linux_pbm_info *pbm = bus2pbm[bus];
+
+       if (pbm && pbm->parent && pbm->parent->pci_bus)
+               return sabre_write_config_byte(pbm, bus, devfn, where, value);
+       return pbm_write_config_byte(pbm, bus, devfn, where, value);
 }
 
 int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
                               unsigned char where, unsigned short value)
 {
+       struct linux_pbm_info *pbm = bus2pbm[bus];
+
+       if (pbm && pbm->parent && pbm->parent->pci_bus)
+               return sabre_write_config_word(pbm, bus, devfn, where, value);
        return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value);
 }
 
 int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
                                unsigned char where, unsigned int value)
 {
+       struct linux_pbm_info *pbm = bus2pbm[bus];
+
+       if (pbm && pbm->parent && pbm->parent->pci_bus)
+               return sabre_write_config_dword(pbm, bus, devfn, where, value);
        return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value);
 }
 
@@ -1692,4 +2397,9 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
        return err;
 }
 
+__initfunc(char *pcibios_setup(char *str))
+{
+       return str;
+}
+
 #endif
index 932addbb43d8b19ba25433bee28618bee7881d9a..cdc8f47dedd9d0f7acce2f6e501c9caac8d654cb 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.18 1997/12/18 02:43:00 ecd Exp $
+/*  $Id: setup.c,v 1.20 1998/02/24 17:02:39 jj Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -55,11 +55,6 @@ struct screen_info screen_info = {
 
 unsigned int phys_bytes_of_ram, end_of_phys_memory;
 
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
-       return memory_start;
-}
-
 /* Typing sync at the prom prompt calls the function pointed to by
  * the sync callback which I set to the following function.
  * This should sync all filesystems and return, for now it just
@@ -413,14 +408,17 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 extern char *sparc_cpu_type[];
 extern char *sparc_fpu_type[];
 
-extern char *smp_info(void);
-extern char *mmu_info(void);
+extern int smp_info(char *);
+extern int smp_bogo(char *);
+extern int mmu_info(char *);
 
 int get_cpuinfo(char *buffer)
 {
        int cpuid=smp_processor_id();
+       int len;
 
-       return sprintf(buffer, "cpu\t\t: %s\n"
+       len = sprintf(buffer, 
+           "cpu\t\t: %s\n"
             "fpu\t\t: %s\n"
             "promlib\t\t: Version 3 Revision %d\n"
             "prom\t\t: %d.%d.%d\n"
@@ -429,33 +427,22 @@ int get_cpuinfo(char *buffer)
            "ncpus active\t: %d\n"
 #ifndef __SMP__
             "BogoMips\t: %lu.%02lu\n"
-#else
-           "Cpu0Bogo\t: %lu.%02lu\n"
-           "Cpu1Bogo\t: %lu.%02lu\n"
-           "Cpu2Bogo\t: %lu.%02lu\n"
-           "Cpu3Bogo\t: %lu.%02lu\n"
-#endif
-           "%s"
-#ifdef __SMP__
-           "%s"
 #endif
            ,
             sparc_cpu_type[cpuid],
             sparc_fpu_type[cpuid],
             prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
-           linux_num_cpus, smp_num_cpus,
+           linux_num_cpus, smp_num_cpus
 #ifndef __SMP__
-            loops_per_sec/500000, (loops_per_sec/5000) % 100,
-#else
-           cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100,
-           cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100,
-           cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100,
-           cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100,
+            , loops_per_sec/500000, (loops_per_sec/5000) % 100
 #endif
-           mmu_info()
+           );
 #ifdef __SMP__
-           , smp_info()
+       len += smp_bogo(buffer + len);
 #endif
-            );
-
+       len += mmu_info(buffer + len);
+#ifdef __SMP__
+       len += smp_info(buffer + len);
+#endif
+       return len;
 }
index 8ca15c80b2ec0a31daafacbb3bcedbfd0b81f338..269ff413d78f2c5dec74521dc75c9023f66bcabb 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.34 1997/12/15 15:04:49 jj Exp $
+/*  $Id: signal32.c,v 1.35 1998/04/01 07:00:43 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -1023,6 +1023,7 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
                spin_lock_irq(&current->sigmask_lock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
                sigaddset(&current->blocked,signr);
+               recalc_sigpending(current);
                spin_unlock_irq(&current->sigmask_lock);
        }
 }
index 932534c05ebc52207e99482f9cde8d25de31327b..ca2aa436051728577907aa80936fab14293b0ac4 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 #include <asm/uaccess.h>
+#include <asm/timer.h>
 
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 
 extern int linux_num_cpus;
 extern void calibrate_delay(void);
+extern unsigned prom_cpu_nodes[];
 
 volatile int smp_processors_ready = 0;
 unsigned long cpu_present_map = 0;
@@ -39,35 +42,46 @@ int smp_threads_ready = 0;
 
 struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
 
-static unsigned char boot_cpu_id = 0;
+static unsigned char boot_cpu_id __initdata = 0;
 static int smp_activated = 0;
 
 volatile int cpu_number_map[NR_CPUS];
-volatile int cpu_logical_map[NR_CPUS];
+volatile int __cpu_logical_map[NR_CPUS];
 
 struct klock_info klock_info = { KLOCK_CLEAR, 0 };
 
-void smp_setup(char *str, int *ints)
+__initfunc(void smp_setup(char *str, int *ints))
 {
        /* XXX implement me XXX */
 }
 
-static char smp_buf[512];
+int smp_info(char *buf)
+{
+       int len = 7, i;
+       
+       strcpy(buf, "State:\n");
+       for (i = 0; i < NR_CPUS; i++)
+               if(cpu_present_map & (1UL << i))
+                       len += sprintf(buf + len,
+                                       "CPU%d:\t\t%s\n",
+                                       i, klock_info.akp == i ? "akp" : "online");
+       return len;
+}
 
-char *smp_info(void)
+int smp_bogo(char *buf)
 {
-       /* XXX not SMP safe and need to support up to 64 penguins */
-       sprintf(smp_buf,
-"        CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
-"State:  %s\t\t%s\t\t%s\t\t%s\n",
-(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline",
-(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline",
-(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline",
-(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline");
-       return smp_buf;
+       int len = 0, i;
+       
+       for (i = 0; i < NR_CPUS; i++)
+               if(cpu_present_map & (1UL << i))
+                       len += sprintf(buf + len,
+                                      "Cpu%dBogo\t: %lu.%02lu\n",
+                                      i, cpu_data[i].udelay_val / 500000,
+                                      (cpu_data[i].udelay_val / 5000) % 100);
+       return len;
 }
 
-void smp_store_cpu_info(int id)
+__initfunc(void smp_store_cpu_info(int id))
 {
        cpu_data[id].udelay_val                 = loops_per_sec;
        cpu_data[id].irq_count                  = 0;
@@ -80,7 +94,7 @@ void smp_store_cpu_info(int id)
 
 extern void distribute_irqs(void);
 
-void smp_commence(void)
+__initfunc(void smp_commence(void))
 {
        distribute_irqs();
 }
@@ -92,7 +106,7 @@ static volatile unsigned long callin_flag = 0;
 extern void inherit_locked_prom_mappings(int save_p);
 extern void cpu_probe(void);
 
-void smp_callin(void)
+__initfunc(void smp_callin(void))
 {
        int cpuid = hard_smp_processor_id();
 
@@ -156,22 +170,24 @@ extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 
 extern unsigned long smp_trampoline;
 
-void smp_boot_cpus(void)
+__initfunc(void smp_boot_cpus(void))
 {
        int cpucount = 0, i;
 
        printk("Entering UltraSMPenguin Mode...\n");
+       boot_cpu_id = hard_smp_processor_id();
        smp_tickoffset_init();
        __sti();
        cpu_present_map = 0;
        for(i = 0; i < linux_num_cpus; i++)
-               cpu_present_map |= (1UL << i);
+               cpu_present_map |= (1UL << linux_cpus[i].mid);
        for(i = 0; i < NR_CPUS; i++) {
                cpu_number_map[i] = -1;
-               cpu_logical_map[i] = -1;
+               __cpu_logical_map[i] = -1;
        }
        cpu_number_map[boot_cpu_id] = 0;
-       cpu_logical_map[0] = boot_cpu_id;
+       prom_cpu_nodes[boot_cpu_id] = linux_cpus[0].prom_node;
+       __cpu_logical_map[0] = boot_cpu_id;
        klock_info.akp = boot_cpu_id;
        current->processor = boot_cpu_id;
        smp_store_cpu_info(boot_cpu_id);
@@ -188,13 +204,18 @@ void smp_boot_cpus(void)
                        unsigned long entry = (unsigned long)(&smp_trampoline);
                        struct task_struct *p;
                        int timeout;
+                       int no;
+                       extern unsigned long phys_base;
 
-                       entry -= KERNBASE;
+                       entry += phys_base - KERNBASE;
                        kernel_thread(start_secondary, NULL, CLONE_PID);
                        p = task[++cpucount];
                        p->processor = i;
                        callin_flag = 0;
-                       prom_startcpu(linux_cpus[i].prom_node,
+                       for (no = 0; no < linux_num_cpus; no++)
+                               if (linux_cpus[no].mid == i)
+                                       break;
+                       prom_startcpu(linux_cpus[no].prom_node,
                                      entry, ((unsigned long)p));
                        for(timeout = 0; timeout < 5000000; timeout++) {
                                if(callin_flag)
@@ -202,8 +223,9 @@ void smp_boot_cpus(void)
                                udelay(100);
                        }
                        if(callin_flag) {
-                               cpu_number_map[i] = i;
-                               cpu_logical_map[i] = i;
+                               cpu_number_map[i] = cpucount;
+                               prom_cpu_nodes[i] = linux_cpus[no].prom_node;
+                               __cpu_logical_map[cpucount] = i;
                        } else {
                                cpucount--;
                                printk("Processor %d is stuck.\n", i);
@@ -248,9 +270,9 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
 
 /* #define XCALL_DEBUG */
 
-static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
+static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu)
 {
-       u64 result, target = (((unsigned long)linux_cpus[cpu].mid) << 14) | 0x70;
+       u64 result, target = (cpu << 14) | 0x70;
        int stuck;
 
 #ifdef XCALL_DEBUG
@@ -307,12 +329,15 @@ void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
        if(smp_processors_ready) {
                unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id()));
                u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
-               int i, ncpus = smp_num_cpus;
+               int i, ncpus = smp_num_cpus - 1;
 
                __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
-               for(i = 0; i < ncpus; i++) {
-                       if(mask & (1UL << i))
+               for(i = 0; i < NR_CPUS; i++) {
+                       if(mask & (1UL << i)) {
                                xcall_deliver(data0, data1, data2, pstate, i);
+                               ncpus--;
+                       }
+                       if (!ncpus) break;
                }
                /* NOTE: Caller runs local copy on master. */
        }
@@ -489,13 +514,14 @@ static inline void sparc64_do_profile(unsigned long pc)
 #endif
 }
 
-static unsigned long real_tick_offset, current_tick_offset;
+static unsigned long current_tick_offset;
 
 #define prof_multiplier(__cpu)         cpu_data[(__cpu)].multiplier
 #define prof_counter(__cpu)            cpu_data[(__cpu)].counter
 
 extern void update_one_process(struct task_struct *p, unsigned long ticks,
-                              unsigned long user, unsigned long system);
+                              unsigned long user, unsigned long system,
+                              int cpu);
 
 void smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
@@ -503,32 +529,62 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
        int cpu = smp_processor_id();
        int user = user_mode(regs);
 
+       /*
+        * Check for level 14 softint.
+        */
+       if (!(get_softint() & (1UL << 0))) {
+               extern void handler_irq(int, struct pt_regs *);
+
+               handler_irq(14, regs);
+               return;
+       }
+
        clear_softint((1UL << 0));
        do {
                if(!user)
                        sparc64_do_profile(regs->tpc);
                if(!--prof_counter(cpu)) {
+
+                       if (cpu == boot_cpu_id) {
+                               extern void irq_enter(int, int);
+                               extern void irq_exit(int, int);
+
+                               irq_enter(cpu, 0);
+                               kstat.irqs[cpu][0]++;
+
+                               timer_tick_interrupt(regs);
+
+                               irq_exit(cpu, 0);
+                       }
+
                        if(current->pid) {
-                               unsigned int *inc_me;
+                               unsigned int *inc, *inc2;
 
-                               update_one_process(current, 1, user, !user);
+                               update_one_process(current, 1, user, !user, cpu);
                                if(--current->counter < 0) {
                                        current->counter = 0;
                                        need_resched = 1;
                                }
 
                                if(user) {
-                                       if(current->priority < DEF_PRIORITY)
-                                               inc_me = &kstat.cpu_nice;
-                                       else
-                                               inc_me = &kstat.cpu_user;
+                                       if(current->priority < DEF_PRIORITY) {
+                                               inc = &kstat.cpu_nice;
+                                               inc2 = &kstat.per_cpu_nice[cpu];
+                                       } else {
+                                               inc = &kstat.cpu_user;
+                                               inc2 = &kstat.per_cpu_user[cpu];
+                                       }
                                } else {
-                                       inc_me = &kstat.cpu_system;
+                                       inc = &kstat.cpu_system;
+                                       inc2 = &kstat.per_cpu_system[cpu];
                                }
-                               atomic_inc((atomic_t *)inc_me);
+                               atomic_inc((atomic_t *)inc);
+                               atomic_inc((atomic_t *)inc2);
                        }
+
                        prof_counter(cpu) = prof_multiplier(cpu);
                }
+
                __asm__ __volatile__("rd        %%tick_cmpr, %0\n\t"
                                     "add       %0, %2, %0\n\t"
                                     "wr        %0, 0x0, %%tick_cmpr\n\t"
@@ -538,12 +594,55 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
        } while (tick >= compare);
 }
 
-static void smp_setup_percpu_timer(void)
+__initfunc(static void smp_setup_percpu_timer(void))
 {
        int cpu = smp_processor_id();
 
        prof_counter(cpu) = prof_multiplier(cpu) = 1;
 
+       if (cpu == boot_cpu_id) {
+               extern unsigned long tl0_itick;
+               extern unsigned long tl0_smp_itick;
+               unsigned long flags;
+
+               save_flags(flags); cli();
+
+               /*
+                * Steal TICK_INT interrupts from timer_interrupt().
+                */
+               __asm__ __volatile__("
+                       .globl  tl0_smp_itick
+                       b,pt    %%xcc, 1f
+                        nop
+
+               tl0_smp_itick:
+                       rdpr    %%pil, %%g2
+                       wrpr    %%g0, 15, %%pil
+                       b,pt    %%xcc, etrap_irq
+                        rd     %%pc, %%g7
+                       call    smp_percpu_timer_interrupt
+                        add    %%sp, %0, %%o0
+                       b,pt    %%xcc, rtrap
+                        clr    %%l6
+
+               1:"
+                       : /* no outputs */
+                       : "i" (STACK_BIAS + REGWIN_SZ));
+
+               memcpy(&tl0_itick, &tl0_smp_itick, 8 * 4);
+
+               __asm__ __volatile__("
+                       membar  #StoreStore
+                       flush   %0 + 0x00
+                       flush   %0 + 0x08
+                       flush   %0 + 0x10
+                       flush   %0 + 0x18"
+                       : /* no outputs */
+                       : "r" (&tl0_itick));
+
+               restore_flags(flags);
+       }
+
        __asm__ __volatile__("rd        %%tick, %%g1\n\t"
                             "add       %%g1, %0, %%g1\n\t"
                             "wr        %%g1, 0x0, %%tick_cmpr"
@@ -552,22 +651,17 @@ static void smp_setup_percpu_timer(void)
                             : "g1");
 }
 
-static void smp_tickoffset_init(void)
+__initfunc(static void smp_tickoffset_init(void))
 {
-       int node;
-
-       node = linux_cpus[0].prom_node;
-       real_tick_offset = prom_getint(node, "clock-frequency");
-       real_tick_offset = real_tick_offset / HZ;
-       current_tick_offset = real_tick_offset;
+       current_tick_offset = timer_tick_offset;
 }
 
-int setup_profiling_timer(unsigned int multiplier)
+__initfunc(int setup_profiling_timer(unsigned int multiplier))
 {
        unsigned long flags;
        int i;
 
-       if((!multiplier) || (real_tick_offset / multiplier) < 1000)
+       if((!multiplier) || (timer_tick_offset / multiplier) < 1000)
                return -EINVAL;
 
        save_and_cli(flags);
@@ -575,7 +669,7 @@ int setup_profiling_timer(unsigned int multiplier)
                if(cpu_present_map & (1UL << i))
                        prof_multiplier(i) = multiplier;
        }
-       current_tick_offset = (real_tick_offset / multiplier);
+       current_tick_offset = (timer_tick_offset / multiplier);
        restore_flags(flags);
 
        return 0;
index b776ea06e32abab0b40f8615391af4fa40cd0d15..0eb16d7bb5f8305d6ffdcb113e8d191047ae44a4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.27 1997/11/19 07:57:46 jj Exp $
+/* $Id: sparc64_ksyms.c,v 1.33 1998/04/06 16:09:40 jj Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -50,6 +50,7 @@ struct poll {
        short revents;
 };
 
+extern unsigned prom_cpu_nodes[NR_CPUS];
 extern void die_if_kernel(char *str, struct pt_regs *regs);
 extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
                                unsigned long, unsigned long, unsigned long);
@@ -112,6 +113,8 @@ EXPORT_SYMBOL_PRIVATE(global_restore_flags);
 #else
 EXPORT_SYMBOL(local_irq_count);
 #endif
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL_PRIVATE(_lock_kernel);
 EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
 
@@ -134,7 +137,9 @@ EXPORT_SYMBOL(dma_chain);
 #endif
 #if CONFIG_PCI
 EXPORT_SYMBOL(ebus_chain);
-EXPORT_SYMBOL(pci_devices);
+EXPORT_SYMBOL(pci_dvma_offset);
+EXPORT_SYMBOL(pci_dvma_mask);
+EXPORT_SYMBOL(empty_zero_page);
 #endif
 
 /* Solaris/SunOS binary compatibility */
@@ -171,7 +176,6 @@ EXPORT_SYMBOL(__prom_getsibling);
 
 /* sparc library symbols */
 EXPORT_SYMBOL(bcopy);
-EXPORT_SYMBOL(memscan);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strcpy);
@@ -179,7 +183,6 @@ EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strpbrk);
@@ -201,15 +204,11 @@ EXPORT_SYMBOL(sys_sigsuspend);
 EXPORT_SYMBOL(sys_getppid);
 EXPORT_SYMBOL(svr4_getcontext);
 EXPORT_SYMBOL(svr4_setcontext);
-EXPORT_SYMBOL(linux_cpus);
+EXPORT_SYMBOL(prom_cpu_nodes);
 EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(sys32_ioctl);
 #endif
 
-#ifdef CONFIG_MATHEMU_MODULE
-EXPORT_SYMBOL(handle_mathemu);
-#endif
-
 /* Special internal versions of library functions. */
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memset);
index d94a7c6d6613bc3040af70510ed550d6dd5dbc72..a0bfb47ef45d316636bfc418df65556768d94bc2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl32.c,v 1.5 1997/09/18 10:37:57 rth Exp $
+/* $Id: sunos_ioctl32.c,v 1.9 1998/03/29 10:10:53 davem Exp $
  * sunos_ioctl32.c: SunOS ioctl compatability on sparc64.
  *
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -18,6 +18,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
@@ -88,15 +89,12 @@ extern asmlinkage int sys_setsid(void);
 
 asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg)
 {
-       struct file *filp;
        int ret = -EBADF;
 
        lock_kernel();
        if(fd >= SUNOS_NR_OPEN)
                goto out;
-
-       filp = current->files->fd[fd];
-       if(!filp)
+       if(!fcheck(fd))
                goto out;
 
        if(cmd == TIOCSETD) {
@@ -168,7 +166,7 @@ asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg)
                ret = sys32_ioctl(fd, SIOCGIFBRDADDR, arg);
                goto out;
        case _IOW('i', 24, struct ifreq32):
-               ret = sys32_ioctl(fd, SIOCGIFBRDADDR, arg);
+               ret = sys32_ioctl(fd, SIOCSIFBRDADDR, arg);
                goto out;
        case _IOWR('i', 25, struct ifreq32):
                ret = sys32_ioctl(fd, SIOCGIFNETMASK, arg);
index 6fb6f739b3427ba98a1d93a4c4f00fbb1237764c..44f17ca01d273c9ae253a481f393dc568e516f72 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.4 1997/09/09 17:13:29 jj Exp $
+/* $Id: sys32.S,v 1.5 1998/03/24 05:57:56 ecd Exp $
  * sys32.S: I-cache tricks for 32-bit compatability layer simple
  *          conversions.
  *
@@ -24,7 +24,7 @@ sys32_mmap:
 
        .align          32
        .globl          sys32_lseek
-       .globl          sys32_chmod, sys32_chown, sys32_mknod
+       .globl          sys32_chmod, sys32_chown, sys32_lchown, sys32_mknod
 sys32_lseek:
        sra             %o1, 0, %o1
        mov             %o7, %g1
@@ -46,6 +46,15 @@ sys32_chown:
        srl             %o2, 16, %o2
        call            sys_chown
         mov            %g1, %o7
+sys32_lchown:
+       sll             %o1, 16, %o1
+       mov             %o7, %g1
+       sll             %o2, 16, %o2
+       srl             %o0, 0, %o0
+       srl             %o1, 16, %o1
+       srl             %o2, 16, %o2
+       call            sys_lchown
+        mov            %g1, %o7
 sys32_mknod:
        sll             %o2, 16, %o2
        mov             %o7, %g1
index e0e69abd943df33984c56c883e002640be701bc6..b5198074d38605359fe2a3bea54199285b2031ee 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.9 1997/12/11 15:15:44 jj Exp $
+/* $Id: sys_sparc.c,v 1.13 1998/03/29 10:10:52 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/mm.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
@@ -40,7 +41,7 @@ asmlinkage unsigned long sparc_brk(unsigned long brk)
        unsigned long ret;
 
        lock_kernel();
-       if(brk >= 0x80000000000ULL) {   /* VM hole */
+       if(brk >= 0x80000000000UL) {    /* VM hole */
                ret = current->mm->brk;
                goto out;
        }
@@ -128,6 +129,16 @@ asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long thir
        if (call <= SHMCTL) 
                switch (call) {
                case SHMAT:
+                       if (first >= 0) {
+                               extern struct shmid_ds *shm_segs[];
+                               struct shmid_ds *shp = shm_segs[(unsigned int) first % SHMMNI];
+                               if (shp == IPC_UNUSED || shp == IPC_NOID) {
+                                       err = -ENOMEM;
+                                       if ((unsigned long)ptr >= 0x80000000000UL - shp->shm_segsz &&
+                                           (unsigned long)ptr < 0xfffff80000000000UL)
+                                               goto out; /* Somebody is trying to fool us */
+                               }
+                       }
                        err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
                        goto out;
                case SHMDT:
@@ -162,29 +173,39 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
 
        lock_kernel();
        if (!(flags & MAP_ANONYMOUS)) {
-               if (fd >= NR_OPEN || !(file = current->files->fd[fd])){
+               file = fget(fd);
+               if (!file)
                        goto out;
-           }
        }
        retval = -ENOMEM;
+       len = PAGE_ALIGN(len);
        if(!(flags & MAP_FIXED) && !addr) {
                addr = get_unmapped_area(addr, len);
-               if(!addr){
-                       goto out;
-               }
+               if(!addr)
+                       goto out_putf;
        }
 
-       /* See asm-sparc64/uaccess.h */
        retval = -EINVAL;
-       if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
-               goto out;
-
-       if(addr >= 0x80000000000ULL) {
-               retval = current->mm->brk;
-               goto out;
+       if (current->tss.flags & SPARC_FLAG_32BIT) {
+               if (len > 0xf0000000UL || addr > 0xf0000000UL - len)
+                       goto out_putf;
+       } else {
+               if (len >= 0x80000000000UL || 
+                   (addr < 0x80000000000UL &&
+                    addr > 0x80000000000UL-len))
+                       goto out_putf;
+               if (addr >= 0x80000000000ULL && addr < 0xfffff80000000000UL) {
+                       /* VM hole */
+                       retval = current->mm->brk;
+                       goto out_putf;
+               }
        }
 
        retval = do_mmap(file, addr, len, prot, flags, off);
+
+out_putf:
+       if (file)
+               fput(file);
 out:
        unlock_kernel();
        return retval;
index 66993ebcb9282beaf261f1d9dde7a4d356b708b3..2844a4bf202ca908989f6d5e6d8f8bc5fadb258e 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: sys_sparc32.c,v 1.71 1997/12/11 15:15:11 jj Exp $
+/* $Id: sys_sparc32.c,v 1.77 1998/03/29 10:10:50 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  *
  * These routines maintain argument size conversion between 32bit and 64bit
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/fs.h> 
+#include <linux/file.h> 
 #include <linux/signal.h>
 #include <linux/utime.h>
 #include <linux/resource.h>
-#include <linux/sched.h>
 #include <linux/times.h>
 #include <linux/utime.h>
 #include <linux/utsname.h>
@@ -41,6 +42,7 @@
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/personality.h>
+#include <linux/stat.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -59,7 +61,6 @@
 extern char * getname_quicklist;
 extern int getname_quickcount;
 extern struct semaphore getname_quicklock;
-extern int kerneld_msqid;
 
 /* Tuning: increase locality by reusing same pages again...
  * if getname_quicklist becomes too long on low memory machines, either a limit
@@ -324,19 +325,9 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
                                if (!p) err = -ENOMEM;
                                else {
                                        err = 0;
-                                       if (first == kerneld_msqid) {
-                                               *(int *)p->mtext = 0;
-                                               if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
-                                                   __copy_from_user(&p->mtext[4], &(((struct msgbuf32 *)A(ptr))->mtext[0]), 4) ||
-                                                   __copy_from_user(&p->mtext[8], &(((struct msgbuf32 *)A(ptr))->mtext[4]), second-4))
-                                                       err = -EFAULT;
-                                               else
-                                                       second += 4;
-                                       } else {
-                                               if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
-                                                   __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
-                                                       err = -EFAULT;
-                                       }
+                                       if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+                                           __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
+                                               err = -EFAULT;
                                        if (!err) {
                                                mm_segment_t old_fs = get_fs();
                                                set_fs (KERNEL_DS);
@@ -379,18 +370,9 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
                                if (err < 0)
                                        goto out;
 
-                               if (first == kerneld_msqid) {
-                                       if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
-                                           __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[0]), &p->mtext[4], 4) ||
-                                           __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[4]), &p->mtext[8], err-8))
-                                               err = -EFAULT;
-                                       else
-                                               err -= 4;
-                               } else {
-                                       if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
-                                           __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err))
-                                               err = -EFAULT;
-                               }
+                               if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+                                   __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err))
+                                       err = -EFAULT;
                                kfree (p);
                                goto out;
                        }
@@ -939,14 +921,12 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
 {
        int error = -EBADF;
        struct file * file;
+       struct inode * inode;
        struct readdir_callback32 buf;
 
        lock_kernel();
-       if(fd >= NR_OPEN)
-               goto out;
-
-       file = current->files->fd[fd];
-       if(!file)
+       file = fget(fd);
+       if (!file)
                goto out;
 
        buf.count = 0;
@@ -954,12 +934,18 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
 
        error = -ENOTDIR;
        if (!file->f_op || !file->f_op->readdir)
-               goto out;
-
+               goto out_putf;
+       
+       inode = file->f_dentry->d_inode;
+       down(&inode->i_sem);
        error = file->f_op->readdir(file, &buf, fillonedir);
+       up(&inode->i_sem);
        if (error < 0)
-               goto out;
+               goto out_putf;
        error = buf.count;
+
+out_putf:
+       fput(file);
 out:
        unlock_kernel();
        return error;
@@ -1006,16 +992,14 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
 asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
 {
        struct file * file;
+       struct inode * inode;
        struct linux_dirent32 * lastdirent;
        struct getdents_callback32 buf;
        int error = -EBADF;
 
        lock_kernel();
-       if(fd >= NR_OPEN)
-               goto out;
-
-       file = current->files->fd[fd];
-       if(!file)
+       file = fget(fd);
+       if (!file)
                goto out;
 
        buf.current_dir = (struct linux_dirent32 *) A(dirent);
@@ -1025,17 +1009,22 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
 
        error = -ENOTDIR;
        if (!file->f_op || !file->f_op->readdir)
-               goto out;
+               goto out_putf;
 
+       inode = file->f_dentry->d_inode;
+       down(&inode->i_sem);
        error = file->f_op->readdir(file, &buf, filldir);
+       up(&inode->i_sem);
        if (error < 0)
-               goto out;
+               goto out_putf;
        lastdirent = buf.previous;
        error = buf.error;
        if(lastdirent) {
                put_user(file->f_pos, &lastdirent->d_off);
                error = count - buf.count;
        }
+out_putf:
+       fput(file);
 out:
        unlock_kernel();
        return error;
@@ -1258,6 +1247,27 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
        return ret;
 }
 
+extern asmlinkage int sys_xstat(int ver, char *filename, struct stat64 * statbuf);
+
+asmlinkage int sys32_xstat(int ver, u32 file, u32 statbuf)
+{
+       switch (ver & __XSTAT_VER_MASK) {
+       case __XSTAT_VER_1:
+               switch (ver & __XSTAT_VER_TYPEMASK) {
+               case __XSTAT_VER_XSTAT:
+                       return sys32_newstat(file, statbuf);
+               case __XSTAT_VER_LXSTAT:
+                       return sys32_newlstat(file, statbuf);
+               case __XSTAT_VER_FXSTAT:
+                       return sys32_newfstat(file, statbuf);
+               }
+               return -EINVAL;
+       case __XSTAT_VER_2:
+               return sys_xstat(ver, (char *)A(file), (struct stat64 *)A(statbuf));
+       }
+       return -EINVAL;
+}
+
 extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
 
 asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
@@ -2222,18 +2232,19 @@ asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags)
        char address[MAX_SOCK_ADDR];
        struct iovec iov[UIO_FASTIOV];
        unsigned char ctl[sizeof(struct cmsghdr) + 20];
-       struct msghdr kern_msg;
-       int err;
-       int total_len;
        unsigned char *ctl_buf = ctl;
+       struct msghdr kern_msg;
+       int err, total_len;
 
        if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg)))
                return -EFAULT;
        if(kern_msg.msg_iovlen > UIO_MAXIOV)
                return -EINVAL;
-       total_len = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
-       if(total_len < 0)
-               return total_len;
+       err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+       if (err < 0)
+               goto out;
+       total_len = err;
+
        if(kern_msg.msg_controllen) {
                struct cmsghdr32 *ucmsg = (struct cmsghdr32 *)kern_msg.msg_control;
                unsigned long *kcmsg;
@@ -2241,41 +2252,40 @@ asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags)
 
                if(kern_msg.msg_controllen > sizeof(ctl) &&
                   kern_msg.msg_controllen <= 256) {
+                       err = -ENOBUFS;
                        ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL);
-                       if(!ctl_buf) {
-                               if(kern_msg.msg_iov != iov)
-                                       kfree(kern_msg.msg_iov);
-                               return -ENOBUFS;
-                       }
+                       if(!ctl_buf)
+                               goto out_freeiov;
                }
                __get_user(cmlen, &ucmsg->cmsg_len);
                kcmsg = (unsigned long *) ctl_buf;
                *kcmsg++ = (unsigned long)cmlen;
+               err = -EFAULT;
                if(copy_from_user(kcmsg, &ucmsg->cmsg_level,
-                                 kern_msg.msg_controllen - sizeof(__kernel_size_t32))) {
-                       if(ctl_buf != ctl)
-                               kfree_s(ctl_buf, kern_msg.msg_controllen);
-                       if(kern_msg.msg_iov != iov)
-                               kfree(kern_msg.msg_iov);
-                       return -EFAULT;
-               }
+                                 kern_msg.msg_controllen - sizeof(__kernel_size_t32)))
+                       goto out_freectl;
                kern_msg.msg_control = ctl_buf;
        }
        kern_msg.msg_flags = user_flags;
 
        lock_kernel();
-       if(current->files->fd[fd]->f_flags & O_NONBLOCK)
-               kern_msg.msg_flags |= MSG_DONTWAIT;
-       if((sock = sockfd_lookup(fd, &err)) != NULL) {
+       sock = sockfd_lookup(fd, &err);
+       if (sock != NULL) {
+               if (sock->file->f_flags & O_NONBLOCK)
+                       kern_msg.msg_flags |= MSG_DONTWAIT;
                err = sock_sendmsg(sock, &kern_msg, total_len);
                sockfd_put(sock);
        }
        unlock_kernel();
 
+out_freectl:
+       /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
        if(ctl_buf != ctl)
-               kfree_s(ctl_buf, kern_msg.msg_controllen);
+               kfree(ctl_buf);
+out_freeiov:
        if(kern_msg.msg_iov != iov)
                kfree(kern_msg.msg_iov);
+out:
        return err;
 }
 
@@ -2299,17 +2309,18 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
        uaddr = kern_msg.msg_name;
        uaddr_len = &((struct msghdr32 *)A(user_msg))->msg_namelen;
        err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
-       if(err < 0)
-               return err;
+       if (err < 0)
+               goto out;
        total_len = err;
 
        cmsg_ptr = (unsigned long) kern_msg.msg_control;
        kern_msg.msg_flags = 0;
 
        lock_kernel();
-       if(current->files->fd[fd]->f_flags & O_NONBLOCK)
-               user_flags |= MSG_DONTWAIT;
-       if((sock = sockfd_lookup(fd, &err)) != NULL) {
+       sock = sockfd_lookup(fd, &err);
+       if (sock != NULL) {
+               if (sock->file->f_flags & O_NONBLOCK)
+                       user_flags |= MSG_DONTWAIT;
                err = sock_recvmsg(sock, &kern_msg, total_len, user_flags);
                if(err >= 0)
                        len = err;
@@ -2317,8 +2328,6 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
        }
        unlock_kernel();
 
-       if(kern_msg.msg_iov != iov)
-               kfree(kern_msg.msg_iov);
        if(uaddr != NULL && err >= 0)
                err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
        if(err >= 0) {
@@ -2330,6 +2339,10 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
                                         &((struct msghdr32 *)A(user_msg))->msg_controllen);
                }
        }
+
+       if(kern_msg.msg_iov != iov)
+               kfree(kern_msg.msg_iov);
+out:
        if(err < 0)
                return err;
        return len;
@@ -2838,25 +2851,25 @@ asmlinkage int sys32_get_kernel_syms(u32 table)
 #else /* CONFIG_MODULES */
 
 asmlinkage unsigned long
-sys_create_module(const char *name_user, size_t size)
+sys32_create_module(const char *name_user, size_t size)
 {
        return -ENOSYS;
 }
 
 asmlinkage int
-sys_init_module(const char *name_user, struct module *mod_user)
+sys32_init_module(const char *name_user, struct module *mod_user)
 {
        return -ENOSYS;
 }
 
 asmlinkage int
-sys_delete_module(const char *name_user)
+sys32_delete_module(const char *name_user)
 {
        return -ENOSYS;
 }
 
 asmlinkage int
-sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
+sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize,
                 size_t *ret)
 {
        /* Let the program know about the new interface.  Not that
@@ -2868,7 +2881,7 @@ sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
 }
 
 asmlinkage int
-sys_get_kernel_syms(struct kernel_sym *table)
+sys32_get_kernel_syms(struct kernel_sym *table)
 {
        return -ENOSYS;
 }
@@ -3327,3 +3340,19 @@ asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, u32 ubuf,
 {
        return sys_pwrite(fd, (char *) A(ubuf), count, pos);
 }
+
+
+extern asmlinkage int sys_personality(unsigned long);
+
+asmlinkage int sys32_personality(unsigned long personality)
+{
+       int ret;
+       lock_kernel();
+       if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+               personality = PER_LINUX32;
+       ret = sys_personality(personality);
+       unlock_kernel();
+       if (ret == PER_LINUX32)
+               ret = PER_LINUX;
+       return ret;
+}
index 4af388b998307c0951c242b9c9955abf9704434d..ad7bac534bf0db3ea50ec3990c9e90e8bd6f6657 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.7 1997/12/11 15:15:19 jj Exp $
+/* $Id: sys_sunos32.c,v 1.11 1998/03/29 10:10:55 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -16,6 +16,7 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/resource.h>
 #include <linux/ipc.h>
 #include <linux/shm.h>
@@ -70,23 +71,30 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
                flags &= ~MAP_NORESERVE;
        }
        retval = -EBADF;
-       if(!(flags & MAP_ANONYMOUS))
-               if(fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+       if(!(flags & MAP_ANONYMOUS)) {
+               if(fd >= SUNOS_NR_OPEN)
                        goto out;
+               file = fget(fd);
+               if (!file)
+                       goto out;
+               if (file->f_dentry && file->f_dentry->d_inode) {
+                       struct inode * inode = file->f_dentry->d_inode;
+                       if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
+                          MINOR(inode->i_rdev) == 5) {
+                               flags |= MAP_ANONYMOUS;
+                               fput(file);
+                               file = NULL;
+                       }
+               }
+       }
+
        retval = -ENOMEM;
        if(!(flags & MAP_FIXED) && !addr) {
                unsigned long attempt = get_unmapped_area(addr, len);
                if(!attempt || (attempt >= 0xf0000000UL))
-                       goto out;
+                       goto out_putf;
                addr = (u32) attempt;
        }
-       if(file->f_dentry && file->f_dentry->d_inode) {
-               if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
-                  MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
-                       flags |= MAP_ANONYMOUS;
-                       file = 0;
-               }
-       }
        if(!(flags & MAP_FIXED))
                addr = 0;
        ret_type = flags & _MAP_NEW;
@@ -98,6 +106,9 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
                         (unsigned long) off);
        if(!ret_type)
                retval = ((retval < 0xf0000000) ? 0 : retval);
+out_putf:
+       if (file)
+               fput(file);
 out:
        unlock_kernel();
        return (u32) retval;
@@ -372,6 +383,7 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
 asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
 {
        struct file * file;
+       struct inode * inode;
        struct sunos_dirent * lastdirent;
        struct sunos_dirent_callback buf;
        int error = -EBADF;
@@ -381,32 +393,39 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
        if(fd >= SUNOS_NR_OPEN)
                goto out;
 
-       file = current->files->fd[fd];
+       file = fget(fd);
        if(!file)
                goto out;
 
        error = -ENOTDIR;
        if (!file->f_op || !file->f_op->readdir)
-               goto out;
+               goto out_putf;
 
        error = -EINVAL;
        if(cnt < (sizeof(struct sunos_dirent) + 255))
-               goto out;
+               goto out_putf;
 
        buf.curr = (struct sunos_dirent *) dirent;
        buf.previous = NULL;
        buf.count = cnt;
        buf.error = 0;
 
+       inode = file->f_dentry->d_inode;
+       down(&inode->i_sem);
        error = file->f_op->readdir(file, &buf, sunos_filldir);
+       up(&inode->i_sem);
        if (error < 0)
-               goto out;
+               goto out_putf;
+
        lastdirent = buf.previous;
        error = buf.error;
        if (lastdirent) {
                put_user(file->f_pos, &lastdirent->d_off);
                error = cnt - buf.count;
        }
+
+out_putf:
+       fput(file);
 out:
        unlock_kernel();
        return error;
@@ -454,43 +473,51 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
 asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent,
                                   int cnt, u32 u_basep)
 {
+       void *dirent = (void *) A(u_dirent);
+       unsigned int *basep = (unsigned int *)A(u_basep);
        struct file * file;
+       struct inode * inode;
        struct sunos_direntry * lastdirent;
-       struct sunos_direntry_callback buf;
        int error = -EBADF;
-       void *dirent = (void *) A(u_dirent);
-       unsigned int *basep = (unsigned int *)A(u_basep);
+       struct sunos_direntry_callback buf;
 
        lock_kernel();
        if(fd >= SUNOS_NR_OPEN)
                goto out;
 
-       file = current->files->fd[fd];
+       file = fget(fd);
        if(!file)
                goto out;
 
        error = -ENOTDIR;
        if (!file->f_op || !file->f_op->readdir)
-               goto out;
+               goto out_putf;
 
        error = -EINVAL;
        if(cnt < (sizeof(struct sunos_direntry) + 255))
-               goto out;
+               goto out_putf;
 
        buf.curr = (struct sunos_direntry *) dirent;
        buf.previous = NULL;
        buf.count = cnt;
        buf.error = 0;
 
+       inode = file->f_dentry->d_inode;
+       down(&inode->i_sem);
        error = file->f_op->readdir(file, &buf, sunos_filldirentry);
+       up(&inode->i_sem);
        if (error < 0)
-               goto out;
+               goto out_putf;
+
        lastdirent = buf.previous;
        error = buf.error;
        if (lastdirent) {
                put_user(file->f_pos, basep);
                error = cnt - buf.count;
        }
+
+out_putf:
+       fput(file);
 out:
        unlock_kernel();
        return error;
@@ -622,14 +649,28 @@ asmlinkage int sunos_pathconf(u32 u_path, int name)
 extern asmlinkage int
 sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp);
 
-asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp)
+struct timeval32
+{
+       int tv_sec, tv_usec;
+};
+
+asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp_x)
 {
        int ret;
 
        /* SunOS binaries expect that select won't change the tvp contents */
        lock_kernel();
        current->personality |= STICKY_TIMEOUTS;
-       ret = sys32_select (width, inp, outp, exp, tvp);
+       ret = sys32_select (width, inp, outp, exp, tvp_x);
+       if (ret == -EINTR && tvp_x) {
+               struct timeval32 *tvp = (struct timeval32 *)A(tvp_x);
+               time_t sec, usec;
+
+               __get_user(sec, &tvp->tv_sec);
+               __get_user(usec, &tvp->tv_usec);
+               if (sec == 0 && usec == 0)
+                       ret = 0;
+       }
        unlock_kernel();
        return ret;
 }
@@ -1297,8 +1338,11 @@ asmlinkage int sunos_open(u32 filename, int flags, int mode)
 
 static inline int check_nonblock(int ret, int fd)
 {
-       if (ret == -EAGAIN && (current->files->fd[fd]->f_flags & O_NDELAY))
-               return -SUNOS_EWOULDBLOCK;
+       if (ret == -EAGAIN) {
+               struct file * file = fcheck(fd);
+               if (file && (file->f_flags & O_NDELAY))
+                       ret = -SUNOS_EWOULDBLOCK;
+       }
        return ret;
 }
 
@@ -1370,12 +1414,42 @@ asmlinkage int sunos_send(int fd, u32 buff, int len, unsigned flags)
        return ret;
 }
 
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+                                    char *optval, int optlen);
+
+asmlinkage int sunos_socket(int family, int type, int protocol)
+{
+       int ret, one = 1;
+
+       lock_kernel();
+       ret = sys_socket(family, type, protocol);
+       if (ret < 0)
+               goto out;
+
+       sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT,
+                      (char *)&one, sizeof(one));
+out:
+       unlock_kernel();
+       return ret;
+}
+
 asmlinkage int sunos_accept(int fd, u32 sa, u32 addrlen)
 {
-       int ret;
+       int ret, one = 1;
 
        lock_kernel();
-       ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa), (int *)A(addrlen)), fd);
+       while (1) {
+               ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa),
+                                               (int *)A(addrlen)), fd);
+               if (ret != -ENETUNREACH && ret != -EHOSTUNREACH)
+                       break;
+       }
+       if (ret < 0)
+               goto out;
+
+       sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT,
+                      (char *)&one, sizeof(one));
+out:
        unlock_kernel();
        return ret;
 }
index 48ae0ecdf5a34496c1a61d1c39c1bcedd9dd8f06..6389681dd7d8e0d414e7cb66651b9d05d2433923 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.37 1997/12/24 17:27:31 ecd Exp $
+/* $Id: systbls.S,v 1.41 1998/03/24 05:57:57 ecd Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -19,8 +19,8 @@
 sys_call_table32:
 /*0*/  .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
 /*5*/  .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
-/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod
-/*15*/ .word sys32_chmod, sys32_chown, sparc_brk, sys_nis_syscall, sys32_lseek
+/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_xstat, sys32_mknod
+/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_xmknod, sys32_lseek
 /*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
 /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys32_pause
 /*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -55,7 +55,7 @@ sys_call_table32:
        .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
        .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/        .word sys32_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*190*/        .word sys32_init_module, sys32_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
        .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/        .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
        .word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
@@ -78,8 +78,8 @@ sys_call_table64:
 sys_call_table:
 /*0*/  .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
 /*5*/  .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
-/*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_xstat, sys_mknod
+/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_xmknod, sys_lseek
 /*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
 /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_nis_syscall
 /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -117,7 +117,7 @@ sys_call_table:
 /*190*/        .word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
        .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_sigaction, sys_sgetmask
 /*200*/        .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
-       .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+       .word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
 /*210*/        .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
        .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
 /*220*/        .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
@@ -139,7 +139,7 @@ sunos_sys_table:
        .word sys_close, sunos_wait4, sys_creat
        .word sys_link, sys_unlink, sunos_execv
        .word sys_chdir, sunos_nosys, sys32_mknod
-       .word sys32_chmod, sys32_chown, sunos_brk
+       .word sys32_chmod, sys32_lchown, sunos_brk
        .word sunos_nosys, sys32_lseek, sunos_getpid
        .word sunos_nosys, sunos_nosys, sunos_nosys
        .word sunos_getuid, sunos_nosys, sys_ptrace
@@ -166,7 +166,7 @@ sunos_sys_table:
        .word sys32_getitimer, sys_gethostname, sys_sethostname
        .word sunos_getdtablesize, sys_dup2, sunos_nop
        .word sys32_fcntl, sunos_select, sunos_nop
-       .word sys_fsync, sys_setpriority, sys_socket
+       .word sys_fsync, sys_setpriority, sunos_socket
        .word sys_connect, sunos_accept
 /*100*/        .word sys_getpriority, sunos_send, sunos_recv
        .word sunos_nosys, sys_bind, sunos_setsockopt
index 8b0152231a17a94d7187c2ab919a4a430858aa5e..debb08888d6fb09ffa4364899b0842c7c143569e 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: time.c,v 1.12 1997/08/22 20:12:13 davem Exp $
+/* $Id: time.c,v 1.13 1998/03/15 17:23:47 ecd Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Eddie C. Dost   (ecd@skynet.be)
  *
  * Based largely on code which is:
  *
@@ -42,29 +43,64 @@ 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.
  */
-extern struct sun5_timer *linux_timers;
+unsigned long timer_tick_offset;
+static unsigned long timer_tick_compare;
+static unsigned long timer_ticks_per_usec;
 
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static __inline__ void timer_check_rtc(void)
 {
        /* 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. */
        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 */
+           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 */
+       }
+}
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       unsigned long ticks;
+
+       do {
+               do_timer(regs);
+
+               __asm__ __volatile__("
+                       rd      %%tick_cmpr, %0
+                       add     %0, %2, %0
+                       wr      %0, 0, %%tick_cmpr
+                       rd      %%tick, %1"
+                       : "=&r" (timer_tick_compare), "=r" (ticks)
+                       : "r" (timer_tick_offset));
+       } while (ticks >= timer_tick_compare);
+
+       timer_check_rtc();
 }
 
+#ifdef __SMP__
+void timer_tick_interrupt(struct pt_regs *regs)
+{
+       do_timer(regs);
+
+       /*
+        * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
+        */
+       __asm__ __volatile__("
+               rd      %%tick_cmpr, %0
+               add     %0, %1, %0"
+               : "=&r" (timer_tick_compare)
+               : "r" (timer_tick_offset));
+
+       timer_check_rtc();
+}
+#endif
+
 /* 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.
@@ -318,29 +354,32 @@ __initfunc(void time_init(void))
         */
 }
 
-extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+extern void init_timers(void (*func)(int, void *, struct pt_regs *),
+                       unsigned long *);
 
 __initfunc(void sun4u_start_timers(void))
 {
-       init_timers(timer_interrupt);
+       unsigned long clock;
+
+       init_timers(timer_interrupt, &clock);
+       timer_tick_offset = clock / HZ;
+       timer_ticks_per_usec = clock / 1000000;
 }
 
 static __inline__ unsigned long do_gettimeoffset(void)
 {
-       unsigned long offset = 0;
-       unsigned int count;
-
-       /* XXX -DaveM */
-#if 0
-       count = (*master_l10_counter >> 10) & 0x1fffff;
-#else
-       count = 0;
-#endif
+       unsigned long ticks;
 
-       if(test_bit(TIMER_BH, &bh_active))
-               offset = 1000000;
-
-       return offset + count;
+       __asm__ __volatile__("
+               rd      %%tick, %%g1
+               add     %1, %%g1, %0
+               sub     %0, %2, %0
+"
+               : "=r" (ticks)
+               : "r" (timer_tick_offset), "r" (timer_tick_compare)
+               : "g1", "g2");
+
+       return ticks / timer_ticks_per_usec;
 }
 
 void do_gettimeofday(struct timeval *tv)
@@ -353,13 +392,16 @@ void do_gettimeofday(struct timeval *tv)
         * nucleus atomic quad 128-bit loads.
         */
        __asm__ __volatile__("
-       sethi   %hi(linux_timers), %o1
+       sethi   %hi(timer_tick_offset), %g3
        sethi   %hi(xtime), %g2
-       ldx     [%o1 + %lo(linux_timers)], %g3
+       sethi   %hi(timer_tick_compare), %g1
+       ldx     [%g3 + %lo(timer_tick_offset)], %g3
        or      %g2, %lo(xtime), %g2
+       or      %g1, %lo(timer_tick_compare), %g1
 1:     ldda    [%g2] 0x24, %o4
        membar  #LoadLoad | #MemIssue
-       ldx     [%g3], %o1
+       rd      %tick, %o1
+       ldx     [%g1], %g7
        membar  #LoadLoad | #MemIssue
        ldda    [%g2] 0x24, %o2
        membar  #LoadLoad
@@ -367,24 +409,28 @@ void do_gettimeofday(struct timeval *tv)
        xor     %o5, %o3, %o3
        orcc    %o2, %o3, %g0
        bne,pn  %xcc, 1b
-        cmp    %o1, 0
-       bge,pt  %icc, 1f
-        sethi  %hi(tick), %o3
-       ldx     [%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
+        sethi  %hi(lost_ticks), %o2
+       sethi   %hi(timer_ticks_per_usec), %o3
+       ldx     [%o2 + %lo(lost_ticks)], %o2
+       add     %g3, %o1, %o1
+       ldx     [%o3 + %lo(timer_ticks_per_usec)], %o3
+       sub     %o1, %g7, %o1
+       brz,pt  %o2, 1f
+        udivx  %o1, %o3, %o1
+       sethi   %hi(10000), %g2
+       or      %g2, %lo(10000), %g2
+       add     %o1, %g2, %o1
+1:     sethi   %hi(1000000), %o2
+       srlx    %o5, 32, %o5
        or      %o2, %lo(1000000), %o2
+       add     %o5, %o1, %o5
        cmp     %o5, %o2
        bl,a,pn %xcc, 1f
         stx    %o4, [%o0 + 0x0]
        add     %o4, 0x1, %o4
        sub     %o5, %o2, %o5
        stx     %o4, [%o0 + 0x0]
-1:     stx     %o5, [%o0 + 0x8]");
+1:     st      %o5, [%o0 + 0x8]");
 }
 
 void do_settimeofday(struct timeval *tv)
@@ -401,6 +447,7 @@ void do_settimeofday(struct timeval *tv)
        time_state = TIME_BAD;
        time_maxerror = 0x70000000;
        time_esterror = 0x70000000;
+
        sti();
 }
 
index b5ca851ac091509144f4e4eb8848fc50399e204a..8604b330108df1ef0ca0b3c55a0317900d9ea2ca 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.2 1997/07/28 02:57:32 davem Exp $
+/* $Id: trampoline.S,v 1.3 1998/02/22 21:06:11 jj Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -172,8 +172,10 @@ bounce:
        mov     %o2, %g6
 
        wrpr    %o1, (PSTATE_MG | PSTATE_IE), %pstate
-       sethi   %hi(0x1ff8), %g2
-       or      %g2, %lo(0x1ff8), %g2
+#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+       sethi   %uhi(KERN_HIGHBITS), %g2
+       sllx    %g2, 32, %g2
+#undef KERN_HIGHBITS
        ldx     [%o2 + AOFF_task_mm], %g6
        ldx     [%g6 + AOFF_mm_pgd], %g6
        clr     %g7
index 6e1d30990620ac8ee74257f9fc0ffe253e18630d..b255c76239af02024b6ea61ae39382009107e389 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.44 1998/01/09 16:39:35 jj Exp $
+/* $Id: traps.c,v 1.49 1998/04/06 16:09:38 jj Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -191,7 +191,7 @@ void bad_trap (struct pt_regs *regs, long lvl)
                die_if_kernel ("Kernel bad trap", regs);
         current->tss.sig_desc = SUBSIG_BADTRAP(lvl - 0x100);
         current->tss.sig_address = regs->tpc;
-        send_sig(SIGILL, current, 1);
+        force_sig(SIGILL, current);
        unlock_kernel ();
 }
 
@@ -225,7 +225,9 @@ void data_access_exception (struct pt_regs *regs)
                        return;
                }
        }
-       send_sig(SIGSEGV, current, 1);
+       lock_kernel();
+       force_sig(SIGSEGV, current);
+       unlock_kernel();
 }
 
 #ifdef CONFIG_PCI
@@ -235,16 +237,35 @@ extern volatile int pci_poke_in_progress;
 extern volatile int pci_poke_faulted;
 #endif
 
+/* When access exceptions happen, we must do this. */
+static __inline__ void clean_and_reenable_l1_caches(void)
+{
+       unsigned long va;
+
+       /* Clean 'em. */
+       for(va =  0; va < (PAGE_SIZE << 1); va += 32) {
+               spitfire_put_icache_tag(va, 0x0);
+               spitfire_put_dcache_tag(va, 0x0);
+       }
+
+       /* Re-enable. */
+       __asm__ __volatile__("flush %%g6\n\t"
+                            "membar #Sync\n\t"
+                            "stxa %0, [%%g0] %1\n\t"
+                            "membar #Sync"
+                            : /* no outputs */
+                            : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+                                   LSU_CONTROL_IM | LSU_CONTROL_DM),
+                            "i" (ASI_LSU_CONTROL)
+                            : "memory");
+}
+
 void do_dae(struct pt_regs *regs)
 {
 #ifdef CONFIG_PCI
-#ifdef DEBUG_PCI_POKES
-       prom_printf(" (POKE ");
-#endif
        if(pci_poke_in_progress) {
-               unsigned long va;
 #ifdef DEBUG_PCI_POKES
-               prom_printf("tpc[%016lx] tnpc[%016lx] ",
+               prom_printf(" (POKE tpc[%016lx] tnpc[%016lx] ",
                            regs->tpc, regs->tnpc);
 #endif
                pci_poke_faulted = 1;
@@ -255,39 +276,30 @@ void do_dae(struct pt_regs *regs)
                prom_printf("PCI) ");
                /* prom_halt(); */
 #endif
-               /* Re-enable I/D caches, Ultra turned them off. */
-               for(va =  0; va < (PAGE_SIZE << 1); va += 32) {
-                       spitfire_put_icache_tag(va, 0x0);
-                       spitfire_put_dcache_tag(va, 0x0);
-               }
-               __asm__ __volatile__("flush %%g6\n\t"
-                                    "membar #Sync\n\t"
-                                    "stxa %0, [%%g0] %1\n\t"
-                                    "membar #Sync"
-                                    : /* no outputs */
-                                    : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
-                                           LSU_CONTROL_IM | LSU_CONTROL_DM),
-                                      "i" (ASI_LSU_CONTROL)
-                                    : "memory");
+               clean_and_reenable_l1_caches();
                return;
        }
-#ifdef DEBUG_PCI_POKES
-       prom_printf("USER) ");
-       prom_printf("tpc[%016lx] tnpc[%016lx]\n");
-       prom_halt();
 #endif
-#endif
-       send_sig(SIGSEGV, current, 1);
+       clean_and_reenable_l1_caches();
+       lock_kernel();
+       force_sig(SIGSEGV, current);
+       unlock_kernel();
 }
 
 void instruction_access_exception (struct pt_regs *regs)
 {
-       send_sig(SIGSEGV, current, 1);
+       clean_and_reenable_l1_caches();
+
+       lock_kernel();
+       force_sig(SIGSEGV, current);
+       unlock_kernel();
 }
 
 void do_iae(struct pt_regs *regs)
 {
-       send_sig(SIGSEGV, current, 1);
+       lock_kernel();
+       force_sig(SIGSEGV, current);
+       unlock_kernel();
 }
 
 void do_fpe_common(struct pt_regs *regs)
@@ -312,11 +324,7 @@ void do_fpieee(struct pt_regs *regs)
        do_fpe_common(regs);
 }
 
-#ifdef CONFIG_MATHEMU_MODULE
-volatile int (*handle_mathemu)(struct pt_regs *, struct fpustate *) = NULL;
-#else
 extern int do_mathemu(struct pt_regs *, struct fpustate *);
-#endif
 
 void do_fpother(struct pt_regs *regs)
 {
@@ -326,18 +334,7 @@ void do_fpother(struct pt_regs *regs)
        switch ((f->fsr & 0x1c000)) {
        case (2 << 14): /* unfinished_FPop */
        case (3 << 14): /* unimplemented_FPop */
-#ifdef CONFIG_MATHEMU_MODULE
-#ifdef CONFIG_KMOD
-               if (!handle_mathemu)
-                       request_module("math-emu");
-#endif
-               if (handle_mathemu)
-                       ret = handle_mathemu(regs, f);
-#else
-#ifdef CONFIG_MATHEMU
                ret = do_mathemu(regs, f);
-#endif
-#endif
                break;
        }
        if (ret) return;
@@ -576,27 +573,33 @@ void cache_flush_trap(struct pt_regs *regs)
 #else
 #error SMP not supported on sparc64 yet
 #endif
+
+#if 0
+/* Broken */
        int size = prom_getintdefault(node, "ecache-size", 512*1024);
        int i, j;
-       unsigned long addr, page_nr;
+       unsigned long addr;
+       struct page *page, *end;
 
        regs->tpc = regs->tnpc;
        regs->tnpc = regs->tnpc + 4;
        if (!suser()) return;
        size >>= PAGE_SHIFT;
        addr = PAGE_OFFSET - PAGE_SIZE;
+       page = mem_map - 1;
+       end = mem_map + max_mapnr;
        for (i = 0; i < size; i++) {
                do {
                        addr += PAGE_SIZE;
-                       page_nr = MAP_NR(addr);
-                       if (page_nr >= max_mapnr) {
+                       page++;
+                       if (page >= end)
                                return;
-                       }
-               } while (!PageReserved (mem_map + page_nr));
+               } while (!PageReserved(page));
                /* E-Cache line size is 64B. Let us pollute it :)) */
                for (j = 0; j < PAGE_SIZE; j += 64)
                        __asm__ __volatile__ ("ldx [%0 + %1], %%g1" : : "r" (j), "r" (addr) : "g1");
        }
+#endif
 }
 #endif
 
index b22cf82f7e2104d1ba997c79ba842310206e5460..3d17fb3cb6510f32ac1401781e4c00da88f527bc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.22 1997/10/16 07:07:46 jj Exp $
+/* $Id: ttable.S,v 1.23 1998/03/15 17:23:48 ecd Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -6,7 +6,7 @@
 
 #include <linux/config.h>
 
-       .globl  sparc64_ttable_tl0, sparc64_ttable_tl1
+       .globl  sparc64_ttable_tl0, tl0_itick, sparc64_ttable_tl1,
 
 sparc64_ttable_tl0:
 tl0_resv000:   BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
@@ -45,7 +45,7 @@ tl0_irq7:     TRAP_IRQ(handler_irq, 7)  TRAP_IRQ(handler_irq, 8)
 tl0_irq9:      TRAP_IRQ(handler_irq, 9)  TRAP_IRQ(handler_irq, 10)
 tl0_irq11:     TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
 tl0_irq13:     TRAP_IRQ(handler_irq, 13)
-tl0_itick:     TRAP_TICK
+tl0_itick:     TRAP_IRQ(handler_irq, 14)
 tl0_irq15:     TRAP_IRQ(handler_irq, 15)
 tl0_resv050:   BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
 tl0_resv056:   BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
index efd2bfcd58c35a7b2f2bd17f51b5a44a14317429..fff41bab24b362a57b1d3dd69b96fb621e35d790 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: VIScsumcopy.S,v 1.2 1997/08/19 15:25:22 jj Exp $
+/* $Id: VIScsumcopy.S,v 1.4 1998/04/01 08:29:52 davem Exp $
  * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
  *            copying utilizing the UltraSparc Visual Instruction Set.
  *
@@ -393,22 +393,22 @@ vis0s:    wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
        add             %src, 128, %src         /*  IEU0        Group                   */
        ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
        ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
-       fmovd           %f48, %f62              /*  FPA         Group                   */
-       faligndata      %f0, %f2, %f48          /*  FPA         Group                   */
-       fcmpgt32        %f32, %f2, %x1          /*  FPM         Group                   */
+       fmovd           %f48, %f62              /*  FPA         Group   f0 available    */
+       faligndata      %f0, %f2, %f48          /*  FPA         Group   f2 available    */
+       fcmpgt32        %f32, %f2, %x1          /*  FPM         Group   f4 available    */
        fpadd32         %f0, %f62, %f0          /*  FPA                                 */
-       fcmpgt32        %f32, %f4, %x2          /*  FPM         Group                   */
+       fcmpgt32        %f32, %f4, %x2          /*  FPM         Group   f6 available    */
        faligndata      %f2, %f4, %f50          /*  FPA                                 */
-       fcmpgt32        %f62, %f0, %x3          /*  FPM         Group                   */
+       fcmpgt32        %f62, %f0, %x3          /*  FPM         Group   f8 available    */
        faligndata      %f4, %f6, %f52          /*  FPA                                 */
-       fcmpgt32        %f32, %f6, %x4          /*  FPM         Group                   */
+       fcmpgt32        %f32, %f6, %x4          /*  FPM         Group   f10 available   */
        inc             %x1                     /*  IEU0                                */
        faligndata      %f6, %f8, %f54          /*  FPA                                 */
-       fcmpgt32        %f32, %f8, %x5          /*  FPM         Group                   */
+       fcmpgt32        %f32, %f8, %x5          /*  FPM         Group   f12 available   */
        srl             %x1, 1, %x1             /*  IEU0                                */
        inc             %x2                     /*  IEU1                                */
        faligndata      %f8, %f10, %f56         /*  FPA                                 */
-       fcmpgt32        %f32, %f10, %x6         /*  FPM         Group                   */
+       fcmpgt32        %f32, %f10, %x6         /*  FPM         Group   f14 available   */
        srl             %x2, 1, %x2             /*  IEU0                                */
        add             %sum, %x1, %sum         /*  IEU1                                */
        faligndata      %f10, %f12, %f58        /*  FPA                                 */
@@ -451,6 +451,7 @@ vis1s:      wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
        add             %src, 128 - 8, %src     /*  IEU0        Group                   */
        ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
        ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f0, %f58               /*  FPA         Group                   */
        fmovd           %f48, %f0               /*  FPA         Group                   */
        fcmpgt32        %f32, %f2, %x2          /*  FPM         Group                   */
        faligndata      %f2, %f4, %f48          /*  FPA                                 */
@@ -503,9 +504,10 @@ vis2s:     wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
        add             %src, 128 - 16, %src    /*  IEU0        Group                   */
        ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
        ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f0, %f56               /*  FPA         Group                   */
        fmovd           %f48, %f0               /*  FPA         Group                   */      
        sub             %dst, 64, %dst          /*  IEU0                                */
-       fzero           %f2                     /*  FPA         Group                   */
+       fpsub32         %f2, %f2, %f2           /*  FPA         Group                   */
        fcmpgt32        %f32, %f4, %x3          /*  FPM         Group                   */
        faligndata      %f4, %f6, %f48          /*  FPA                                 */
        fcmpgt32        %f32, %f6, %x4          /*  FPM         Group                   */
@@ -552,10 +554,11 @@ vis3s:    wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
        add             %src, 128 - 24, %src    /*  IEU0        Group                   */
        ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
        ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f0, %f54               /*  FPA         Group                   */
        fmovd           %f48, %f0               /*  FPA         Group                   */
        sub             %dst, 64, %dst          /*  IEU0                                */
-       fzero           %f2                     /*  FPA         Group                   */
-       fzero           %f4                     /*  FPA         Group                   */
+       fpsub32         %f2, %f2, %f2           /*  FPA         Group                   */
+       fpsub32         %f4, %f4, %f4           /*  FPA         Group                   */
        fcmpgt32        %f32, %f6, %x4          /*  FPM         Group                   */
        faligndata      %f6, %f8, %f48          /*  FPA                                 */
        fcmpgt32        %f32, %f8, %x5          /*  FPM         Group                   */
@@ -597,11 +600,12 @@ vis4s:    wr              %g2, ASI_BLK_XOR, %asi  /*  LSU         Group                   */
        add             %src, 128 - 32, %src    /*  IEU0        Group                   */
        ldda            [%src-128] %asi, %f0    /*  Load        Group                   */
        ldda            [%src-64] %asi, %f16    /*  Load        Group                   */
+       fmovd           %f0, %f52               /*  FPA         Group                   */
        fmovd           %f48, %f0               /*  FPA         Group                   */
        sub             %dst, 64, %dst          /*  IEU0                                */
-       fzero           %f2                     /*  FPA         Group                   */
-       fzero           %f4                     /*  FPA         Group                   */
-       fzero           %f6                     /*  FPA         Group                   */
+       fpsub32         %f2, %f2, %f2           /*  FPA         Group                   */
+       fpsub32         %f4, %f4, %f4           /*  FPA         Group                   */
+       fpsub32         %f6, %f6, %f6           /*  FPA         Group                   */
        clr             %x4                     /*  IEU0                                */
        fcmpgt32        %f32, %f8, %x5          /*  FPM         Group                   */
        faligndata      %f8, %f10, %f48         /*  FPA                                 */
@@ -697,9 +701,9 @@ vis6s:      add             %src, 128 - 48, %src    /*  IEU0        Group                   */
        clr             %x6                     /*  IEU0                                */
        fcmpgt32        %f32, %f12, %x7         /*  FPM         Group                   */
        sub             %dst, 64, %dst          /*  IEU0                                */
-       faligndata      %f12, %f14, %f48        /*  FPA                                 */
        fcmpgt32        %f32, %f14, %x8         /*  FPM         Group                   */
-       fmovd           %f14, %f50              /*  FPA                                 */
+       faligndata      %f12, %f14, %f48        /*  FPA                                 */
+       fmovd           %f14, %f50              /*  FPA         Group                   */
 vis6:  DO_THE_TRICK(   f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,     
                        ,f52,f54,f56,f58,f60,f62,f48,f50,f50,
                        ,LDBLK(f32),    ,,,,,,STBLK,,
index ea816d98eef7b2ae5c8bdd85f2df32699c8aa1bb..8f695b1e259e00cfa772064e2f5f7405c421e9f1 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Makefile for the FPU Quad (long double) instruction emulation.
+# Makefile for the FPU instruction emulation.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
@@ -16,18 +16,10 @@ O_OBJS   := math.o fabsq.o faddq.o fdivq.o fdmulq.o fitoq.o                 \
                fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o                \
                fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o
 
-ifeq ($(CONFIG_MATHEMU),m)
-M_OBJS   := $(O_TARGET)
-endif
-
 .S.s:
        $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
 
 .S.o:
        $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
-ifneq ($(CONFIG_MATHEMU),y)
-do_it_all:
-endif
-
 include $(TOPDIR)/Rules.make
index b68d76790d3f2ba9aabeef490eafbaca2bdf1c4d..6aff6fdd5ff3cdf3a9915a21e85265fc85bda785 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 #if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickle kid.  Go buy yourself a real computer."
+#error "Here's a nickel kid.  Go buy yourself a real computer."
 #endif
 
 #if _FP_W_TYPE_SIZE < 64
index e6aa497c8ae9d44e2ab2bc55df8da18a8c90c6fa..e01b02046b700bf273ac3cdba66a9323551d1add 100644 (file)
@@ -1,18 +1,5 @@
-#include "soft-fp.h"
-#include "quad.h"
-
 int FABSQ(unsigned long *rd, unsigned long *rs2)
 {
-/*
-       FP_DECL_Q(A); FP_DECL_Q(R);
-
-       __FP_UNPACK_Q(A, rs2);
-       _FP_FRAC_COPY_2(R, A);
-       R_c = A_c;
-       R_e = A_e;
-       R_s = 0;
-       __FP_PACK_Q(rd, R);
- */
        rd[0] = rs2[0] & 0x7fffffffffffffffUL;
        rd[1] = rs2[1];
        return 1;
index cb37bc0db2219277887aa0f57de003918b34ec5d..e74b1b06bbf20cb92c0e5691fa935d9655ba0e7a 100644 (file)
@@ -11,11 +11,8 @@ int FCMPEQ(void *rd, void *rs2, void *rs1)
        rd = (void *)(((long)rd)&~3);
        __FP_UNPACK_Q(A, rs1);
        __FP_UNPACK_Q(B, rs2);
-       FP_CMP_Q(ret, A, B, 3);
-       switch (ret) {
-       case 1: ret = 2; break;
-       case -1: ret = 1; break;
-       }
+       FP_CMP_Q(ret, B, A, 3);
+       if (ret == -1) ret = 2;
        fsr = *(unsigned long *)rd;
        switch (fccno) {
        case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
index 81dadf47aa26ab44872c6d869c894ad6f9966a09..9effefb1f15d9f52a20f607e475e47e5189e5c78 100644 (file)
@@ -11,11 +11,8 @@ int FCMPQ(void *rd, void *rs2, void *rs1)
        rd = (void *)(((long)rd)&~3);
        __FP_UNPACK_Q(A, rs1);
        __FP_UNPACK_Q(B, rs2);
-       FP_CMP_Q(ret, A, B, 3);
-       switch (ret) {
-       case 1: ret = 2; break;
-       case -1: ret = 1; break;
-       }
+       FP_CMP_Q(ret, B, A, 3);
+       if (ret == -1) ret = 2;
        fsr = *(unsigned long *)rd;
        switch (fccno) {
        case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
index dcdea32021a6fe99e55dd341b0b73022615aff1b..2251e330872c0d013e2bae1765eafa82102b5d58 100644 (file)
@@ -1,18 +1,7 @@
-#include "soft-fp.h"
-#include "quad.h"
-
 int FNEGQ(unsigned long *rd, unsigned long *rs2)
 {
-/*
-       FP_DECL_Q(A); FP_DECL_Q(R);
-
-       __FP_UNPACK_Q(A, rs2);
-       FP_NEG_Q(R, A);
-       __FP_PACK_Q(rd, R);
- */
        rd[0] = rs2[0] ^ 0x8000000000000000UL;
        rd[1] = rs2[1];
        return 1;
 }
 
-                
index 58ed21062c0eb41a0d3c281ffeb8b2fb193d8128..e0380720f68c07fffc4292a3b04848e3c968b589 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: math.c,v 1.3 1997/10/15 07:28:55 jj Exp $
+/* $Id: math.c,v 1.4 1998/04/06 16:09:57 jj Exp $
  * arch/sparc64/math-emu/math.c
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -7,7 +7,6 @@
  * of glibc and has appropriate copyrights in it.
  */
 
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 
@@ -70,7 +69,6 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
 
        if(tstate & TSTATE_PRIV)
                die_if_kernel("FPQuad from kernel", regs);
-       MOD_INC_USE_COUNT;
        if(current->tss.flags & SPARC_FLAG_32BIT)
                pc = (u32)pc;
        if (get_user(insn, (u32 *)pc) != -EFAULT) {
@@ -182,28 +180,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
                func(rd, rs2, rs1);
                regs->tpc = regs->tnpc;
                regs->tnpc += 4;
-               MOD_DEC_USE_COUNT;
                return 1;
        }
-err:   MOD_DEC_USE_COUNT;
-       return 0;
+err:   return 0;
 }
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Jakub Jelinek (jj@sunsite.mff.cuni.cz), Richard Henderson (rth@cygnus.com)");
-MODULE_DESCRIPTION("FPU emulation module");
-
-extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
-
-int init_module(void)
-{
-       handle_mathemu = do_mathemu;
-       return 0;
-}
-
-void cleanup_module(void)
-{
-       handle_mathemu = NULL;
-}
-#endif
index 879b6004f4fe1d95bcff41c19c5880ffd8866a7f..5999cfc3bd24e0e7dbdfa34f2447b384f4e5b37e 100644 (file)
     R##_f1 = _FP_FRAC_WORD_4(_z,1);                                    \
   } while (0)
 
+/* This next macro appears to be totally broken. Fortunately nowhere
+ * seems to use it :-> The problem is that we define _z[4] but
+ * then use it in _FP_FRAC_SRS_4, which will attempt to access
+ * _z_f[n] which will cause an error. The fix probably involves 
+ * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998 
+ */
 #define _FP_MUL_MEAT_2_gmp(fs, R, X, Y)                                        \
   do {                                                                 \
     _FP_W_TYPE _x[2], _y[2], _z[4];                                    \
 
 /*
  * Division algorithms:
+ * This seems to be giving me difficulties -- PMM 
+ * Look, NetBSD seems to be able to comment algorithms. Can't you?
+ * I've thrown printks at the problem.
+ * This now appears to work, but I still don't really know why.
+ * Also, I don't think the result is properly normalised...
  */
 
 #define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y)                            \
     _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0;               \
     _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0;                             \
     _FP_W_TYPE _rmem[2], _qmem[2];                                     \
-                                                                       \
+    /* I think this check is to ensure that the result is normalised.   \
+     * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in         \
+     * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y.      \
+     * In this case we tweak things. (this is based on comments in      \
+     * the NetBSD FPU emulation code. )                                 \
+     * We know X,Y are normalised because we ensure this as part of     \
+     * the unpacking process. -- PMM                                    \
+     */                                                                        \
     if (_FP_FRAC_GT_2(X, Y))                                           \
       {                                                                        \
-       R##_e++;                                                        \
+/*     R##_e++; */                                                     \
        _n_f3 = X##_f1 >> 1;                                            \
        _n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1;          \
        _n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1);                        \
       }                                                                        \
     else                                                               \
       {                                                                        \
+       R##_e--;                                                        \
        _n_f3 = X##_f1;                                                 \
        _n_f2 = X##_f0;                                                 \
        _n_f1 = _n_f0 = 0;                                              \
       }                                                                        \
                                                                        \
     /* Normalize, i.e. make the most significant bit of the            \
-       denominator set.  */                                            \
-    _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs - 1);                                \
+       denominator set.  CHANGED: - 1 to nothing -- PMM */             \
+    _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs /* -1 */);                   \
                                                                        \
     /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4    \
        primitive snagged from libgcc2.c.  */                           \
                                                                        \
     R##_f1 = _q_f1;                                                    \
     R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0);                           \
+    /* adjust so answer is normalized again. I'm not sure what the     \
+     * final sz param should be. In practice it's never used since      \
+     * N is 1 which is always going to be < _FP_W_TYPE_SIZE...         \
+     */                                                                        \
+    /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs); */                      \
   } while (0)
 
 
     D##_f1 = 0;                                                                \
     _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
   } while (0)
+
index 2f917a847ba56e5e34cf2a41b960392533a4d2bf..5f7099271f731e0979513709b942920a0b6d40b9 100644 (file)
@@ -1,11 +1,41 @@
 /*
  * Basic four-word fraction declaration and manipulation.
+ *
+ * When adding quadword support for 32 bit machines, we need
+ * to be a little careful as double multiply uses some of these
+ * macros: (in op-2.h)
+ * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4,
+ * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4
+ * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use
+ * _FP_FRAC_DECL_4: it appears to be broken and is not used 
+ * anywhere anyway. )
+ *
+ * I've now fixed all the macros that were here from the sparc64 code.
+ * [*none* of the shift macros were correct!] -- PMM 02/1998
+ * 
+ * The only quadword stuff that remains to be coded is: 
+ * 1) the conversion to/from ints, which requires 
+ * that we check (in op-common.h) that the following do the right thing
+ * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt)
+ * 2) multiply, divide and sqrt, which require:
+ * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q),
+ * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to
+ * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h.
+ * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for
+ * these; they are used nowhere else. ]
  */
 
 #define _FP_FRAC_DECL_4(X)     _FP_W_TYPE X##_f[4]
 #define _FP_FRAC_COPY_4(D,S)                   \
   (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1],   \
    D##_f[2] = S##_f[2], D##_f[3] = S##_f[3])
+/* The _FP_FRAC_SET_n(X,I) macro is intended for use with another
+ * macro such as _FP_ZEROFRAC_n which returns n comma separated values.
+ * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3)
+ * which just assigns the In values to the array X##_f[]. 
+ * This is why the number of parameters doesn't appear to match
+ * at first glance...      -- PMM 
+ */
 #define _FP_FRAC_SET_4(X,I)    __FP_FRAC_SET_4(X, I)
 #define _FP_FRAC_HIGH_4(X)     (X##_f[3])
 #define _FP_FRAC_LOW_4(X)      (X##_f[0])
     _down = _FP_W_TYPE_SIZE - _up;                                     \
     for (_i = 3; _i > _skip; --_i)                                     \
       X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down; \
-    X##_f[_i] <<= _up;                                                 \
+/* bugfixed: was X##_f[_i] <<= _up;  -- PMM 02/1998 */                  \
+    X##_f[_i] = X##_f[0] << _up;                                       \
     for (--_i; _i >= 0; --_i)                                          \
       X##_f[_i] = 0;                                                   \
   } while (0)
 
+/* This one was broken too */
 #define _FP_FRAC_SRL_4(X,N)                                            \
   do {                                                                 \
     _FP_I_TYPE _up, _down, _skip, _i;                                  \
     _skip = (N) / _FP_W_TYPE_SIZE;                                     \
     _down = (N) % _FP_W_TYPE_SIZE;                                     \
     _up = _FP_W_TYPE_SIZE - _down;                                     \
-    for (_i = 0; _i < 4-_skip; ++_i)                                   \
+    for (_i = 0; _i < 3-_skip; ++_i)                                   \
       X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
-    X##_f[_i] >>= _down;                                               \
+    X##_f[_i] = X##_f[3] >> _down;                                     \
     for (++_i; _i < 4; ++_i)                                           \
       X##_f[_i] = 0;                                                   \
   } while (0)
 
 
-/* Right shift with sticky-lsb.  */
+/* Right shift with sticky-lsb. 
+ * What this actually means is that we do a standard right-shift,
+ * but that if any of the bits that fall off the right hand side
+ * were one then we always set the LSbit.
+ */
 #define _FP_FRAC_SRS_4(X,N,size)                                       \
   do {                                                                 \
     _FP_I_TYPE _up, _down, _skip, _i;                                  \
     _up = _FP_W_TYPE_SIZE - _down;                                     \
     for (_s = _i = 0; _i < _skip; ++_i)                                        \
       _s |= X##_f[_i];                                                 \
-    _s = X##_f[_i] << _up;                                             \
-    X##_f[0] = X##_f[_skip] >> _down | X##_f[_skip+1] << _up | (_s != 0); \
-    for (_i = 1; _i < 4-_skip; ++_i)                                   \
+    _s |= X##_f[_i] << _up;                                            \
+/* s is now != 0 if we want to set the LSbit */                         \
+    for (_i = 0; _i < 3-_skip; ++_i)                                   \
       X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
-    X##_f[_i] >>= _down;                                               \
+    X##_f[_i] = X##_f[3] >> _down;                                     \
     for (++_i; _i < 4; ++_i)                                           \
       X##_f[_i] = 0;                                                   \
+    /* don't fix the LSB until the very end when we're sure f[0] is stable */ \
+    X##_f[0] |= (_s != 0);                                              \
   } while (0)
 
 #define _FP_FRAC_ADD_4(R,X,Y)                                          \
                  X##_f[3], X##_f[2], X##_f[1], X##_f[0],               \
                  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
 
+#define _FP_FRAC_SUB_4(R,X,Y)                                           \
+  __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],              \
+                 X##_f[3], X##_f[2], X##_f[1], X##_f[0],               \
+                 Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
+
+#define _FP_FRAC_ADDI_4(X,I)                                            \
+  __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I)
+
+#define _FP_ZEROFRAC_4  0,0,0,0
+#define _FP_MINFRAC_4   0,0,0,1
+
+#define _FP_FRAC_ZEROP_4(X)     ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
+#define _FP_FRAC_NEGP_4(X)      ((_FP_WS_TYPE)X##_f[3] < 0)
+#define _FP_FRAC_OVERP_4(fs,X)  (X##_f[0] & _FP_OVERFLOW_##fs)
+
+#define _FP_FRAC_EQ_4(X,Y)                              \
+ (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1]          \
+  && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3])
+
+#define _FP_FRAC_GT_4(X,Y)                              \
+ (X##_f[3] > Y##_f[3] ||                                \
+  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||      \
+   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||     \
+    (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0])       \
+   ))                                                   \
+  ))                                                    \
+ )
+
+#define _FP_FRAC_GE_4(X,Y)                              \
+ (X##_f[3] > Y##_f[3] ||                                \
+  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||      \
+   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||     \
+    (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0])      \
+   ))                                                   \
+  ))                                                    \
+ )
+
+
+#define _FP_FRAC_CLZ_4(R,X)             \
+  do {                                  \
+    if (X##_f[3])                       \
+    {                                   \
+        __FP_CLZ(R,X##_f[3]);           \
+    }                                   \
+    else if (X##_f[2])                  \
+    {                                   \
+        __FP_CLZ(R,X##_f[2]);           \
+        R += _FP_W_TYPE_SIZE;           \
+    }                                   \
+    else if (X##_f[1])                  \
+    {                                   \
+        __FP_CLZ(R,X##_f[2]);           \
+        R += _FP_W_TYPE_SIZE*2;         \
+    }                                   \
+    else                                \
+    {                                   \
+        __FP_CLZ(R,X##_f[0]);           \
+        R += _FP_W_TYPE_SIZE*3;         \
+    }                                   \
+  } while(0)
+
+
+#define _FP_UNPACK_RAW_4(fs, X, val)                            \
+  do {                                                          \
+    union _FP_UNION_##fs _flo; _flo.flt = (val);               \
+    X##_f[0] = _flo.bits.frac0;                                 \
+    X##_f[1] = _flo.bits.frac1;                                 \
+    X##_f[2] = _flo.bits.frac2;                                 \
+    X##_f[3] = _flo.bits.frac3;                                 \
+    X##_e  = _flo.bits.exp;                                     \
+    X##_s  = _flo.bits.sign;                                    \
+  } while (0)
+
+#define _FP_PACK_RAW_4(fs, val, X)                              \
+  do {                                                          \
+    union _FP_UNION_##fs _flo;                                 \
+    _flo.bits.frac0 = X##_f[0];                                 \
+    _flo.bits.frac1 = X##_f[1];                                 \
+    _flo.bits.frac2 = X##_f[2];                                 \
+    _flo.bits.frac3 = X##_f[3];                                 \
+    _flo.bits.exp   = X##_e;                                    \
+    _flo.bits.sign  = X##_s;                                    \
+    (val) = _flo.flt;                                          \
+  } while (0)
+
+
 /*
  * Internals 
  */
    r2 = x2 + y2 + (r1 < x1),                                           \
    r3 = x3 + y3 + (r2 < x2))
 #endif
+
+#ifndef __FP_FRAC_SUB_4
+#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)           \
+  (r0 = x0 - y0,                                                        \
+   r1 = x1 - y1 - (r0 > x0),                                            \
+   r2 = x2 - y2 - (r1 > x1),                                            \
+   r3 = x3 - y3 - (r2 > x2))
+#endif
+
+#ifndef __FP_FRAC_ADDI_4
+/* I always wanted to be a lisp programmer :-> */
+#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)                                 \
+  (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2)))
+#endif
+
+/* Convert FP values between word sizes. This appears to be more
+ * complicated than I'd have expected it to be, so these might be
+ * wrong... These macros are in any case somewhat bogus because they
+ * use information about what various FRAC_n variables look like 
+ * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do
+ * the ones in op-2.h and op-1.h. 
+ */
+#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S)                               \
+   do {                                                                 \
+     _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
+                        _FP_WFRACBITS_##sfs);                           \
+     D##_f = S##_f[0];                                                   \
+  } while (0)
+
+#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S)                               \
+   do {                                                                 \
+     _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
+                        _FP_WFRACBITS_##sfs);                           \
+     D##_f0 = S##_f[0];                                                  \
+     D##_f1 = S##_f[1];                                                  \
+  } while (0)
+
+/* Assembly/disassembly for converting to/from integral types.  
+ * No shifting or overflow handled here.
+ */
+/* Put the FP value X into r, which is an integer of size rsize. */
+#define _FP_FRAC_ASSEMBLE_4(r, X, rsize)                                \
+  do {                                                                  \
+    if (rsize <= _FP_W_TYPE_SIZE)                                       \
+      r = X##_f[0];                                                     \
+    else if (rsize <= 2*_FP_W_TYPE_SIZE)                                \
+    {                                                                   \
+      r = X##_f[1];                                                     \
+      r <<= _FP_W_TYPE_SIZE;                                            \
+      r += X##_f[0];                                                    \
+    }                                                                   \
+    else                                                                \
+    {                                                                   \
+      /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \
+      /* and int == 4words as a single case.                         */ \
+      r = X##_f[3];                                                     \
+      r <<= _FP_W_TYPE_SIZE;                                            \
+      r += X##_f[2];                                                    \
+      r <<= _FP_W_TYPE_SIZE;                                            \
+      r += X##_f[1];                                                    \
+      r <<= _FP_W_TYPE_SIZE;                                            \
+      r += X##_f[0];                                                    \
+    }                                                                   \
+  } while (0)
+
+/* "No disassemble Number Five!" */
+/* move an integer of size rsize into X's fractional part. We rely on
+ * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid
+ * having to mask the values we store into it.
+ */
+#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize)                             \
+  do {                                                                  \
+    X##_f[0] = r;                                                       \
+    X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);   \
+    X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
+    X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
+  } while (0);
+
+#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S)                               \
+   do {                                                                 \
+     D##_f[0] = S##_f;                                                  \
+     D##_f[1] = D##_f[2] = D##_f[3] = 0;                                \
+     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
+   } while (0)
+
+#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S)                               \
+   do {                                                                 \
+     D##_f[0] = S##_f0;                                                 \
+     D##_f[1] = S##_f1;                                                 \
+     D##_f[2] = D##_f[3] = 0;                                           \
+     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
+   } while (0)
+
+/* FIXME! This has to be written */
+#define _FP_SQRT_MEAT_4(R, S, T, X, q)
index 8123e4c46347dd5e6e46115653babccedd2fa8c2..d4ce104f688a961c8fb58e64fc53ea83ef702dd9 100644 (file)
@@ -1,3 +1,4 @@
+
 #define _FP_DECL(wc, X)                        \
   _FP_I_TYPE X##_c, X##_s, X##_e;      \
   _FP_FRAC_DECL_##wc(X)
@@ -507,6 +508,29 @@ do {                                                                       \
  * Convert from FP to integer
  */
 
+/* "When a NaN, infinity, large positive argument >= 2147483648.0, or 
+ * large negative argument <= -2147483649.0 is converted to an integer,
+ * the invalid_current bit...should be set and fp_exception_IEEE_754 should
+ * be raised. If the floating point invalid trap is disabled, no trap occurs
+ * and a numerical result is generated: if the sign bit of the operand
+ * is 0, the result is 2147483647; if the sign bit of the operand is 1,
+ * the result is -2147483648."
+ * Similarly for conversion to extended ints, except that the boundaries
+ * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and
+ * -2^63 for s=1.
+ * -- SPARC Architecture Manual V9, Appendix B, which specifies how
+ * SPARCs resolve implementation dependencies in the IEEE-754 spec.
+ * I don't believe that the code below follows this. I'm not even sure
+ * it's right! 
+ * It doesn't cope with needing to convert to an n bit integer when there
+ * is no n bit integer type. Fortunately gcc provides long long so this
+ * isn't a problem for sparc32.
+ * I have, however, fixed its NaN handling to conform as above.
+ *         -- PMM 02/1998
+ * NB: rsigned is not 'is r declared signed?' but 'should the value stored
+ * in r be signed or unsigned?'. r is always(?) declared unsigned.
+ * Comments below are mine, BTW -- PMM 
+ */
 #define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)                               \
   do {                                                                         \
     switch (X##_c)                                                             \
@@ -514,13 +538,14 @@ do {                                                                      \
       case FP_CLS_NORMAL:                                                      \
        if (X##_e < 0)                                                          \
          {                                                                     \
-         case FP_CLS_NAN:                                                      \
+         /* case FP_CLS_NAN: see above! */                                     \
          case FP_CLS_ZERO:                                                     \
            r = 0;                                                              \
          }                                                                     \
        else if (X##_e >= rsize - (rsigned != 0))                               \
-         {                                                                     \
-         case FP_CLS_INF:                                                      \
+         {     /* overflow */                                                  \
+         case FP_CLS_NAN:                                                      \
+          case FP_CLS_INF:                                                     \
            if (rsigned)                                                        \
              {                                                                 \
                r = 1;                                                          \
@@ -604,6 +629,23 @@ do {                                                                       \
 /* Count leading zeros in a word.  */
 
 #ifndef __FP_CLZ
+#if _FP_W_TYPE_SIZE < 64
+/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
+#define __FP_CLZ(r, x)                         \
+  do {                                         \
+    _FP_W_TYPE _t = (x);                       \
+    r = _FP_W_TYPE_SIZE - 1;                   \
+    if (_t > 0xffff) r -= 16;                  \
+    if (_t > 0xffff) _t >>= 16;                        \
+    if (_t > 0xff) r -= 8;                     \
+    if (_t > 0xff) _t >>= 8;                   \
+    if (_t & 0xf0) r -= 4;                     \
+    if (_t & 0xf0) _t >>= 4;                   \
+    if (_t & 0xc) r -= 2;                      \
+    if (_t & 0xc) _t >>= 2;                    \
+    if (_t & 0x2) r -= 1;                      \
+  } while (0)
+#else /* not _FP_W_TYPE_SIZE < 64 */
 #define __FP_CLZ(r, x)                         \
   do {                                         \
     _FP_W_TYPE _t = (x);                       \
@@ -620,9 +662,11 @@ do {                                                                       \
     if (_t & 0xc) _t >>= 2;                    \
     if (_t & 0x2) r -= 1;                      \
   } while (0)
-#endif
+#endif /* not _FP_W_TYPE_SIZE < 64 */
+#endif /* ndef __FP_CLZ */
 
 #define _FP_DIV_HELP_imm(q, r, n, d)           \
   do {                                         \
     q = n / d, r = n % d;                      \
   } while (0)
+
index dfc3b4eeaa60df57f97c3d957b490ad573ac915b..48fcc798c3158bd64a195ca7f1815f1de1682b7a 100644 (file)
@@ -1,12 +1,17 @@
 /*
  * Definitions for IEEE Quad Precision
  */
-
-#if _FP_W_TYPE_SIZE < 64
-#error "Only stud muffins allowed, schmuck."
+#if _FP_W_TYPE_SIZE < 32
+/* It appears to be traditional to abuse 16bitters in these header files... */
+#error "Here's a nickel, kid. Go buy yourself a real computer."
 #endif
 
+#if _FP_W_TYPE_SIZE < 64
+/* This is all terribly experimental and I don't know if it'll work properly -- PMM 02/1998 */
+#define _FP_FRACTBITS_Q         (4*_FP_W_TYPE_SIZE)
+#else
 #define _FP_FRACTBITS_Q                (2*_FP_W_TYPE_SIZE)
+#endif
 
 #define _FP_FRACBITS_Q         113
 #define _FP_FRACXBITS_Q                (_FP_FRACTBITS_Q - _FP_FRACBITS_Q)
 #define _FP_OVERFLOW_Q         \
        ((_FP_W_TYPE)1 << (_FP_WFRACBITS_Q % _FP_W_TYPE_SIZE))
 
+#if _FP_W_TYPE_SIZE < 64
+
+union _FP_UNION_Q
+{
+   long double flt;
+   struct 
+   {
+#if __BYTE_ORDER == __BIG_ENDIAN
+      unsigned sign : 1;
+      unsigned exp : _FP_EXPBITS_Q;
+      unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3);
+      unsigned long frac2 : _FP_W_TYPE_SIZE;
+      unsigned long frac1 : _FP_W_TYPE_SIZE;
+      unsigned long frac0 : _FP_W_TYPE_SIZE;
+#else
+      unsigned long frac0 : _FP_W_TYPE_SIZE;
+      unsigned long frac1 : _FP_W_TYPE_SIZE;
+      unsigned long frac2 : _FP_W_TYPE_SIZE;
+      unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3);
+      unsigned exp : _FP_EXPBITS_Q;
+      unsigned sign : 1;
+#endif /* not bigendian */
+   } bits __attribute__((packed));
+};
+
+
+#define FP_DECL_Q(X)           _FP_DECL(4,X)
+#define FP_UNPACK_RAW_Q(X,val) _FP_UNPACK_RAW_4(Q,X,val)
+#define FP_PACK_RAW_Q(val,X)   _FP_PACK_RAW_4(Q,val,X)
+
+#define FP_UNPACK_Q(X,val)             \
+  do {                                 \
+    _FP_UNPACK_RAW_4(Q,X,val);         \
+    _FP_UNPACK_CANONICAL(Q,4,X);       \
+  } while (0)
+
+#define FP_PACK_Q(val,X)               \
+  do {                                 \
+    _FP_PACK_CANONICAL(Q,4,X);         \
+    _FP_PACK_RAW_4(Q,val,X);           \
+  } while (0)
+
+#define FP_NEG_Q(R,X)          _FP_NEG(Q,4,R,X)
+#define FP_ADD_Q(R,X,Y)                _FP_ADD(Q,4,R,X,Y)
+/* single.h and double.h define FP_SUB_t this way too. However, _FP_SUB is
+ * never defined in op-common.h! Fortunately nobody seems to use the FP_SUB_t 
+ * macros: I suggest a combination of FP_NEG and FP_ADD :-> -- PMM 02/1998
+ */
+#define FP_SUB_Q(R,X,Y)                _FP_SUB(Q,4,R,X,Y)
+#define FP_MUL_Q(R,X,Y)                _FP_MUL(Q,4,R,X,Y)
+#define FP_DIV_Q(R,X,Y)                _FP_DIV(Q,4,R,X,Y)
+#define FP_SQRT_Q(R,X)         _FP_SQRT(Q,4,R,X)
+
+#define FP_CMP_Q(r,X,Y,un)     _FP_CMP(Q,4,r,X,Y,un)
+#define FP_CMP_EQ_Q(r,X,Y)     _FP_CMP_EQ(Q,4,r,X,Y)
+
+#define FP_TO_INT_Q(r,X,rsz,rsg)  _FP_TO_INT(Q,4,r,X,rsz,rsg)
+#define FP_FROM_INT_Q(X,r,rs,rt)  _FP_FROM_INT(Q,4,X,r,rs,rt)
+
+#else   /* not _FP_W_TYPE_SIZE < 64 */
 union _FP_UNION_Q
 {
   long double flt /* __attribute__((mode(TF))) */ ;
@@ -69,3 +134,5 @@ union _FP_UNION_Q
 
 #define FP_TO_INT_Q(r,X,rsz,rsg)  _FP_TO_INT(Q,2,r,X,rsz,rsg)
 #define FP_FROM_INT_Q(X,r,rs,rt)  _FP_FROM_INT(Q,2,X,r,rs,rt)
+
+#endif /* not _FP_W_TYPE_SIZE < 64 */
index fa7f386cd41d6c58afae3b4431d47a6e29e20472..f19d99451815ea638139159c061ab1bef5208978 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 #if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickle kid.  Go buy yourself a real computer."
+#error "Here's a nickel kid.  Go buy yourself a real computer."
 #endif
 
 #define _FP_FRACBITS_S         24
index 6bc52f3ebe4f217486a7c5fd2fac230452a13266..21389e397351cd90b832b6fd31fde9005f1a4b64 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.20 1997/08/04 16:16:51 davem Exp $
+/* $Id: fault.c,v 1.21 1998/03/25 10:43:20 jj Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -209,7 +209,7 @@ bad_area:
                } else {
                        current->tss.sig_address = address;
                        current->tss.sig_desc = SUBSIG_NOMAPPING;
-                       send_sig(SIGSEGV, current, 1);
+                       force_sig(SIGSEGV, current);
                        goto out;
                }
                unhandled_fault (address, current, regs);
index b564dc0dce98a72405731fc6f38e68626fdc9e89..e7d863997cd3318e1e3ceaf37eaf463b976a3f94 100644 (file)
@@ -1,8 +1,8 @@
-/*  $Id: init.c,v 1.60 1998/01/10 18:19:51 ecd Exp $
+/*  $Id: init.c,v 1.71 1998/03/27 07:00:08 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- *  Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
  
 #include <linux/config.h>
 #include <asm/mmu_context.h>
 #include <asm/vaddrs.h>
 
+/* Turn this off if you suspect some place in some physical memory hole
+   might get into page tables (something would be broken very much). */
+   
+#define FREE_UNUSED_MEM_MAP
+
 extern void show_net_buffers(void);
 extern unsigned long device_scan(unsigned long);
 
 struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 
 /* Ugly, but necessary... -DaveM */
-unsigned long phys_base, null_pmd_table, null_pte_table;
+unsigned long phys_base;
+unsigned int null_pte_table;
+unsigned long two_null_pmd_table, two_null_pte_table;
 
 extern unsigned long empty_null_pmd_table;
 extern unsigned long empty_null_pte_table;
@@ -42,12 +49,12 @@ extern void __bfill64(void *, unsigned long *);
 
 static __inline__ void __init_pmd(pmd_t *pmdp)
 {
-       __bfill64((void *)pmdp, &null_pte_table);
+       __bfill64((void *)pmdp, &two_null_pte_table);
 }
 
 static __inline__ void __init_pgd(pgd_t *pgdp)
 {
-       __bfill64((void *)pgdp, &null_pmd_table);
+       __bfill64((void *)pgdp, &two_null_pmd_table);
 }
 
 /*
@@ -88,26 +95,36 @@ pte_t __bad_page(void)
 
 void show_mem(void)
 {
-       int i,free = 0,total = 0,reserved = 0;
-       int shared = 0;
+       int free = 0,total = 0,reserved = 0;
+       int shared = 0, cached = 0;
+       struct page *page, *end;
 
        printk("\nMem-info:\n");
        show_free_areas();
        printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-       i = max_mapnr;
-       while (i-- > 0) {
+       for (page = mem_map, end = mem_map + max_mapnr;
+            page < end; page++) {
+               if (PageSkip(page)) {
+                       if (page->next_hash < page)
+                               break;
+                       page = page->next_hash;
+               }
                total++;
-               if (PageReserved(mem_map + i))
+               if (PageReserved(page))
                        reserved++;
-               else if (!atomic_read(&mem_map[i].count))
+               else if (PageSwapCache(page))
+                       cached++;
+               else if (!atomic_read(&page->count))
                        free++;
                else
-                       shared += atomic_read(&mem_map[i].count) - 1;
+                       shared += atomic_read(&page->count) - 1;
        }
        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);
+       printk("%d pages swap cached\n",cached);
+       printk("%ld pages in page table cache\n",pgtable_cache_size);
        show_buffers();
 #ifdef CONFIG_NET
        show_net_buffers();
@@ -409,14 +426,10 @@ void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus
        spin_unlock_irqrestore(&iommu->iommu_lock, flags);
 }
 
-static char sfmmuinfo[512];
-
-char *mmu_info(void)
+int mmu_info(char *buf)
 {
        /* We'll do the rest later to make it nice... -DaveM */
-       sprintf(sfmmuinfo, "MMU Type\t: Spitfire\n");
-
-       return sfmmuinfo;
+       return sprintf(buf, "MMU Type\t: Spitfire\n");
 }
 
 static unsigned long mempool;
@@ -633,10 +646,7 @@ void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx)
 }
 
 #ifndef __SMP__
-unsigned long *pgd_quicklist = NULL;
-unsigned long *pmd_quicklist = NULL;
-unsigned long *pte_quicklist = NULL;
-unsigned long pgtable_cache_size = 0;
+struct pgtable_cache_struct pgt_quicklists;
 #endif
 
 pgd_t *get_pgd_slow(void)
@@ -653,7 +663,7 @@ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
 {
        pmd_t *pmd;
 
-       pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+       pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
        if(pmd) {
                __init_pmd(pmd);
                pgd_set(pgd, pmd);
@@ -666,9 +676,9 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
 {
        pte_t *pte;
 
-       pte = (pte_t *) __get_free_page(GFP_KERNEL);
+       pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
        if(pte) {
-               clear_page((unsigned long)pte);
+               memset((void *)pte, 0, PTE_TABLE_SIZE);
                pmd_set(pmd, pte);
                return pte + offset;
        }
@@ -737,6 +747,7 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr)
        pte_clear(ptep);
 }
 
+#if NOTUSED
 void sparc_ultra_dump_itlb(void)
 {
         int slot;
@@ -766,6 +777,7 @@ void sparc_ultra_dump_dtlb(void)
                        slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
         }
 }
+#endif
 
 /* paging_init() sets up the page tables */
 
@@ -808,23 +820,30 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        /* Now set kernel pgd to upper alias so physical page computations
         * work.
         */
-       init_mm.pgd += ((shift) / (sizeof(pgd_t *)));
+       init_mm.pgd += ((shift) / (sizeof(pgd_t)));
 
        /* The funny offsets are to make page table operations much quicker and
         * requite less state, see pgtable.h for gory details.
+        * pgtable.h assumes null_pmd_table is null_pte_table - PAGE_SIZE, lets
+        * check it now.
         */
-       null_pmd_table=__pa(((unsigned long)&empty_null_pmd_table)+shift);
        null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift);
+       if (null_pmd_table != __pa(((unsigned long)&empty_null_pmd_table)+shift)) {
+               prom_printf("null_p{md|te}_table broken.\n");
+               prom_halt();
+       }
+       two_null_pmd_table = (((unsigned long)null_pmd_table) << 32) | null_pmd_table;
+       two_null_pte_table = (((unsigned long)null_pte_table) << 32) | null_pte_table;
 
        pmdp = (pmd_t *) &empty_null_pmd_table;
-       for(i = 0; i < 1024; i++)
+       for(i = 0; i < PTRS_PER_PMD; i++)
                pmd_val(pmdp[i]) = null_pte_table;
 
-       memset((void *) &empty_null_pte_table, 0, PAGE_SIZE);
+       memset((void *) &empty_null_pte_table, 0, PTE_TABLE_SIZE);
 
        /* Now can init the kernel/bad page tables. */
-       __bfill64((void *)swapper_pg_dir, &null_pmd_table);
-       __bfill64((void *)&empty_bad_pmd_table, &null_pte_table);
+       __bfill64((void *)swapper_pg_dir, &two_null_pmd_table);
+       __bfill64((void *)&empty_bad_pmd_table, &two_null_pte_table);
 
        /* We use mempool to create page tables, therefore adjust it up
         * such that __pa() macros etc. work.
@@ -867,21 +886,34 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
 
 __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
 {
-       unsigned long addr, tmp2 = 0;
-
-       for(addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
-               if(addr >= PAGE_OFFSET && addr < start_mem)
-                       addr = start_mem;
-               for(tmp2=0; sp_banks[tmp2].num_bytes != 0; tmp2++) {
-                       unsigned long phys_addr = __pa(addr);
-                       unsigned long base = sp_banks[tmp2].base_addr;
-                       unsigned long limit = base + sp_banks[tmp2].num_bytes;
-
-                       if((phys_addr >= base) && (phys_addr < limit) &&
-                          ((phys_addr + PAGE_SIZE) < limit))
-                               mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
-                       if (phys_addr >= 0xf0000000)
-                               mem_map[MAP_NR(addr)].flags &= ~(1<<PG_DMA);
+       unsigned long tmp = 0, paddr, endaddr;
+       unsigned long end = __pa(end_mem);
+
+       for (paddr = __pa(start_mem); paddr < end; ) {
+               for (; sp_banks[tmp].num_bytes != 0; tmp++)
+                       if (sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes > paddr)
+                               break;
+               if (!sp_banks[tmp].num_bytes) {
+                       mem_map[paddr>>PAGE_SHIFT].flags |= (1<<PG_skip);
+                       mem_map[paddr>>PAGE_SHIFT].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
+                       return;
+               }
+               
+               if (sp_banks[tmp].base_addr > paddr) {
+                       /* Making a one or two pages PG_skip holes is not necessary */
+                       if (sp_banks[tmp].base_addr - paddr > 2 * PAGE_SIZE) {
+                               mem_map[paddr>>PAGE_SHIFT].flags |= (1<<PG_skip);
+                               mem_map[paddr>>PAGE_SHIFT].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT);
+                       }
+                       paddr = sp_banks[tmp].base_addr;
+               }
+               
+               endaddr = sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes;
+               while (paddr < endaddr) {
+                       mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_reserved);
+                       if (paddr >= 0xf0000000)
+                               mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_DMA);
+                       paddr += PAGE_SIZE;
                }
        }
 }
@@ -891,31 +923,65 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
        int codepages = 0;
        int datapages = 0;
        int initpages = 0;
-       unsigned long tmp2, addr;
+       unsigned long addr;
        unsigned long alias_base = phys_base + PAGE_OFFSET - (long)(&empty_zero_page);
+       struct page *page, *end;
 
        end_mem &= PAGE_MASK;
        max_mapnr = MAP_NR(end_mem);
        high_memory = (void *) end_mem;
 
        start_mem = PAGE_ALIGN(start_mem);
-       num_physpages = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+       num_physpages = 0;
+       
+       if (phys_base) {
+               mem_map[0].flags |= (1<<PG_skip) | (1<<PG_reserved);
+               mem_map[0].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
+       }
 
-       addr = PAGE_OFFSET;
+       addr = PAGE_OFFSET + phys_base;
        while(addr < start_mem) {
 #ifdef CONFIG_BLK_DEV_INITRD
-               if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) {
+               if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end)
                        mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
-                       num_physpages--;
-               } else
+               else
 #endif 
                        mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
                addr += PAGE_SIZE;
        }
 
        taint_real_pages(start_mem, end_mem);
+       
+#ifdef FREE_UNUSED_MEM_MAP     
+       end = mem_map + max_mapnr;
+       for (page = mem_map; page < end; page++) {
+               if (PageSkip(page)) {
+                       unsigned long low, high;
+                       
+                       low = PAGE_ALIGN((unsigned long)(page+1));
+                       if (page->next_hash < page)
+                               high = ((unsigned long)end) & PAGE_MASK;
+                       else
+                               high = ((unsigned long)page->next_hash) & PAGE_MASK;
+                       while (low < high) {
+                               mem_map[MAP_NR(low)].flags &= ~(1<<PG_reserved);
+                               low += PAGE_SIZE;
+                       }
+               }
+       }
+#endif
+       
        for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
-               if(PageReserved(mem_map + MAP_NR(addr))) {
+               if (PageSkip(mem_map + MAP_NR(addr))) {
+                       unsigned long next = mem_map[MAP_NR(addr)].next_hash - mem_map;
+                       
+                       next = (next << PAGE_SHIFT) + PAGE_OFFSET;
+                       if (next < addr || next >= end_mem)
+                               break;
+                       addr = next;
+               }
+               num_physpages++;
+               if (PageReserved(mem_map + MAP_NR(addr))) {
                        if ((addr < ((unsigned long) &etext) + alias_base) && (addr >= alias_base))
                                codepages++;
                        else if((addr >= ((unsigned long)&__init_begin) + alias_base)
@@ -926,7 +992,6 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
                        continue;
                }
                atomic_set(&mem_map[MAP_NR(addr)].count, 1);
-               num_physpages++;
 #ifdef CONFIG_BLK_DEV_INITRD
                if (!initrd_start ||
                    (addr < initrd_start || addr >= initrd_end))
@@ -934,18 +999,16 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
                        free_page(addr);
        }
 
-       tmp2 = nr_free_pages << PAGE_SHIFT;
-
-       printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%016lx,%016lx]\n",
-              tmp2 >> 10,
+       printk("Memory: %uk available (%dk kernel code, %dk data, %dk init) [%016lx,%016lx]\n",
+              nr_free_pages << (PAGE_SHIFT-10),
               codepages << (PAGE_SHIFT-10),
               datapages << (PAGE_SHIFT-10), 
               initpages << (PAGE_SHIFT-10), 
               PAGE_OFFSET, end_mem);
 
        freepages.low = nr_free_pages >> 7;
-       if(freepages.low < 16)
-               freepages.low = 16;
+       if(freepages.low < 48)
+               freepages.low = 48;
        freepages.low = freepages.low + (freepages.low >> 1);
        freepages.high = freepages.low + freepages.low;
 }
@@ -967,20 +1030,25 @@ void free_initmem (void)
 
 void si_meminfo(struct sysinfo *val)
 {
-       int i;
+       struct page *page, *end;
 
-       i = MAP_NR(high_memory);
        val->totalram = 0;
        val->sharedram = 0;
        val->freeram = nr_free_pages << PAGE_SHIFT;
        val->bufferram = buffermem;
-       while (i-- > 0)  {
-               if (PageReserved(mem_map + i))
+       for (page = mem_map, end = mem_map + max_mapnr;
+            page < end; page++) {
+               if (PageSkip(page)) {
+                       if (page->next_hash < page)
+                               break;
+                       page = page->next_hash;
+               }
+               if (PageReserved(page))
                        continue;
                val->totalram++;
-               if (!atomic_read(&mem_map[i].count))
+               if (!atomic_read(&page->count))
                        continue;
-               val->sharedram += atomic_read(&mem_map[i].count) - 1;
+               val->sharedram += atomic_read(&page->count) - 1;
        }
        val->totalram <<= PAGE_SHIFT;
        val->sharedram <<= PAGE_SHIFT;
index e6b4b2223ba059a9431e1b0b35a7019a489a2e20..303b98996a9236507c9fe6c3016c1dcee99156c3 100644 (file)
@@ -1,7 +1,7 @@
-/*  $Id: modutil.c,v 1.1 1997/06/27 14:53:35 jj Exp $
+/*  $Id: modutil.c,v 1.3 1998/01/16 16:35:02 jj Exp $
  *  arch/sparc64/mm/modutil.c
  *
- *  Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *  Based upon code written by Linus Torvalds and others.
  */
  
@@ -21,7 +21,7 @@ void module_unmap (void * addr)
        if (!addr)
                return;
        if ((PAGE_SIZE-1) & (unsigned long) addr) {
-               printk("Trying to vfree() bad address (%p)\n", addr);
+               printk("Trying to unmap module with bad address (%p)\n", addr);
                return;
        }
        for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
@@ -35,6 +35,32 @@ void module_unmap (void * addr)
        printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
 }
 
+void module_shrink(void * addr, unsigned long size)
+{
+       struct vm_struct *tmp;
+
+       if (!addr)
+               return;
+       if ((PAGE_SIZE-1) & (unsigned long) addr) {
+               printk("Trying to shrink module with bad address (%p)\n", addr);
+               return;
+       }
+       size = PAGE_ALIGN(size);
+       if (!size)
+               module_unmap(addr);
+       for (tmp = modvmlist; tmp; tmp = tmp->next) {
+               if (tmp->addr == addr) {
+                       if (size > tmp->size - PAGE_SIZE) {
+                               printk("Trying to expand module with module_shrink()\n");
+                               return;
+                       }
+                       vmfree_area_pages(VMALLOC_VMADDR(tmp->addr)+size, tmp->size-size);
+                       return;
+               }
+       }
+       printk("Trying to shrink nonexistent module vm area (%p)\n", addr);
+}
+
 void * module_map (unsigned long size)
 {
        void * addr;
index 7ef17159d3a9469b76e7ae132195696f97ab0442..6d53b8be23a7943efffa457312322482868cf8a7 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: bootstr.c,v 1.4 1997/06/17 13:25:35 jj Exp $
+/* $Id: bootstr.c,v 1.5 1998/01/23 08:51:39 jj Exp $
  * bootstr.c:  Boot string/argument acquisition from the PROM.
  *
  * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright(C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright(C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/string.h>
@@ -10,9 +10,9 @@
 #include <asm/oplib.h>
 
 #define BARG_LEN  256
-int bootstr_len __initdata = BARG_LEN;
-static int bootstr_valid __initdata = 0;
-static char bootstr_buf[BARG_LEN] __initdata = { 0 };
+int bootstr_len = BARG_LEN;
+static int bootstr_valid = 0;
+static char bootstr_buf[BARG_LEN] = { 0 };
 
 __initfunc(char *
 prom_getbootargs(void))
index 7dcef7642f98e3ded918696aa51c494a0ee3be05..4c1bd1e007cc72f3940c90577714f007f59ccb60 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.7 1997/03/24 17:43:59 jj Exp $
+/* $Id: init.c,v 1.8 1998/03/15 10:14:44 ecd Exp $
  * init.c:  Initialize internal variables used by the PROM
  *          library functions.
  *
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -32,11 +33,13 @@ extern void prom_cif_init(void *, void *);
 
 __initfunc(void prom_init(void *cif_handler, void *cif_stack))
 {
-       char buffer[80];
+       char buffer[80], *p;
+       int ints[3];
        int node;
-       
+       int i = 0;
+
        prom_vers = PROM_P1275;
-       
+
        prom_cif_init(cif_handler, cif_stack);
 
        prom_root_node = prom_getsibling(0);
@@ -46,34 +49,45 @@ __initfunc(void prom_init(void *cif_handler, void *cif_stack))
        prom_chosen_node = prom_finddevice("/chosen");
        if (!prom_chosen_node || prom_chosen_node == -1)
                prom_halt();
-               
+
        prom_stdin = prom_getint (prom_chosen_node, "stdin");
        prom_stdout = prom_getint (prom_chosen_node, "stdout");
 
        node = prom_finddevice("/openprom");
        if (!node || node == -1)
                prom_halt();
-               
+
        prom_getstring (node, "version", buffer, sizeof (buffer));
-       
+
        prom_printf ("\n");
-       
-       if (strncmp (buffer, "OBP ", 4) || buffer[5] != '.' || buffer[7] != '.') {
-               prom_printf ("Strange OBP version `%s'.\n", buffer);
-               prom_halt ();
+
+       if (strncmp (buffer, "OBP ", 4))
+               goto strange_version;
+
+       /* Version field is expected to be 'OBP xx.yy.zz date...' */
+
+       p = buffer + 4;
+       while (p && isdigit(*p) && i < 3) {
+               ints[i++] = simple_strtoul(p, NULL, 0);
+               if ((p = strchr(p, '.')) != NULL)
+                       p++;
        }
-       /* Version field is expected to be 'OBP x.y.z date...' */
-       
-       prom_rev = buffer[6] - '0';
-       prom_prev = ((buffer[4] - '0') << 16) | 
-                   ((buffer[6] - '0') << 8) |
-                   (buffer[8] - '0');
-                   
+       if (i != 3)
+               goto strange_version;
+
+       prom_rev = ints[1];
+       prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2];
+
        printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4);
-       
+
        prom_meminit();
 
        prom_ranges_init();
 
        /* Initialization successful. */
+       return;
+
+strange_version:
+       prom_printf ("Strange OBP version `%s'.\n", buffer);
+       prom_halt ();
 }
index 83f860d45f0a5aedc5ba48b7aa212127d640bfda..7b889bac1cc27d71f4749213648361aac392afdb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ranges.c,v 1.8 1997/08/17 22:39:45 ecd Exp $
+/* $Id: ranges.c,v 1.10 1998/03/24 05:54:29 ecd Exp $
  * ranges.c: Handle ranges in newer proms for obio/sbus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -140,17 +140,61 @@ __initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus))
                ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
 }
 
+__initfunc(void prom_ebus_intmap_init(struct linux_ebus *ebus))
+{
+       int success;
+
+       ebus->num_ebus_intmap = 0;
+       success = prom_getproperty(ebus->prom_node, "interrupt-map",
+                                  (char *)ebus->ebus_intmap,
+                                  sizeof(ebus->ebus_intmap));
+       if (success == -1)
+               return;
+
+       ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
+
+       success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
+                                  (char *)&ebus->ebus_intmask,
+                                  sizeof(ebus->ebus_intmask));
+       if (success == -1) {
+               prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
+               prom_halt();
+       }
+}
+
 __initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm))
 {
        int success;
 
        pbm->num_pbm_ranges = 0;
-       success = prom_getproperty(pbm->prom_node, "ranges",
+       success = prom_getproperty(pnode, "ranges",
                                   (char *)&pbm->pbm_ranges,
                                   sizeof(pbm->pbm_ranges));
        if(success != -1)
                pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges));
 }
+
+__initfunc(void prom_pbm_intmap_init(int pnode, struct linux_pbm_info *pbm))
+{
+       int success;
+
+       pbm->num_pbm_intmap = 0;
+       success = prom_getproperty(pnode, "interrupt-map",
+                                  (char *)pbm->pbm_intmap,
+                                  sizeof(pbm->pbm_intmap));
+       if (success == -1)
+               return;
+
+       pbm->num_pbm_intmap = (success/sizeof(struct linux_prom_pci_intmap));
+
+       success = prom_getproperty(pnode, "interrupt-map-mask",
+                                  (char *)&pbm->pbm_intmask,
+                                  sizeof(pbm->pbm_intmask));
+       if (success == -1) {
+               prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
+               prom_halt();
+       }
+}
 #endif
 
 void
index 056909b6f59d2b4a42538948b115be425c12a628..691601a3ea92dc980564053fa1a791fb8a03d096 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := solaris.o
-O_OBJS   := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o
+O_OBJS   := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o timod.o
 ifeq ($(CONFIG_SOLARIS_EMUL),m)
 M_OBJS   := $(O_TARGET)
 CPPFLAGS = $(MODFLAGS)
index c806d3dc1032ae929b9b8c020200f1d512cd5f62..fa716f595e741c3e0d82756d7a06d6d1125632b0 100644 (file)
@@ -1,10 +1,11 @@
-/* $Id: conv.h,v 1.2 1997/09/03 12:29:13 jj Exp $
+/* $Id: conv.h,v 1.3 1998/03/26 08:46:13 jj Exp $
  * conv.h: Utility macros for Solaris emulation
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
  
 /* #define DEBUG_SOLARIS */
+#define DEBUG_SOLARIS_KMALLOC
 
 #ifndef __ASSEMBLY__
 
@@ -25,4 +26,12 @@ extern unsigned sunos_sys_table[];
 #define SYS(name) ((long)sys_call_table[__NR_##name])
 #define SUNOS(x) ((long)sunos_sys_table[x])
 
+#ifdef DEBUG_SOLARIS
+#define SOLD(s) printk("%s,%d,%s(): %s\n",__FILE__,__LINE__,__FUNCTION__,(s))
+#define SOLDD(s) printk("solaris: "); printk s
+#else
+#define SOLD(s)
+#define SOLDD(s)
+#endif
+
 #endif /* __ASSEMBLY__ */
index 41450652230b7a8fbaa56c5f473e1648f89188b8..53d825e6dfe5915fc3ae329338bd9b6941128f82 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: entry64.S,v 1.4 1997/09/09 17:13:50 jj Exp $
+/* $Id: entry64.S,v 1.5 1998/03/26 08:46:15 jj Exp $
  * entry64.S:  Solaris syscall emulation entry point.
  *
- * Copyright (C) 1996,1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1997,1998 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Miguel de Icaza      (miguel@nuclecu.unam.mx)
  */
@@ -29,8 +29,11 @@ solaris_syscall_trace:
        mov             %i4, %o4
        srl             %i1, 0, %o1
        mov             %i5, %o5
-       b,pt            %xcc, 2f
+       andcc           %l3, 1, %g0
+       be,pt           %icc, 2f
         srl            %i2, 0, %o2
+       b,pt            %xcc, 2f
+        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
 
 solaris_sucks:
 /* Solaris is a big system which needs to be able to do all the things
@@ -59,9 +62,9 @@ solaris_reg:
         mov            %i4, %o4
 
 linux_syscall_for_solaris:
-       sll             %l7, 2, %l4
+       sll             %l3, 2, %l4
        ba,pt           %xcc, 10f
-        lduw           [%l6 + %l4], %l7
+        lduw           [%l6 + %l4], %l3
 
        /* Solaris system calls enter here... */
        .align  32
@@ -78,18 +81,18 @@ solaris_sparc_syscall:
        cmp             %l0, 1
        bne,pn          %icc, solaris_reg
 1:      srl            %i0, 0, %o0
-       lduw            [%l7 + %l4], %l7
+       lduw            [%l7 + %l4], %l3
        srl             %i1, 0, %o1
        ldx             [%g6 + AOFF_task_flags], %l5
-       cmp             %l7, NR_SYSCALLS
+       cmp             %l3, NR_SYSCALLS
        bleu,a,pn       %xcc, linux_syscall_for_solaris
         sethi          %hi(sys_call_table32), %l6
-       andcc           %l7, 1, %g0
+       andcc           %l3, 1, %g0
        bne,a,pn        %icc, 10f
         add            %sp, STACK_BIAS + REGWIN_SZ, %o0
 10:    srl             %i2, 0, %o2
        mov             %i5, %o5
-       andn            %l7, 3, %l7
+       andn            %l3, 3, %l7
        andcc           %l5, 0x20, %g0                          
        bne,pn          %icc, solaris_syscall_trace             
         mov            %i0, %l5
@@ -110,12 +113,20 @@ ret_from_solaris:
        andn            %g3, %g2, %g3
        stx             %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]      
        bne,pn          %icc, solaris_syscall_trace2
-        ldx            [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
-       add             %l1, 0x4, %l2                                    !npc = npc+4
-       stx             %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
-       clr             %l6
+        ldx            [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1
+       andcc           %l1, 1, %g0
+       bne,pn          %icc, 2f
+        clr            %l6
+       add             %l1, 0x4, %l2                                    
+       stx             %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]  ! pc = npc
        call            rtrap
-        stx            %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+        stx            %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc+4
+
+       /* When tnpc & 1, this comes from setcontext and we don't want to advance pc */
+2:     andn            %l1, 3, %l1
+       call            rtrap
+        stx            %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc&~3
+
 1:
        /* System call failure, set Carry condition code.
         * Also, get abs(errno) to return to the process.
@@ -134,15 +145,20 @@ ret_from_solaris:
        mov             1, %l6
        stx             %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
        bne,pn          %icc, solaris_syscall_trace2
-        ldx            [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
-       add             %l1, 0x4, %l2                                    !npc = npc+4
-
-       stx             %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+        ldx            [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1
+       andcc           %l1, 1, %g0
+       bne,pn          %icc, 2b
+        add            %l1, 0x4, %l2
+       stx             %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]  ! pc = npc
        call            rtrap
-        stx            %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+        stx            %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc+4 
+
 solaris_syscall_trace2:
        call            syscall_trace
         add            %l1, 0x4, %l2                   /* npc = npc+4 */
+       andcc           %l1, 1, %g0
+       bne,pn          %icc, 2b
+        nop
        stx             %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
        call            rtrap
         stx            %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
index 4d144880924dd784d2609ee353474502bf172b14..39e69d2420b938a42ceab87cbd52f4f3cf1ee421 100644 (file)
@@ -1,11 +1,13 @@
-/* $Id: fs.c,v 1.6 1997/10/13 03:54:05 davem Exp $
+/* $Id: fs.c,v 1.8 1998/03/29 10:11:02 davem Exp $
  * fs.c: fs related syscall emulation for Solaris
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/types.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/stat.h>
 #include <linux/smp_lock.h>
 #include <linux/limits.h>
@@ -339,9 +341,12 @@ asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
        int error;
 
        lock_kernel();
-       if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-               error = -EBADF;
-       else if (!(dentry = file->f_dentry))
+       error = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+
+       if (!(dentry = file->f_dentry))
                error = -ENOENT;
        else if (!(inode = dentry->d_inode))
                error = -ENOENT;
@@ -351,6 +356,8 @@ asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
                error = -ENOSYS;
        else
                error = report_statvfs(inode, buf);
+       fput(file);
+out:
        unlock_kernel();
        return error;
 }
@@ -516,7 +523,7 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
                newattrs.ia_mode &= ~S_ISGID;
                newattrs.ia_valid |= ATTR_MODE;
        }
-       DQUOT_TRANSFER(inode, newattrs);
+       DQUOT_TRANSFER(dentry, newattrs);
 out:
        return error;
 }
@@ -563,13 +570,15 @@ asmlinkage int solaris_pread(int fd, u32 buf, u32 nbyte, s32 offset)
        
        lock_kernel();
        retval = -EBADF;
-       if (fd >= NR_OPEN ||
-            !(file = current->files->fd[fd]))
+       file = fget(fd);
+       if (!file)
                goto bad;
+
        temp = file->f_pos;
        if (temp != offset) {
                retval = sys_lseek(fd, offset, 0);
-               if (retval < 0) goto bad;
+               if (retval < 0)
+                       goto out_putf;
        }
        retval = sys_read(fd, (char *)A(buf), nbyte);
        if (file->f_pos != temp) {
@@ -578,6 +587,9 @@ asmlinkage int solaris_pread(int fd, u32 buf, u32 nbyte, s32 offset)
                else
                        sys_lseek(fd, temp, 0);
        }
+
+out_putf:
+       fput(file);
 bad:
        unlock_kernel();
        return retval;
@@ -595,13 +607,15 @@ asmlinkage int solaris_pwrite(int fd, u32 buf, u32 nbyte, s32 offset)
        
        lock_kernel();
        retval = -EBADF;
-       if (fd >= NR_OPEN ||
-            !(file = current->files->fd[fd]))
+        file = fget(fd);
+       if (!file)
                goto bad;
+
        temp = file->f_pos;
        if (temp != offset) {
                retval = sys_lseek(fd, offset, 0);
-               if (retval < 0) goto bad;
+               if (retval < 0)
+                       goto out_putf;
        }
        retval = sys_write(fd, (char *)A(buf), nbyte);
        if (file->f_pos != temp) {
@@ -610,6 +624,9 @@ asmlinkage int solaris_pwrite(int fd, u32 buf, u32 nbyte, s32 offset)
                else
                        sys_lseek(fd, temp, 0);
        }
+
+out_putf:
+       fput(file);
 bad:
        unlock_kernel();
        return retval;
index c5ef7b99f2263e9cefd8e2f5ec00d33c75a01f31..242d1e914e39750e67d7a6e40d1ceacec90fa04a 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: ioctl.c,v 1.4 1997/09/18 10:38:24 rth Exp $
+/* $Id: ioctl.c,v 1.10 1998/03/29 10:11:00 davem Exp $
  * ioctl.c: Solaris ioctl emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
  *
  * Streams & timod emulation based on code
  * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
 #include <linux/smp_lock.h>
 #include <linux/ioctl.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/netdevice.h>
 
 #include <asm/uaccess.h>
 #include <asm/termios.h>
 
 #include "conv.h"
+#include "socksys.h"
 
-extern char * getname32(u32 filename);
+extern char *getname32(u32 filename);
 #define putname32 putname
 
 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 
@@ -31,6 +34,11 @@ extern asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd,
        u32 arg);
 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 
+extern int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,
+                       char *data_buf, int data_len, int flags);
+extern int timod_getmsg(unsigned int fd, char *ctl_buf, int ctl_maxlen, int *ctl_len,
+                       char *data_buf, int data_maxlen, int *data_len, int *flags);
+
 /* termio* stuff {{{ */
 
 struct solaris_termios {
@@ -231,31 +239,303 @@ struct strioctl {
        u32 data;
 };
 
+struct solaris_si_sockparams {
+       int sp_family;
+       int sp_type;
+       int sp_protocol;
+};
+
+struct solaris_o_si_udata {
+       int tidusize;
+       int addrsize;
+       int optsize;
+       int etsdusize;
+       int servtype;
+       int so_state;
+       int so_options;
+       int tsdusize;
+};
+
+struct solaris_si_udata {
+       int tidusize;
+       int addrsize;
+       int optsize;
+       int etsdusize;
+       int servtype;
+       int so_state;
+       int so_options;
+       int tsdusize;
+       struct solaris_si_sockparams sockparams;
+};
+
+#define SOLARIS_MODULE_TIMOD    0
+#define SOLARIS_MODULE_SOCKMOD  1
+#define SOLARIS_MODULE_MAX      2
+
+static struct module_info {
+        const char *name;
+        /* can be expanded further if needed */
+} module_table[ SOLARIS_MODULE_MAX + 1 ] = {
+        /* the ordering here must match the module numbers above! */
+        { "timod" },
+        { "sockmod" },
+        { NULL }
+};
+
+static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg)
+{
+       struct inode *ino;
+       /* I wonder which of these tests are superfluous... --patrik */
+       if (! current->files->fd[fd] ||
+           ! current->files->fd[fd]->f_dentry ||
+           ! (ino = current->files->fd[fd]->f_dentry->d_inode) ||
+           ! ino->i_sock)
+               return TBADF;
+       
+       switch (cmd & 0xff) {
+       case 109: /* SI_SOCKPARAMS */
+       {
+               struct solaris_si_sockparams si;
+               if (copy_from_user (&si, (struct solaris_si_sockparams *) A(arg), sizeof(si)))
+                       return (EFAULT << 8) | TSYSERR;
+
+               /* Should we modify socket ino->socket_i.ops and type? */
+               return 0;
+       }
+       case 110: /* SI_GETUDATA */
+       {
+               int etsdusize, servtype;
+               switch (ino->u.socket_i.type) {
+               case SOCK_STREAM:
+                       etsdusize = 1;
+                       servtype = 2;
+                       break;
+               default:
+                       etsdusize = -2;
+                       servtype = 3;
+                       break;
+               }
+               if (put_user(16384, &((struct solaris_si_udata *)A(arg))->tidusize) ||
+                   __put_user(sizeof(struct sockaddr), &((struct solaris_si_udata *)A(arg))->addrsize) ||
+                   __put_user(-1, &((struct solaris_si_udata *)A(arg))->optsize) ||
+                   __put_user(etsdusize, &((struct solaris_si_udata *)A(arg))->etsdusize) ||
+                   __put_user(servtype, &((struct solaris_si_udata *)A(arg))->servtype) ||
+                   __put_user(0, &((struct solaris_si_udata *)A(arg))->so_state) ||
+                   __put_user(0, &((struct solaris_si_udata *)A(arg))->so_options) ||
+                   __put_user(16384, &((struct solaris_si_udata *)A(arg))->tsdusize) ||
+                   __put_user(ino->u.socket_i.ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_family) ||
+                   __put_user(ino->u.socket_i.type, &((struct solaris_si_udata *)A(arg))->sockparams.sp_type) ||
+                   __put_user(ino->u.socket_i.ops->family, &((struct solaris_si_udata *)A(arg))->sockparams.sp_protocol))
+                       return (EFAULT << 8) | TSYSERR;
+               return 0;
+       }
+       case 101: /* O_SI_GETUDATA */
+       {
+               int etsdusize, servtype;
+               switch (ino->u.socket_i.type) {
+               case SOCK_STREAM:
+                       etsdusize = 1;
+                       servtype = 2;
+                       break;
+               default:
+                       etsdusize = -2;
+                       servtype = 3;
+                       break;
+               }
+               if (put_user(16384, &((struct solaris_o_si_udata *)A(arg))->tidusize) ||
+                   __put_user(sizeof(struct sockaddr), &((struct solaris_o_si_udata *)A(arg))->addrsize) ||
+                   __put_user(-1, &((struct solaris_o_si_udata *)A(arg))->optsize) ||
+                   __put_user(etsdusize, &((struct solaris_o_si_udata *)A(arg))->etsdusize) ||
+                   __put_user(servtype, &((struct solaris_o_si_udata *)A(arg))->servtype) ||
+                   __put_user(0, &((struct solaris_o_si_udata *)A(arg))->so_state) ||
+                   __put_user(0, &((struct solaris_o_si_udata *)A(arg))->so_options) ||
+                   __put_user(16384, &((struct solaris_o_si_udata *)A(arg))->tsdusize))
+                       return (EFAULT << 8) | TSYSERR;
+               return 0;
+       }
+       case 102: /* SI_SHUTDOWN */
+       case 103: /* SI_LISTEN */
+       case 104: /* SI_SETMYNAME */
+       case 105: /* SI_SETPEERNAME */
+       case 106: /* SI_GETINTRANSIT */
+       case 107: /* SI_TCL_LINK */
+       case 108: /* SI_TCL_UNLINK */
+       }
+       return TNOTSUPPORT;
+}
+
+static inline int solaris_timod(unsigned int fd, unsigned int cmd, u32 arg,
+                                    int len, int *len_p)
+{
+        struct file *filp;
+        struct inode *ino;
+       int ret;
+
+        filp = current->files->fd[fd];
+        if (! filp ||
+           ! (ino = filp->f_dentry->d_inode) ||
+           ! ino->i_sock)
+               return TBADF;
+               
+       switch (cmd & 0xff) {
+       case 141: /* TI_OPTMGMT */
+       {
+               int i;
+               u32 prim;
+               SOLD("TI_OPMGMT entry");
+               ret = timod_putmsg(fd, (char *)A(arg), len, NULL, -1, 0);
+               SOLD("timod_putmsg() returned");
+               if (ret)
+                       return (-ret << 8) | TSYSERR;
+               i = MSG_HIPRI;
+               SOLD("calling timod_getmsg()");
+               ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
+               SOLD("timod_getmsg() returned");
+               if (ret)
+                       return (-ret << 8) | TSYSERR;
+               SOLD("ret ok");
+               if (get_user(prim, (u32 *)A(arg)))
+                       return (EFAULT << 8) | TSYSERR;
+               SOLD("got prim");
+               if (prim == T_ERROR_ACK) {
+                       u32 tmp, tmp2;
+                       SOLD("prim is T_ERROR_ACK");
+                       if (get_user(tmp, (u32 *)A(arg)+3) ||
+                           get_user(tmp2, (u32 *)A(arg)+2))
+                               return (EFAULT << 8) | TSYSERR;
+                       return (tmp2 << 8) | tmp;
+               }
+               SOLD("TI_OPMGMT return 0");
+               return 0;
+       }
+       case 142: /* TI_BIND */
+       {
+               int i;
+               u32 prim;
+               SOLD("TI_BIND entry");
+               ret = timod_putmsg(fd, (char *)A(arg), len, NULL, -1, 0);
+               SOLD("timod_putmsg() returned");
+               if (ret)
+                       return (-ret << 8) | TSYSERR;
+               len = 1024; /* Solaris allows arbitrary return size */
+               i = MSG_HIPRI;
+               SOLD("calling timod_getmsg()");
+               ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
+               SOLD("timod_getmsg() returned");
+               if (ret)
+                       return (-ret << 8) | TSYSERR;
+               SOLD("ret ok");
+               if (get_user(prim, (u32 *)A(arg)))
+                       return (EFAULT << 8) | TSYSERR;
+               SOLD("got prim");
+               if (prim == T_ERROR_ACK) {
+                       u32 tmp, tmp2;
+                       SOLD("prim is T_ERROR_ACK");
+                       if (get_user(tmp, (u32 *)A(arg)+3) ||
+                           get_user(tmp2, (u32 *)A(arg)+2))
+                               return (EFAULT << 8) | TSYSERR;
+                       return (tmp2 << 8) | tmp;
+               }
+               SOLD("no ERROR_ACK requested");
+               if (prim != T_OK_ACK)
+                       return TBADSEQ;
+               SOLD("OK_ACK requested");
+               i = MSG_HIPRI;
+               SOLD("calling timod_getmsg()");
+               ret = timod_getmsg(fd, (char *)A(arg), len, len_p, NULL, -1, NULL, &i);
+               SOLD("timod_getmsg() returned");
+               if (ret)
+                       return (-ret << 8) | TSYSERR;
+               SOLD("TI_BIND return ok");
+               return 0;
+       }
+       case 140: /* TI_GETINFO */
+       case 143: /* TI_UNBIND */
+       case 144: /* TI_GETMYNAME */
+       case 145: /* TI_GETPEERNAME */
+       case 146: /* TI_SETMYNAME */
+       case 147: /* TI_SETPEERNAME */
+       }
+       return TNOTSUPPORT;
+}
+
 static inline int solaris_S(unsigned int fd, unsigned int cmd, u32 arg)
 {
        char *p;
        int ret;
        mm_segment_t old_fs;
        struct strioctl si;
-       
+       struct inode *ino;
+        struct file *filp;
+        struct sol_socket_struct *sock;
+        struct module_info *mi;
+
+        filp = current->files->fd[fd];
+        if (! filp ||
+           ! (ino = filp->f_dentry->d_inode) ||
+           ! ino->i_sock)
+               return -EBADF;
+        sock = filp->private_data;
+        if (! sock) {
+                printk("solaris_S: NULL private_data\n");
+                return -EBADF;
+        }
+        if (sock->magic != SOLARIS_SOCKET_MAGIC) {
+                printk("solaris_S: invalid magic\n");
+                return -EBADF;
+        }
+        
+
        switch (cmd & 0xff) {
        case 1: /* I_NREAD */
                return -ENOSYS;
        case 2: /* I_PUSH */
+        {
                p = getname32 (arg);
                if (IS_ERR (p))
                        return PTR_ERR(p);
+                ret = -EINVAL;
+                for (mi = module_table; mi->name; mi++) {
+                        if (strcmp(mi->name, p) == 0) {
+                                sol_module m;
+                                if (sock->modcount >= MAX_NR_STREAM_MODULES) {
+                                        ret = -ENXIO;
+                                        break;
+                                }
+                                m = (sol_module) (mi - module_table);
+                                sock->module[sock->modcount++] = m;
+                                ret = 0;
+                                break;
+                        }
+                }
                putname32 (p);
-               return 0;
+               return ret;
+        }
        case 3: /* I_POP */
+                if (sock->modcount <= 0) return -EINVAL;
+                sock->modcount--;
                return 0;
+        case 4: /* I_LOOK */
+        {
+               const char *p;
+                if (sock->modcount <= 0) return -EINVAL;
+                p = module_table[(unsigned)sock->module[sock->modcount]].name;
+                if (copy_to_user ((char *)A(arg), p, strlen(p)))
+                       return -EFAULT;
+                return 0;
+        }
        case 5: /* I_FLUSH */
                return 0;
        case 8: /* I_STR */
-               if (copy_from_user (&si, (struct strioctl *)A(arg), sizeof(struct strioctl)))
+               if (copy_from_user(&si, (struct strioctl *)A(arg), sizeof(struct strioctl)))
                        return -EFAULT;
+                /* We ignore what module is actually at the top of stack. */
                switch ((si.cmd >> 8) & 0xff) {
+               case 'I':
+                        return solaris_sockmod(fd, si.cmd, si.data);
                case 'T':
+                        return solaris_timod(fd, si.cmd, si.data, si.len,
+                                                &((struct strioctl*)A(arg))->len);
                default:
                        return solaris_ioctl(fd, si.cmd, si.data);
                }
@@ -269,12 +549,25 @@ static inline int solaris_S(unsigned int fd, unsigned int cmd, u32 arg)
                if (ret == current->pid) return 0x3ff;
                else return -EINVAL;
        case 11: /* I_FIND */
+        {
+                int i;
                p = getname32 (arg);
                if (IS_ERR (p))
                        return PTR_ERR(p);
-               ret = !strcmp(p, "timod");
+                ret = 0;
+                for (i = 0; i < sock->modcount; i++) {
+                        unsigned m = sock->module[i];
+                        if (strcmp(module_table[m].name, p) == 0) {
+                                ret = 1;
+                                break;
+                        } 
+                }
                putname32 (p);
                return ret;
+        }
+       case 19: /* I_SWROPT */
+       case 32: /* I_SETCLTIME */
+               return 0;       /* Lie */
        }
        return -ENOSYS;
 }
@@ -287,7 +580,8 @@ static inline int solaris_s(unsigned int fd, unsigned int cmd, u32 arg)
                return 0; /* We don't support them */
        case 1: /* SIOCGHIWAT */
        case 3: /* SIOCGLOWAT */
-               put_user_ret (0, (u32 *)A(arg), -EFAULT);
+               if (put_user (0, (u32 *)A(arg)))
+                       return -EFAULT;
                return 0; /* Lie */
        case 7: /* SIOCATMARK */
                return sys_ioctl(fd, SIOCATMARK, arg);
@@ -368,8 +662,10 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
                        ret = sys_socketcall(((cmd & 0xff) == 52) ? SYS_GETSOCKNAME : SYS_GETPEERNAME,
                                        args);
                        set_fs(old_fs);
-                       if (ret >= 0)
-                               copy_to_user_ret((char *)A(arg), &uaddr, uaddr_len, -EFAULT);
+                       if (ret >= 0) {
+                               if (copy_to_user((char *)A(arg), &uaddr, uaddr_len))
+                                       return -EFAULT;
+                       }
                        return ret;
                }
 #if 0          
@@ -382,7 +678,8 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
                        int i = 0;
                        
                        for (d = dev_base; d; d = d->next) i++;
-                       put_user_ret (i, (int *)A(arg), -EFAULT);
+                       if (put_user (i, (int *)A(arg)))
+                               return -EFAULT;
                        return 0;
                }
        }
@@ -393,14 +690,13 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
 
 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
 {
-       struct file * filp;
+       struct file *filp;
        int error = -EBADF;
 
        lock_kernel();
-       if(fd >= NR_OPEN) goto out;
-
-       filp = current->files->fd[fd];
-       if(!filp) goto out;
+       filp = fcheck(fd);
+       if (!filp)
+               goto out;
 
        error = -EFAULT;
        switch ((cmd >> 8) & 0xff) {
@@ -410,6 +706,7 @@ asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        case 'r': error = solaris_r(fd, cmd, arg); break;
        case 's': error = solaris_s(fd, cmd, arg); break;
        case 't': error = solaris_t(fd, cmd, arg); break;
+       case 'f': error = sys_ioctl(fd, cmd, arg); break;
        default:
                error = -ENOSYS;
                break;
index 7a6fb5969b3943adcd6bbca245d3a05547d85512..4179f54b30ede327a34b5e7a1c5a5c66d1e84348 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.6 1997/12/14 23:40:15 ecd Exp $
+/* $Id: misc.c,v 1.10 1998/04/01 05:16:06 davem Exp $
  * misc.c: Miscelaneous syscall emulation for Solaris
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -106,7 +106,7 @@ static char *machine(void)
 
 static char *platform(char *buffer)
 {
-       int i;
+       int i, len;
        struct {
                char *platform;
                int id_machtype;
@@ -128,7 +128,9 @@ static char *platform(char *buffer)
        };
 
        *buffer = 0;
-       prom_getproperty(prom_root_node, "name", buffer, 256);
+       len = prom_getproperty(prom_root_node, "name", buffer, 256);
+       if(len > 0)
+               buffer[len] = 0;
        if (*buffer) {
                char *p;
 
@@ -145,10 +147,13 @@ static char *platform(char *buffer)
 static char *serial(char *buffer)
 {
        int node = prom_getchild(prom_root_node);
+       int len;
 
        node = prom_searchsiblings(node, "options");
        *buffer = 0;
-       prom_getproperty(node, "system-board-serial#", buffer, 256);
+       len = prom_getproperty(node, "system-board-serial#", buffer, 256);
+       if(len > 0)
+               buffer[len] = 0;
        if (!*buffer)
                return "4512348717234";
        else
@@ -268,6 +273,8 @@ asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
 #define        SOLARIS_CONFIG_PHYS_PAGES               26
 #define        SOLARIS_CONFIG_AVPHYS_PAGES             27
 
+extern unsigned prom_cpu_nodes[NR_CPUS];
+
 asmlinkage int solaris_sysconf(int id)
 {
        switch (id) {
@@ -279,9 +286,8 @@ asmlinkage int solaris_sysconf(int id)
        case SOLARIS_CONFIG_XOPEN_VER:  return 3;
        case SOLARIS_CONFIG_CLK_TCK:
        case SOLARIS_CONFIG_PROF_TCK:
-               return prom_getintdefault(
-                       linux_cpus[smp_processor_id()].prom_node,
-                       "clock-frequency", 167000000);
+               return prom_getintdefault(prom_cpu_nodes[smp_processor_id()],
+                                         "clock-frequency", 167000000);
 #ifdef __SMP__ 
        case SOLARIS_CONFIG_NPROC_CONF: return NR_CPUS;
        case SOLARIS_CONFIG_NPROC_ONLN: return smp_num_cpus;
@@ -362,6 +368,14 @@ asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid)
        return -EINVAL;
 }
 
+asmlinkage int solaris_gettimeofday(u32 tim)
+{
+       int (*sys_gettimeofday)(struct timeval *, struct timezone *) =
+               (int (*)(struct timeval *, struct timezone *))SYS(gettimeofday);
+               
+       return sys_gettimeofday((struct timeval *)(u64)tim, NULL);
+}
+
 asmlinkage int do_sol_unimplemented(struct pt_regs *regs)
 {
        printk ("Unimplemented Solaris syscall %d %08x %08x %08x %08x\n", 
@@ -401,10 +415,13 @@ struct exec_domain solaris_exec_domain = {
        NULL
 };
 
+extern int init_socksys(void);
+
 #ifdef MODULE
 
-MODULE_AUTHOR("Jakub Jelinek (jj@sunsite.mff.cuni.cz)");
+MODULE_AUTHOR("Jakub Jelinek (jj@ultra.linux.cz), Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)");
 MODULE_DESCRIPTION("Solaris binary emulation module");
+EXPORT_NO_SYMBOLS;
 
 #ifdef __sparc_v9__
 extern u32 tl0_solaris[8];
@@ -416,12 +433,13 @@ extern u32 tl0_solaris[8];
 
 extern u32 solaris_sparc_syscall[];
 extern u32 solaris_syscall[];
-extern int init_socksys(void);
 extern void cleanup_socksys(void);
 
 int init_module(void)
 {
        int ret;
+
+       SOLDD(("Solaris module at %p\n", solaris_sparc_syscall));
        register_exec_domain(&solaris_exec_domain);
        if ((ret = init_socksys())) {
                unregister_exec_domain(&solaris_exec_domain);
index 3a18916c96cb48a8737e1dd7559b1d8b2f42a591..523073a6d56c8be78dc7af4b4922217ef69a4e30 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: socksys.c,v 1.2 1997/09/08 11:29:38 jj Exp $
+/* $Id: socksys.c,v 1.7 1998/03/29 10:11:04 davem Exp $
  * socksys.c: /dev/inet/ stuff for Solaris emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997, 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
  * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
  */
 
 #include <linux/smp_lock.h>
 #include <linux/ioctl.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/file.h>
+#include <linux/malloc.h>
 
 #include <asm/uaccess.h>
 #include <asm/termios.h>
 
 #include "conv.h"
+#include "socksys.h"
 
 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 
        unsigned long arg);
@@ -30,6 +34,20 @@ IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW,
 0, 0, 0, 0, 0, 0,
 };
 
+#ifndef DEBUG_SOLARIS_KMALLOC
+
+#define mykmalloc kmalloc
+#define mykfree kfree
+
+#else
+
+extern void * mykmalloc(size_t s, int gfp);
+extern void mykfree(void *);
+
+#endif
+
+static unsigned int (*sock_poll)(struct file *, poll_table *);
+
 static struct file_operations socksys_file_ops = {
        NULL,           /* lseek */
        NULL,           /* read */
@@ -48,6 +66,7 @@ static int socksys_open(struct inode * inode, struct file * filp)
        struct dentry *dentry;
        int (*sys_socket)(int,int,int) =
                (int (*)(int,int,int))SUNOS(97);
+        struct sol_socket_struct * sock;
        
        family = ((MINOR(inode->i_rdev) >> 4) & 0xf);
        switch (family) {
@@ -68,30 +87,78 @@ static int socksys_open(struct inode * inode, struct file * filp)
                protocol = 0;
                break;
        }
+
        fd = sys_socket(family, type, protocol);
-       if (fd < 0) return fd;
+       if (fd < 0)
+               return fd;
+       /*
+        * N.B. The following operations are not legal!
+        * Try instead:
+        * d_delete(filp->f_dentry), then d_instantiate with sock inode
+        */
        dentry = filp->f_dentry;
-       filp->f_dentry = current->files->fd[fd]->f_dentry;
+       filp->f_dentry = dget(fcheck(fd)->f_dentry);
        filp->f_dentry->d_inode->i_rdev = inode->i_rdev;
        filp->f_dentry->d_inode->i_flock = inode->i_flock;
        filp->f_dentry->d_inode->u.socket_i.file = filp;
        filp->f_op = &socksys_file_ops;
+        sock = (struct sol_socket_struct*) 
+               mykmalloc(sizeof(struct sol_socket_struct), GFP_KERNEL);
+        if (!sock) return -ENOMEM;
+       SOLDD(("sock=%016lx(%016lx)\n", sock, filp));
+        sock->magic = SOLARIS_SOCKET_MAGIC;
+        sock->modcount = 0;
+        sock->state = TS_UNBND;
+        sock->offset = 0;
+        sock->pfirst = sock->plast = NULL;
+        filp->private_data = sock;
+       SOLDD(("filp->private_data %016lx\n", filp->private_data));
+
+       sys_close(fd);
        dput(dentry);
-       FD_CLR(fd, &current->files->close_on_exec);
-       FD_CLR(fd, &current->files->open_fds);
-       put_filp(current->files->fd[fd]);
-       current->files->fd[fd] = NULL;
        return 0;
 }
 
 static int socksys_release(struct inode * inode, struct file * filp)
 {
+        struct sol_socket_struct * sock;
+        struct T_primsg *it;
+
+       /* XXX: check this */
+       sock = (struct sol_socket_struct *)filp->private_data;
+       SOLDD(("sock release %016lx(%016lx)\n", sock, filp));
+       it = sock->pfirst;
+       while (it) {
+               struct T_primsg *next = it->next;
+               
+               SOLDD(("socksys_release %016lx->%016lx\n", it, next));
+               mykfree((char*)it);
+               it = next;
+       }
+       filp->private_data = NULL;
+       SOLDD(("socksys_release %016lx\n", sock));
+       mykfree((char*)sock);
        return 0;
 }
 
 static unsigned int socksys_poll(struct file * filp, poll_table * wait)
 {
-       return 0;
+       struct inode *ino;
+       unsigned int mask = 0;
+
+       ino=filp->f_dentry->d_inode;
+       if (ino && ino->i_sock) {
+               struct sol_socket_struct *sock;
+               sock = (struct sol_socket_struct*)filp->private_data;
+               if (sock && sock->pfirst) {
+                       mask |= POLLIN | POLLRDNORM;
+                       if (sock->pfirst->pri == MSG_HIPRI)
+                               mask |= POLLPRI;
+               }
+       }
+       if (sock_poll)
+               mask |= (*sock_poll)(filp, wait);
+       return mask;
 }
        
 static struct file_operations socksys_fops = {
@@ -110,6 +177,7 @@ __initfunc(int
 init_socksys(void))
 {
        int ret;
+       struct file * file;
        int (*sys_socket)(int,int,int) =
                (int (*)(int,int,int))SUNOS(97);
        int (*sys_close)(unsigned int) = 
@@ -125,8 +193,11 @@ init_socksys(void))
                printk ("Couldn't create socket\n");
                return ret;
        }
-       socksys_file_ops = *current->files->fd[ret]->f_op;
+       file = fcheck(ret);
+       /* N.B. Is this valid? Suppose the f_ops are in a module ... */
+       socksys_file_ops = *file->f_op;
        sys_close(ret);
+       sock_poll = socksys_file_ops.poll;
        socksys_file_ops.poll = socksys_poll;
        socksys_file_ops.release = socksys_release;
        return 0;
diff --git a/arch/sparc64/solaris/socksys.h b/arch/sparc64/solaris/socksys.h
new file mode 100644 (file)
index 0000000..5d1b78e
--- /dev/null
@@ -0,0 +1,208 @@
+/* $Id: socksys.h,v 1.2 1998/03/26 08:46:07 jj Exp $
+ * socksys.h: Definitions for STREAMS modules emulation code.
+ *
+ * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
+ */
+
+#define MSG_HIPRI      0x01
+#define MSG_ANY                0x02
+#define MSG_BAND       0x04
+
+#define MORECTL                1
+#define MOREDATA       2
+
+#define        TBADADDR                1
+#define        TBADOPT                 2
+#define        TACCES                  3
+#define TBADF                  4
+#define TNOADDR                        5
+#define TOUTSTATE              6
+#define TBADSEQ                        7
+#define TSYSERR                        8
+#define TLOOK                  9
+#define TBADDATA              10
+#define TBUFOVFLW             11
+#define TFLOW                 12
+#define        TNODATA                13
+#define TNODIS                14
+#define TNOUDERR              15
+#define TBADFLAG              16
+#define TNOREL                17
+#define TNOTSUPPORT           18
+#define TSTATECHNG            19
+
+#define T_CONN_REQ      0
+#define T_CONN_RES      1
+#define T_DISCON_REQ    2
+#define T_DATA_REQ      3
+#define T_EXDATA_REQ    4
+#define T_INFO_REQ      5
+#define T_BIND_REQ      6
+#define T_UNBIND_REQ    7
+#define T_UNITDATA_REQ  8
+#define T_OPTMGMT_REQ   9
+#define T_ORDREL_REQ    10
+
+#define T_CONN_IND      11
+#define T_CONN_CON      12
+#define T_DISCON_IND    13
+#define T_DATA_IND      14
+#define T_EXDATA_IND    15
+#define T_INFO_ACK      16
+#define T_BIND_ACK      17
+#define T_ERROR_ACK     18
+#define T_OK_ACK        19
+#define T_UNITDATA_IND  20
+#define T_UDERROR_IND   21
+#define T_OPTMGMT_ACK   22
+#define T_ORDREL_IND    23
+
+#define T_NEGOTIATE    0x0004
+#define T_FAILURE      0x0040
+
+#define TS_UNBND       0       /* unbound */
+#define        TS_WACK_BREQ    1       /* waiting for T_BIND_REQ ack  */
+#define TS_WACK_UREQ   2       /* waiting for T_UNBIND_REQ ack */
+#define TS_IDLE                3       /* idle */
+#define TS_WACK_OPTREQ 4       /* waiting for T_OPTMGMT_REQ ack */
+#define TS_WACK_CREQ   5       /* waiting for T_CONN_REQ ack */
+#define TS_WCON_CREQ   6       /* waiting for T_CONN_REQ confirmation */
+#define        TS_WRES_CIND    7       /* waiting for T_CONN_IND */
+#define TS_WACK_CRES   8       /* waiting for T_CONN_RES ack */
+#define TS_DATA_XFER   9       /* data transfer */
+#define TS_WIND_ORDREL 10      /* releasing read but not write */
+#define TS_WREQ_ORDREL 11      /* wait to release write but not read */
+#define TS_WACK_DREQ6  12      /* waiting for T_DISCON_REQ ack */
+#define TS_WACK_DREQ7  13      /* waiting for T_DISCON_REQ ack */
+#define TS_WACK_DREQ9  14      /* waiting for T_DISCON_REQ ack */
+#define TS_WACK_DREQ10 15      /* waiting for T_DISCON_REQ ack */
+#define TS_WACK_DREQ11 16      /* waiting for T_DISCON_REQ ack */
+#define TS_NOSTATES    17
+
+struct T_conn_req {
+       s32 PRIM_type; 
+       s32 DEST_length;
+       s32 DEST_offset;
+       s32 OPT_length;
+       s32 OPT_offset;
+};
+
+struct T_bind_req {
+       s32 PRIM_type;
+       s32 ADDR_length;
+       s32 ADDR_offset;
+       u32 CONIND_number;
+};
+
+struct T_unitdata_req {
+       s32 PRIM_type; 
+       s32 DEST_length;
+       s32 DEST_offset;
+       s32 OPT_length;
+       s32 OPT_offset;
+};
+
+struct T_optmgmt_req {
+       s32 PRIM_type; 
+       s32 OPT_length;
+       s32 OPT_offset;
+       s32 MGMT_flags;
+};
+
+struct T_bind_ack {
+       s32 PRIM_type;
+       s32 ADDR_length;
+       s32 ADDR_offset;
+       u32 CONIND_number;
+};
+
+struct T_error_ack {
+       s32 PRIM_type;
+       s32 ERROR_prim;
+       s32 TLI_error;
+       s32 UNIX_error;
+};
+
+struct T_ok_ack {
+       s32 PRIM_type;
+       s32 CORRECT_prim;
+};
+
+struct T_conn_ind {
+       s32 PRIM_type;
+       s32 SRC_length;
+       s32 SRC_offset;
+       s32 OPT_length;
+       s32 OPT_offset;
+       s32 SEQ_number;
+};
+
+struct T_conn_con {
+       s32 PRIM_type;
+       s32 RES_length;
+       s32 RES_offset;
+       s32 OPT_length;
+       s32 OPT_offset;
+};
+
+struct T_discon_ind {
+       s32 PRIM_type;
+       s32 DISCON_reason;
+       s32 SEQ_number;
+};
+
+struct T_unitdata_ind {
+       s32 PRIM_type;
+       s32 SRC_length;
+       s32 SRC_offset;
+       s32 OPT_length;
+       s32 OPT_offset;
+};
+
+struct T_optmgmt_ack {
+       s32 PRIM_type; 
+       s32 OPT_length;
+       s32 OPT_offset;
+       s32 MGMT_flags;
+};
+
+struct opthdr {
+       s32 level;
+       s32 name;
+       s32 len;
+       char value[0];  
+};
+
+struct T_primsg {
+       struct T_primsg *next;
+       unsigned char pri;
+       unsigned char band;
+       int length;
+       s32 type;
+};
+
+struct strbuf {
+       s32 maxlen;
+       s32 len;
+       u32 buf;
+} ;
+
+/* Constants used by STREAMS modules emulation code */
+
+typedef char sol_module;
+
+#define MAX_NR_STREAM_MODULES   16
+
+/* Private data structure assigned to sockets. */
+
+struct sol_socket_struct {
+        int magic;
+        int modcount;
+        sol_module module[MAX_NR_STREAM_MODULES];
+        long state;
+        int offset;
+        struct T_primsg *pfirst, *plast;
+};
+
+#define SOLARIS_SOCKET_MAGIC    0xADDED
+
index c425fb721893012ec4bc5668607cd60d250d9a0c..bb18807f16dd04ec6ee0bb11bf162593816320ed 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbl.S,v 1.5 1997/09/04 15:46:24 jj Exp $
+/* $Id: systbl.S,v 1.6 1998/03/26 08:46:08 jj Exp $
  * systbl.S: System call entry point table for Solaris compatibility.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 #define REGS(name)     name+1
 
 /* Hack till all be implemented */
-#define solaris_getmsg         solaris_unimplemented
 #define solaris_getpmsg                solaris_unimplemented
 #define solaris_hrtsys         solaris_unimplemented
 #define solaris_msgsys         solaris_unimplemented
-#define solaris_putmsg         solaris_unimplemented
 #define solaris_putpmsg                solaris_unimplemented
 #define solaris_semsys         solaris_unimplemented
 
@@ -115,8 +113,8 @@ solaris_sys_table:
        .word solaris_unimplemented     /* libattach            82      */
        .word solaris_unimplemented     /* libdetach            83      */
        .word CHAIN(sysfs)              /* sysfs        dxx     84      */
-       .word REGS(solaris_getmsg)      /* getmsg       dxxx    85      */
-       .word REGS(solaris_putmsg)      /* putmsg       dxxd    86      */
+       .word solaris_getmsg            /* getmsg       dxxx    85      */
+       .word solaris_putmsg            /* putmsg       dxxd    86      */
        .word CHAIN(poll)               /* poll         xdd     87      */
        .word solaris_lstat             /* lstat        sp      88      */
        .word CHAIN(symlink)            /* symlink      ss      89      */
@@ -186,7 +184,7 @@ solaris_sys_table:
        .word solaris_unimplemented     /* fchroot      d       153     */
        .word solaris_unimplemented     /* lvlproc      dx      154     */
        .word solaris_unimplemented     /* ?                    155     */
-       .word CHAIN(gettimeofday)       /* gettimeofday xx      156     */
+       .word solaris_gettimeofday      /* gettimeofday x       156     */
        .word CHAIN(getitimer)          /* getitimer    dx      157     */
        .word CHAIN(setitimer)          /* setitimer    dxx     158     */
        .word solaris_unimplemented     /* lwp-xxx              159     */
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
new file mode 100644 (file)
index 0000000..7673702
--- /dev/null
@@ -0,0 +1,979 @@
+/* $Id: timod.c,v 1.1 1998/03/26 08:46:18 jj Exp $
+ * timod.c: timod emulation.
+ *
+ * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
+ *
+ * Streams & timod emulation based on code
+ * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+
+#include <asm/uaccess.h>
+#include <asm/termios.h>
+
+#include "conv.h"
+#include "socksys.h"
+
+extern char *getname32(u32 filename);
+#define putname32 putname
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, 
+       unsigned long arg);
+extern asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd,
+       u32 arg);
+asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+
+#ifdef __SMP__
+spinlock_t timod_pagelock = SPIN_LOCK_UNLOCKED;
+#endif
+static char * page = NULL ;
+
+#ifndef DEBUG_SOLARIS_KMALLOC
+
+#define mykmalloc kmalloc
+#define mykfree kfree
+
+#else
+
+void * mykmalloc(size_t s, int gfp)
+{
+       static char * page;
+       static size_t free = 0;
+       void * r;
+       s = ((s + 63) & ~63);
+       if( s > PAGE_SIZE ) {
+               SOLD("too big size, calling real kmalloc");
+               return kmalloc(s, gfp);
+       }
+       if( s > free ) {
+               /* we are wasting memory, but we don't care */
+               page = (char *)__get_free_page(gfp);
+               free = PAGE_SIZE;
+       }
+       r = page;
+       page += s;
+       free -= s;
+       return r;
+}
+
+void mykfree(void *p)
+{
+}
+
+#endif
+
+#ifndef DEBUG_SOLARIS
+
+#define BUF_SIZE       PAGE_SIZE
+#define PUT_MAGIC(a,m)
+#define CHECK_MAGIC(a,m)
+#define BUF_OFFSET     0
+#define MKCTL_TRAILER  0
+
+#else
+
+#define BUF_SIZE       (PAGE_SIZE-2*sizeof(u64))
+#define BUFPAGE_MAGIC  0xBADC0DEDDEADBABEL
+#define MKCTL_MAGIC    0xDEADBABEBADC0DEDL
+#define PUT_MAGIC(a,m) do{(*(u64*)(a))=(m);}while(0)
+#define CHECK_MAGIC(a,m)       do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\
+                               __FILE__,__LINE__,__FUNCTION__,(m),(a));}while(0)
+#define BUF_OFFSET     sizeof(u64)
+#define MKCTL_TRAILER  sizeof(u64)
+
+#endif
+
+static char *getpage( void )
+{
+       char *r;
+       SOLD("getting page");
+       spin_lock(&timod_pagelock);
+       if (page) {
+               r = page;
+               page = NULL;
+               spin_unlock(&timod_pagelock);
+               SOLD("got cached");
+               return r + BUF_OFFSET;
+       }
+       spin_unlock(&timod_pagelock);
+       SOLD("getting new");
+       r = (char *)__get_free_page(GFP_KERNEL);
+       PUT_MAGIC(r,BUFPAGE_MAGIC);
+       PUT_MAGIC(r+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
+       return r + BUF_OFFSET;
+}
+
+static void putpage(char *p)
+{
+       SOLD("putting page");
+       p = p - BUF_OFFSET;
+       CHECK_MAGIC(p,BUFPAGE_MAGIC);
+       CHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
+       spin_lock(&timod_pagelock);
+       if (page) {
+               spin_unlock(&timod_pagelock);
+               free_page((unsigned long)p);
+               SOLD("freed it");
+       } else {
+               page = p;
+               spin_unlock(&timod_pagelock);
+               SOLD("cached it");
+       }
+}
+
+static struct T_primsg *timod_mkctl(int size)
+{
+       struct T_primsg *it;
+
+       SOLD("creating primsg");
+       it = (struct T_primsg *)mykmalloc(size+sizeof(*it)-sizeof(s32)+2*MKCTL_TRAILER, GFP_KERNEL);
+       if (it) {
+               SOLD("got it");
+               it->pri = MSG_HIPRI;
+               it->length = size;
+               PUT_MAGIC((char*)((u64)(((char *)&it->type)+size+7)&~7),MKCTL_MAGIC);
+       }
+       return it;
+}
+
+static void timod_wake_socket(unsigned int fd)
+{
+       struct socket *sock;
+
+       SOLD("wakeing socket");
+       sock = &current->files->fd[fd]->f_dentry->d_inode->u.socket_i;
+       wake_up_interruptible(&sock->wait);
+       if (sock->fasync_list && !(sock->flags & SO_WAITDATA))
+               kill_fasync(sock->fasync_list, SIGIO);
+       SOLD("done");
+}
+
+static void timod_queue(unsigned int fd, struct T_primsg *it)
+{
+       struct sol_socket_struct *sock;
+
+       SOLD("queuing primsg");
+       sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
+       it->next = sock->pfirst;
+       sock->pfirst = it;
+       if (!sock->plast)
+               sock->plast = it;
+       timod_wake_socket(fd);
+       SOLD("done");
+}
+
+static void timod_queue_end(unsigned int fd, struct T_primsg *it)
+{
+       struct sol_socket_struct *sock;
+
+       SOLD("queuing primsg at end");
+       sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
+       it->next = NULL;
+       if (sock->plast)
+               sock->plast->next = it;
+       else
+               sock->pfirst = it;
+       sock->plast = it;
+       SOLD("done");
+}
+
+static void timod_error(unsigned int fd, int prim, int terr, int uerr)
+{
+       struct T_primsg *it;
+       
+       SOLD("making error");
+       it = timod_mkctl(sizeof(struct T_error_ack));
+       if (it) {
+               struct T_error_ack *err = (struct T_error_ack *)&it->type;
+               
+               SOLD("got it");
+               err->PRIM_type = T_ERROR_ACK;
+               err->ERROR_prim = prim;
+               err->TLI_error = terr;
+               err->UNIX_error = uerr; /* FIXME: convert this */
+               timod_queue(fd, it);
+       }
+       SOLD("done");
+}
+
+static void timod_ok(unsigned int fd, int prim)
+{
+       struct T_primsg *it;
+       struct T_ok_ack *ok;
+       
+       SOLD("creating ok ack");
+       it = timod_mkctl(sizeof(*ok));
+       if (it) {
+               SOLD("got it");
+               ok = (struct T_ok_ack *)&it->type;
+               ok->PRIM_type = T_OK_ACK;
+               ok->CORRECT_prim = prim;
+               timod_queue(fd, it);
+       }
+       SOLD("done");
+}
+
+static int timod_optmgmt(unsigned int fd, int flag, char *opt_buf, int opt_len, int do_ret)
+{
+       int error, failed;
+       int ret_space, ret_len;
+       long args[5];
+       char *ret_pos,*ret_buf;
+       int (*sys_socketcall)(int, unsigned long *) =
+               (int (*)(int, unsigned long *))SYS(socketcall);
+       mm_segment_t old_fs = get_fs();
+
+       SOLD("entry");
+       SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));
+       if (!do_ret && (!opt_buf || opt_len <= 0))
+               return 0;
+       SOLD("getting page");
+       ret_pos = ret_buf = getpage();
+       ret_space = BUF_SIZE;
+       ret_len = 0;
+       
+       error = failed = 0;
+       SOLD("looping");
+       while(opt_len >= sizeof(struct opthdr)) {
+               struct opthdr *opt;
+               int orig_opt_len; 
+               SOLD("loop start");
+               opt = (struct opthdr *)ret_pos; 
+               if (ret_space < sizeof(struct opthdr)) {
+                       failed = TSYSERR;
+                       break;
+               }
+               SOLD("getting opthdr");
+               if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||
+                       opt->len > opt_len) {
+                       failed = TBADOPT;
+                       break;
+               }
+               SOLD("got opthdr");
+               if (flag == T_NEGOTIATE) {
+                       char *buf;
+                       
+                       SOLD("handling T_NEGOTIATE");
+                       buf = ret_pos + sizeof(struct opthdr);
+                       if (ret_space < opt->len + sizeof(struct opthdr) ||
+                               copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {
+                               failed = TSYSERR;
+                               break;
+                       }
+                       SOLD("got optdata");
+                       args[0] = fd;
+                       args[1] = opt->level;
+                       args[2] = opt->name;
+                       args[3] = (long)buf;
+                       args[4] = opt->len;
+                       SOLD("calling SETSOCKOPT");
+                       set_fs(KERNEL_DS);
+                       error = sys_socketcall(SYS_SETSOCKOPT, args);
+                       set_fs(old_fs);
+                       if (error) {
+                               failed = TBADOPT;
+                               break;
+                       }
+                       SOLD("SETSOCKOPT ok");
+               }
+               orig_opt_len = opt->len;
+               opt->len = ret_space - sizeof(struct opthdr);
+               if (opt->len < 0) {
+                       failed = TSYSERR;
+                       break;
+               }
+               args[0] = fd;
+               args[1] = opt->level;
+               args[2] = opt->name;
+               args[3] = (long)(ret_pos+sizeof(struct opthdr));
+               args[4] = (long)&opt->len;
+               SOLD("calling GETSOCKOPT");
+               set_fs(KERNEL_DS);
+               error = sys_socketcall(SYS_GETSOCKOPT, args);
+               set_fs(old_fs);;
+               if (error) {
+                       failed = TBADOPT;
+                       break;
+               }
+               SOLD("GETSOCKOPT ok");
+               ret_space -= sizeof(struct opthdr) + opt->len;
+               ret_len += sizeof(struct opthdr) + opt->len;
+               ret_pos += sizeof(struct opthdr) + opt->len;
+               opt_len -= sizeof(struct opthdr) + orig_opt_len;
+               opt_buf += sizeof(struct opthdr) + orig_opt_len;
+               SOLD("loop end");
+       }
+       SOLD("loop done");
+       if (do_ret) {
+               SOLD("generating ret msg");
+               if (failed)
+                       timod_error(fd, T_OPTMGMT_REQ, failed, -error);
+               else {
+                       struct T_primsg *it;
+                       it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);
+                       if (it) {
+                               struct T_optmgmt_ack *ack =
+                                       (struct T_optmgmt_ack *)&it->type;
+                               SOLD("got primsg");
+                               ack->PRIM_type = T_OPTMGMT_ACK;
+                               ack->OPT_length = ret_len;
+                               ack->OPT_offset = sizeof(struct T_optmgmt_ack);
+                               ack->MGMT_flags = (failed ? T_FAILURE : flag);
+                               memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),
+                                       ret_buf, ret_len);
+                               timod_queue(fd, it);
+                       }
+               }
+       }
+       SOLDD(("put_page %p\n", ret_buf));
+       putpage(ret_buf);
+       SOLD("done");   
+       return 0;
+}
+
+int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len,
+                       char *data_buf, int data_len, int flags)
+{
+       int ret, error, terror;
+       char *buf;
+       struct file *filp;
+       struct inode *ino;
+       struct sol_socket_struct *sock;
+       mm_segment_t old_fs = get_fs();
+       long args[6];
+       int (*sys_socketcall)(int, unsigned long *) =
+               (int (*)(int, unsigned long *))SYS(socketcall);
+       int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) =
+               (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto);
+       filp = current->files->fd[fd];
+       ino = filp->f_dentry->d_inode;
+       sock = (struct sol_socket_struct *)filp->private_data;
+       SOLD("entry");
+       if (get_user(ret, (int *)A(ctl_buf)))
+               return -EFAULT;
+       switch (ret) {
+       case T_BIND_REQ:
+       {
+               struct T_bind_req req;
+               
+               SOLDD(("bind %016lx(%016lx)\n", sock, filp));
+               SOLD("T_BIND_REQ");
+               if (sock->state != TS_UNBND) {
+                       timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);
+                       return 0;
+               }
+               SOLD("state ok");
+               if (copy_from_user(&req, ctl_buf, sizeof(req))) {
+                       timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
+                       return 0;
+               }
+               SOLD("got ctl req");
+               if (req.ADDR_offset && req.ADDR_length) {
+                       if (req.ADDR_length > BUF_SIZE) {
+                               timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
+                               return 0;
+                       }
+                       SOLD("req size ok");
+                       buf = getpage();
+                       if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {
+                               timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
+                               putpage(buf);
+                               return 0;
+                       }
+                       SOLD("got ctl data");
+                       args[0] = fd;
+                       args[1] = (long)buf;
+                       args[2] = req.ADDR_length;
+                       SOLD("calling BIND");
+                       set_fs(KERNEL_DS);
+                       error = sys_socketcall(SYS_BIND, args);
+                       set_fs(old_fs);
+                       putpage(buf);
+                       SOLD("BIND returned");
+               } else 
+                       error = 0;
+               if (!error) {
+                       struct T_primsg *it;
+                       if (req.CONIND_number) {
+                               args[0] = fd;
+                               args[1] = req.CONIND_number;
+                               SOLD("calling LISTEN");
+                               set_fs(KERNEL_DS);
+                               error = sys_socketcall(SYS_LISTEN, args);
+                               set_fs(old_fs);
+                               SOLD("LISTEN done");
+                       }
+                       it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
+                       if (it) {
+                               struct T_bind_ack *ack;
+
+                               ack = (struct T_bind_ack *)&it->type;
+                               ack->PRIM_type = T_BIND_ACK;
+                               ack->ADDR_offset = sizeof(*ack);
+                               ack->ADDR_length = sizeof(struct sockaddr);
+                               ack->CONIND_number = req.CONIND_number;
+                               args[0] = fd;
+                               args[1] = (long)(ack+sizeof(*ack));
+                               args[2] = (long)&ack->ADDR_length;
+                               set_fs(KERNEL_DS);
+                               sys_socketcall(SYS_GETSOCKNAME,args);
+                               set_fs(old_fs);
+                               sock->state = TS_IDLE;
+                               timod_ok(fd, T_BIND_REQ);
+                               timod_queue_end(fd, it);
+                               SOLD("BIND done");
+                               return 0;
+                       }
+               }
+               SOLD("some error");
+               switch (error) {
+                       case -EINVAL:
+                               terror = TOUTSTATE;
+                               error = 0;
+                               break;
+                       case -EACCES:
+                               terror = TACCES;
+                               error = 0;
+                               break;
+                       case -EADDRNOTAVAIL:
+                       case -EADDRINUSE:
+                               terror = TNOADDR;
+                               error = 0;
+                               break;
+                       default:
+                               terror = TSYSERR;
+                               break;
+               }
+               timod_error(fd, T_BIND_REQ, terror, -error);
+               SOLD("BIND done");
+               return 0;
+       }
+       case T_CONN_REQ:
+       {
+               struct T_conn_req req;
+               unsigned short oldflags;
+               struct T_primsg *it;
+               SOLD("T_CONN_REQ");
+               if (sock->state != TS_UNBND && sock->state != TS_IDLE) {
+                       timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
+                       return 0;
+               }
+               SOLD("state ok");
+               if (copy_from_user(&req, ctl_buf, sizeof(req))) {
+                       timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
+                       return 0;
+               }
+               SOLD("got ctl req");
+               if (ctl_len > BUF_SIZE) {
+                       timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
+                       return 0;
+               }
+               SOLD("req size ok");
+               buf = getpage();
+               if (copy_from_user(buf, ctl_buf, ctl_len)) {
+                       timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
+                       putpage(buf);
+                       return 0;
+               }
+#ifdef DEBUG_SOLARIS           
+               {
+                       char * ptr = buf;
+                       int len = ctl_len;
+                       printk("returned data (%d bytes): ",len);
+                       while( len-- ) {
+                               if (!(len & 7))
+                                       printk(" ");
+                               printk("%02x",(unsigned char)*ptr++);
+                       }
+                       printk("\n");
+               }
+#endif
+               SOLD("got ctl data");
+               args[0] = fd;
+               args[1] = (long)buf+req.DEST_offset;
+               args[2] = req.DEST_length;
+               oldflags = filp->f_flags;
+               filp->f_flags &= ~O_NONBLOCK;
+               SOLD("calling CONNECT");
+               set_fs(KERNEL_DS);
+               error = sys_socketcall(SYS_CONNECT, args);
+               set_fs(old_fs);
+               filp->f_flags = oldflags;
+               SOLD("CONNECT done");
+               if (!error) {
+                       struct T_conn_con *con;
+                       SOLD("no error");
+                       it = timod_mkctl(ctl_len);
+                       if (!it) {
+                               putpage(buf);
+                               return -ENOMEM;
+                       }
+                       con = (struct T_conn_con *)&it->type;
+#ifdef DEBUG_SOLARIS                   
+                       {
+                               char * ptr = buf;
+                               int len = ctl_len;
+                               printk("returned data (%d bytes): ",len);
+                               while( len-- ) {
+                                       if (!(len & 7))
+                                               printk(" ");
+                                       printk("%02x",(unsigned char)*ptr++);
+                               }
+                               printk("\n");
+                       }
+#endif
+                       memcpy(con, buf, ctl_len);
+                       SOLD("copied ctl_buf");
+                       con->PRIM_type = T_CONN_CON;
+                       sock->state = TS_DATA_XFER;
+               } else {
+                       struct T_discon_ind *dis;
+                       SOLD("some error");
+                       it = timod_mkctl(sizeof(*dis));
+                       if (!it) {
+                               putpage(buf);
+                               return -ENOMEM;
+                       }
+                       SOLD("got primsg");
+                       dis = (struct T_discon_ind *)&it->type;
+                       dis->PRIM_type = T_DISCON_IND;
+                       dis->DISCON_reason = -error;    /* FIXME: convert this as in iABI_errors() */
+                       dis->SEQ_number = 0;
+               }
+               putpage(buf);
+               timod_ok(fd, T_CONN_REQ);
+               it->pri = 0;
+               timod_queue_end(fd, it);
+               SOLD("CONNECT done");
+               return 0;
+       }
+       case T_OPTMGMT_REQ:
+       {
+               struct T_optmgmt_req req;
+               SOLD("OPTMGMT_REQ");
+               if (copy_from_user(&req, ctl_buf, sizeof(req)))
+                       return -EFAULT;
+               SOLD("got req");
+               return timod_optmgmt(fd, req.MGMT_flags,
+                               req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL,
+                               req.OPT_length, 1);
+       }
+       case T_UNITDATA_REQ:
+       {
+               struct T_unitdata_req req;
+               
+               int err;
+               SOLD("T_UNITDATA_REQ");
+               if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) {
+                       timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
+                       return 0;
+               }
+               SOLD("state ok");
+               if (copy_from_user(&req, ctl_buf, sizeof(req))) {
+                       timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
+                       return 0;
+               }
+               SOLD("got ctl req");
+#ifdef DEBUG_SOLARIS           
+               {
+                       char * ptr = ctl_buf+req.DEST_offset;
+                       int len = req.DEST_length;
+                       printk("socket address (%d bytes): ",len);
+                       while( len-- ) {
+                               char c;
+                               if (get_user(c,ptr))
+                                       printk("??");
+                               else
+                                       printk("%02x",(unsigned char)c);
+                               ptr++;
+                       }
+                       printk("\n");
+               }
+#endif         
+               err = sys_sendto(fd, data_buf, data_len, 0, req.DEST_length > 0 ? (struct sockaddr*)(ctl_buf+req.DEST_offset) : NULL, req.DEST_length);
+               if (err == data_len)
+                       return 0;
+               if(err >= 0) {
+                       printk("timod: sendto failed to send all the data\n");
+                       return 0;
+               }
+               timod_error(fd, T_CONN_REQ, TSYSERR, -err);
+               return 0;
+       }
+       default:
+               printk("timod_putmsg: unsuported command %u.\n", ret);
+               break;
+       }
+       return -EINVAL;
+}
+
+/* copied directly from fs/select.c */
+
+static void free_wait(poll_table * p)
+{
+       struct poll_table_entry * entry = p->entry + p->nr;
+
+       SOLD("entry");
+       while (p->nr > 0) {
+               p->nr--;
+               entry--;
+               remove_wait_queue(entry->wait_address,&entry->wait);
+       }
+       SOLD("done");
+}
+
+
+int timod_getmsg(unsigned int fd, char *ctl_buf, int ctl_maxlen, s32 *ctl_len,
+                       char *data_buf, int data_maxlen, s32 *data_len, int *flags_p)
+{
+       int error;
+       int oldflags;
+       struct file *filp;
+       struct inode *ino;
+       struct sol_socket_struct *sock;
+       struct T_unitdata_ind udi;
+       mm_segment_t old_fs = get_fs();
+       long args[6];
+       char *tmpbuf;
+       int tmplen;
+       int (*sys_socketcall)(int, unsigned long *) =
+               (int (*)(int, unsigned long *))SYS(socketcall);
+       int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *);
+       
+       SOLD("entry");
+       SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p));
+       filp = current->files->fd[fd];
+       ino = filp->f_dentry->d_inode;
+       sock = (struct sol_socket_struct *)filp->private_data;
+       SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
+       if ( ctl_maxlen > 0 && !sock->pfirst && ino->u.socket_i.type == SOCK_STREAM
+               && sock->state == TS_IDLE) {
+               SOLD("calling LISTEN");
+               args[0] = fd;
+               args[1] = -1;
+               set_fs(KERNEL_DS);
+               sys_socketcall(SYS_LISTEN, args);
+               set_fs(old_fs);
+               SOLD("LISTEN done");
+       }
+       if (!(filp->f_flags & O_NONBLOCK)) {
+               poll_table wait_table, *wait;
+               struct poll_table_entry *entry;
+               SOLD("getting poll_table");
+               entry = (struct poll_table_entry *)__get_free_page(GFP_KERNEL);
+               if (!entry)
+                       return -ENOMEM;
+               SOLD("got one");
+               wait_table.nr = 0;
+               wait_table.entry = entry;
+               wait = &wait_table;
+               for(;;) {
+                       SOLD("loop");
+                       current->state = TASK_INTERRUPTIBLE;
+                       /* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
+                       /* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
+                       /* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
+                       /* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */ 
+                       /* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */ 
+                       /* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */ 
+                       if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI))
+                               break;
+                       SOLD("cond 1 passed");
+                       if (
+                       #if 1
+                               *flags_p != MSG_HIPRI &&
+                       #endif
+                               ((filp->f_op->poll(filp, wait) & POLLIN) ||
+                               (filp->f_op->poll(filp, NULL) & POLLIN) ||
+                               signal_pending(current))
+                       ) {
+                               break;
+                       }
+                       if( *flags_p == MSG_HIPRI ) {
+                               SOLD("avoiding lockup");
+                               break ;
+                       }
+                       SOLD("scheduling");
+                       schedule();
+               }
+               SOLD("loop done");
+               current->state = TASK_RUNNING;
+               free_wait(&wait_table);
+               free_page((unsigned long)entry);
+               if (signal_pending(current)) {
+                       SOLD("signal pending");
+                       return -EINTR;
+               }
+       }
+       if (ctl_maxlen >= 0 && sock->pfirst) {
+               struct T_primsg *it = sock->pfirst;
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+               int l = min(ctl_maxlen, it->length);
+               CHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC);
+               SOLD("purting ctl data");
+               if(copy_to_user(ctl_buf,
+                       (char*)&it->type + sock->offset, l))
+                       return -EFAULT;
+               SOLD("pur it");
+               if(put_user(l, ctl_len))
+                       return -EFAULT;
+               SOLD("set ctl_len");
+               *flags_p = it->pri;
+               it->length -= l;
+               if (it->length) {
+                       SOLD("more ctl");
+                       sock->offset += l;
+                       return MORECTL;
+               } else {
+                       SOLD("removing message");
+                       sock->pfirst = it->next;
+                       if (!sock->pfirst)
+                               sock->plast = NULL;
+                       SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst));
+                       mykfree(it);
+                       sock->offset = 0;
+                       SOLD("ctl done");
+                       return 0;
+               }
+       }
+       *flags_p = 0;
+       if (ctl_maxlen >= 0) {
+               SOLD("ACCEPT perhaps?");
+               if (ino->u.socket_i.type == SOCK_STREAM && sock->state == TS_IDLE) {
+                       struct T_conn_ind ind;
+                       char *buf = getpage();
+                       int len = BUF_SIZE;
+
+                       SOLD("trying ACCEPT");
+                       if (put_user(ctl_maxlen - sizeof(ind), ctl_len))
+                               return -EFAULT;
+                       args[0] = fd;
+                       args[1] = (long)buf;
+                       args[2] = (long)&len;
+                       oldflags = filp->f_flags;
+                       filp->f_flags |= O_NONBLOCK;
+                       SOLD("calling ACCEPT");
+                       set_fs(KERNEL_DS);
+                       error = sys_socketcall(SYS_ACCEPT, args);
+                       set_fs(old_fs);
+                       filp->f_flags = oldflags;
+                       if (error < 0) {
+                               SOLD("some error");
+                               putpage(buf);
+                               return error;
+                       }
+                       if (error) {
+                               SOLD("connect");
+                               putpage(buf);
+                               if (sizeof(ind) > ctl_maxlen) {
+                                       SOLD("generating CONN_IND");
+                                       ind.PRIM_type = T_CONN_IND;
+                                       ind.SRC_length = len;
+                                       ind.SRC_offset = sizeof(ind);
+                                       ind.OPT_length = ind.OPT_offset = 0;
+                                       ind.SEQ_number = error;
+                                       if(copy_to_user(ctl_buf, &ind, sizeof(ind))||
+                                          put_user(sizeof(ind)+ind.SRC_length,ctl_len))
+                                               return -EFAULT;
+                                       SOLD("CONN_IND created");
+                               }
+                               if (data_maxlen >= 0)
+                                       put_user(0, data_len);
+                               SOLD("CONN_IND done");
+                               return 0;
+                       }
+                       if (len>ctl_maxlen) {
+                               SOLD("data don't fit");
+                               putpage(buf);
+                               return -EFAULT;         /* XXX - is this ok ? */
+                       }
+                       if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){
+                               SOLD("can't copy data");
+                               putpage(buf);
+                               return -EFAULT;
+                       }
+                       SOLD("ACCEPT done");
+                       putpage(buf);
+               }
+       }
+       SOLD("checking data req");
+       if (data_maxlen <= 0) {
+               if (data_maxlen == 0)
+                       put_user(0, data_len);
+               if (ctl_maxlen >= 0)
+                       put_user(0, ctl_len);
+               return -EAGAIN;
+       }
+       SOLD("wants data");
+       if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
+               SOLD("udi fits");
+               tmpbuf = ctl_buf + sizeof(udi);
+               tmplen = ctl_maxlen - sizeof(udi);
+       } else {
+               SOLD("udi does not fit");
+               tmpbuf = NULL;
+               tmplen = 0;
+       }
+       if (put_user(tmplen, ctl_len))
+               return -EFAULT;
+       SOLD("set ctl_len");
+       oldflags = filp->f_flags;
+       filp->f_flags |= O_NONBLOCK;
+       SOLD("calling recvfrom");
+       sys_recvfrom = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom);
+       error = sys_recvfrom(fd, data_buf, min(0,data_maxlen), 0, (struct sockaddr*)tmpbuf, ctl_len);
+       filp->f_flags = oldflags;
+       if (error < 0)
+               return error;
+       SOLD("error >= 0" ) ;
+       if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
+               SOLD("generating udi");
+               udi.PRIM_type = T_UNITDATA_IND;
+               get_user(udi.SRC_length, ctl_len);
+               udi.SRC_offset = sizeof(udi);
+               udi.OPT_length = udi.OPT_offset = 0;
+               copy_to_user(ctl_buf, &udi, sizeof(udi));
+               put_user(sizeof(udi)+udi.SRC_length, ctl_len);
+               SOLD("udi done");
+       } else
+               put_user(0, ctl_len);
+       put_user(error, data_len);
+       SOLD("done");
+       return 0;
+}
+
+asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
+{
+       struct file *filp;
+       struct inode *ino;
+       struct strbuf *ctlptr, *datptr;
+       struct strbuf ctl, dat;
+       int *flgptr;
+       int flags;
+       int error = -EBADF;
+
+       SOLD("entry");
+       lock_kernel();
+       if(fd >= NR_OPEN) goto out;
+
+       filp = current->files->fd[fd];
+       if(!filp) goto out;
+
+       ino = filp->f_dentry->d_inode;
+       if (!ino) goto out;
+
+       if (!ino->i_sock)
+               goto out;
+
+       ctlptr = (struct strbuf *)A(arg1);
+       datptr = (struct strbuf *)A(arg2);
+       flgptr = (int *)A(arg3);
+
+       error = -EFAULT;
+
+       if (ctlptr) {
+               if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) || 
+                   put_user(-1,&ctlptr->len))
+                       goto out;
+       } else
+               ctl.maxlen = -1;
+
+       if (datptr) {
+               if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) || 
+                   put_user(-1,&datptr->len))
+                       goto out;
+       } else
+               dat.maxlen = -1;
+
+       if (get_user(flags,flgptr))
+               goto out;
+
+       switch (flags) {
+       case 0:
+       case MSG_HIPRI:
+       case MSG_ANY:
+       case MSG_BAND:
+               break;
+       default:
+               error = -EINVAL;
+               goto out;
+       }
+
+       error = timod_getmsg(fd,(char*)A(ctl.buf),ctl.maxlen,&ctlptr->len,
+                               (char*)A(dat.buf),dat.maxlen,&datptr->len,&flags);
+
+       if (!error && put_user(flags,flgptr))
+               error = -EFAULT;
+out:
+       unlock_kernel();
+       SOLD("done");
+       return error;
+}
+
+asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
+{
+       struct file *filp;
+       struct inode *ino;
+       struct strbuf *ctlptr, *datptr;
+       struct strbuf ctl, dat;
+       int flags = (int) arg3;
+       int error = -EBADF;
+
+       SOLD("entry");
+       lock_kernel();
+       if(fd >= NR_OPEN) goto out;
+
+       filp = current->files->fd[fd];
+       if(!filp) goto out;
+
+       ino = filp->f_dentry->d_inode;
+       if (!ino) goto out;
+
+       if (!ino->i_sock &&
+               (MAJOR(ino->i_rdev) != 30 || MINOR(ino->i_rdev) != 1))
+               goto out;
+
+       ctlptr = (struct strbuf *)A(arg1);
+       datptr = (struct strbuf *)A(arg2);
+
+       error = -EFAULT;
+
+       if (ctlptr) {
+               if (copy_from_user(&ctl,ctlptr,sizeof(ctl)))
+                       goto out;
+               if (ctl.len < 0 && flags) {
+                       error = -EINVAL;
+                       goto out;
+               }
+       } else {
+               ctl.len = 0;
+               ctl.buf = 0;
+       }
+
+       if (datptr) {
+               if (copy_from_user(&dat,datptr,sizeof(dat)))
+                       goto out;
+       } else {
+               dat.len = 0;
+               dat.buf = 0;
+       }
+
+       error = timod_putmsg(fd,(char*)A(ctl.buf),ctl.len,
+                               (char*)A(dat.buf),dat.len,flags);
+out:
+       unlock_kernel();
+       SOLD("done");
+       return error;
+}
index 661acc098b1b6cb07aecba387d308fc72b6e6aff..d2c08f0fe0690f7c08f88deb5fb6375d5cb6258a 100644 (file)
@@ -52,12 +52,9 @@ SECTIONS
    . += 8192;
    empty_bad_pte_table = .;
    . += 8192;
-   empty_bad_page = .;
-   . += 8192;
    . += 0x40;
    empty_null_pmd_table = .;
    . += 8192;
-   . += 0x40;
    empty_null_pte_table = .;
    . += 8192;
   }
index ff711db0194dc7c67ab6966389b411cf3aab3763..2cbed353922c0f0c8edc12624e83181d8b99702d 100644 (file)
@@ -333,7 +333,7 @@ __initfunc(void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigne
  */
 __initfunc(unsigned long ide_get_or_set_dma_base (struct pci_dev *dev, ide_hwif_t *hwif, int extra, const char *name))
 {
-       unsigned long new, dma_base = 0;
+       unsigned long dma_base = 0;
 
        if (hwif->mate && hwif->mate->dma_base) {
                dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
@@ -341,19 +341,7 @@ __initfunc(unsigned long ide_get_or_set_dma_base (struct pci_dev *dev, ide_hwif_
                dma_base = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
                if (!dma_base || dma_base == PCI_BASE_ADDRESS_IO_MASK) {
                        printk("%s: dma_base is invalid (0x%04lx, BIOS problem), please report to <mj@ucw.cz>\n", name, dma_base);
-                       new = ide_find_free_region(16 + extra);
-                       hwif->no_autodma = 1;   /* default DMA off if we had to configure it here */
-                       if (new) {
-                               printk("%s: setting dma_base to 0x%04lx\n", name, new);
-                               new |= PCI_BASE_ADDRESS_SPACE_IO;
-                               (void) pci_write_config_dword(dev, PCI_BASE_ADDRESS_4, new);
-                               dma_base = 0;
-                               (void) pci_read_config_dword(dev, PCI_BASE_ADDRESS_4, (unsigned int *) &dma_base);
-                               if (dma_base != new) {
-                                       printk("%s: Operation failed, DMA disabled\n", name);
-                                       dma_base = 0;
-                               }
-                       }
+                       dma_base = 0;
                }
        }
        if (dma_base) {
index 01d59a5cc8df693b1a8736490431f1b1be01cde7..9dd5487f30c99dda631e445f5a14fc73cd1a1b00 100644 (file)
@@ -115,31 +115,6 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
        {DEVID_AEC6210, "AEC6210",      NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
        {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }};
 
-/*
- * Search for an (apparently) unused block of I/O space
- * of "size" bytes in length.  Ideally we ought to do a pass
- * through pcicfg space to eliminate ports already allocated
- * by the BIOS, to avoid conflicts later in the init cycle,
- * but we don't.       FIXME
- */
-unsigned long ide_find_free_region (unsigned short size) /* __init */
-{
-       static unsigned short base = 0x5800;    /* it works for me */
-       unsigned short i;
-
-       for (; base > 0; base -= 0x200) {
-               if (!check_region(base,size)) {
-                       for (i = 0; i < size; i++) {
-                               if (inb(base+i) != 0xff)
-                                       goto next;
-                       }
-                       return base;    /* success */
-               }
-       next:
-       }
-       return 0;       /* failure */
-}
-
 /*
  * Match a PCI IDE port against an entry in ide_hwifs[],
  * based on io_base port if possible.
@@ -197,7 +172,6 @@ __initfunc(static ide_hwif_t *ide_match_hwif (unsigned long io_base, const char
 
 __initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name))
 {
-       unsigned int base, readback;
        byte reg, progif = 0;
 
        /*
@@ -218,16 +192,11 @@ __initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *n
        /*
         * Setup base registers for IDE command/control spaces for each interface:
         */
-       if (!(base = ide_find_free_region(32)))
-               return 1;
-       for (reg = 0; reg < 4; reg++, base += 8) {
-               (void) pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + reg, base | PCI_BASE_ADDRESS_SPACE_IO);
-               if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + reg, &readback) ||
-                   readback != (base | PCI_BASE_ADDRESS_SPACE_IO)) {
-                       printk("%s: readback failed for basereg 0x%02x: wrote 0x%04x, read 0x%x04\n", name, reg, base, readback);
+       for (reg = 0; reg < 4; reg++)
+               if (!dev->base_address[reg]) {
+                       printk("%s: Missing I/O address #%d, please report to <mj@ucw.cz>\n", name, reg);
                        return 1;
                }
-       }
        return 0;
 }
 
index 60ad885b8819c6504376965f697722b4ee443385..a86a51fdddb308393a1481659e9e51bb9a24e85e 100644 (file)
@@ -226,7 +226,7 @@ static int proc_ide_write_config
                                                restore_flags(flags);
                                                printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
                                                        msg, dev->bus->number, dev->devfn, reg, val);
-                                               printk("proc_ide_write_config: %s\n", pcibios_strerror(rc));
+                                               printk("proc_ide_write_config: error %d\n", rc);
                                                return -EIO;
                                        }
 #endif /* CONFIG_BLK_DEV_IDEPCI */
@@ -271,7 +271,7 @@ static int proc_ide_read_config
                if (rc) {
                        printk("proc_ide_read_config: error reading bus %02x dev %02x reg 0x%02x\n",
                                dev->bus->number, dev->devfn, reg);
-                       printk("proc_ide_read_config: %s\n", pcibios_strerror(rc));
+                       printk("proc_ide_read_config: error %d\n", rc);
                        return -EIO;
                        out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
                } else
index bfd6c4e5faf800e059603e1781b92b93781e19b0..11f84e6b4e7b1b17cd3c421d88451144c6d61f7c 100644 (file)
@@ -16,6 +16,7 @@ bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
 if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
    bool '   Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
    bool '   Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
+   bool '   Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ
    bool '   Support special multiport boards' CONFIG_SERIAL_MULTIPORT
    bool '   Support the Bell Technologies HUB6 card' CONFIG_HUB6
 fi
index 4bcd9748f7bdfb82fe097627406dbdcfcf09c358..8f796beefef2dfb79451057761d28c87cd6bda5f 100644 (file)
 
 /* This driver should, in theory, work with any parallel port that has an
  * appropriate low-level driver; all I/O is done through the parport
- * abstraction layer.  There is a performance penalty for this, but parallel
- * ports are comparitively low-speed devices anyway.
+ * abstraction layer.
  *
  * If this driver is built into the kernel, you can configure it using the
  * kernel command-line.  For example:
  *
- *      lp=parport1,none,parport2      (bind lp0 to parport1, disable lp1 and
+ *     lp=parport1,none,parport2       (bind lp0 to parport1, disable lp1 and
  *                                      bind lp2 to parport2)
  *
  *     lp=auto                         (assign lp devices to all ports that
  *                                      have printers attached, as determined
  *                                      by the IEEE-1284 autoprobe)
  * 
- *      lp=reset                       (reset the printer during 
+ *     lp=reset                        (reset the printer during 
  *                                      initialisation)
  *
  *     lp=off                          (disable the printer driver entirely)
  * If the driver is loaded as a module, similar functionality is available
  * using module parameters.  The equivalent of the above commands would be:
  *
- *     # insmod lp.o parport=1,-1,2    (use -1 for disabled ports, since
- *                                      module parameters do not allow you
- *                                      to mix textual and numeric values)
+ *     # insmod lp.o parport=1,none,2
  *
- *      # insmod lp.o autoprobe=1
+ *     # insmod lp.o parport=auto
  *
- *     # insmod lp.0 reset=1
+ *     # insmod lp.o reset=1
  */
 
 /* COMPATIBILITY WITH OLD KERNELS
@@ -652,13 +649,12 @@ static struct file_operations lp_fops = {
 
 #ifdef MODULE
 
-static int parport[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static char *parport[LP_NO] = { NULL,  };
 static int reset = 0;
-static int autoprobe = 0;
 
-MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "i");
+MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "s");
 MODULE_PARM(reset, "i");
-MODULE_PARM(autoprobe, "i");
 
 #else
 
@@ -720,7 +716,7 @@ int lp_init(void)
        unsigned int i;
        struct parport *port;
 
-       switch (parport[0])
+       switch (parport_nr[0])
        {
        case LP_PARPORT_OFF:
                return 0;
@@ -729,7 +725,7 @@ int lp_init(void)
        case LP_PARPORT_AUTO:
                for (port = parport_enumerate(); port; port = port->next) {
 
-                       if (parport[0] == LP_PARPORT_AUTO &&
+                       if (parport_nr[0] == LP_PARPORT_AUTO &&
                            port->probe_info.class != PARPORT_CLASS_PRINTER)
                                continue;
 
@@ -739,12 +735,11 @@ int lp_init(void)
                }
                break;
 
-       case LP_PARPORT_NONE:
        default:
                for (i = 0; i < LP_NO; i++) {
-                       if (parport[i] >= 0) {
+                       if (parport_nr[i] >= 0) {
                                char buffer[16];
-                               sprintf(buffer, "parport%d", parport[i]);
+                               sprintf(buffer, "parport%d", parport_nr[i]);
                                for (port = parport_enumerate(); port; 
                                     port = port->next) {
                                        if (!strcmp(port->name, buffer)) {
@@ -773,8 +768,28 @@ int lp_init(void)
 #ifdef MODULE
 int init_module(void)
 {
-       if (autoprobe)
-               parport[0] = LP_PARPORT_AUTO;
+       if (parport[0]) {
+               /* The user gave some parameters.  Let's see what they were.  */
+               if (!strncmp(parport[0], "auto", 4))
+                       parport_nr[0] = LP_PARPORT_AUTO;
+               else {
+                       int n;
+                       for (n = 0; n < LP_NO && parport[n]; n++) {
+                               if (!strncmp(parport[n], "none", 4))
+                                       parport_nr[n] = LP_PARPORT_NONE;
+                               else {
+                                       char *ep;
+                                       unsigned long r = simple_strtoul(parport[n], &ep, 0);
+                                       if (ep != parport[n]) 
+                                               parport_nr[n] = r;
+                                       else {
+                                               printk(KERN_ERR "lp: bad port specifier `%s'\n", parport[n]);
+                                               return -ENODEV;
+                                       }
+                               }
+                       }
+               }
+       }
 
        return lp_init();
 }
index 4216d14bd8bdb7462e76396880a56a93b1830ec4..3ddffff0be2a33e056d0cb96378e71aa8add9c84 100644 (file)
@@ -544,7 +544,7 @@ __initfunc(int chr_dev_init(void))
 #ifdef CONFIG_JOYSTICK
        /*
         *      Some joysticks only appear when the soundcard they are
-        *      connected too is confgured. Keep the sound/joystick ordering.
+        *      connected to is configured. Keep the sound/joystick ordering.
         */
        js_init();
 #endif 
index eeb865dd3a516cb60da81b12e08405a28e8af427..2113bac7d3ed72deac1a4c1f573d92b89c2f5720 100644 (file)
  *  8/97: Fix bug in rs_set_termios with RTS
  *        Stanislav V. Voronyi <stas@uanet.kharkov.ua>
  *
+ *  3/98: Change the IRQ detection, use of probe_irq_o*(),
+ *       supress TIOCSERGWILD and TIOCSERSWILD
+ *       Etienne Lorrain <etienne.lorrain@ibm.net>
+ *
+ *  4/98: Added changes to support the ARM architecture proposed by
+ *       Russell King
+ *
  * This module exports the following rs232 io functions:
  *
  *     int rs_init(void);
  */
 
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
-#endif
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-
-static char *serial_name = "Serial driver";
-static char *serial_version = "4.24";
-
-static DECLARE_TASK_QUEUE(tq_serial);
-
-static struct tty_driver serial_driver, callout_driver;
-static int serial_refcount;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
 /*
  * Serial driver configuration section.  Here are the various options:
  *
@@ -86,6 +54,9 @@ static int serial_refcount;
  * CONFIG_SERIAL_SHARE_IRQ
  *             Enables support for multiple serial ports on one IRQ
  *
+ * CONFIG_SERIAL_DETECT_IRQ
+ *             Enable the autodetection of IRQ on standart ports
+ *
  * SERIAL_PARANOIA_CHECK
  *             Check the magic number for the async_structure where
  *             ever possible.
@@ -100,6 +71,7 @@ static int serial_refcount;
 
 #define CONFIG_SERIAL_MANY_PORTS
 #define CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_DETECT_IRQ
 #define CONFIG_SERIAL_MULTIPORT
 #define CONFIG_HUB6
 #endif
@@ -133,7 +105,7 @@ static int serial_refcount;
 
 #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
 
-#define _INLINE_ inline
+#define SERIAL_INLINE
   
 #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
 #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
@@ -142,23 +114,71 @@ static int serial_refcount;
 #define DBG_CNT(s)
 #endif
 
+/*
+ * End of serial driver configuration section.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/serial.h>
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+       
+static char *serial_name = "Serial driver";
+static char *serial_version = "4.25";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
 /*
  * IRQ_timeout         - How long the timeout should be for each IRQ
  *                             should be after the IRQ has been active.
  */
 
-static struct async_struct *IRQ_ports[16];
+static struct async_struct *IRQ_ports[NR_IRQS];
 #ifdef CONFIG_SERIAL_MULTIPORT
-static struct rs_multiport_struct rs_multiport[16];
+static struct rs_multiport_struct rs_multiport[NR_IRQS];
 #endif
-static int IRQ_timeout[16];
-static volatile int rs_irq_triggered;
-static volatile int rs_triggered;
-static int rs_wild_int_mask;
+static int IRQ_timeout[NR_IRQS];
 #ifdef CONFIG_SERIAL_CONSOLE
 static struct console sercons;
 #endif
 
+static unsigned detect_uart_irq (struct serial_state * state);
 static void autoconfig(struct serial_state * info);
 static void change_speed(struct async_struct *info);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -180,109 +200,9 @@ static struct serial_uart_config uart_config[] = {
        { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
        { 0, 0}
 };
-       
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD ( 1843200 / 16 )
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-       
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
 
 static struct serial_state rs_table[] = {
-       /* UART CLK   PORT IRQ     FLAGS        */
-       { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */
-       { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */
-       { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */
-       { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
-#ifdef CONFIG_SERIAL_MANY_PORTS
-       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */
-       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */
-       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */
-       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */
-
-       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */
-       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */
-       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */
-       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */
-       
-       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */
-       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare; user configurable) */
-       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare; user configurable) */
-
-       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */
-       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */
-       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */
-       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */
-       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */
-       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */
-       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */
-       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */
-       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */
-       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */
-       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */
-       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */
-       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */
-       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */
-       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */
-       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#ifdef CONFIG_HUB6
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },       /* ttyS32 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },       /* ttyS33 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },       /* ttyS34 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },       /* ttyS35 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },       /* ttyS36 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },       /* ttyS37 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },       /* ttyS38 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },       /* ttyS39 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },       /* ttyS40 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },       /* ttyS41 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },       /* ttyS42 */
-       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },       /* ttyS43 */
-#endif
-#endif /* CONFIG_SERIAL_MANY_PORTS */
-#ifdef CONFIG_MCA
-       { 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS },
-       { 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS },
-       { 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS },
-       { 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS },
-       { 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS },
-       { 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS },
-#endif
+       SERIAL_PORT_DFNS        /* Defined in serial.h */
 };
 
 #define NR_PORTS       (sizeof(rs_table)/sizeof(struct serial_state))
@@ -304,7 +224,7 @@ static struct termios *serial_termios_locked[NR_PORTS];
  * buffer across all the serial ports, since it significantly saves
  * memory if large numbers of serial ports are open.
  */
-static unsigned char *tmp_buf = 0;
+static unsigned char *tmp_buf;
 static struct semaphore tmp_buf_sem = MUTEX;
 
 static inline int serial_paranoia_check(struct async_struct *info,
@@ -442,17 +362,6 @@ static void rs_start(struct tty_struct *tty)
  * -----------------------------------------------------------------------
  */
 
-/*
- * This is the serial driver's interrupt routine while we are probing
- * for submarines.
- */
-static void rs_probe(int irq, void *dev_id, struct pt_regs * regs)
-{
-       rs_irq_triggered = irq;
-       rs_triggered |= 1 << irq;
-       return;
-}
-
 /*
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
@@ -923,7 +832,7 @@ static void rs_timer(void)
        unsigned int    i;
 
        if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
-               for (i=1; i < 16; i++) {
+               for (i=1; i < NR_IRQS; i++) {
                        info = IRQ_ports[i];
                        if (!info)
                                continue;
@@ -974,38 +883,6 @@ static void rs_timer(void)
  * ---------------------------------------------------------------
  */
 
-/*
- * Grab all interrupts in preparation for doing an automatic irq
- * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
- * mask of irq's which were grabbed and should therefore be freed
- * using free_all_interrupts().
- */
-static int grab_all_interrupts(int dontgrab)
-{
-       int                     irq_lines = 0;
-       int                     i, mask;
-       
-       for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
-               if (!(mask & dontgrab) && !request_irq(i, rs_probe, SA_INTERRUPT, "serial probe", NULL)) {
-                       irq_lines |= mask;
-               }
-       }
-       return irq_lines;
-}
-
-/*
- * Release all interrupts grabbed by grab_all_interrupts
- */
-static void free_all_interrupts(int irq_lines)
-{
-       int     i;
-       
-       for (i = 0; i < 16; i++) {
-               if (irq_lines & (1 << i))
-                       free_irq(i, NULL);
-       }
-}
-
 /*
  * This routine figures out the correct timeout for a particular IRQ.
  * It uses the smallest timeout of all of the serial ports in a
@@ -1541,44 +1418,61 @@ static int rs_write(struct tty_struct * tty, int from_user,
 
        if (!tty || !info->xmit_buf || !tmp_buf)
                return 0;
-           
-       if (from_user)
-               down(&tmp_buf_sem);
+
        save_flags(flags);
-       while (1) {
-               cli();          
-               c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                  SERIAL_XMIT_SIZE - info->xmit_head));
-               if (c <= 0)
-                       break;
+       if (from_user) {
+               down(&tmp_buf_sem);
+               while (1) {
+                       c = MIN(count,
+                               MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                   SERIAL_XMIT_SIZE - info->xmit_head));
+                       if (c <= 0)
+                               break;
 
-               if (from_user) {
                        c -= copy_from_user(tmp_buf, buf, c);
                        if (!c) {
                                if (!ret)
                                        ret = -EFAULT;
                                break;
                        }
+                       cli();
                        c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                       SERIAL_XMIT_SIZE - info->xmit_head));
                        memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-               } else
+                       info->xmit_head = ((info->xmit_head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       info->xmit_cnt += c;
+                       restore_flags(flags);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+               up(&tmp_buf_sem);
+       } else {
+               while (1) {
+                       cli();          
+                       c = MIN(count,
+                               MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                   SERIAL_XMIT_SIZE - info->xmit_head));
+                       if (c <= 0) {
+                               restore_flags(flags);
+                               break;
+                       }
                        memcpy(info->xmit_buf + info->xmit_head, buf, c);
-               info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt += c;
-               restore_flags(flags);
-               buf += c;
-               count -= c;
-               ret += c;
+                       info->xmit_head = ((info->xmit_head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       info->xmit_cnt += c;
+                       restore_flags(flags);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
        }
-       if (from_user)
-               up(&tmp_buf_sem);
        if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
            !(info->IER & UART_IER_THRI)) {
                info->IER |= UART_IER_THRI;
                serial_out(info, UART_IER, info->IER);
        }
-       restore_flags(flags);
        return ret;
 }
 
@@ -1759,10 +1653,9 @@ static int set_serial_info(struct async_struct * info,
                goto check_and_exit;
        }
 
-       if (new_serial.irq == 2)
-               new_serial.irq = 9;
+       new_serial.irq = irq_cannonicalize(new_serial.irq);
 
-       if ((new_serial.irq > 15) || (new_serial.port > 0xffff) ||
+       if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
            (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
                return -EINVAL;
        }
@@ -1793,6 +1686,7 @@ static int set_serial_info(struct async_struct * info,
        state->type = new_serial.type;
        state->close_delay = new_serial.close_delay * HZ/100;
        state->closing_wait = new_serial.closing_wait * HZ/100;
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
        info->xmit_fifo_size = state->xmit_fifo_size =
                new_serial.xmit_fifo_size;
 
@@ -1951,9 +1845,9 @@ static int do_autoconfig(struct async_struct * info)
        
        shutdown(info);
 
-       cli();
        autoconfig(info->state);
-       sti();
+       if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0))
+               info->state->irq = detect_uart_irq(info->state);
 
        retval = startup(info);
        if (retval)
@@ -1984,50 +1878,6 @@ static void rs_break(struct tty_struct *tty, int break_state)
        restore_flags(flags);
 }
 
-/*
- * This routine returns a bitfield of "wild interrupts".  Basically,
- * any unclaimed interrupts which is flapping around.
- */
-static int check_wild_interrupts(int doprint)
-{
-       int     i, mask;
-       int     wild_interrupts = 0;
-       int     irq_lines;
-       unsigned long timeout;
-       unsigned long flags;
-       
-       /* Turn on interrupts (they may be off) */
-       save_flags(flags); sti();
-
-       irq_lines = grab_all_interrupts(0);
-       
-       /*
-        * Delay for 0.1 seconds -- we use a busy loop since this may 
-        * occur during the bootup sequence
-        */
-       timeout = jiffies+HZ/10;
-       while (timeout >= jiffies)
-               ;
-       
-       rs_triggered = 0;       /* Reset after letting things settle */
-
-       timeout = jiffies+HZ/10;
-       while (timeout >= jiffies)
-               ;
-       
-       for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
-               if ((rs_triggered & (1 << i)) &&
-                   (irq_lines & (1 << i))) {
-                       wild_interrupts |= mask;
-                       if (doprint)
-                               printk("Wild interrupt?  (IRQ %d)\n", i);
-               }
-       }
-       free_all_interrupts(irq_lines);
-       restore_flags(flags);
-       return wild_interrupts;
-}
-
 #ifdef CONFIG_SERIAL_MULTIPORT
 static int get_multiport_struct(struct async_struct * info,
                                struct serial_multiport_struct *retinfo)
@@ -2155,8 +2005,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                return -ENODEV;
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
            (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
                if (tty->flags & (1 << TTY_IO_ERROR))
                    return -EIO;
@@ -2178,23 +2027,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                case TIOCSERCONFIG:
                        return do_autoconfig(info);
 
-               case TIOCSERGWILD:
-                       return put_user(rs_wild_int_mask,
-                                       (unsigned int *) arg);
                case TIOCSERGETLSR: /* Get line status register */
                        return get_lsr_info(info, (unsigned int *) arg);
 
-               case TIOCSERSWILD:
-                       if (!suser())
-                               return -EPERM;
-                       error = get_user(rs_wild_int_mask,
-                                        (unsigned int *) arg);
-                       if (error)
-                               return error;
-                       if (rs_wild_int_mask < 0)
-                               rs_wild_int_mask = check_wild_interrupts(0);
-                       return 0;
-
                case TIOCSERGSTRUCT:
                        if (copy_to_user((struct async_struct *) arg,
                                         info, sizeof(struct async_struct)))
@@ -2216,7 +2051,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
                 * Caller should use TIOCGICOUNT to see which one it was
                 */
-                case TIOCMIWAIT:
+               case TIOCMIWAIT:
                        cli();
                        /* note the counters on entry */
                        cprev = info->state->icount;
@@ -2707,6 +2542,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
 #endif
        tty->driver_data = info;
        info->tty = tty;
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
        if (!tmp_buf) {
                page = get_free_page(GFP_KERNEL);
@@ -2778,7 +2614,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
  * /proc fs routines....
  */
 
-static int inline line_info(char *buf, struct serial_state *state)
+static inline int line_info(char *buf, struct serial_state *state)
 {
        struct async_struct *info = state->info, scr_info;
        char    stat_buf[30], control, status;
@@ -2906,7 +2742,10 @@ static _INLINE_ void show_serial_version(void)
 #endif
 #ifdef CONFIG_SERIAL_SHARE_IRQ
        printk(" SHARE_IRQ");
+#endif
 #define SERIAL_OPT
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+       printk(" DETECT_IRQ");
 #endif
 #ifdef SERIAL_OPT
        printk(" enabled\n");
@@ -2917,105 +2756,54 @@ static _INLINE_ void show_serial_version(void)
 }
 
 /*
- * This routine is called by do_auto_irq(); it attempts to determine
- * which interrupt a serial port is configured to use.  It is not
- * fool-proof, but it works a large part of the time.
+ * This routine detect the IRQ of a serial port by clearing OUT2 when
+ * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
+ * each time, as long as no other device permanently request the IRQ.
+ * If no IRQ is detected, or multiple IRQ appear, this function returns 0.
+ * The variable "state" and the field "state->port" should not be null.
  */
-static int get_auto_irq(struct async_struct *info)
+static unsigned detect_uart_irq (struct serial_state * state)
 {
-        
-       unsigned char save_MCR, save_IER;
-       unsigned long timeout;
-#ifdef CONFIG_SERIAL_MANY_PORTS
-       unsigned char save_ICP=0;
-       unsigned short ICP=0, port = info->port;
-#endif
+       int irq;
+       unsigned long irqs;
+       unsigned char save_mcr;
+       struct async_struct scr_info; /* serial_{in,out} because HUB6 */
 
-       
-       /*
-        * Enable interrupts and see who answers
-        */
-       rs_irq_triggered = 0;
-       cli();
-       save_IER = serial_inp(info, UART_IER);
-       save_MCR = serial_inp(info, UART_MCR);
 #ifdef CONFIG_SERIAL_MANY_PORTS
-       if (info->flags & ASYNC_FOURPORT)  {
-               serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
-               serial_outp(info, UART_IER, 0x0f);      /* enable all intrs */
-               ICP = (port & 0xFE0) | 0x01F;
+       unsigned char save_ICP=0; /* no warning */
+       unsigned short ICP=0;
+
+       if (state->flags & ASYNC_FOURPORT)  {
+               ICP = (state->port & 0xFE0) | 0x01F;
                save_ICP = inb_p(ICP);
                outb_p(0x80, ICP);
                (void) inb_p(ICP);
-       } else 
-#endif
-        {
-               serial_outp(info, UART_MCR,
-                           UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
-               serial_outp(info, UART_IER, 0x0f);      /* enable all intrs */
        }
-       sti();
-       /*
-        * Next, clear the interrupt registers.
-        */
-       (void)serial_inp(info, UART_LSR);
-       (void)serial_inp(info, UART_RX);
-       (void)serial_inp(info, UART_IIR);
-       (void)serial_inp(info, UART_MSR);
-       
-       timeout = jiffies+ ((2*HZ)/100);
-       while (timeout >= jiffies) {
-               if (rs_irq_triggered)
-                       break;
-       }
-       /*
-        * Now check to see if we got any business, and clean up.
-        */
-       cli();
-       serial_outp(info, UART_IER, save_IER);
-       serial_outp(info, UART_MCR, save_MCR);
-#ifdef CONFIG_SERIAL_MANY_PORTS
-       if (info->flags & ASYNC_FOURPORT)
-               outb_p(save_ICP, ICP);
 #endif
-       sti();
-       return(rs_irq_triggered);
-}
+       scr_info.magic = SERIAL_MAGIC;
+       scr_info.port = state->port;
+       scr_info.flags = state->flags;
+#ifdef CONFIG_HUB6
+       scr_info.hub6 = state->hub6;
+#endif
 
-/*
- * Calls get_auto_irq() multiple times, to make sure we don't get
- * faked out by random interrupts
- */
-static int do_auto_irq(struct async_struct * info)
-{
-       unsigned                port = info->port;
-       int                     irq_lines = 0;
-       int                     irq_try_1 = 0, irq_try_2 = 0;
-       int                     retries;
-       unsigned long flags;
+       /* forget possible initially masked and pending IRQ */
+       probe_irq_off(probe_irq_on());
+       save_mcr = serial_inp(&scr_info, UART_MCR);
 
-       if (!port)
-               return 0;
+       serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+       irqs = probe_irq_on();
+       serial_outp(&scr_info, UART_MCR, 0);
+       udelay (1);
+       irq = probe_irq_off(irqs);
 
-       /* Turn on interrupts (they may be off) */
-       save_flags(flags); sti();
+       serial_outp(&scr_info, UART_MCR, save_mcr);
 
-       irq_lines = grab_all_interrupts(rs_wild_int_mask);
-       
-       for (retries = 0; retries < 5; retries++) {
-               if (!irq_try_1)
-                       irq_try_1 = get_auto_irq(info);
-               if (!irq_try_2)
-                       irq_try_2 = get_auto_irq(info);
-               if (irq_try_1 && irq_try_2) {
-                       if (irq_try_1 == irq_try_2)
-                               break;
-                       irq_try_1 = irq_try_2 = 0;
-               }
-       }
-       restore_flags(flags);
-       free_all_interrupts(irq_lines);
-       return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       if (state->flags & ASYNC_FOURPORT)
+               outb_p(save_ICP, ICP);
+#endif
+       return (irq > 0)? irq : 0;
 }
 
 /*
@@ -3041,6 +2829,9 @@ static void autoconfig(struct serial_state * state)
        info->magic = SERIAL_MAGIC;
        info->port = state->port;
        info->flags = state->flags;
+#ifdef CONFIG_HUB6
+       info->hub6 = state->hub6;
+#endif
 
        save_flags(flags); cli();
        
@@ -3086,13 +2877,6 @@ static void autoconfig(struct serial_state * state)
                }
        } 
        
-       /*
-        * If the AUTO_IRQ flag is set, try to do the automatic IRQ
-        * detection.
-        */
-       if (state->flags & ASYNC_AUTO_IRQ)
-               state->irq = do_auto_irq(info);
-               
        scratch2 = serial_in(info, UART_LCR);
        serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
        serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
@@ -3174,6 +2958,7 @@ static void autoconfig(struct serial_state * state)
        serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
                                     UART_FCR_CLEAR_XMIT));
        (void)serial_in(info, UART_RX);
+       serial_outp(info, UART_IER, 0);
        
        restore_flags(flags);
 }
@@ -3191,15 +2976,21 @@ __initfunc(int rs_init(void))
 {
        int i;
        struct serial_state * state;
-       
+       extern void atomwide_serial_init (void);
+       extern void dualsp_serial_init (void);
+
+#ifdef CONFIG_ATOMWIDE_SERIAL
+       atomwide_serial_init ();
+#endif
+#ifdef CONFIG_DUALSP_SERIAL
+       dualsp_serial_init ();
+#endif
+
        init_bh(SERIAL_BH, do_serial_bh);
        timer_table[RS_TIMER].fn = rs_timer;
        timer_table[RS_TIMER].expires = 0;
-#ifdef CONFIG_AUTO_IRQ
-       rs_wild_int_mask = check_wild_interrupts(1);
-#endif
 
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < NR_IRQS; i++) {
                IRQ_ports[i] = 0;
                IRQ_timeout[i] = 0;
 #ifdef CONFIG_SERIAL_MULTIPORT
@@ -3291,17 +3082,26 @@ __initfunc(int rs_init(void))
                state->icount.rx = state->icount.tx = 0;
                state->icount.frame = state->icount.parity = 0;
                state->icount.overrun = state->icount.brk = 0;
-               if (state->irq == 2)
-                       state->irq = 9;
-               if (state->type == PORT_UNKNOWN) {
-                       if (!(state->flags & ASYNC_BOOT_AUTOCONF))
-                               continue;
-                       if (check_region(state->port,8))
-                               continue;
-                       autoconfig(state);
-                       if (state->type == PORT_UNKNOWN)
-                               continue;
+               state->irq = irq_cannonicalize(state->irq);
+               if (check_region(state->port,8)) {
+                       state->type = PORT_UNKNOWN;
+                       continue;
                }
+               if (   (state->type == PORT_UNKNOWN)
+                   && (state->flags & ASYNC_BOOT_AUTOCONF))
+                       autoconfig(state);
+       }
+       /*
+        * Detect the IRQ only once every port is initialised,
+        * because some 16450 do not reset to 0 the MCR register.
+        */
+       for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+               if (state->type == PORT_UNKNOWN)
+                       continue;
+               if (   (state->flags & ASYNC_BOOT_AUTOCONF)
+                   && (state->flags & ASYNC_AUTO_IRQ)
+                   && (state->port != 0))
+                       state->irq = detect_uart_irq(state);
                printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
                       state->line,
                       (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
@@ -3354,10 +3154,14 @@ int register_serial(struct serial_struct *req)
                printk("register_serial(): autoconfig failed\n");
                return -1;
        }
+       restore_flags(flags);
+
+       if ((state->flags & ASYNC_AUTO_IRQ) && (state->port != 0))
+               state->irq = detect_uart_irq(state);
+
        printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n",
               state->line, state->port, state->irq,
               uart_config[state->type].name);
-       restore_flags(flags);
        return state->line;
 }
 
@@ -3597,7 +3401,7 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
         *      Divisor, bytesize and parity
         */
        ser = rs_table + co->index;
-       quot = BASE_BAUD / baud;
+       quot = ser->baud_base / baud;
        cval = cflag & (CSIZE | CSTOPB);
 #if defined(__powerpc__) || defined(__alpha__)
        cval >>= 8;
@@ -3613,13 +3417,12 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
         *      Disable UART interrupts, set DTR and RTS high
         *      and set speed.
         */
-       outb(cval, ser->port + UART_LCR);  /* don't assume that DLAB is clear */
-       outb(0, ser->port + UART_IER);
-       outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
        outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);       /* set DLAB */
        outb(quot & 0xff, ser->port + UART_DLL);        /* LS of divisor */
        outb(quot >> 8, ser->port + UART_DLM);          /* MS of divisor */
        outb(cval, ser->port + UART_LCR);               /* reset DLAB */
+       outb(0, ser->port + UART_IER);
+       outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
 
        /*
         *      If we read 0xff from the LSR, there is no UART here.
index 35be2317763eafe2f7d76734c433b44368e4c284..bf2e642c4dec9dc5eb03d5881f2897a7777e669f 100644 (file)
@@ -131,12 +131,13 @@ static int tty_fasync(struct file * filp, int on);
 /*
  * This routine returns the name of tty.
  */
+#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \
+                        (tty)->driver.name_base)
+       
 char *tty_name(struct tty_struct *tty, char *buf)
 {
        if (tty)
-               sprintf(buf, "%s%d", tty->driver.name,
-                       MINOR(tty->device) - tty->driver.minor_start +
-                       tty->driver.name_base);
+               sprintf(buf, "%s%d", tty->driver.name, TTY_NUMBER(tty));
        else
                strcpy(buf, "NULL tty");
        return buf;
@@ -1287,9 +1288,17 @@ init_dev_done:
                tty->pgrp = current->pgrp;
        }
        if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) &&
-           (tty->driver.subtype == SERIAL_TYPE_CALLOUT)) {
-               printk(KERN_INFO "Warning, %s opened, is a deprecated tty "
-                      "callout device\n", tty_name(tty, buf));
+           (tty->driver.subtype == SERIAL_TYPE_CALLOUT) &&
+           (tty->count == 1)) {
+               static int nr_warns = 0;
+               if (nr_warns < 5) {
+                       printk(KERN_WARNING "tty_io.c: "
+                               "process %d (%s) used obsolete /dev/%s - " 
+                               "update software to use /dev/ttyS%d\n",
+                               current->pid, current->comm, 
+                               tty_name(tty, buf), TTY_NUMBER(tty));
+                       nr_warns++;
+               }
        }
        return 0;
 }
index 839a2eb4f0ecf58f7283ba3fa68a0643a65c6bb9..226f4a80b9356711c6f45b658172d7659446b8df 100644 (file)
@@ -1183,20 +1183,14 @@ void complete_change_console(unsigned int new_console)
 #ifdef CONFIG_SUN_CONSOLE
        if (old_vc_mode != vt_cons[new_console]->vc_mode)
        {
-               extern void set_cursor(int currcons);
-               extern void hide_cursor(void);
-
                if (old_vc_mode == KD_GRAPHICS)
                {
-                       extern void sun_clear_margin(void);
-                       extern void render_screen(void);
-                       
-                       sun_clear_margin();
-                       render_screen();
-                       set_cursor(fg_console);
+                       suncons_ops.clear_margin();
+                       suncons_ops.render_screen();
+                       suncons_ops.set_cursor(fg_console);
                }
                else
-                       hide_cursor();
+                       suncons_ops.hide_cursor();
        }
 #endif         
       /*
index 04a18c0ff62fceeff4d25214d6cc02939bf139bd..720453a87c0b4858ec293546f72ab8f6b0648278 100644 (file)
@@ -1,7 +1,7 @@
 /* fc.c: Generic Fibre Channel and FC4 SCSI driver.
  *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 Jiri Hanika (geo@ff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jiri Hanika (geo@ff.cuni.cz)
  *
  * Sources:
  *     Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
@@ -51,9 +51,9 @@ static inline dma_handle fc_sync_dma_entry(void *buf, int len, fc_channel *fc)
        return mmu_get_scsi_one (buf, len, fc->dev->my_bus);
 }
 
-static inline void fc_sync_dma_exit(void *buf, long size, fc_channel *fc)
+static inline void fc_sync_dma_exit(dma_handle dmh, long size, fc_channel *fc)
 {
-       mmu_release_scsi_one ((u32)(long)buf, size, fc->dev->my_bus);
+       mmu_release_scsi_one (dmh, size, fc->dev->my_bus);
 }
 
 static inline void fc_sync_dma_entry_sg(struct scatterlist *list, int count, fc_channel *fc)
@@ -73,28 +73,28 @@ static inline void fc_sync_dma_exit_sg(struct scatterlist *list, int count, fc_c
 #define FC_SCMND(SCpnt) ((fc_channel *)(SCpnt->host->hostdata[0]))
 #define SC_FCMND(fcmnd) ((Scsi_Cmnd *)((long)fcmnd - (long)&(((Scsi_Cmnd *)0)->SCp)))
 
-static void fcp_scsi_insert_queue (fc_channel *fc, int no, fcp_cmnd *fcmd)
+static void fcp_scsi_insert_queue (fc_channel *fc, fcp_cmnd *fcmd)
 {
-       if (!fc->scsi_que[no]) {
-               fc->scsi_que[no] = fcmd;
+       if (!fc->scsi_que) {
+               fc->scsi_que = fcmd;
                fcmd->next = fcmd;
                fcmd->prev = fcmd;
        } else {
-               fc->scsi_que[no]->prev->next = fcmd;
-               fcmd->prev = fc->scsi_que[no]->prev;
-               fc->scsi_que[no]->prev = fcmd;
-               fcmd->next = fc->scsi_que[no];
+               fc->scsi_que->prev->next = fcmd;
+               fcmd->prev = fc->scsi_que->prev;
+               fc->scsi_que->prev = fcmd;
+               fcmd->next = fc->scsi_que;
        }
 }
 
-static void fcp_scsi_remove_queue (fc_channel *fc, int no, fcp_cmnd *fcmd)
+static void fcp_scsi_remove_queue (fc_channel *fc, fcp_cmnd *fcmd)
 {
        if (fcmd == fcmd->next) {
-               fc->scsi_que[no] = NULL;
+               fc->scsi_que = NULL;
                return;
        }
-       if (fcmd == fc->scsi_que[no])
-               fc->scsi_que[no] = fcmd->next;
+       if (fcmd == fc->scsi_que)
+               fc->scsi_que = fcmd->next;
        fcmd->prev->next = fcmd->next;
        fcmd->next->prev = fcmd->prev;
 }
@@ -151,7 +151,7 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                        fc->state = FC_STATE_FPORT_OK;
                        fcmd = l->fcmds + i;
                        plogi = l->logi + 3 * i;
-                       fc_sync_dma_exit (plogi, 3 * sizeof(logi), fc);
+                       fc_sync_dma_exit (fcmd->cmd, 3 * sizeof(logi), fc);
                        plogi->code = LS_PLOGI;
                        memcpy (&plogi->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn));
                        memcpy (&plogi->node_wwn, &fc->wwn_node, sizeof(fc_wwn));
@@ -159,7 +159,6 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                        memcpy (&plogi->class1, fc->class_svcs, 3*sizeof(svc_parm));
                        fch = &fcmd->fch;
                        fcmd->token += l->count;
-                       fcmd->rsp += sizeof(logi);
                        FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, fc->did);
                        FILL_FCHDR_SID(fch, fc->sid);
 #ifdef FCDEBUG
@@ -172,7 +171,8 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                                printk ("\n");
                        }
 #endif                 
-                       fc_sync_dma_entry (plogi, 3 * sizeof(logi), fc);
+                       fcmd->cmd = fc_sync_dma_entry (plogi, 3 * sizeof(logi), fc);
+                       fcmd->rsp = fcmd->cmd + 2 * sizeof(logi);
                        if (fc->hw_enque (fc, fcmd))
                                printk ("FC: Cannot enque PLOGI packet on %s\n", fc->name);
                        break;
@@ -194,7 +194,7 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                switch (status) {
                case FC_STATUS_OK:
                        plogi = l->logi + 3 * i;
-                       fc_sync_dma_exit (plogi, 3 * sizeof(logi), fc);
+                       fc_sync_dma_exit (l->fcmds[i].cmd, 3 * sizeof(logi), fc);
                        if (!fc->wwn_dest.lo && !fc->wwn_dest.hi) {
                                memcpy (&fc->wwn_dest, &plogi[1].node_wwn, sizeof(fc_wwn)); 
                                FCD(("Dest WWN %08x%08x\n", *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo))
@@ -212,7 +212,7 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
                        break;
                case FC_STATUS_ERR_OFFLINE:
                        fc->state = FC_STATE_OFFLINE;
-                       fc_sync_dma_exit (l->logi + 3 * i, 3 * sizeof(logi), fc);
+                       fc_sync_dma_exit (l->fcmds[i].cmd, 3 * sizeof(logi), fc);
                        printk ("%s: FC is offline\n", fc->name);
                        if (atomic_dec_and_test (&l->todo))
                                up(&l->sem);
@@ -228,26 +228,41 @@ static void fcp_login_done(fc_channel *fc, int i, int status)
 void fcp_register(fc_channel *fc, u8 type, int unregister)
 {
        int size, i;
+       int slots = (fc->can_queue * 3) >> 1;
+
+       FCND(("Going to %sregister\n", unregister ? "un" : ""))
 
        if (type == TYPE_SCSI_FCP) {
                if (!unregister) {
                        fc->scsi_cmd_pool = 
-                               (fcp_cmd *) fc_dma_alloc (fc->can_queue * (sizeof (fcp_cmd) + fc->rsp_size), 
+                               (fcp_cmd *) fc_dma_alloc (slots * (sizeof (fcp_cmd) + fc->rsp_size), 
                                                          "FCP SCSI cmd & rsp queues", &fc->dma_scsi_cmd);
-                       fc->scsi_rsp_pool = (char *)(fc->scsi_cmd_pool + fc->can_queue);
-                       fc->dma_scsi_rsp = fc->dma_scsi_cmd + fc->can_queue * sizeof (fcp_cmd);
-                       fc->scsi_bitmap_end = ((fc->can_queue + 63) & ~63);
+                       fc->scsi_rsp_pool = (char *)(fc->scsi_cmd_pool + slots);
+                       fc->dma_scsi_rsp = fc->dma_scsi_cmd + slots * sizeof (fcp_cmd);
+                       fc->scsi_bitmap_end = (slots + 63) & ~63;
                        size = fc->scsi_bitmap_end / 8;
                        fc->scsi_bitmap = kmalloc (size, GFP_KERNEL);
                        memset (fc->scsi_bitmap, 0, size);
+                       set_bit (0, fc->scsi_bitmap);
                        for (i = fc->can_queue; i < fc->scsi_bitmap_end; i++)
                                set_bit (i, fc->scsi_bitmap);
                        fc->scsi_free = fc->can_queue;
-                       fc->token_tab = (fcp_cmnd **)kmalloc(fc->can_queue * sizeof(fcp_cmnd*), GFP_KERNEL);
+                       fc->token_tab = (fcp_cmnd **)kmalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL);
+                       fc->abort_count = 0;
                } else {
                        fc->scsi_name[0] = 0;
                        kfree (fc->scsi_bitmap);
                        kfree (fc->token_tab);
+                       FCND(("Unregistering\n"));
+                       if (fc->rst_pkt) {
+                               if (fc->rst_pkt->eh_state == SCSI_STATE_UNUSED)
+                                       kfree(fc->rst_pkt);
+                               else {
+                                       /* Can't happen. Some memory would be lost. */
+                                       printk("FC: Reset in progress. Now?!");
+                               }
+                       }
+                       FCND(("Unregistered\n"));
                }
        } else
                printk ("FC: %segistering unknown type %02x\n", unregister ? "Unr" : "R", type);
@@ -273,6 +288,7 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
                return;
 
        rsp_status = rsp->fcp_status;
+       FCD(("rsp_status %08x status %08x\n", rsp_status, status))
        switch (status) {
        case FC_STATUS_OK:
                host_status=DID_OK;
@@ -305,11 +321,11 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
                        if (SCpnt->use_sg)
                                fc_sync_dma_exit_sg((struct scatterlist *)SCpnt->buffer, SCpnt->use_sg, fc);
                        else
-                               fc_sync_dma_exit(SCpnt->request_buffer, SCpnt->request_bufflen, fc);
+                               fc_sync_dma_exit(fcmd->data, SCpnt->request_bufflen, fc);
                }
                break;
        default:
-               host_status=DID_ERROR;
+               host_status=DID_ERROR; /* FIXME */
                FCD(("Wrong FC status %d for token %d\n", status, token))
                break;
        }
@@ -319,16 +335,21 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
        }       
        
        SCpnt->result = (host_status << 16) | (rsp_status & 0xff);
+#ifdef FCDEBUG 
+       if (host_status || SCpnt->result || rsp_status) printk("FC: host_status %d, packet status %d\n",
+                       host_status, SCpnt->result);
+#endif
        SCpnt->done = fcmd->done;
        fcmd->done=NULL;
        clear_bit(token, fc->scsi_bitmap);
        fc->scsi_free++;
+       FCD(("Calling scsi_done with %08lx\n", SCpnt->result))
        SCpnt->scsi_done(SCpnt);
 }
 
 void fcp_receive_solicited(fc_channel *fc, int proto, int token, int status, fc_hdr *fch)
 {
-       FCD(("Receive solicited %d %d %d\n", proto, token, status))
+       FCD(("receive_solicited %d %d %d\n", proto, token, status))
        switch (proto) {
        case TYPE_SCSI_FCP:
                fcp_scsi_receive(fc, token, status, fch); break;
@@ -337,7 +358,7 @@ void fcp_receive_solicited(fc_channel *fc, int proto, int token, int status, fc_
                        ls *l = (ls *)fc->ls;
                        int i = (token >= l->count) ? token - l->count : token;
 
-                       /* Make us sure */
+                       /* Let's be sure */
                        if ((unsigned)i < l->count && l->fcmds[i].fc == fc) {
                                fcp_login_done(fc, token, status);
                                break;
@@ -417,6 +438,7 @@ int fcp_initialize(fc_channel *fcchain, int count)
                fcmd = l->fcmds + i;
                fc->login = fcmd;
                fc->ls = (void *)l;
+               fc->rst_pkt = NULL;     /* kmalloc when first used */
                fch = &fcmd->fch;
                FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT);
                FILL_FCHDR_SID(fch, 0);
@@ -448,7 +470,7 @@ int fcp_initialize(fc_channel *fcchain, int count)
                                } else {
                                        fc->state = FC_STATE_OFFLINE;
                                        enable_irq(fc->irq);
-                                       fc_sync_dma_exit (l->logi + 3 * i, 3 * sizeof(logi), fc);
+                                       fc_sync_dma_exit (l->fcmds[i].cmd, 3 * sizeof(logi), fc);
                                        if (atomic_dec_and_test (&l->todo))
                                                goto all_done;
                                }
@@ -472,7 +494,7 @@ all_done:
                switch (fc->state) {
                case FC_STATE_ONLINE: break;
                case FC_STATE_OFFLINE: break;
-               default: fc_sync_dma_exit (l->logi + i, 3 * sizeof(logi), fc);
+               default: fc_sync_dma_exit (l->fcmds[i].cmd, 3 * sizeof(logi), fc);
                        break;
                }
                fc->ls = NULL;
@@ -535,24 +557,54 @@ int fcp_init(fc_channel *fcchain)
 {
        fc_channel *fc;
        int count=0;
+       int ret;
        
        for (fc = fcchain; fc; fc = fc->next) {
                fc->fcp_register = fcp_register;
-               fc->fcp_state_change = fcp_state_change;
                count++;
        }
 
-       fcp_initialize (fcchain, count);
+       ret = fcp_initialize (fcchain, count);
+
+       if (!ret) {     
+               if (!fc_channels)
+                       fc_channels = fcchain;
+               else {
+                       for (fc = fc_channels; fc->next; fc = fc->next);
+                       fc->next = fcchain;
+               }
+       }
+       return ret;
+}
+
+void fcp_release(fc_channel *fcchain, int count)  /* count must > 0 */
+{
+       fc_channel *fc;
+       fc_channel *fcx;
+
+       for (fc = fcchain; --count && fc->next; fc = fc->next);
+       if (count) {
+               printk("FC: nothing to release\n");
+               return;
+       }
        
-       if (!fc_channels)
-               fc_channels = fcchain;
+       if (fc_channels == fcchain)
+               fc_channels = fc->next;
        else {
-               for (fc = fc_channels; fc->next; fc = fc->next);
-               fc->next = fcchain;
+               for (fcx = fc_channels; fcx->next != fcchain; fcx = fcx->next);
+               fcx->next = fc->next;
        }
-       return 0;
+       fc->next = NULL;
+
+       /*
+        *  We've just grabbed fcchain out of the fc_channel list
+        *  and zero-terminated it, while destroying the count.
+        *
+        *  Freeing the fc's is the low level driver's responsibility.
+        */
 }
 
+
 static void fcp_scsi_done (Scsi_Cmnd *SCpnt)
 {
        if (FCP_CMND(SCpnt)->done)
@@ -561,16 +613,15 @@ static void fcp_scsi_done (Scsi_Cmnd *SCpnt)
 
 static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare)
 {
+       long i;
+       fcp_cmd *cmd;
+       u32 fcp_cntl;
        if (prepare) {
-               long i;
-               fcp_cmd *cmd;
-               u32 fcp_cntl;
-
                i = find_first_zero_bit (fc->scsi_bitmap, fc->scsi_bitmap_end);
                set_bit (i, fc->scsi_bitmap);
                fcmd->token = i;
                cmd = fc->scsi_cmd_pool + i;
-               FCD(("Chose token %ld %08lx\n", i, (long)cmd))
+
                if (fc->encode_addr (SCpnt, cmd->fcp_addr)) {
                        /* Invalid channel/id/lun and couldn't map it into fcp_addr */
                        clear_bit (i, fc->scsi_bitmap);
@@ -620,14 +671,14 @@ static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, i
                FCD(("XXX: %04x.%04x.%04x.%04x - %08x%08x%08x\n", cmd->fcp_addr[0], cmd->fcp_addr[1], cmd->fcp_addr[2], cmd->fcp_addr[3], *(u32 *)SCpnt->cmnd, *(u32 *)(SCpnt->cmnd+4), *(u32 *)(SCpnt->cmnd+8)))
        }
        FCD(("Trying to enque %08x\n", (int)fcmd))
-       if (!fc->scsi_que[1]) {
+       if (!fc->scsi_que) {
                if (!fc->hw_enque (fc, fcmd)) {
                        FCD(("hw_enque succeeded for %08x\n", (int)fcmd))
                        return 0;
                }
        }
        FCD(("Putting into que1 %08x\n", (int)fcmd))
-       fcp_scsi_insert_queue (fc, 1, fcmd);
+       fcp_scsi_insert_queue (fc, fcmd);
        return 0;
 }
 
@@ -643,8 +694,10 @@ int fcp_scsi_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *))
                SCpnt->scsi_done = done;
                fcmd->proto = TYPE_SCSI_FCP;
                if (!fc->scsi_free) {
-                       FCD(("Putting into que0\n"))
-                       fcp_scsi_insert_queue (fc, 0, fcmd);
+                       FCD(("FC: !scsi_free, putting cmd on ML queue\n"))
+#if (FCP_SCSI_USE_NEW_EH_CODE == 0)
+                       printk("fcp_scsi_queue_command: queue full, losing cmd, bad\n");
+#endif
                        return 1;
                }
                return fcp_scsi_queue_it(fc, SCpnt, fcmd, 1);
@@ -656,24 +709,166 @@ void fcp_queue_empty(fc_channel *fc)
 {
        fcp_cmnd *fcmd;
        FCD(("Queue empty\n"))
-       while ((fcmd = fc->scsi_que[1])) {
-               /* The hw tell us we can try again queue some packet */
+       while ((fcmd = fc->scsi_que)) {
+               /* The hw told us we can try again queue some packet */
                if (fc->hw_enque (fc, fcmd))
                        return;
-               fcp_scsi_remove_queue (fc, 1, fcmd);
+               fcp_scsi_remove_queue (fc, fcmd);
        }
 }
 
+int fcp_old_abort(Scsi_Cmnd *SCpnt)
+{
+       printk("FC: Abort not implemented\n");
+       return 1;
+}
+
 int fcp_scsi_abort(Scsi_Cmnd *SCpnt)
 {
-       printk ("FC: AIEEE, abort!\n");
-       return 0;
+       /* Internal bookkeeping only. Lose 1 token_tab slot. */
+       fcp_cmnd *fcmd = FCP_CMND(SCpnt);
+       fc_channel *fc = FC_SCMND(SCpnt);
+       
+       /*
+        * We react to abort requests by simply forgetting
+        * about the command and pretending everything's sweet.
+        * This may or may not be silly. We can't, however,
+        * immediately reuse the command's token_tab slot,
+        * as its result may arrive later and we cannot
+        * check whether it is the aborted one, can't we?
+        *
+        * Therefore, after the first few aborts are done,
+        * we tell the scsi error handler to do something clever.
+        * It will eventually call host reset, refreshing
+        * token_tab for us.
+        *
+        * There is a theoretical chance that we sometimes allow
+        * more than can_queue packets to the jungle this way,
+        * but the worst outcome possible is a series of
+        * more aborts and eventually the dev_reset catharsis.
+        */
+
+       if (++fc->abort_count < (fc->can_queue >> 1)) {
+               SCpnt->result = DID_ABORT;
+               fcmd->done(SCpnt);
+               printk("FC: soft abort\n");
+               return SUCCESS;
+       } else {
+               printk("FC: hard abort refused\n");
+               return FAILED;
+       }
 }
 
-int fcp_scsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+void fcp_scsi_reset_done(Scsi_Cmnd *SCpnt)
 {
-       printk ("FC: AIEEE, reset!\n");
-       return 0;
+       fc_channel *fc = FC_SCMND(SCpnt);
+
+       fc->rst_pkt->eh_state = SCSI_STATE_FINISHED;
+       up(fc->rst_pkt->host->eh_action);
+}
+
+#define FCP_RESET_TIMEOUT (2*HZ)
+
+int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt)
+{
+       fcp_cmd *cmd;
+       fcp_cmnd *fcmd;
+       fc_channel *fc = FC_SCMND(SCpnt);
+        struct semaphore sem = MUTEX_LOCKED;
+
+       if (!fc->rst_pkt) {
+               fc->rst_pkt = (Scsi_Cmnd *) kmalloc(sizeof(SCpnt), GFP_KERNEL);
+               if (!fc->rst_pkt) return FAILED;
+               
+               fcmd = FCP_CMND(fc->rst_pkt);
+
+
+               fcmd->token = 0;
+               cmd = fc->scsi_cmd_pool + 0;
+               FCD(("Preparing rst packet\n"))
+               if (fc->encode_addr (SCpnt, /*?*/cmd->fcp_addr))
+               fc->rst_pkt->channel = SCpnt->channel;
+               fc->rst_pkt->target = SCpnt->target;
+               fc->rst_pkt->lun = 0;
+               fc->rst_pkt->cmd_len = 0;
+               
+               fc->token_tab[0] = fcmd;
+
+               cmd->fcp_cntl = FCP_CNTL_QTYPE_ORDERED | FCP_CNTL_RESET;
+               fcmd->data = (dma_handle)NULL;
+               fcmd->proto = TYPE_SCSI_FCP;
+
+               memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len);
+               memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len);
+               FCD(("XXX: %04x.%04x.%04x.%04x - %08x%08x%08x\n", cmd->fcp_addr[0], cmd->fcp_addr[1], cmd->fcp_addr[2], cmd->fcp_addr[3], *(u32 *)SCpnt->cmnd, *(u32 *)(SCpnt->cmnd+4), *(u32 *)(SCpnt->cmnd+8)))
+       } else {
+               fcmd = FCP_CMND(fc->rst_pkt);
+               if (fc->rst_pkt->eh_state == SCSI_STATE_QUEUED)
+                       return FAILED; /* or SUCCESS. Only these */
+       }
+       fc->rst_pkt->done = NULL;
+
+
+        fc->rst_pkt->eh_state = SCSI_STATE_QUEUED;
+
+       fc->rst_pkt->eh_timeout.data = (unsigned long) fc->rst_pkt;
+       fc->rst_pkt->eh_timeout.expires = jiffies + FCP_RESET_TIMEOUT;
+       fc->rst_pkt->eh_timeout.function = (void (*)(unsigned long))fcp_scsi_reset_done;
+
+        add_timer(&fc->rst_pkt->eh_timeout);
+
+       /*
+        * Set up the semaphore so we wait for the command to complete.
+        */
+
+       fc->rst_pkt->host->eh_action = &sem;
+       fc->rst_pkt->request.rq_status = RQ_SCSI_BUSY;
+
+       fc->rst_pkt->done = fcp_scsi_reset_done;
+       fcp_scsi_queue_it(fc, fc->rst_pkt, fcmd, 0);
+       
+       down(&sem);
+
+       fc->rst_pkt->host->eh_action = NULL;
+       del_timer(&fc->rst_pkt->eh_timeout);
+
+       /*
+        * See if timeout.  If so, tell the host to forget about it.
+        * In other words, we don't want a callback any more.
+        */
+       if (fc->rst_pkt->eh_state == SCSI_STATE_TIMEOUT ) {
+               fc->rst_pkt->eh_state = SCSI_STATE_UNUSED;
+               return FAILED;
+       }
+       fc->rst_pkt->eh_state = SCSI_STATE_UNUSED;
+       return SUCCESS;
+}
+
+int fcp_scsi_bus_reset(Scsi_Cmnd *SCpnt)
+{
+       printk ("FC: bus reset!\n");
+       return FAILED;
+}
+
+int fcp_scsi_host_reset(Scsi_Cmnd *SCpnt)
+{
+       fc_channel *fc = FC_SCMND(SCpnt);
+       fcp_cmnd *fcmd = FCP_CMND(SCpnt);
+       int i;
+
+       printk ("FC: host reset\n");
+
+       for (i=0; i < fc->can_queue; i++) {
+               if (fc->token_tab[i] && SCpnt->result != DID_ABORT) {
+                       SCpnt->result = DID_RESET;
+                       fcmd->done(SCpnt);
+                       fc->token_tab[i] = NULL;
+               }
+       }
+       fc->reset(fc);
+       fc->abort_count = 0;
+       if (fcp_initialize(fc, 1)) return SUCCESS;
+       else return FAILED;
 }
 
 #ifdef MODULE
index f896a9b0f1903daec4934f87fda0d7f2aa0688bf..28e080380ec076cb457091b6c93c6a2e486bef34 100644 (file)
 #include "fcp_scsi.h"
 
 EXPORT_SYMBOL(fcp_init);
+EXPORT_SYMBOL(fcp_release);
 EXPORT_SYMBOL(fcp_queue_empty);
 EXPORT_SYMBOL(fcp_receive_solicited);
 EXPORT_SYMBOL(fc_channels);
+EXPORT_SYMBOL(fcp_state_change);
 
 /* SCSI stuff */
 EXPORT_SYMBOL(fcp_scsi_queuecommand);
+EXPORT_SYMBOL(fcp_old_abort);
 EXPORT_SYMBOL(fcp_scsi_abort);
-EXPORT_SYMBOL(fcp_scsi_reset);
+EXPORT_SYMBOL(fcp_scsi_dev_reset);
+EXPORT_SYMBOL(fcp_scsi_bus_reset);
+EXPORT_SYMBOL(fcp_scsi_host_reset);
 
 #endif /* CONFIG_MODULES */
index 6f8cc0257113ccbb7470b741b0f9ca5066f74e6f..3717740c7cf0d3049102374e34c92e73d3c3a944 100644 (file)
@@ -1,6 +1,7 @@
 /* fcp_scsi.h: Generic SCSI on top of FC4 - interface defines.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1998 Jiri Hanika (geo@ff.cuni.cz)
  */
 
 #ifndef _FCP_SCSI_H
@@ -22,6 +23,9 @@ typedef u32   dma_handle;
 #error Need to port FC layer to your architecture
 #endif
 
+/* 0 or 1 */
+#define        FCP_SCSI_USE_NEW_EH_CODE        0
+
 #define FC_CLASS_OUTBOUND      0x01
 #define FC_CLASS_INBOUND       0x02
 #define FC_CLASS_SIMPLE                0x03
@@ -62,7 +66,6 @@ typedef struct _fc_channel {
        int                     did;
        char                    name[16];
        void                    (*fcp_register)(struct _fc_channel *, u8, int);
-       void                    (*fcp_state_change)(struct _fc_channel *, int);
        void                    (*reset)(struct _fc_channel *);
        int                     (*hw_enque)(struct _fc_channel *, fcp_cmnd *);
        fc_wwn                  wwn_node;
@@ -73,8 +76,10 @@ typedef struct _fc_channel {
 #ifdef __sparc__       
        struct linux_sbus_device *dev;
 #endif
+       struct module           *module;
        /* FCP SCSI stuff */
-       int                     can_queue;
+       short                   can_queue;
+       short                   abort_count;
        int                     rsp_size;
        fcp_cmd                 *scsi_cmd_pool;
        char                    *scsi_rsp_pool;
@@ -83,12 +88,13 @@ typedef struct _fc_channel {
        long                    scsi_bitmap_end;
        int                     scsi_free;
        int                     (*encode_addr)(Scsi_Cmnd *cmnd, u16 *addr);
-       fcp_cmnd                *scsi_que[2];
+       fcp_cmnd                *scsi_que;
        char                    scsi_name[4];
        fcp_cmnd                **token_tab;
        int                     channels;
        int                     targets;
        long                    *ages;
+       Scsi_Cmnd               *rst_pkt;
        /* LOGIN stuff */
        fcp_cmnd                *login;
        void                    *ls;
@@ -124,7 +130,9 @@ extern fc_channel *fc_channels;
 
 void fcp_queue_empty(fc_channel *);
 int fcp_init(fc_channel *);
+void fcp_release(fc_channel *fc_chain, int count);
 void fcp_receive_solicited(fc_channel *, int, int, int, fc_hdr *);
+void fcp_state_change(fc_channel *, int);
 
 #define for_each_fc_channel(fc)                                \
        for (fc = fc_channels; fc; fc = fc->next)
@@ -134,7 +142,10 @@ void fcp_receive_solicited(fc_channel *, int, int, int, fc_hdr *);
                if (fc->state == FC_STATE_ONLINE)
 
 int fcp_scsi_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+int fcp_old_abort(Scsi_Cmnd *);
 int fcp_scsi_abort(Scsi_Cmnd *);
-int fcp_scsi_reset(Scsi_Cmnd *, unsigned int);
+int fcp_scsi_dev_reset(Scsi_Cmnd *);
+int fcp_scsi_bus_reset(Scsi_Cmnd *);
+int fcp_scsi_host_reset(Scsi_Cmnd *);
 
 #endif /* !(_FCP_SCSI_H) */
index ee3f513e1597bc3ddd462d81716713e7aab79d82..1db437b3fa70cbc0d61065541fabfb1ca883c1bc 100644 (file)
@@ -1,15 +1,26 @@
 /* soc.c: Sparc SUNW,soc (Serial Optical Channel) Fibre Channel Sbus adapter support.
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 Jiri Hanika (geo@ff.cuni.cz)
+ * Copyright (C) 1997,1998 Jiri Hanika (geo@ff.cuni.cz)
  *
  * Sources:
  *     Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
  *     dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
+ *
+ * Supported hardware:
+ *      Tested on SOC sbus card bought with SS1000 in Linux running on SS5 and Ultra1. 
+ *      Should run on on-board SOC/SOC+ cards of Ex000 servers as well, but it is not
+ *      tested (let us know if you succeed).
+ *      For SOC sbus cards, you have to make sure your FCode is 1.52 or later.
+ *      If you have older FCode, you should try to upgrade or get SOC microcode from Sun
+ *      (the microcode is present in Solaris soc driver as well). In that case you need
+ *      to #define HAVE_SOC_UCODE and format the microcode into soc_asm.c. For the exact
+ *      format mail me and I will tell you. I cannot offer you the actual microcode though,
+ *      unless Sun confirms they don't mind.
  */
 
 static char *version =
-        "soc.c:v1.0 24/Nov/97 Jakub Jelinek (jj@sunsite.mff.cuni.cz), Jiri Hanika (geo@ff.cuni.cz)\n";
+        "soc.c:v1.2 27/Feb/98 Jakub Jelinek (jj@sunsite.mff.cuni.cz), Jiri Hanika (geo@ff.cuni.cz)\n";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -68,6 +79,7 @@ static inline void soc_enable(struct soc *s)
        s->regs->sae = 0; s->regs->cfg = s->cfg;
        s->regs->cmd = SOC_CMD_RSP_QALL; 
        SOC_SETIMASK(s, SOC_IMASK_RSP_QALL | SOC_IMASK_SAE);
+       SOD(("imask %08lx %08lx\n", s->imask, s->regs->imask));
 }
 
 static void soc_reset(fc_channel *fc)
@@ -148,6 +160,7 @@ static void inline soc_solicited (struct soc *s)
 static void inline soc_request (struct soc *s, u32 cmd)
 {
        SOC_SETIMASK(s, s->imask & ~(cmd & SOC_CMD_REQ_QALL));
+       SOD(("imask %08lx %08lx\n", s->imask, s->regs->imask));
 
        SOD(("Queues available %08x OUT %X %X\n", cmd, xram_get_8((xram_p)&s->req[0].hw_cq->out), xram_get_8((xram_p)&s->req[0].hw_cq->out)))
        if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) {
@@ -179,6 +192,7 @@ static void inline soc_unsolicited (struct soc *s)
        while (sw_cq->in != sw_cq->out) {
                /* ...real work per entry here... */
                hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out;
+
                hwrspc = NULL;
                flags = hwrsp->shdr.flags;
                count = xram_get_8 ((xram_p)&hwrsp->count);
@@ -218,10 +232,12 @@ static void inline soc_unsolicited (struct soc *s)
                        status = xram_get_32low ((xram_p)&hwrsp->status);
                        switch (status) {
                        case SOC_ONLINE:
-                               fc->fcp_state_change(fc, FC_STATE_ONLINE);
+                               SOD(("State change to ONLINE\n"));
+                               fcp_state_change(fc, FC_STATE_ONLINE);
                                break;
                        case SOC_OFFLINE:
-                               fc->fcp_state_change(fc, FC_STATE_OFFLINE);
+                               SOD(("State change to OFFLINE\n"));
+                               fcp_state_change(fc, FC_STATE_OFFLINE);
                                break;
                        default:
                                printk ("%s: Unknown STATUS no %d\n", fc->name, status);
@@ -316,8 +332,10 @@ static int soc_hw_enque (fc_channel *fc, fcp_cmnd *fcmd)
        else
                qno = 0;
        SOD(("Putting a FCP packet type %d into hw queue %d\n", fcmd->proto, qno))
-       if (s->imask & (SOC_IMASK_REQ_Q0 << qno))
+       if (s->imask & (SOC_IMASK_REQ_Q0 << qno)) {
+               SOD(("EIO %08x\n", s->imask))
                return -EIO;
+       }
        sw_cq = s->req + qno;
        cq_next_in = (sw_cq->in + 1) & sw_cq->last;
        
@@ -325,7 +343,9 @@ static int soc_hw_enque (fc_channel *fc, fcp_cmnd *fcmd)
                    && cq_next_in == (sw_cq->out = xram_get_8((xram_p)&sw_cq->hw_cq->out))) {
                SOD(("%d IN %d OUT %d LAST %d\n", qno, sw_cq->in, sw_cq->out, sw_cq->last))
                SOC_SETIMASK(s, s->imask | (SOC_IMASK_REQ_Q0 << qno));
-               return -EBUSY;  // If queue full, just say NO
+               SOD(("imask %08lx %08lx\n", s->imask, s->regs->imask));
+               /* If queue is full, just say NO */
+               return -EBUSY;
        }
        
        request = sw_cq->pool + sw_cq->in;
@@ -478,9 +498,7 @@ static inline void soc_init_bursts(struct soc *s, struct linux_sbus_device *sdev
 
 static inline void soc_init(struct linux_sbus_device *sdev, int no)
 {
-#ifdef __sparc_v9__
         struct devid_cookie dcookie;
-#endif
        unsigned char tmp[60];
        int propl;
        struct soc *s;
@@ -497,7 +515,14 @@ static inline void soc_init(struct linux_sbus_device *sdev, int no)
        SOD(("socs %08lx soc_intr %08lx soc_hw_enque %08x\n", (long)socs, (long)soc_intr, (long)soc_hw_enque))  
        if (version_printed++ == 0)
                printk (version);
-               
+#ifdef MODULE
+       s->port[0].fc.module = &__this_module;
+       s->port[1].fc.module = &__this_module;
+#else
+       s->port[0].fc.module = NULL;
+       s->port[1].fc.module = NULL;
+#endif
+                                               
        s->next = socs;
        socs = s;
        s->port[0].fc.dev = sdev;
@@ -574,9 +599,22 @@ static inline void soc_init(struct linux_sbus_device *sdev, int no)
        irq = sdev->irqs[0].pri;
 
 #ifndef __sparc_v9__   
-       if (request_irq (irq, soc_intr, SA_SHIRQ, "SOC", (void *)s)) {
-               soc_printk ("Cannot order irq %d to go\n", irq);
-               return;
+       if (sparc_cpu_model != sun4d) {
+               if (request_irq (irq, soc_intr, SA_SHIRQ, "SOC", (void *)s)) {
+                       soc_printk ("Cannot order irq %d to go\n", irq);
+                       socs = s->next;
+                       return;
+               }
+       } else {
+               dcookie.real_dev_id = s;
+               dcookie.bus_cookie = sdev;
+               if (request_irq(irq, soc_intr, (SA_SHIRQ | SA_DCOOKIE), "SOC", &dcookie)) {
+                       soc_printk ("Cannot order irq %d to go\n", irq);
+                       socs = s->next;
+                       return;
+               }
+               SOD(("IRQ %d %x\n", irq, dcookie.ret_ino))
+               irq = dcookie.ret_ino;
        }
 #else
        dcookie.real_dev_id = s;
@@ -585,6 +623,7 @@ static inline void soc_init(struct linux_sbus_device *sdev, int no)
        dcookie.bus_cookie = sdev->my_bus;
        if (request_irq (irq, soc_intr, (SA_SHIRQ | SA_SBUS | SA_DCOOKIE), "SOC", &dcookie)) {
                soc_printk ("Cannot order irq %d to go\n", irq);
+               socs = s->next;
                return;
        }
        irq = dcookie.ret_ino;
@@ -693,10 +732,12 @@ void cleanup_module(void)
        struct linux_sbus_device *sdev;
        
        for_each_soc(s) {
-               /* FIXME: Tell FC layer we say good bye */
                irq = s->port[0].fc.irq;
                disable_irq (irq);
                free_irq (irq, s);
+
+               fcp_release(&(s->port[0].fc), 2);
+
                sdev = s->port[0].fc.dev;
                if (sdev->num_registers == 1)
                        sparc_free_io ((char *)s->xram, sdev->reg_addrs [0].reg_size);
index 2d280d4c8768b7a407689abae0721e3c0e94917f..116a1d98e27bd47ef7144c97b77e4536ca09d3c3 100644 (file)
@@ -14,7 +14,10 @@ MOD_SUB_DIRS := $(SUB_DIRS)
 
 L_TARGET := macintosh.a
 M_OBJS   :=
-L_OBJS   := via-cuda.o adb.o nvram.o macio-adb.o
+
+ifndef CONFIG_MBX
+L_OBJS   := via-cuda.o adb.o nvram.o macio-adb.o via-pmu.o mediabay.o
+endif
 
 ifeq ($(CONFIG_SERIAL)$(CONFIG_PMAC),yy)
   LX_OBJS += macserial.o
@@ -25,7 +28,7 @@ else
 endif
 
 ifdef CONFIG_MAC_KEYBOARD
-L_OBJS += mac_keyb.o mackeymap.o
+L_OBJS += mac_keyb.o
 endif
 
 ifdef CONFIG_VT
@@ -54,5 +57,7 @@ endif
 
 include $(TOPDIR)/Rules.make
 
-mackeymap.c: mackeymap.map
-       loadkeys --mktable mackeymap.map > mackeymap.c
+# Integrated in mac_keyb.c
+# mackeymap.map is retained for historical reasons
+#mackeymap.c: mackeymap.map
+#      loadkeys --mktable mackeymap.map > mackeymap.c
index 945c7d456d6436b4576c93cd78d665836a7c5d52..c20efde6b97dd4727dca3c59cd170982f4d1ded8 100644 (file)
 #include <linux/malloc.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <asm/prom.h>
 #include <asm/adb.h>
 #include <asm/cuda.h>
+#include <asm/pmu.h>
 #include <asm/uaccess.h>
 #include <asm/hydra.h>
 
 enum adb_hw adb_hardware;
 int (*adb_send_request)(struct adb_request *req, int sync);
 int (*adb_autopoll)(int on);
+static void adb_scan_bus(void);
 
 static struct adb_handler {
        void (*handler)(unsigned char *, int, struct pt_regs *, int);
+       int original_address;
+       int handler_id;
 } adb_handler[16];
 
 static int adb_nodev(void)
@@ -29,17 +34,123 @@ static int adb_nodev(void)
        return -1;
 }
 
+#if 0
+static void printADBreply(struct adb_request *req)
+{
+        int i;
+
+        printk("adb reply (%d)", req->reply_len);
+        for(i = 0; i < req->reply_len; i++)
+                printk(" %x", req->reply[i]);
+        printk("\n");
+
+}
+#endif
+
+static void adb_scan_bus(void)
+{
+       int i, highFree=0, noMovement;
+       struct adb_request req;
+       
+       /* reset ADB bus */
+       /*adb_request(&req, NULL, ADBREQ_SYNC, 1, 0);*/
+
+       /* assumes adb_handler[] is all zeroes at this point */
+       for (i = 1; i < 16; i++) {
+               /* see if there is anything at address i */
+               adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+                            (i << 4) | 0xf);
+               if (req.reply_len > 1)
+                       /* one or more devices at this address */
+                       adb_handler[i].original_address = i;
+               else if (i > highFree)
+                       highFree = i;
+       }
+
+       /* Note we reset noMovement to 0 each time we move a device */
+       for (noMovement = 1; noMovement < 2 && highFree > 0; noMovement++) {
+               for (i = 1; i < 16; i++) {
+                       if (adb_handler[i].original_address == 0)
+                               continue;
+                       /*
+                        * Send a "talk register 3" command to address i
+                        * to provoke a collision if there is more than
+                        * one device at this address.
+                        */
+                       adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+                                   (i << 4) | 0xf);
+                       /*
+                        * Move the device(s) which didn't detect a
+                        * collision to address `highFree'.  Hopefully
+                        * this only moves one device.
+                        */
+                       adb_request(&req, NULL, ADBREQ_SYNC, 3,
+                                   (i<< 4) | 0xb, (highFree | 0x60), 0xfe);
+                       /*
+                        * Test whether there are any device(s) left
+                        * at address i.
+                        */
+                       adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+                                   (i << 4) | 0xf);
+                       if (req.reply_len > 1) {
+                               /*
+                                * There are still one or more devices
+                                * left at address i.  Register the one(s)
+                                * we moved to `highFree', and find a new
+                                * value for highFree.
+                                */
+                               adb_handler[highFree].original_address =
+                                       adb_handler[i].original_address;
+                               while (highFree > 0 &&
+                                      adb_handler[highFree].original_address)
+                                       highFree--;
+                               if (highFree <= 0)
+                                       break;
+
+                               noMovement = 0;
+                       }
+                       else {
+                               /*
+                                * No devices left at address i; move the
+                                * one(s) we moved to `highFree' back to i.
+                                */
+                               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+                                           (highFree << 4) | 0xb,
+                                           (i | 0x60), 0xfe);
+                       }
+               }       
+       }
+
+       /* Now fill in the handler_id field of the adb_handler entries. */
+       printk(KERN_DEBUG "adb devices:");
+       for (i = 1; i < 16; i++) {
+               if (adb_handler[i].original_address == 0)
+                       continue;
+               adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+                           (i << 4) | 0xf);
+               adb_handler[i].handler_id = req.reply[2];
+               printk(" [%d]: %d %x", i, adb_handler[i].original_address,
+                      adb_handler[i].handler_id);
+       }
+       printk("\n");
+}
+
 void adb_init(void)
 {
        adb_hardware = ADB_NONE;
        adb_send_request = (void *) adb_nodev;
        adb_autopoll = (void *) adb_nodev;
+       if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+               return;         
        via_cuda_init();
+       via_pmu_init();
        macio_adb_init();
        if (adb_hardware == ADB_NONE)
                printk(KERN_WARNING "Warning: no ADB interface detected\n");
-       else
+       else {
+               adb_scan_bus();
                adb_autopoll(1);
+       }
 }
 
 int
@@ -67,12 +178,25 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *),
 /* Ultimately this should return the number of devices with
    the given default id. */
 int
-adb_register(int default_id,
+adb_register(int default_id, int handler_id, struct adb_ids *ids,
             void (*handler)(unsigned char *, int, struct pt_regs *, int))
 {
-       if (adb_handler[default_id].handler != 0)
-               panic("Two handlers for ADB device %d\n", default_id);
-       adb_handler[default_id].handler = handler;
+       int i;
+
+       ids->nids = 0;
+       for (i = 1; i < 16; i++) {
+               if ((adb_handler[i].original_address == default_id) ||
+                   (adb_handler[i].handler_id == handler_id)) {
+                       if (adb_handler[i].handler != 0) {
+                               printk(KERN_ERR
+                                      "Two handlers for ADB device %d\n",
+                                      default_id);
+                               return 0;
+                       }
+                       adb_handler[i].handler = handler;
+                       ids->id[ids->nids++] = i;
+               }
+       }
        return 1;
 }
 
@@ -103,44 +227,40 @@ adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll)
 extern void adbdev_init(void);
 
 struct adbdev_state {
-       struct adb_request req;
+       spinlock_t      lock;
+       atomic_t        n_pending;
+       struct adb_request *completed;
+       struct wait_queue *wait_queue;
+       int             inuse;
 };
 
-static struct wait_queue *adb_wait;
-
-static int adb_wait_reply(struct adbdev_state *state, struct file *file)
-{
-       int ret = 0;
-       struct wait_queue wait = { current, NULL };
-
-       add_wait_queue(&adb_wait, &wait);
-       current->state = TASK_INTERRUPTIBLE;
-
-       while (!state->req.complete) {
-               if (file->f_flags & O_NONBLOCK) {
-                       ret = -EAGAIN;
-                       break;
-               }
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&adb_wait, &wait);
-
-       return ret;
-}
-
 static void adb_write_done(struct adb_request *req)
 {
+       struct adbdev_state *state = (struct adbdev_state *) req->arg;
+       unsigned long flags;
+
        if (!req->complete) {
                req->reply_len = 0;
                req->complete = 1;
        }
-       wake_up_interruptible(&adb_wait);
+       spin_lock_irqsave(&state->lock, flags);
+       atomic_dec(&state->n_pending);
+       if (!state->inuse) {
+               kfree(req);
+               if (atomic_read(&state->n_pending) == 0) {
+                       spin_unlock_irqrestore(&state->lock, flags);
+                       kfree(state);
+                       return;
+               }
+       } else {
+               struct adb_request **ap = &state->completed;
+               while (*ap != NULL)
+                       ap = &(*ap)->next;
+               req->next = NULL;
+               *ap = req;
+               wake_up_interruptible(&state->wait_queue);
+       }
+       spin_unlock_irqrestore(&state->lock, flags);
 }
 
 static int adb_open(struct inode *inode, struct file *file)
@@ -153,20 +273,31 @@ static int adb_open(struct inode *inode, struct file *file)
        if (state == 0)
                return -ENOMEM;
        file->private_data = state;
-       state->req.reply_expected = 0;
+       spin_lock_init(&state->lock);
+       atomic_set(&state->n_pending, 0);
+       state->completed = NULL;
+       state->wait_queue = NULL;
+       state->inuse = 1;
+
        return 0;
 }
 
 static int adb_release(struct inode *inode, struct file *file)
 {
        struct adbdev_state *state = file->private_data;
+       unsigned long flags;
 
        if (state) {
                file->private_data = NULL;
-               if (state->req.reply_expected && !state->req.complete)
-                       if (adb_wait_reply(state, file))
-                               return 0;
-               kfree(state);
+               spin_lock_irqsave(&state->lock, flags);
+               if (atomic_read(&state->n_pending) == 0
+                   && state->completed == NULL) {
+                       spin_unlock_irqrestore(&state->lock, flags);
+                       kfree(state);
+               } else {
+                       state->inuse = 0;
+                       spin_unlock_irqrestore(&state->lock, flags);
+               }
        }
        return 0;
 }
@@ -181,27 +312,57 @@ static ssize_t adb_read(struct file *file, char *buf,
 {
        int ret;
        struct adbdev_state *state = file->private_data;
+       struct adb_request *req;
+       struct wait_queue wait = { current, NULL };
+       unsigned long flags;
 
        if (count < 2)
                return -EINVAL;
-       if (count > sizeof(state->req.reply))
-               count = sizeof(state->req.reply);
+       if (count > sizeof(req->reply))
+               count = sizeof(req->reply);
        ret = verify_area(VERIFY_WRITE, buf, count);
        if (ret)
                return ret;
 
-       if (!state->req.reply_expected)
-               return 0;
+       req = NULL;
+       add_wait_queue(&state->wait_queue, &wait);
+       current->state = TASK_INTERRUPTIBLE;
+
+       for (;;) {
+               spin_lock_irqsave(&state->lock, flags);
+               req = state->completed;
+               if (req != NULL)
+                       state->completed = req->next;
+               else if (atomic_read(&state->n_pending) == 0)
+                       ret = -EIO;
+               spin_unlock_irqrestore(&state->lock, flags);
+               if (req != NULL || ret != 0)
+                       break;
+               
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       break;
+               }
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               schedule();
+       }
+
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&state->wait_queue, &wait);
 
-       ret = adb_wait_reply(state, file);
        if (ret)
                return ret;
 
-       state->req.reply_expected = 0;
-       ret = state->req.reply_len;
-       if (copy_to_user(buf, state->req.reply, ret))
-               return -EFAULT;
+       ret = req->reply_len;
+       if (ret > count)
+               ret = count;
+       if (ret > 0 && copy_to_user(buf, req->reply, ret))
+               ret = -EFAULT;
 
+       kfree(req);
        return ret;
 }
 
@@ -210,46 +371,64 @@ static ssize_t adb_write(struct file *file, const char *buf,
 {
        int ret, i;
        struct adbdev_state *state = file->private_data;
+       struct adb_request *req;
 
-       if (count < 2 || count > sizeof(state->req.data))
+       if (count < 2 || count > sizeof(req->data))
                return -EINVAL;
        ret = verify_area(VERIFY_READ, buf, count);
        if (ret)
                return ret;
 
-       if (state->req.reply_expected && !state->req.complete) {
-               /* A previous request is still being processed.
-                  Wait for it to finish. */
-               ret = adb_wait_reply(state, file);
-               if (ret)
-                       return ret;
-       }
+       req = (struct adb_request *) kmalloc(sizeof(struct adb_request),
+                                            GFP_KERNEL);
+       if (req == NULL)
+               return -ENOMEM;
 
-       state->req.nbytes = count;
-       state->req.done = adb_write_done;
-       state->req.complete = 0;
-       if (copy_from_user(state->req.data, buf, count))
-               return -EFAULT;
+       req->nbytes = count;
+       req->done = adb_write_done;
+       req->arg = (void *) state;
+       req->complete = 0;
 
+       ret = -EFAULT;
+       if (copy_from_user(req->data, buf, count))
+               goto out;
+
+       atomic_inc(&state->n_pending);
        switch (adb_hardware) {
        case ADB_NONE:
-               return -ENXIO;
+               ret = -ENXIO;
+               break;
        case ADB_VIACUDA:
-               state->req.reply_expected = 1;
-               cuda_send_request(&state->req);
+               req->reply_expected = 1;
+               ret = cuda_send_request(req);
                break;
+       case ADB_VIAPMU:
+               if (req->data[0] != ADB_PACKET) {
+                       ret = pmu_send_request(req);
+                       break;
+               }
+               /* else fall through */
        default:
-               if (state->req.data[0] != ADB_PACKET)
-                       return -EINVAL;
-               for (i = 1; i < state->req.nbytes; ++i)
-                       state->req.data[i] = state->req.data[i+1];
-               state->req.reply_expected =
-                       ((state->req.data[0] & 0xc) == 0xc);
-               adb_send_request(&state->req, 0);
+               ret = -EINVAL;
+               if (req->data[0] != ADB_PACKET)
+                       break;
+               for (i = 0; i < req->nbytes-1; ++i)
+                       req->data[i] = req->data[i+1];
+               req->nbytes--;
+               req->reply_expected = ((req->data[0] & 0xc) == 0xc);
+               ret = adb_send_request(req, 0);
                break;
        }
 
+       if (ret != 0) {
+               atomic_dec(&state->n_pending);
+               goto out;
+       }
        return count;
+
+out:
+       kfree(req);
+       return ret;
 }
 
 static struct file_operations adb_fops = {
@@ -266,6 +445,8 @@ static struct file_operations adb_fops = {
 
 void adbdev_init()
 {
+       if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+               return;         
        if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
                printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
 }
index b986cc38e6b36ccb86cbd02265627508cc51d60e..df48c1865bf39597c1ce2cd218cc9ed7daf49016 100644 (file)
@@ -1,64 +1,37 @@
-#if 0          /* not filled inaty_gt_reg_init yet */
-/* Register values for 1280x1024, 75Hz mode (20) */
+/* Register values for 1280x1024, 75Hz (WAS 60) mode (20) */
 static struct aty_regvals aty_gx_reg_init_20 = {
-       { 0x10, 0x28, 0x3c },
-       { },
-       { }     /* pixel clock = 134.61MHz for V=74.81Hz */
-};
+   { 0x200, 0x200, 0x200 },
 
-/* Register values for 1280x960, 75Hz mode (19) */
-static struct aty_regvals aty_gx_reg_init_19 = {
-       { 0x10, 0x28, 0x3c },
-       { },
-       { }     /* pixel clock = 126.01MHz for V=75.01 Hz */
-};
+    { 0x1200a5, 0x1200a3, 0x1200a3 },
+    { 0x30c0200, 0x30e0300, 0x30e0300 },
+    { 0x2, 0x3, 0x3 },
+
+    0x9f00d2, 0x3ff0429, 0x30400, 0x28100040,
+    { 0xd4, 0x9 }
+};     
 
 /* Register values for 1152x870, 75Hz mode (18) */
 static struct aty_regvals aty_gx_reg_init_18 = {
-       { 0x10, 0x28, 0x50 },
-       { },
-       { }     /* pixel clock = 100.33MHz for V=75.31Hz */
-};
+    { 0x200, 0x200, 0x200 },
 
-/* Register values for 1024x768, 75Hz mode (17) */
-static struct aty_regvals aty_gx_reg_init_17 = {
-       { 0x10, 0x28, 0x50 },
-       { },
-       { }     /* pixel clock = 79.55MHz for V=74.50Hz */
-};
+    { 0x300097, 0x300095, 0x300094 },
+    { 0x3090200, 0x30e0300, 0x30e0600 },
+    { 0x2, 0x3, 0x6 },
 
-/* Register values for 1024x768, 72Hz mode (15) */
-static struct aty_regvals aty_gx_reg_init_15 = {
-       { 0x10, 0x28, 0x50 },
-       { },
-       { }     /* pixel clock = 78.12MHz for V=72.12Hz */
+    0x8f00b5, 0x3650392, 0x230368, 0x24100040,
+    { 0x53, 0x3 }
 };
 
-#endif
-
-
-/* Register values for 1280x1024, 60Hz mode (20) */
-static struct aty_regvals aty_gx_reg_init_20 = {
-   { 0, 0, 0 },
-
-    { 0x310086, 0x310084, 0x310084 },
-    { 0x3070200, 0x30e0300, 0x30e0300 },
-    { 0x2002312, 0x3002312, 0x3002312 },
-
-    0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
-    { 0x88, 0x7 }
-};     
-
 /* Register values for 1024x768, 75Hz mode (17) */
 static struct aty_regvals aty_gx_reg_init_17 = {
-    { 0, 0, 0 },
+    { 0x200, 0x200, 0x200 },
 
-    { 0xc0085, 0xc0083, 0xc0083 },
-    { 0x3070200, 0x30e0300, 0x30e0300 },
-    { 0x2002312, 0x3002312, 0x3002312 },
+    { 0x2c0087, 0x2c0085, 0x2c0084 },
+    { 0x3070200, 0x30e0300, 0x30e0600 },
+    { 0x2, 0x3, 0x6 },
 
-    0x7f00a3, 0x2ff031f, 0x30300, 0x20100000,
-    { 0x41, 0x3 }
+    0x7f00a5, 0x2ff0323, 0x230302, 0x20100000,
+    { 0x42, 0x3 }
 };
 
 /* Register values for 1024x768, 72Hz mode (15) */
@@ -87,14 +60,14 @@ static struct aty_regvals aty_gx_reg_init_14 = {
 
 /* Register values for 832x624, 75Hz mode (13) */
 static struct aty_regvals aty_gx_reg_init_13 = {
-       { 0x200, 0x200, 0x200 },
+    { 0x200, 0x200, 0x200 },
 
-       { 0x28006f, 0x28006d, 0x28006c },
-       { 0x3050200, 0x30b0300, 0x30e0600 },
-       { 0x2002312, 0x3002312, 0x6002312 },
+    { 0x28006f, 0x28006d, 0x28006c },
+    { 0x3050200, 0x30b0300, 0x30e0600 },
+    { 0x2, 0x3, 0x6 },
 
-       0x67008f, 0x26f029a, 0x230270, 0x1a100040,
-        { 0x4f, 0x05 }
+    0x67008f, 0x26f029a, 0x230270, 0x1a100040,
+    { 0x4f, 0x5 }
 };
 
 #if 0          /* not filled in yet */
index ec70b4a505bf246b9e1d01142ed27dafac179195..7bd48052b8d567015e086e06ace635cd2cbcde97 100644 (file)
 #include <linux/string.h>
 #include <linux/vc_ioctl.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/nvram.h>
 #include <linux/selection.h>
 #include <linux/vt_kern.h>
 #include <asm/prom.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/pci-bridge.h>
 #include "pmac-cons.h"
 #include "aty.h"
@@ -61,10 +61,12 @@ static int aty_vram_reqd(int vmode, int cmode);
 static aty_regvals *get_aty_struct(void);
 
 static unsigned char *frame_buffer;
+static unsigned long frame_buffer_phys;
 static int total_vram;         /* total amount of video memory, bytes */
 static int chip_type;          /* what chip type was detected */
 
 static unsigned long ati_regbase;
+static unsigned long ati_regbase_phys;
 static struct aty_cmap_regs *aty_cmap_regs;
 
 #if 0
@@ -126,7 +128,8 @@ static struct aty_regvals *aty_gx_reg_init[20] = {
        &aty_gx_reg_init_15,
        NULL,
        &aty_gx_reg_init_17,
-       NULL, NULL,
+       &aty_gx_reg_init_18,
+       NULL,
        &aty_gx_reg_init_20
 };
 
@@ -323,7 +326,8 @@ map_aty_display(struct device_node *dp)
        printk("Warning: expecting 1 or 3 addresses for ATY (got %d)",
               dp->n_addrs);
 
-       ati_regbase = (int) ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
+       ati_regbase_phys = 0x7ffc00 + dp->addrs[0].address;
+       ati_regbase = (int) ioremap(ati_regbase_phys, 0x1000);
        aty_cmap_regs = (struct aty_cmap_regs *) (ati_regbase + 0xC0);
 
        /* enable memory-space accesses using config-space command register */
@@ -384,12 +388,12 @@ map_aty_display(struct device_node *dp)
                        total_vram = 0x80000;
                }
 
-#if 1
+#if 0
        printk("aty_display_init: node = %p, addrs = ", dp->node);
        printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
        printk(", intrs =");
        for (i = 0; i < dp->n_intrs; ++i)
-       printk(" %x", dp->intrs[i]);
+       printk(" %x", dp->intrs[i].line);
        printk("\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int) ati_regbase,
                bus, devfn, total_vram, (int) aty_cmap_regs);
 #endif
@@ -398,10 +402,11 @@ map_aty_display(struct device_node *dp)
 
        /* use the big-endian aperture (??) */
        addr += 0x800000;
-       frame_buffer = ioremap(addr, 0x800000);
+       frame_buffer_phys = addr;
+       frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
 
        sense = read_aty_sense();
-       printk("monitor sense = %x\n", sense);
+       printk(KERN_INFO "monitor sense = %x\n", sense);
        if (video_mode == VMODE_NVRAM) {
                video_mode = nvram_read_byte(NV_VMODE);
                init = get_aty_struct();
@@ -720,11 +725,11 @@ aty_init()
                break;
        }
        display_info.fb_address = (chip_type != MACH64_GT_ID) ?
-               (unsigned long) frame_buffer + init->offset[color_mode] :
-               (unsigned long) frame_buffer;
-       display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex;
-       display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut;
-       display_info.disp_reg_address = ati_regbase;
+               frame_buffer_phys + init->offset[color_mode] :
+               frame_buffer_phys;
+       display_info.cmap_adr_address = ati_regbase_phys + 0xc0;
+       display_info.cmap_data_address = ati_regbase_phys + 0xc1;
+       display_info.disp_reg_address = ati_regbase_phys;
 }
 
 int
index d959608cb9d5ebe6956e4620473516bb2b065118..d60abe84ff103c3b5d01011799cd61ceae22e7ad 100644 (file)
 #include <linux/string.h>
 #include <linux/vc_ioctl.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/selection.h>
 #include <asm/prom.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+#include <asm/pmu.h>
 #include <asm/pci-bridge.h>
 #include "pmac-cons.h"
 #include "chips.h"
@@ -26,6 +29,8 @@
 static unsigned char *frame_buffer;
 static unsigned char *blitter_regs;
 static unsigned char *io_space;
+static unsigned long chips_base_phys;
+static unsigned long chips_io_phys;
 
 void
 map_chips_display(struct device_node *dp)
@@ -35,17 +40,21 @@ map_chips_display(struct device_node *dp)
     unsigned long addr;
 
     addr = dp->addrs[0].address;
-    frame_buffer = ioremap(addr + 0x800000, 0x100000);
+    chips_base_phys = addr;
+    frame_buffer = __ioremap(addr + 0x800000, 0x100000, _PAGE_WRITETHRU);
     blitter_regs = ioremap(addr + 0xC00000, 4096);
     
-    printk("Mapped chips65550 frame buffer at %p, blitter at %p\n", frame_buffer, blitter_regs);
+    printk("Mapped chips65550 frame buffer at %p, blitter at %p\n",
+          frame_buffer, blitter_regs);
     
     if (pci_device_loc(dp, &bus, &devfn) == 0) {
        pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
        cmd |= 3;       // enable memory and IO space
        pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
-       io_space = ioremap((unsigned long) pci_io_base(bus), 4096);
-       printk("Mapped chips65550 IO space at %p\n", io_space);
+       io_space = (unsigned char *) pci_io_base(bus);
+       /* XXX really want the physical address here */
+       chips_io_phys = (unsigned long) pci_io_base(bus);
+       printk("Chips65550 IO space at %p\n", io_space);
     }
 
     video_mode = VMODE_800_600_60;
@@ -65,11 +74,15 @@ chips_init()
     unsigned *p;
     int i, hres;
 
-    if (video_mode != VMODE_800_600_60)
-       panic("chips65550: display mode %d not supported", video_mode);
+    if (video_mode != VMODE_800_600_60) {
+       printk(KERN_ERR "chips65550: display mode %d not supported", video_mode);
+       video_mode = VMODE_800_600_60;
+    }
 
-    if (color_mode != CMODE_8 && color_mode != CMODE_16)
-       panic("chips65550: color mode %d not supported", color_mode);
+    if (color_mode != CMODE_8 && color_mode != CMODE_16) {
+       printk(KERN_ERR "chips65550: color mode %d not supported", color_mode);
+       color_mode = CMODE_8;
+    }
     
     n_scanlines = 600;
     hres        = 800;
@@ -106,15 +119,18 @@ chips_init()
     display_info.pitch = line_pitch;
     display_info.mode = video_mode;
     strncpy(display_info.name, "chips65550", sizeof(display_info.name));
-    display_info.fb_address = (unsigned long) frame_buffer;
-    display_info.cmap_adr_address = 0;
-    display_info.cmap_data_address = 0;
-    display_info.disp_reg_address = 0;
+    display_info.fb_address = chips_base_phys + 0x800000;
+    display_info.cmap_adr_address = chips_io_phys + 0x3c8;
+    display_info.cmap_data_address = chips_io_phys + 0x3c9;
+    display_info.disp_reg_address = chips_base_phys + 0xC00000;
 
     /* Clear screen */
     p = (unsigned *) frame_buffer;
     for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
        *p++ = 0;
+
+    /* Turn on backlight */
+    pmu_enable_backlight(1);
 }
 
 int
@@ -164,4 +180,5 @@ chips_set_palette(unsigned char red[], unsigned char green[],
 void
 chips_set_blanking(int blank_mode)
 {
+    pmu_enable_backlight(blank_mode == VESA_NO_BLANKING);
 }
index 4f6e6c84b81bdea418762532a64617ee72aff42b..9db048a4af8a0f4fafb5ea76b29d092f115f4f5a 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/io.h>
 #include <asm/adb.h>
 #include <asm/cuda.h>
+#include <asm/pgtable.h>
 #include <linux/selection.h>
 #include "pmac-cons.h"
 #include "control.h"
@@ -88,6 +89,10 @@ static struct cmap_regs *cmap_regs;
 static struct control_regs *disp_regs;
 static int control_use_bank2;
 
+static unsigned long frame_buffer_phys;
+static unsigned long disp_regs_phys;
+static unsigned long cmap_regs_phys;
+
 /*
  * Register initialization tables for the control display.
  *
@@ -317,7 +322,7 @@ map_control_display(struct device_node *dp)
                printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
        printk(", intrs =");
        for (i = 0; i < dp->n_intrs; ++i)
-               printk(" %x", dp->intrs[i]);
+               printk(" %x", dp->intrs[i].line);
        printk("\n");
 #endif
 
@@ -329,12 +334,15 @@ map_control_display(struct device_node *dp)
                        /* use the big-endian aperture (??) */
                        addr += 0x800000;
                        /* map at most 8MB for the frame buffer */
-                       frame_buffer = ioremap(addr, 0x800000);
+                       frame_buffer_phys = addr;
+                       frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
                } else {
+                       disp_regs_phys = addr;
                        disp_regs = ioremap(addr, size);
                }
        }
-       cmap_regs = ioremap(0xf301b000, 0x1000);        /* XXX not in prom? */
+       cmap_regs_phys = 0xf301b000;    /* XXX not in prom? */
+       cmap_regs = ioremap(cmap_regs_phys, 0x1000);
 
        /* Work out which banks of VRAM we have installed. */
        frame_buffer[0] = 0x5a;
@@ -454,10 +462,10 @@ control_init()
        display_info.pitch = line_pitch;
        display_info.mode = video_mode;
        strncpy(display_info.name, "control", sizeof(display_info.name));
-       display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
-       display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
-       display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
-       display_info.disp_reg_address = (unsigned long) &disp_regs;
+       display_info.fb_address = frame_buffer_phys + init->offset[color_mode];
+       display_info.cmap_adr_address = cmap_regs_phys;
+       display_info.cmap_data_address = cmap_regs_phys + 0x30;
+       display_info.disp_reg_address = disp_regs_phys;
 }
 
 int
index 2f74a153c3f2a0f3f43cd66851b864965122e7c7..32513a5e28588f6f2025abd6fd7e350963252ff4 100644 (file)
@@ -2,28 +2,41 @@
  * imstt.c: Console support for PowerMac "imstt" display adaptor.
  *
  * Copyright (C) 1997 Sigurdur Asgeirsson
+ * Modified by Danilo Beuche 1997
  *     
  * 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/module.h>
+
+#include <linux/config.h>
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/vc_ioctl.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/nvram.h>
 #include <asm/prom.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/pci-bridge.h>
 #include <linux/selection.h>
 #include <linux/vt_kern.h>
 #include "pmac-cons.h"
 #include "imstt.h"
 
+
+enum { 
+  IBMRAMDAC = 0x00,
+  TVPRAMDAC  = 0x01
+};
+
+
+// IMS TWIN TURBO 
 enum
 {
   S1SA         =  0, /* 0x00 */
@@ -79,6 +92,8 @@ enum
 #endif
 };
 
+
+// IBM RAMDAC
 enum
 {
  PADDRW                = 0x00,
@@ -97,12 +112,256 @@ enum
  PC0           = 0x23
 };
 
+// TI TVP 3030 RAMDAC Direct Registers
+enum 
+{
+       TVPADDRW = 0x00, // 0  Palette/Cursor RAM Write Adress/Index
+       TVPPDATA = 0x04, // 1  Palette Data RAM Data
+       TVPPMASK = 0x08, // 2  Pixel Read-Mask
+       TVPPADRR = 0x0c, // 3  Palette/Cursor RAM Read Adress
+       TVPCADRW = 0x10, // 4  Cursor/Overscan Color Write Address
+       TVPCDATA = 0x14, // 5  Cursor/Overscan Color Data
+                        // 6  reserved
+       TVPCADRR = 0x1c, // 7  Cursor/Overscan Color Read Address
+                        // 8  reserved
+       TVPDCCTL = 0x24, // 9  Direct Cursor Control
+       TVPIDATA = 0x28, // 10 Index Data
+       TVPCRDAT = 0x2c, // 11 Cursor RAM Data
+       TVPCXPOL = 0x30, // 12 Cursor-Position X LSB
+       TVPCXPOH = 0x34, // 13 Cursor-Position X MSB
+       TVPCYPOL = 0x38, // 14 Cursor-Position Y LSB
+       TVPCYPOH = 0x3c, // 15 Cursor-Position Y MSB
+};
+
+// TI TVP 3030 RAMDAC Indirect Registers
+enum
+{
+       TVPIRREV = 0x01, // Silicon Revision [RO] 
+       TVPIRICC = 0x06, // Indirect Cursor Control     (0x00) 
+       TVPIRBRC = 0x07, // Byte Router Control         (0xe4)
+       TVPIRLAC = 0x0f, // Latch Control               (0x06)
+       TVPIRTCC = 0x18, // True Color Control          (0x80)
+       TVPIRMXC = 0x19, // Multiplex Control           (0x98)
+       TVPIRCLS = 0x1a, // Clock Selection             (0x07)
+       TVPIRPPG = 0x1c, // Palette Page                (0x00)
+       TVPIRGEC = 0x1d, // General Control             (0x00)
+       TVPIRMIC = 0x1e, // Miscellaneous Control       (0x00)
+       TVPIRPLA = 0x2c, // PLL Address                 
+       TVPIRPPD = 0x2d, // Pixel Clock PLL Data
+       TVPIRMPD = 0x2e, // Memory Clock PLL Data
+       TVPIRLPD = 0x2f, // Loop Clock PLL Data
+       TVPIRCKL = 0x30, // Color-Key Overlay Low
+       TVPIRCKH = 0x31, // Color-Key Overlay High 
+       TVPIRCRL = 0x32, // Color-Key Red Low
+       TVPIRCRH = 0x33, // Color-Key Red High 
+       TVPIRCGL = 0x34, // Color-Key Green Low
+       TVPIRCGH = 0x35, // Color-Key Green High 
+       TVPIRCBL = 0x36, // Color-Key Blue Low
+       TVPIRCBH = 0x37, // Color-Key Blue High 
+       TVPIRCKC = 0x38, // Color-Key Control           (0x00)
+       TVPIRMLC = 0x39, // MCLK/Loop Clock Control     (0x18)
+       TVPIRSEN = 0x3a, // Sense Test                  (0x00)
+       TVPIRTMD = 0x3b, // Test Mode Data
+       TVPIRRML = 0x3c, // CRC Remainder LSB [RO]
+       TVPIRRMM = 0x3d, // CRC Remainder MSB [RO]
+       TVPIRRMS = 0x3e, // CRC  Bit Select [WO] 
+       TVPIRDID = 0x3f, // Device ID [RO]              (0x30)
+       TVPIRRES = 0xff, // Software Reset [WO]
+
+};
+
 struct initvalues
 {
   unsigned char        addr, value;
 };
 
-static struct initvalues initregs[] = 
+
+
+// Values which only depend on resolution not on color mode
+struct tt_single_rmodevals
+{
+       unsigned short hes;     
+       unsigned short heb;     
+       unsigned short hsb;     
+       unsigned short ht;      
+       unsigned short ves;     
+       unsigned short veb;     
+       unsigned short vsb;     
+       unsigned short vt;      
+};
+
+struct tvp_single_rmodevals
+{
+       unsigned char pclk_n;
+       unsigned char pclk_m;
+       unsigned char pclk_p;
+};
+
+struct ibm_single_rmodevals
+{
+       unsigned char pclk_m;
+       unsigned char pclk_n;
+       unsigned char pclk_p;
+       unsigned char pclk_c;
+};
+
+// Values which only depend on color mode not on resolution
+struct tvp_single_cmodevals
+{
+       unsigned char tcc; // True Color control
+       unsigned char mxc; // Multiplexer control
+       unsigned char lckl_n;   // N value of LCKL PLL
+};
+
+struct ibm_single_cmodevals
+{
+       unsigned char pformat; // pixel format
+};
+       
+// Values of the tvp which change depending on colormode x resolution
+struct tvp_single_crmodevals
+{
+       unsigned char mlc;      // Memory Loop Config 0x39
+       unsigned char lckl_p;   // P value of LCKL PLL
+};
+
+struct ibm_single_crmodevals
+{
+    // oh nothing changes
+};
+
+// complete configuration for a resolution in all depths 
+// 0 = 8 Bit, 15/16 bit = 1 , 32 Bit = 2 
+struct ims_crmodevals
+{
+       int pitch;
+       struct tt_single_rmodevals tt[2];  // for each ramdac  seperate tt config
+
+       struct tvp_single_rmodevals tvp_clock;  // for each ramdac  seperate clock config
+       struct tvp_single_crmodevals tvp[3];       // for each colormode 
+
+       struct ibm_single_rmodevals ibm_clock;  // for each ramdac  seperate clock config
+//     struct ibm_single_crmodevals ibm[3];       // for each color mode 
+};
+
+struct ims_modevals
+{
+       int dac;                          // which dac do we have
+       int total_vram;                   // how much vram is on board
+       int sense;                        // what monitor
+       unsigned char*  fb;               // frame buffer address
+       unsigned char*  fb_phys;          // frame buffer address
+       unsigned char*  cmap;             // dac address
+       unsigned char*  cmap_phys;        // dac address
+       unsigned int*   dc;               // tt address
+       unsigned int*   dc_phys;          // tt address
+
+       struct initvalues*     init[2];   // initial register settings for each ramdac
+
+       struct ims_crmodevals* mode[20];  // for each possible mode
+       
+       struct  tvp_single_cmodevals tvp[3]; // for each color mode
+       
+       struct  ibm_single_cmodevals ibm[3]; // for each color mode
+};
+
+
+struct ims_crmodevals imsmode_6 =
+{
+       640,
+       {
+               { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C },
+               { 0x04, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d },
+       },
+       {       0xef, 0x2e, 0xb2 },
+       {
+               { 0x39, 0xf3 },
+               { 0x39, 0xf3 },
+               { 0x38, 0xf3 }
+       },
+       // IBM CLOCK
+       {       0x78, 0x13, 0x02, 0x02 },
+};
+
+struct ims_crmodevals imsmode_13 =
+{
+       832,
+       {
+               { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B },
+               { 0x04, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b},
+       },
+       {       0xfe, 0x3e, 0xf1 },
+       {
+               { 0x39, 0xf3 },
+               { 0x38, 0xf3 },
+               { 0x38, 0xf2 }
+       },
+       { 0x3E, 0x0A, 0x01, 0x02 }
+};
+struct ims_crmodevals imsmode_17 =
+{
+       1024,
+       {
+               { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 } ,
+               { 0x06, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324 },
+       },
+       {       0xfc, 0x3a, 0xf1 },
+       {
+               { 0x39, 0xf3 },
+               { 0x38, 0xf3 },
+               { 0x38, 0xf2 }
+       },
+       { 0x07, 0x00, 0x01, 0x02 }
+};
+struct ims_crmodevals imsmode_18 =
+{
+       1152,
+       {
+               { 0, 0, 0, 0, 0, 0, 0, 0 },
+               { 0x09, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a }, 
+       },
+       {       0xfd, 0x3a, 0xf1 },
+       {
+               { 0x39, 0xf3 },
+               { 0x38, 0xf3 },
+               { 0x38, 0xf2 }
+       },
+       { 0, 0, 0, 0 }
+};
+struct ims_crmodevals imsmode_19 =
+{
+       1280,
+       {
+               { 0, 0, 0, 0, 0, 0, 0, 0 },
+               { 0x09, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8 },
+       },
+       {       0xf7, 0x36, 0xf0 },
+       {
+               { 0x38, 0xf3 },
+               { 0x38, 0xf2 },
+               { 0x38, 0xf1 }
+       },
+       { 0, 0, 0, 0 }
+};
+struct ims_crmodevals imsmode_20 =
+{
+       1280,
+       {
+               { 0, 0, 0, 0, 0, 0, 0, 0 },
+               { 0x09, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a },
+       },
+       {       0xf0, 0x2d, 0xf0 },
+       {
+               { 0x38, 0xf3 },
+               { 0x38, 0xf2 },
+               { 0x38, 0xf1 }
+       },
+       { 0, 0, 0, 0 }
+};
+
+// IBM RAMDAC initial register values
+
+static struct initvalues ibm_initregs[] = 
 {
  { 0x02, 0x21 },       /* (0x01) Miscellaneous Clock Control */
  { 0x03, 0x00 },       /* (0x00) Sync Control */
@@ -129,64 +388,114 @@ static struct initvalues initregs[] =
  { 0x71, 0x45 },       /* (0x00) Miscellaneous Control 2 */
  { 0x72, 0x00 },       /* (0x00) Miscellaneous Control 3 */
  { 0x78, 0x00 },       /* (0x00) Key Control/DB Operation */
+ { 0x00, 0x00 } 
 };
 
-static void set_imstt_clock(unsigned char *params);
-static int read_imstt_sense(void);
-static int imstt_vram_reqd(int vmode, int cmode);
 
-static int total_vram = 2 * 1024 * 1024;               /* total amount of video memory, bytes */
-static unsigned char *frame_buffer;
-static unsigned char *cmap_regs;
-static unsigned *dc_regs;
+static struct initvalues tvp_initregs[] = 
+{
+{ 0x6, 0x00},
+{ 0x7, 0xe4},
+{ 0xf, 0x06},
+{ 0x18, 0x80},
+{ 0x19, 0x4d},
+{ 0x1a, 0x05},
+{ 0x1c, 0x00},
+{ 0x1d, 0x00},
+{ 0x1e, 0x08},
+{ 0x30, 0xff},
+{ 0x31, 0xff},
+{ 0x32, 0xff},
+{ 0x33, 0xff},
+{ 0x34, 0xff},
+{ 0x35, 0xff},
+{ 0x36, 0xff},
+{ 0x37, 0xff},
+{ 0x38, 0x00},
+{ TVPIRPLA, 0x00 },
+{ TVPIRPPD, 0xc0 },
+{ TVPIRPPD, 0xd5 },
+{ TVPIRPPD, 0xea },
+{ TVPIRPLA, 0x00 },
+{ TVPIRMPD, 0xb9 },
+{ TVPIRMPD, 0x3a },
+{ TVPIRMPD, 0xb1 },
+{ TVPIRPLA, 0x00 },
+{ TVPIRLPD, 0xc1 },
+{ TVPIRLPD, 0x3d },
+{ TVPIRLPD, 0xf3 },
+{ 0x00, 0x00 } 
+};
 
 
-/*
- * Register initialization tables for the imstt display.
- *
- * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
- * where m = clk[0], n = clk[1], p = clk[2]
- * clk[3] is c, charge pump bias which depends on the VCO frequency  
- */
-struct imstt_regvals {
-       unsigned short          cfg[8];
-       unsigned char           clk[4];
-       unsigned long           pitch[3];
-} imsttmode;
-
-/* Register values for 1024x768, 75Hz mode (17) */
-static struct imstt_regvals imstt_reg_init_17 = {
-  { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 }, 
-  { 0x07, 0x00, 0x01, 0x02 },
-  { 0x0400, 0x0800, 0x1000 }
-};
+static struct ims_modevals ims_info =
+{
+       -1,     // DAC
+       -1,     // VRAM
+       -1,     // Monitor;
+       0,      // Framebuffer
+       0,      // Framebuffer_phys
+       0,      // colormap
+       0,      // colormap_phys
+       0,      // dc
+       0,      // dc_phys
+       { ibm_initregs, tvp_initregs},
+       {
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               &imsmode_6,
+               &imsmode_6,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               NULL,
+               &imsmode_13,
+               NULL,
+               NULL,
+               NULL,
+               &imsmode_17,
+               &imsmode_18,
+               &imsmode_19,
+               &imsmode_20
+       },
+       {
+               { 0x80, 0x4d, 0xc1 },
+               { 0x44, 0x55, 0xe1 },
+               { 0x46, 0x5d, 0xf1 }
+       },
+       {
+               { 0x03 },
+               { 0x04 },
+               { 0x06 }
+       }       
+};     
+               
+       
 
-/* Register values for 832x624, 75Hz mode (13) */
-static struct imstt_regvals imstt_reg_init_13 = {
-  { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B },
-  { 0x3E, 0x0A, 0x01, 0x02 },
-  { 832, 832 * 2, 832 * 4 }
-};
 
-/* Register values for 640x480, 67Hz mode (6) */
-static struct imstt_regvals imstt_reg_init_6 = {
-  { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C },
-  { 0x78, 0x13, 0x02, 0x02 },
-  { 640, 640 * 2, 640 * 4 }
-};
+// static void set_imstt_clock(unsigned char *params);
+static void map_imstt_display(struct device_node *, int);
+static int read_imstt_sense(void);
+static int imstt_vram_reqd(int vmode, int cmode);
 
-static struct imstt_regvals *imstt_reg_init[20] = {
-       NULL, NULL, NULL, NULL,
-       &imstt_reg_init_6, // fake'm out
-       &imstt_reg_init_6,
-       NULL, NULL, NULL,
-       NULL, NULL, NULL,
-       &imstt_reg_init_13,
-       NULL, NULL, NULL,
-       &imstt_reg_init_17,
-       NULL, NULL, NULL
-};
 
+#if 0
+static int get_tvp_ireg(int iaddr)
+{
+       ims_info.cmap[0] = iaddr & 0xff; eieio();
+       return ims_info.cmap[40];
+}
+#endif
+
+static void set_tvp_ireg(int iaddr,unsigned char value)
+{
+       ims_info.cmap[0] = iaddr & 0xff; eieio();
+       ims_info.cmap[40] = value; eieio();
+}
 /*
  * Get the monitor sense value.
  * Note that this can be called before calibrate_delay,
@@ -199,28 +508,28 @@ read_imstt_sense()
        int sense;
        unsigned gio, gioe;
 
-       gio = ld_le32(dc_regs + GIO) & ~0x0038;
+       gio = ld_le32(ims_info.dc + GIO) & ~0x0038;
        gioe = ld_le32(dc_
        
-       out_le32(dc_regs + GIOE, reg);  /* drive all lines high */
+       out_le32(ims_info.dc + GIOE, reg);      /* drive all lines high */
        __delay(200);
-       out_le32(dc_regs + GIOE, 077);  /* turn off drivers */
+       out_le32(ims_info.dc + GIOE, 077);      /* turn off drivers */
        __delay(2000);
-       sense = (in_le32(dc_regs + GIOE) & 0x1c0) << 2;
+       sense = (in_le32(ims_info.dc + GIOE) & 0x1c0) << 2;
 
        /* drive each sense line low in turn and collect the other 2 */
-       out_le32(dc_regs + GIOE, 033);  /* drive A low */
+       out_le32(ims_info.dc + GIOE, 033);      /* drive A low */
        __delay(2000);
-       sense |= (in_le32(dc_regs + GIOE) & 0xc0) >> 2;
-       out_le32(dc_regs + GIOE, 055);  /* drive B low */
+       sense |= (in_le32(ims_info.dc + GIOE) & 0xc0) >> 2;
+       out_le32(ims_info.dc + GIOE, 055);      /* drive B low */
        __delay(2000);
-       sense |= ((in_le32(dc_regs + GIOE) & 0x100) >> 5)
-               | ((in_le32(dc_regs + GIOE) & 0x40) >> 4);
-       out_le32(dc_regs + GIOE, 066);  /* drive C low */
+       sense |= ((in_le32(ims_info.dc + GIOE) & 0x100) >> 5)
+               | ((in_le32(ims_info.dc + GIOE) & 0x40) >> 4);
+       out_le32(ims_info.dc + GIOE, 066);      /* drive C low */
        __delay(2000);
-       sense |= (in_le32(dc_regs + GIOE) & 0x180) >> 7;
+       sense |= (in_le32(ims_info.dc + GIOE) & 0x180) >> 7;
 
-       out_le32(dc_regs + GIOE, 077);  /* turn off drivers */
+       out_le32(ims_info.dc + GIOE, 077);      /* turn off drivers */
        return sense;
 #else
        return 0;
@@ -229,12 +538,24 @@ read_imstt_sense()
 
 static inline int imstt_vram_reqd(int vmode, int cmode)
 {
-       return vmode_attrs[vmode-1].vres
-               * imstt_reg_init[vmode-1]->pitch[cmode];
+       return vmode_attrs[vmode-1].vres *
+               (ims_info.mode[vmode-1])->pitch * ( 1 << cmode);
+}
+
+void
+map_imstt_display_tvp(struct device_node *dp)
+{
+    map_imstt_display(dp,1);
 }
 
 void
-map_imstt_display(struct device_node *dp)
+map_imstt_display_ibm(struct device_node *dp)
+{
+    map_imstt_display(dp,0);
+}
+
+static void
+map_imstt_display(struct device_node *dp, int which)
 {
        int i, sense;
        unsigned long addr, size, tmp;
@@ -244,7 +565,7 @@ map_imstt_display(struct device_node *dp)
        if (dp->next != 0)
                printk("Warning: only using first imstt display device\n");
 
-#if 1
+#if 0
        printk("pmac_display_init: node = %p, addrs =", dp->node);
        for (i = 0; i < dp->n_addrs; ++i)
                printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
@@ -259,12 +580,14 @@ map_imstt_display(struct device_node *dp)
                addr = dp->addrs[i].address;
                size = dp->addrs[i].size;
                if (size >= 0x02000000) {
-                       frame_buffer = ioremap(addr, size);
-                       dc_regs = (unsigned*)(frame_buffer + 0x00800000);
-                       cmap_regs = (unsigned char*)(frame_buffer + 0x00840000);
-
-                       printk("mapped frame_buffer=%x(%x)", (unsigned)frame_buffer, (unsigned)size);
-                       printk(" dc_regs=%x, cmap_regs=%x\n", (unsigned)dc_regs, (unsigned)cmap_regs);
+                       ims_info.fb = __ioremap(addr, size, _PAGE_NO_CACHE);
+                       ims_info.fb_phys = (unsigned char*)addr;
+                       ims_info.dc = (unsigned*)(ims_info.fb + 0x00800000);
+                       ims_info.dc_phys = (unsigned*)(ims_info.fb_phys + 0x00800000);
+                       ims_info.cmap = (unsigned char*)(ims_info.fb + 0x00840000);
+                       ims_info.cmap_phys = (unsigned char*)(ims_info.fb_phys + 0x00840000);
+                       printk("mapped ims_info.fb=%x(%x)", (unsigned)ims_info.fb, (unsigned)size);
+                       printk(" ims_info.dc=%x, ims_info.cmap=%x\n", (unsigned)ims_info.dc, (unsigned)ims_info.cmap);
                }
        }
 
@@ -282,12 +605,28 @@ map_imstt_display(struct device_node *dp)
        else
          printk("unable to find pci device\n");
 
-       tmp = in_le32(dc_regs + SSTATUS);
+       tmp = in_le32(ims_info.dc + SSTATUS);
        printk("chip version %ld, ", (tmp & 0x0F00) >> 8);
 
-       tmp = in_le32(dc_regs + PRC);
-       total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L;
-       printk("VRAM size %ldM\n", total_vram / 0x000100000L);
+       tmp = in_le32(ims_info.dc + PRC);
+       
+       if (0 == which )
+           ims_info.total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L;
+       else
+           ims_info.total_vram = 0x000800000L;
+       
+       printk("VRAM size %ldM\n", ims_info.total_vram / 0x000100000L);
+       
+       if (ims_info.total_vram == 0x000800000L)
+       {
+               ims_info.dac = TVPRAMDAC;
+               printk("Selecting TVP 3030 RAMDAC\n");
+       }
+       else
+       {
+               ims_info.dac = IBMRAMDAC;
+               printk("Selecting  IBM RAMDAC\n");
+       }
 
        sense = read_imstt_sense();
        printk("Monitor sense value = 0x%x, ", sense);
@@ -311,147 +650,232 @@ map_imstt_display(struct device_node *dp)
        if (color_mode < CMODE_8 || color_mode > CMODE_32)
                color_mode = CMODE_8;
        while (color_mode > CMODE_8
-              && imstt_vram_reqd(video_mode, color_mode) > total_vram)
+              && imstt_vram_reqd(video_mode, color_mode) > ims_info.total_vram)
                --color_mode;
 
 #endif
-
+       // Hack Hack Hack !!!
        video_mode = VMODE_640_480_67;
        color_mode = CMODE_8;
 }
 
+/*
+ * We dont need it ( all is done in ims_init )
+static void
+set_imstt_clock_tvp(char* tvprv)
+{
+  int j;
+  for (j=0;j<3;j++)
+       {
+               set_tvp_ireg(TVPIRPLA,(j << 4) | (j << 2) | j); // Select same value for all plls
+               set_tvp_ireg(TVPIRPPD,tvprv[j]);
+               set_tvp_ireg(TVPIRMPD,tvprv[3+j]);
+               set_tvp_ireg(TVPIRLPD,tvprv[6+j]);
+       }
+}
+
 static void
-set_imstt_clock(unsigned char *params)
+set_imstt_clock_ibm(unsigned char *params)
 {
-  cmap_regs[PIDXHI] = 0; eieio();
-  cmap_regs[PIDXLO] = PM0; eieio();
-  cmap_regs[PIDXDATA] = params[0]; eieio();
+  ims_info.cmap[PIDXHI] = 0; eieio();
+  ims_info.cmap[PIDXLO] = PM0; eieio();
+  ims_info.cmap[PIDXDATA] = params[0]; eieio();
 
-  cmap_regs[PIDXLO] = PN0; eieio();
-  cmap_regs[PIDXDATA] = params[1]; eieio();
+  ims_info.cmap[PIDXLO] = PN0; eieio();
+  ims_info.cmap[PIDXDATA] = params[1]; eieio();
 
-  cmap_regs[PIDXLO] = PP0; eieio();
-  cmap_regs[PIDXDATA] = params[2]; eieio();
+  ims_info.cmap[PIDXLO] = PP0; eieio();
+  ims_info.cmap[PIDXDATA] = params[2]; eieio();
        
-  cmap_regs[PIDXLO] = PC0; eieio();
-  cmap_regs[PIDXDATA] = params[3]; eieio();
+  ims_info.cmap[PIDXLO] = PC0; eieio();
+  ims_info.cmap[PIDXDATA] = params[3]; eieio();
 }
+*/
 
 void
 imstt_init()
 {
   int                   i, yoff, hres;
-  unsigned long                 ctl, pitch, tmp;
-  unsigned char                 pformat;
-  unsigned               *p;
-  struct imstt_regvals   *init;
+  unsigned long                 ctl, pitch, tmp, scrCmode;
+  struct ims_crmodevals   *init;
 
-  if (video_mode <= 0 || video_mode > VMODE_MAX
-      || (init = imstt_reg_init[video_mode-1]) == 0)
-    panic("imstt: display mode %d not supported", video_mode);
+  if (video_mode <= 0 || video_mode > VMODE_MAX ) panic("imstt: display mode %d not supported(not in valid range)", video_mode);
+  if ((init = ims_info.mode[video_mode-1]) == 0) panic("imstt: display mode %d not supported(no mode definition)", video_mode);
+  if (init->tt[ims_info.dac].vt == 0) panic("imstt: display mode %d not supported (no timing definition)", video_mode);
+       
 
   n_scanlines = vmode_attrs[video_mode-1].vres;
   hres = vmode_attrs[video_mode-1].hres;
   pixel_size = 1 << color_mode;
-  line_pitch = init->pitch[color_mode];
+  line_pitch = init->pitch * pixel_size;
   row_pitch = line_pitch * 16;
 
   /* initialize the card */
-  tmp = in_le32(dc_regs + STGCTL);
-  out_le32(dc_regs + STGCTL, tmp & ~0x1);
+  tmp = in_le32(ims_info.dc + STGCTL);
+  out_le32(ims_info.dc + STGCTL, tmp & ~0x1);
 #if 0
-  out_le32(dc_regs + SCR, 0);
+  out_le32(ims_info.dc + SCR, 0);
 #endif
 
-  cmap_regs[PPMASK] = 0xFF;
-  /* set default values for DAC registers */ 
-  cmap_regs[PIDXHI] = 0; eieio();
-  for(i = 0; i < sizeof(initregs) / sizeof(*initregs); i++) {
-    cmap_regs[PIDXLO] = initregs[i].addr; eieio();
-    cmap_regs[PIDXDATA] = initregs[i].value; eieio();
+  switch(ims_info.dac)
+  {
+  case IBMRAMDAC:
+      ims_info.cmap[PPMASK] = 0xFF; eieio();
+      ims_info.cmap[PIDXHI] = 0x00; eieio();
+      for (i = 0; ims_info.init[IBMRAMDAC][i].addr != 0 && ims_info.init[IBMRAMDAC][i].value != 0 ;i++)
+         {
+             ims_info.cmap[PIDXLO] = ims_info.init[IBMRAMDAC][i].addr; eieio();
+             ims_info.cmap[PIDXDATA] = ims_info.init[IBMRAMDAC][i].value; eieio();
+         }
+
+      ims_info.cmap[PIDXHI] = 0; eieio();
+      ims_info.cmap[PIDXLO] = PM0; eieio();
+      ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_m; eieio();
+
+      ims_info.cmap[PIDXLO] = PN0; eieio();
+      ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_n; eieio();
+
+      ims_info.cmap[PIDXLO] = PP0; eieio();
+      ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_p; eieio();
+       
+      ims_info.cmap[PIDXLO] = PC0; eieio();
+      ims_info.cmap[PIDXDATA] = init->ibm_clock.pclk_c; eieio();
+      
+      ims_info.cmap[PIDXLO] = PPIXREP; eieio();
+      ims_info.cmap[PIDXDATA] = ims_info.ibm[color_mode].pformat; eieio();
+
+      break;
+  case TVPRAMDAC:
+       for (i = 0; ims_info.init[TVPRAMDAC][i].addr != 0 && ims_info.init[TVPRAMDAC][i].value != 0 ;i++)
+       {
+               set_tvp_ireg(ims_info.init[TVPRAMDAC][i].addr,ims_info.init[TVPRAMDAC][i].value);       
+       }
+       set_tvp_ireg(TVPIRPLA,0x00);
+       set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_n);
+       set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_m);
+       set_tvp_ireg(TVPIRPPD,init->tvp_clock.pclk_p);
+
+       set_tvp_ireg(TVPIRTCC,ims_info.tvp[color_mode].tcc);
+       set_tvp_ireg(TVPIRMXC,ims_info.tvp[color_mode].mxc);
+
+       set_tvp_ireg(TVPIRPLA,0x00);
+       set_tvp_ireg(TVPIRLPD,ims_info.tvp[color_mode].lckl_n);
+
+       set_tvp_ireg(TVPIRPLA,0x15);
+       set_tvp_ireg(TVPIRMLC,(init->tvp[color_mode]).mlc);
+
+       set_tvp_ireg(TVPIRPLA,0x2a);
+       set_tvp_ireg(TVPIRLPD,init->tvp[color_mode].lckl_p);
+       break;
   }
-  set_imstt_clock(init->clk);
+
 
   switch(color_mode) {
   case CMODE_32:
-    ctl = 0x17b5;
-    pitch = init->pitch[2] / 4;
-    pformat = 0x06;
+    ctl = 0x1785;
+    pitch = init->pitch;
+    scrCmode = 0x300;
     break;
   case CMODE_16:
-    ctl = 0x17b3;
-    pitch = init->pitch[1] / 4;
-    pformat = 0x04;
+    ctl = 0x1783;
+    pitch = init->pitch / 2;
+    scrCmode = 0x100;
     break;
   case CMODE_8:
   default:
-    ctl = 0x17b1;
-    pitch = init->pitch[0] / 4;
-    pformat = 0x03;
+    ctl = 0x1781;
+    pitch = init->pitch / 4;
+    scrCmode = 0x000;
     break;
   }
 
-  out_le32(&dc_regs[HES], init->cfg[0]);
-  out_le32(&dc_regs[HEB], init->cfg[1]);
-  out_le32(&dc_regs[HSB], init->cfg[2]);
-  out_le32(&dc_regs[HT], init->cfg[3]);
-  out_le32(&dc_regs[VES], init->cfg[4]);
-  out_le32(&dc_regs[VEB], init->cfg[5]);
-  out_le32(&dc_regs[VSB], init->cfg[6]);
-  out_le32(&dc_regs[VT], init->cfg[7]);
-  out_le32(&dc_regs[HCIV], 1);
-  out_le32(&dc_regs[VCIV], 1);
-  out_le32(&dc_regs[TCDR], 4);
-  out_le32(&dc_regs[VIL], 0);
+  out_le32(&ims_info.dc[HES], init->tt[ims_info.dac].hes);
+  out_le32(&ims_info.dc[HEB], init->tt[ims_info.dac].heb);
+  out_le32(&ims_info.dc[HSB], init->tt[ims_info.dac].hsb);
+  out_le32(&ims_info.dc[HT], init->tt[ims_info.dac].ht);
+  out_le32(&ims_info.dc[VES], init->tt[ims_info.dac].ves);
+  out_le32(&ims_info.dc[VEB], init->tt[ims_info.dac].veb);
+  out_le32(&ims_info.dc[VSB], init->tt[ims_info.dac].vsb);
+  out_le32(&ims_info.dc[VT], init->tt[ims_info.dac].vt);
+  out_le32(&ims_info.dc[HCIV], 1);
+  out_le32(&ims_info.dc[VCIV], 1);
+  out_le32(&ims_info.dc[TCDR], 4);
+  out_le32(&ims_info.dc[VIL], 0);
        
-  out_le32(&dc_regs[SSR], 0);
-  out_le32(&dc_regs[HRIR], 0x0200);
-  out_le32(&dc_regs[CMR], 0x01FF);
-  out_le32(&dc_regs[SRGCTL], 0x0003);
-  if(total_vram == 0x000200000)
-     out_le32(&dc_regs[SCR], 0x0059D);
-  else {
-    pitch /= 2;
-    out_le32(&dc_regs[SCR], 0x00D0DC);
+  out_le32(&ims_info.dc[SSR], 0);
+  out_le32(&ims_info.dc[HRIR], 0x0200);
+  out_le32(&ims_info.dc[CMR], 0x01FF);
+  out_le32(&ims_info.dc[SRGCTL], 0x0003);
+  switch(ims_info.total_vram)
+  {
+       case 0x000200000:
+               out_le32(&ims_info.dc[SCR], 0x0059D| scrCmode);
+               break;
+       case 0x000400000:
+               pitch /= 2;
+               out_le32(&ims_info.dc[SCR], 0x00D0DC | scrCmode);
+               break;
+       case 0x000800000:
+               pitch /= 2;
+               out_le32(&ims_info.dc[SCR], 0x0150DD | scrCmode);
+               break;
   }
 
-  out_le32(&dc_regs[SPR], pitch);
-
-  cmap_regs[PIDXLO] = PPIXREP; eieio();
-  cmap_regs[PIDXDATA] = pformat; eieio();
+  out_le32(&ims_info.dc[SPR], pitch);
 
+  if (ims_info.dac == IBMRAMDAC)
+  {
+         
 
+  }
+  
   pmac_init_palette(); /* Initialize colormap */
 
-  out_le32(&dc_regs[STGCTL], ctl);
+  out_le32(&ims_info.dc[STGCTL], ctl);
 
   yoff = (n_scanlines % 16) / 2;
-  fb_start = frame_buffer + yoff * line_pitch;
+  fb_start = ims_info.fb + yoff * line_pitch;
 
   /* Clear screen */
-  p = (unsigned *)frame_buffer;
-  for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
-    *p++ = 0;
+  {
+       unsigned long *p;
+       p = (unsigned long*)ims_info.fb;
+       for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+               *p++ = 0;
+  }
 
   display_info.height = n_scanlines;
   display_info.width = hres;
   display_info.depth = pixel_size * 8;
   display_info.pitch = line_pitch;
   display_info.mode = video_mode;
-  strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
-  display_info.fb_address = (unsigned long) frame_buffer;
-  display_info.cmap_adr_address = (unsigned long) &cmap_regs[PADDRW];
-  display_info.cmap_data_address = (unsigned long) &cmap_regs[PDATA];
+
+  if (ims_info.dac == IBMRAMDAC )
+      strncpy(display_info.name, "IMS,tt128mb2/4", sizeof(display_info.name));
+  else
+      strncpy(display_info.name, "IMS,tt128mb8/8A", sizeof(display_info.name));
+  
+  display_info.fb_address = (unsigned long) ims_info.fb_phys;
+  display_info.cmap_adr_address = (unsigned long) &ims_info.cmap_phys[PADDRW];
+  display_info.cmap_data_address = (unsigned long) &ims_info.cmap_phys[PDATA];
   display_info.disp_reg_address = (unsigned long) NULL;
 }
 
 int
 imstt_setmode(struct vc_mode *mode, int doit)
 {
-       int cmode;
+  int cmode;
+  struct ims_crmodevals   *init;
+
+  if (video_mode <= 0 || video_mode > VMODE_MAX )
+               return -EINVAL;
+  if ((init = ims_info.mode[video_mode-1]) == 0)
+               return -EINVAL;
+  if (init->tt[ims_info.dac].vt == 0)
+               return -EINVAL;
 
        if (mode->mode <= 0 || mode->mode > VMODE_MAX
-           || imstt_reg_init[mode->mode-1] == 0)
+           || (ims_info.mode[mode->mode-1] == 0))
                return -EINVAL;
        switch (mode->depth) {
        case 24:
@@ -468,7 +892,7 @@ imstt_setmode(struct vc_mode *mode, int doit)
        default:
                return -EINVAL;
        }
-       if (imstt_vram_reqd(mode->mode, cmode) > total_vram)
+       if (imstt_vram_reqd(mode->mode, cmode) > ims_info.total_vram)
                return -EINVAL;
        if (doit) {
                video_mode = mode->mode;
@@ -478,17 +902,32 @@ imstt_setmode(struct vc_mode *mode, int doit)
        return 0;
 }
 
+// set palette for TI TVP3030 ramdac (used on 8MB version)
+void
+imstt_set_palette_tvp(unsigned char red[], unsigned char green[],
+                   unsigned char blue[], int index, int ncolors)
+{
+       int i;
+       for (i = 0; i < ncolors; ++i) {
+               ims_info.cmap[TVPADDRW] = index + i;    eieio();
+               ims_info.cmap[TVPPDATA] = red[i];       eieio();
+               ims_info.cmap[TVPPDATA] = green[i];     eieio();
+               ims_info.cmap[TVPPDATA] = blue[i];      eieio();
+       }
+}
+
+// set palette for IBM ramdac (used on 2MB/4MB version)
 void
-imstt_set_palette(unsigned char red[], unsigned char green[],
+imstt_set_palette_ibm(unsigned char red[], unsigned char green[],
                    unsigned char blue[], int index, int ncolors)
 {
        int i;
 
        for (i = 0; i < ncolors; ++i) {
-               cmap_regs[PADDRW] = index + i;  eieio();
-               cmap_regs[PDATA] = red[i];      eieio();
-               cmap_regs[PDATA] = green[i];    eieio();
-               cmap_regs[PDATA] = blue[i];     eieio();
+               ims_info.cmap[PADDRW] = index + i;      eieio();
+               ims_info.cmap[PDATA] = red[i];  eieio();
+               ims_info.cmap[PDATA] = green[i];        eieio();
+               ims_info.cmap[PDATA] = blue[i]; eieio();
        }
 }
 
@@ -497,10 +936,12 @@ imstt_set_blanking(int blank_mode)
 {
        long ctrl;
 
-       ctrl = ld_le32(dc_regs + STGCTL) | 0x0030;
+       ctrl = ld_le32(ims_info.dc + STGCTL) | 0x0030;
        if (blank_mode & VESA_VSYNC_SUSPEND)
                ctrl &= ~0x0020;
        if (blank_mode & VESA_HSYNC_SUSPEND)
                ctrl &= ~0x0010;
-       out_le32(dc_regs + STGCTL, ctrl);
+       out_le32(ims_info.dc + STGCTL, ctrl);
 }
+
+
index 853e8f00d9dba8a8a459ce2988174fec75c4abe0..a7f6359828e414b36ae0801915aab23265967a44 100644 (file)
@@ -9,10 +9,13 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-extern void map_imstt_display(struct device_node *);
+extern void map_imstt_display_ibm(struct device_node *);
+extern void map_imstt_display_tvp(struct device_node *);
 extern void imstt_init(void);
 extern int imstt_setmode(struct vc_mode *mode, int doit);
-extern void imstt_set_palette(unsigned char red[], unsigned char green[],
+extern void imstt_set_palette_ibm(unsigned char red[], unsigned char green[],
+                               unsigned char blue[], int index, int ncolors);
+extern void imstt_set_palette_tvp(unsigned char red[], unsigned char green[],
                                unsigned char blue[], int index, int ncolors);
 extern void imstt_set_blanking(int blank_mode);
 
index 49dbd622b81337bc40d0f7dbf1ca07389ccd6891..190e5222a857585feed5dcd07366909e7ae77f55 100644 (file)
@@ -15,8 +15,8 @@
 #include <linux/mm.h>
 #include <linux/signal.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 
-#include <asm/keyboard.h>
 #include <asm/bitops.h>
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #define KEYB_LEDREG    2       /* register # for leds on ADB keyboard */
 #define MOUSE_DATAREG  0       /* reg# for movement/button codes from mouse */
 
+static u_short macplain_map[NR_KEYS] = __initdata {
+       0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+       0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72,
+       0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035,
+       0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f,
+       0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027,
+       0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e,
+       0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+       0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+       0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macshift_map[NR_KEYS] __initdata = {
+       0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58,
+       0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52,
+       0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025,
+       0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f,
+       0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022,
+       0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e,
+       0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a,
+       0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117,
+       0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macaltgr_map[NR_KEYS] __initdata = {
+       0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+       0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72,
+       0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+       0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f,
+       0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200,
+       0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f,
+       0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200,
+       0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516,
+       0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117,
+       0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macctrl_map[NR_KEYS] __initdata = {
+       0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+       0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+       0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d,
+       0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f,
+       0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007,
+       0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e,
+       0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+       0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+       0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macshift_ctrl_map[NR_KEYS] __initdata = {
+       0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+       0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+       0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f,
+       0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200,
+       0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117,
+       0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c,
+};
+
+static u_short macalt_map[NR_KEYS] __initdata = {
+       0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878,
+       0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872,
+       0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835,
+       0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f,
+       0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827,
+       0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e,
+       0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905,
+       0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200,
+       0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+       0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+       0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macctrl_alt_map[NR_KEYS] __initdata = {
+       0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818,
+       0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812,
+       0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f,
+       0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200,
+       0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+       0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+       0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b,
+       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+       0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+
 static void kbd_repeat(unsigned long);
 static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
 static int last_keycode;
@@ -38,8 +172,7 @@ static void leds_done(struct adb_request *);
 
 /* XXX: Hook for mouse driver */
 void (*adb_mouse_interrupt_hook) (char *, int);
-int adb_emulate_button2;
-int adb_emulate_button3;
+static int adb_emulate_buttons = 0;
 extern int console_loglevel;
 
 extern struct kbd_struct kbd_table[];
@@ -47,6 +180,9 @@ extern struct kbd_struct kbd_table[];
 extern void handle_scancode(unsigned char);
 extern void put_queue(int);
 
+static struct adb_ids keyboard_ids;
+static struct adb_ids mouse_ids;
+
 /* this map indicates which keys shouldn't autorepeat. */
 static unsigned char dont_repeat[128] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -118,6 +254,10 @@ input_keycode(int keycode, int repeat)
        up_flag = (keycode & 0x80);
        keycode &= 0x7f;
 
+       /* on the powerbook 3400, the power key gives code 0x7e */
+       if (keycode == 0x7e)
+               keycode = 0x7f;
+
        if (!repeat)
                del_timer(&repeat_timer);
 
@@ -130,7 +270,8 @@ input_keycode(int keycode, int repeat)
         *      Might also want to know how many buttons need to be emulated.
         *      -> hide this as function in arch/m68k/mac ?
         */
-       if (adb_mouse_interrupt_hook || console_loglevel == 10) {
+       if ( (adb_emulate_buttons) &&
+            (adb_mouse_interrupt_hook || console_loglevel == 10) ) {
                unsigned char button, button2, button3, fake_event;
                static unsigned char button2state=0, button3state=0; /* up */
                /* faked ADB packet */
@@ -140,19 +281,19 @@ input_keycode(int keycode, int repeat)
                fake_event = 0;
                switch (keycode) {      /* which 'button' ? */
                        case 0x7c:      /* R-option */
-                               button2 = (!up_flag);           /* new state */
-                               if (button2 != button2state)    /* change ? */
-                                       button = 2; 
-                               button2state = button2;         /* save state */
-                               fake_event = 2;
-                               break; 
-                       case 0x7d:      /* R-control */
                                button3 = (!up_flag);           /* new state */
                                if (button3 != button3state)    /* change ? */ 
                                        button = 3; 
                                button3state = button3;         /* save state */
                                fake_event = 3;
                                break; 
+                       case 0x7d:      /* R-control */
+                               button2 = (!up_flag);           /* new state */
+                               if (button2 != button2state)    /* change ? */
+                                       button = 2; 
+                               button2state = button2;         /* save state */
+                               fake_event = 2;
+                               break; 
                }
                if (fake_event && console_loglevel >= 8)
                        printk("fake event: button2 %d button3 %d button %d\n",
@@ -365,57 +506,134 @@ static unsigned char mac_ledmap[8] = {
 };
 
 static struct adb_request led_request;
-static int leds_pending;
+static int leds_pending[16];
+static int pending_devs[16];
+static int pending_led_start=0;
+static int pending_led_end=0;
+
+static void real_mackbd_leds(unsigned char leds, int device)
+{
+
+    if (led_request.complete) {
+       adb_request(&led_request, leds_done, 0, 3,
+                   ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
+                   ~mac_ledmap[leds]);
+    } else {
+       if (!(leds_pending[device] & 0x100)) {
+           pending_devs[pending_led_end] = device;
+           pending_led_end++;
+           pending_led_end = (pending_led_end < 16) ? pending_led_end : 0;
+       }
+       leds_pending[device] = leds | 0x100;
+    }
+}
 
 void mackbd_leds(unsigned char leds)
 {
-       if (led_request.complete) {
-               adb_request(&led_request, leds_done, 0, 3,
-                            ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG),
-                            0xff, ~mac_ledmap[leds]);
-       } else
-               leds_pending = leds | 0x100;
+    int i;
+
+    for(i = 0; i < keyboard_ids.nids; i++)
+       real_mackbd_leds(leds,keyboard_ids.id[i]);
 }
 
 static void leds_done(struct adb_request *req)
 {
-       int leds;
+    int leds,device;
+
+    if (pending_led_start != pending_led_end) {
+       device = pending_devs[pending_led_start];
+       leds = leds_pending[device] & 0xff;
+       leds_pending[device] = 0;
+       pending_led_start++;
+       pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
+       real_mackbd_leds(leds,device);
+    }
 
-       if (leds_pending) {
-               leds = leds_pending & 0xff;
-               leds_pending = 0;
-               mackbd_leds(leds);
-       }
 }
 
-void mackbd_init_hw(void)
+__initfunc(void mackbd_init_hw(void))
 {
        struct adb_request req;
+       int i;
+
+       if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+           return;
+
+       /* setup key map */
+       memcpy(plain_map, macplain_map, sizeof(plain_map));
+       memcpy(shift_map, macshift_map, sizeof(shift_map));
+       memcpy(altgr_map, macaltgr_map, sizeof(altgr_map));
+       memcpy(ctrl_map, macctrl_map, sizeof(ctrl_map));
+       memcpy(shift_ctrl_map, macshift_ctrl_map, sizeof(shift_ctrl_map));
+       memcpy(alt_map, macalt_map, sizeof(alt_map));
+       memcpy(ctrl_alt_map, macctrl_alt_map, sizeof(ctrl_alt_map));
 
        /* initialize mouse interrupt hook */
        adb_mouse_interrupt_hook = NULL;
-       /* assume broken mouse :-) - should be adjusted based on 
-        * result of the mouse setup !! (or passed as  kernel option) */
-       adb_emulate_button2 = 1;
-       adb_emulate_button3 = 1;
 
-       adb_register(ADB_KEYBOARD, keyboard_input);
-       adb_register(ADB_MOUSE, mouse_input);
+       adb_register(ADB_KEYBOARD, 5, &keyboard_ids, keyboard_input);
+       adb_register(ADB_MOUSE, 1, &mouse_ids, mouse_input);
 
-       /* turn off all leds */
-       adb_request(&req, NULL, ADBREQ_SYNC, 3,
-                   ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff);
+       for(i = 0; i < keyboard_ids.nids; i++) {
+           /* turn off all leds */
+           adb_request(&req, NULL, ADBREQ_SYNC, 3,
+           ADB_WRITEREG(keyboard_ids.id[i], KEYB_LEDREG), 0xff, 0xff);
+       }
 
        /* get the keyboard to send separate codes for
           left and right shift, control, option keys. */
-       adb_request(&req, NULL, ADBREQ_SYNC, 3,
-                   ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3);
+       for(i = 0;i < keyboard_ids.nids; i++) {
+           /* get the keyboard to send separate codes for
+           left and right shift, control, option keys. */
+           adb_request(&req, NULL, ADBREQ_SYNC, 3,
+           ADB_WRITEREG(keyboard_ids.id[i], 3), 0, 3);
+       }
 
        led_request.complete = 1;
 
        /* Try to switch the mouse (id 3) to handler 4, for three-button
           mode. (0x20 is Service Request Enable, 0x03 is Device ID). */
-       adb_request(&req, NULL, ADBREQ_SYNC, 3,
-                   ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 );
+       for(i = 0; i < mouse_ids.nids; i++) {
+           adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+                       ADB_READREG(mouse_ids.id[i], 1));
+
+           if ((req.reply_len) &&
+               (req.reply[1] == 0x9a) && (req.reply[2] == 0x21)) {
+
+               printk("aha, trackball found at %d\n", mouse_ids.id[i]);
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i], 3), 0x63, 4 );
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i],1), 00,0x81);
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i],1), 01,0x81);
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i],1), 02,0x81);
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38);
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i],1), 00,0x81);
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i],1), 01,0x81);
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i],1), 02,0x81);
+
+               adb_request(&req, NULL, ADBREQ_SYNC, 3,
+               ADB_WRITEREG(mouse_ids.id[i],1), 03,0x38);
+           }
+       }
 }
 
+void adb_setup_mouse( char *s, int *ints )
+{
+       if (ints[0] >= 1)
+              adb_emulate_buttons = ints[1];
+}
index 65048b0da1d34899c10133c0de19c035fe85fba6..a826daea6a4759ed700965ae1797585584c7a34f 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/prom.h>
 #include <asm/adb.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/hydra.h>
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -71,7 +72,7 @@ void macio_adb_init(void)
        if (adbs == 0)
                return;
 
-#if 1
+#if 0
        { int i;
 
        printk("macio_adb_init: node = %p, addrs =", adbs->node);
@@ -79,16 +80,17 @@ void macio_adb_init(void)
                printk(" %x(%x)", adbs->addrs[i].address, adbs->addrs[i].size);
        printk(", intrs =");
        for (i = 0; i < adbs->n_intrs; ++i)
-               printk(" %x", adbs->intrs[i]);
+               printk(" %x", adbs->intrs[i].line);
        printk("\n"); }
 #endif
        
-       adb = (volatile struct adb_regs *) adbs->addrs->address;
+       adb = (volatile struct adb_regs *)
+               ioremap(adbs->addrs->address, sizeof(struct adb_regs));
 
-       if (request_irq(openpic_to_irq(adbs->intrs[0]), macio_adb_interrupt,
+       if (request_irq(adbs->intrs[0].line, macio_adb_interrupt,
                        0, "ADB", (void *)0)) {
                printk(KERN_ERR "ADB: can't get irq %d\n",
-                      openpic_to_irq(adbs->intrs[0]));
+                      adbs->intrs[0].line);
                return;
        }
 
diff --git a/drivers/macintosh/mackeymap.c b/drivers/macintosh/mackeymap.c
deleted file mode 100644 (file)
index 49c0aab..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/* Do not edit this file! It was automatically generated by   */
-/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
-       0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
-       0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72,
-       0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035,
-       0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f,
-       0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027,
-       0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e,
-       0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
-       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
-       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
-       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
-       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
-       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
-       0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
-       0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b,
-       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
-       0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
-};
-
-static u_short shift_map[NR_KEYS] = {
-       0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58,
-       0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52,
-       0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025,
-       0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f,
-       0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022,
-       0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e,
-       0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
-       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
-       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
-       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
-       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
-       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
-       0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a,
-       0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b,
-       0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117,
-       0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
-};
-
-static u_short altgr_map[NR_KEYS] = {
-       0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
-       0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72,
-       0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
-       0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f,
-       0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200,
-       0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
-       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
-       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
-       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
-       0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f,
-       0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200,
-       0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516,
-       0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517,
-       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117,
-       0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
-};
-
-static u_short ctrl_map[NR_KEYS] = {
-       0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
-       0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
-       0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d,
-       0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f,
-       0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007,
-       0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e,
-       0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703,
-       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
-       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
-       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
-       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
-       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
-       0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
-       0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b,
-       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
-       0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
-};
-
-static u_short shift_ctrl_map[NR_KEYS] = {
-       0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
-       0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
-       0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f,
-       0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200,
-       0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
-       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
-       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
-       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
-       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
-       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117,
-       0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c,
-};
-
-static u_short alt_map[NR_KEYS] = {
-       0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878,
-       0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872,
-       0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835,
-       0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f,
-       0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827,
-       0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e,
-       0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703,
-       0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200,
-       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
-       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
-       0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905,
-       0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200,
-       0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
-       0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b,
-       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
-       0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
-};
-
-static u_short ctrl_alt_map[NR_KEYS] = {
-       0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818,
-       0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812,
-       0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f,
-       0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200,
-       0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
-       0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
-       0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
-       0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
-       0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
-       0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
-       0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
-       0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b,
-       0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
-       0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
-       plain_map, shift_map, altgr_map, 0,
-       ctrl_map, shift_ctrl_map, 0, 0,
-       alt_map, 0, 0, 0,
-       ctrl_alt_map,   0
-};
-
-unsigned int keymap_count = 7;
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
-       '\033', '[', '[', 'A', 0, 
-       '\033', '[', '[', 'B', 0, 
-       '\033', '[', '[', 'C', 0, 
-       '\033', '[', '[', 'D', 0, 
-       '\033', '[', '[', 'E', 0, 
-       '\033', '[', '1', '7', '~', 0, 
-       '\033', '[', '1', '8', '~', 0, 
-       '\033', '[', '1', '9', '~', 0, 
-       '\033', '[', '2', '0', '~', 0, 
-       '\033', '[', '2', '1', '~', 0, 
-       '\033', '[', '2', '3', '~', 0, 
-       '\033', '[', '2', '4', '~', 0, 
-       '\033', '[', '2', '5', '~', 0, 
-       '\033', '[', '2', '6', '~', 0, 
-       '\033', '[', '2', '8', '~', 0, 
-       '\033', '[', '2', '9', '~', 0, 
-       '\033', '[', '3', '1', '~', 0, 
-       '\033', '[', '3', '2', '~', 0, 
-       '\033', '[', '3', '3', '~', 0, 
-       '\033', '[', '3', '4', '~', 0, 
-       '\033', '[', '1', '~', 0, 
-       '\033', '[', '2', '~', 0, 
-       '\033', '[', '3', '~', 0, 
-       '\033', '[', '4', '~', 0, 
-       '\033', '[', '5', '~', 0, 
-       '\033', '[', '6', '~', 0, 
-       '\033', '[', 'M', 0, 
-       '\033', '[', 'P', 0, 
-};
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0;          /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
-       func_buf + 0,
-       func_buf + 5,
-       func_buf + 10,
-       func_buf + 15,
-       func_buf + 20,
-       func_buf + 25,
-       func_buf + 31,
-       func_buf + 37,
-       func_buf + 43,
-       func_buf + 49,
-       func_buf + 55,
-       func_buf + 61,
-       func_buf + 67,
-       func_buf + 73,
-       func_buf + 79,
-       func_buf + 85,
-       func_buf + 91,
-       func_buf + 97,
-       func_buf + 103,
-       func_buf + 109,
-       func_buf + 115,
-       func_buf + 120,
-       func_buf + 125,
-       func_buf + 130,
-       func_buf + 135,
-       func_buf + 140,
-       func_buf + 145,
-       0,
-       0,
-       func_buf + 149,
-       0,
-};
-
-struct kbdiacr accent_table[MAX_DIACR] = {
-       {'`', 'A', '\300'},     {'`', 'a', '\340'},
-       {'\'', 'A', '\301'},    {'\'', 'a', '\341'},
-       {'^', 'A', '\302'},     {'^', 'a', '\342'},
-       {'~', 'A', '\303'},     {'~', 'a', '\343'},
-       {'"', 'A', '\304'},     {'"', 'a', '\344'},
-       {'O', 'A', '\305'},     {'o', 'a', '\345'},
-       {'0', 'A', '\305'},     {'0', 'a', '\345'},
-       {'A', 'A', '\305'},     {'a', 'a', '\345'},
-       {'A', 'E', '\306'},     {'a', 'e', '\346'},
-       {',', 'C', '\307'},     {',', 'c', '\347'},
-       {'`', 'E', '\310'},     {'`', 'e', '\350'},
-       {'\'', 'E', '\311'},    {'\'', 'e', '\351'},
-       {'^', 'E', '\312'},     {'^', 'e', '\352'},
-       {'"', 'E', '\313'},     {'"', 'e', '\353'},
-       {'`', 'I', '\314'},     {'`', 'i', '\354'},
-       {'\'', 'I', '\315'},    {'\'', 'i', '\355'},
-       {'^', 'I', '\316'},     {'^', 'i', '\356'},
-       {'"', 'I', '\317'},     {'"', 'i', '\357'},
-       {'-', 'D', '\320'},     {'-', 'd', '\360'},
-       {'~', 'N', '\321'},     {'~', 'n', '\361'},
-       {'`', 'O', '\322'},     {'`', 'o', '\362'},
-       {'\'', 'O', '\323'},    {'\'', 'o', '\363'},
-       {'^', 'O', '\324'},     {'^', 'o', '\364'},
-       {'~', 'O', '\325'},     {'~', 'o', '\365'},
-       {'"', 'O', '\326'},     {'"', 'o', '\366'},
-       {'/', 'O', '\330'},     {'/', 'o', '\370'},
-       {'`', 'U', '\331'},     {'`', 'u', '\371'},
-       {'\'', 'U', '\332'},    {'\'', 'u', '\372'},
-       {'^', 'U', '\333'},     {'^', 'u', '\373'},
-       {'"', 'U', '\334'},     {'"', 'u', '\374'},
-       {'\'', 'Y', '\335'},    {'\'', 'y', '\375'},
-       {'T', 'H', '\336'},     {'t', 'h', '\376'},
-       {'s', 's', '\337'},     {'"', 'y', '\377'},
-       {'s', 'z', '\337'},     {'i', 'j', '\377'},
-};
-
-unsigned int accent_table_size = 68;
index 3a99b07b235a8b3d53b13826bee4f4a6c0c01abf..38c8429bd11609decb1d9f4907d03baa380cc92c 100644 (file)
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/init.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
 
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
 
 #include "macserial.h"
 
@@ -43,7 +51,6 @@
    in the order we want. */
 #define RECOVERY_DELAY eieio()
 
-struct mac_zschannel *zs_kgdbchan;
 struct mac_zschannel zs_channels[NUM_CHANNELS];
 
 struct mac_serial zs_soft[NUM_CHANNELS];
@@ -51,31 +58,24 @@ int zs_channels_found;
 struct mac_serial *zs_chain;   /* list of all channels */
 
 struct tty_struct zs_ttys[NUM_CHANNELS];
-/** struct tty_struct *zs_constty; **/
 
-/* Console hooks... */
-static int zs_cons_chan = 0;
-struct mac_serial *zs_consinfo = 0;
-struct mac_zschannel *zs_conschan;
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+#endif
 
-/*
- * Initialization values for when a channel is used for
- * kernel gdb support.
- */
-static unsigned char kgdb_regs[16] = {
-       0, 0, 0,                /* write 0, 1, 2 */
-       (Rx8 | RxENABLE),       /* write 3 */
-       (X16CLK | SB1),         /* write 4 */
-       (Tx8 | TxENAB | RTS),   /* write 5 */
-       0, 0, 0,                /* write 6, 7, 8 */
-       (NV),                   /* write 9 */
-       (NRZ),                  /* write 10 */
-       (TCBR | RCBR),          /* write 11 */
-       1, 0,                   /* 38400 baud divisor, write 12 + 13 */
-       (BRENABL),              /* write 14 */
-       (DCDIE)                 /* write 15 */
+#ifdef CONFIG_KGDB
+struct mac_zschannel *zs_kgdbchan;
+static unsigned char scc_inittab[] = {
+       9,  0x80,       /* reset A side (CHRA) */
+       13, 0,          /* set baud rate divisor */
+       12, 1,
+       14, 1,          /* baud rate gen enable, src=rtxc (BRENABL) */
+       11, 0x50,       /* clocks = br gen (RCBR | TCBR) */
+       5,  0x6a,       /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
+       4,  0x44,       /* x16 clock, 1 stop (SB1 | X16CLK)*/
+       3,  0xc1,       /* rx enable, 8 bits (RxENABLE | Rx8)*/
 };
-
+#endif
 #define ZS_CLOCK         3686400       /* Z8530 RTxC input clock rate */
 
 DECLARE_TASK_QUEUE(tq_serial);
@@ -90,8 +90,8 @@ static int serial_refcount;
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
+/*
+ * Debugging.
  */
 #undef SERIAL_DEBUG_INTR
 #undef SERIAL_DEBUG_OPEN
@@ -233,23 +233,6 @@ static inline void zs_rtsdtr(struct mac_serial *ss, int set)
        return;
 }
 
-static inline void kgdb_chaninit(struct mac_serial *ss, int intson, int bps)
-{
-       int brg;
-
-       if (intson) {
-               kgdb_regs[R1] = INT_ALL_Rx;
-               kgdb_regs[R9] |= MIE;
-       } else {
-               kgdb_regs[R1] = 0;
-               kgdb_regs[R9] &= ~MIE;
-       }
-       brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
-       kgdb_regs[R12] = brg;
-       kgdb_regs[R13] = brg >> 8;
-       load_zsregs(ss->zs_channel, kgdb_regs);
-}
-
 /* Utility routines for the Zilog */
 static inline int get_zsbaud(struct mac_serial *ss)
 {
@@ -300,8 +283,6 @@ static _INLINE_ void rs_sched_event(struct mac_serial *info,
        mark_bh(SERIAL_BH);
 }
 
-extern void breakpoint(void);  /* For the KGDB frame character */
-
 static _INLINE_ void receive_chars(struct mac_serial *info,
                                   struct pt_regs *regs)
 {
@@ -313,17 +294,13 @@ static _INLINE_ void receive_chars(struct mac_serial *info,
                stat = read_zsreg(info->zs_channel, R1);
                ch = read_zsdata(info->zs_channel);
 
-#if 0  /* KGDB not yet supported */
-               /* Look for kgdb 'stop' character, consult the gdb documentation
-                * for remote target debugging and arch/sparc/kernel/sparc-stub.c
-                * to see how all this works.
-                */
-               if ((info->kgdb_channel) && (ch =='\003')) {
-                       breakpoint();
-                       continue;
+#ifdef CONFIG_KGDB
+               if (info->kgdb_channel) {
+                       if (ch == 0x03 || ch == '$')
+                               breakpoint();
+                       return;
                }
 #endif
-
                if (!tty)
                        continue;
                tty_flip_buffer_push(tty);
@@ -767,93 +744,6 @@ static void change_speed(struct mac_serial *info)
        restore_flags(flags);
 }
 
-/* This is for console output over ttya/ttyb */
-static void rs_put_char(char ch)
-{
-       struct mac_zschannel *chan = zs_conschan;
-       int loops = 0;
-       unsigned long flags;
-
-       if(!chan)
-               return;
-
-       save_flags(flags); cli();
-       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
-               if (++loops >= 1000000)
-                       break;
-       write_zsdata(chan, ch);
-       restore_flags(flags);
-}
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
-       struct mac_zschannel *chan = zs_kgdbchan;
-
-       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
-               udelay(5);
-       write_zsdata(chan, kgdb_char);
-}
-
-char getDebugChar(void)
-{
-       struct mac_zschannel *chan = zs_kgdbchan;
-
-       while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
-               udelay(5);
-       return read_zsdata(chan);
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void rs_fair_output(void)
-{
-       int left;               /* Output no more than that */
-       unsigned long flags;
-       struct mac_serial *info = zs_consinfo;
-       char c;
-
-       if (info == 0) return;
-       if (info->xmit_buf == 0) return;
-
-       save_flags(flags);  cli();
-       left = info->xmit_cnt;
-       while (left != 0) {
-               c = info->xmit_buf[info->xmit_tail];
-               info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
-               info->xmit_cnt--;
-               restore_flags(flags);
-
-               rs_put_char(c);
-
-               save_flags(flags);  cli();
-               left = MIN(info->xmit_cnt, left-1);
-       }
-
-       restore_flags(flags);
-       return;
-}
-
-/*
- * zs_console_print is registered for printk.
- */
-static void zs_console_print(const char *p)
-{
-       char c;
-
-       while ((c = *(p++)) != 0) {
-               if (c == '\n')
-                       rs_put_char('\r');
-               rs_put_char(c);
-       }
-
-       /* Comment this if you want to have a strict interrupt-driven output */
-       rs_fair_output();
-}
-
 static void rs_flush_chars(struct tty_struct *tty)
 {
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
@@ -1204,6 +1094,10 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
        int error;
        struct mac_serial * info = (struct mac_serial *)tty->driver_data;
 
+#ifdef CONFIG_KGDB
+       if (info->kgdb_channel)
+               return -ENODEV;
+#endif
        if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
                return -ENODEV;
 
@@ -1340,7 +1234,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
         * At this point we stop accepting input.  To do this, we
         * disable the receiver and receive interrupts.
         */
-       /** if (!info->iscons) ... **/
        info->curregs[3] &= ~RxENABLE;
        info->pendregs[3] = info->curregs[3];
        write_zsreg(info->zs_channel, 3, info->curregs[3]);
@@ -1580,9 +1473,10 @@ int rs_open(struct tty_struct *tty, struct file * filp)
                return -ENODEV;
        info = zs_soft + line;
 
-       /* Is the kgdb running over this line? */
+#ifdef CONFIG_KGDB
        if (info->kgdb_channel)
                return -ENODEV;
+#endif
        if (serial_paranoia_check(info, tty->device, "rs_open"))
                return -ENODEV;
 #ifdef SERIAL_DEBUG_OPEN
@@ -1632,6 +1526,13 @@ int rs_open(struct tty_struct *tty, struct file * filp)
                        *tty->termios = info->callout_termios;
                change_speed(info);
        }
+#ifdef CONFIG_SERIAL_CONSOLE
+       if (sercons.cflag && sercons.index == line) {
+               tty->termios->c_cflag = sercons.cflag;
+               sercons.cflag = 0;
+               change_speed(info);
+       }
+#endif
 
        info->session = current->session;
        info->pgrp = current->pgrp;
@@ -1672,15 +1573,15 @@ probe_sccs()
                                continue;
                        }
                        zs_channels[n].control = (volatile unsigned char *)
-                               ch->addrs[0].address;
+                               ioremap(ch->addrs[0].address, 0x1000);
                        zs_channels[n].data = zs_channels[n].control
                                + ch->addrs[0].size / 2;
                        zs_soft[n].zs_channel = &zs_channels[n];
-                       zs_soft[n].irq = ch->intrs[0];
-                       if (request_irq(ch->intrs[0], rs_interrupt, 0,
+                       zs_soft[n].irq = ch->intrs[0].line;
+                       if (request_irq(ch->intrs[0].line, rs_interrupt, 0,
                                        "SCC", &zs_soft[n]))
-                               panic("macserial: can't get irq %d",
-                                     ch->intrs[0]);
+                               printk(KERN_ERR "macserial: can't get irq %d\n",
+                                      ch->intrs[0].line);
                        /* XXX this assumes the prom puts chan A before B */
                        if (n & 1)
                                zs_soft[n].zs_chan_a = &zs_channels[n-1];
@@ -1769,6 +1670,11 @@ int rs_init(void)
        save_flags(flags); cli();
 
        for (channel = 0; channel < zs_channels_found; ++channel) {
+#ifdef CONFIG_KGDB
+               if (zs_soft[channel].kgdb_channel) {
+                       continue;
+               }
+#endif
                zs_soft[channel].clk_divisor = 16;
                zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
 
@@ -1779,17 +1685,15 @@ int rs_init(void)
                        write_zsreg(zs_soft[channel].zs_channel, R9,
                                    (NV | MIE));
                }
-               /* If this is the kgdb line, enable interrupts because we
-                * now want to receive the 'control-c' character from the
-                * client attached to us asynchronously.
-                */
-               if (zs_soft[channel].kgdb_channel)
-                       kgdb_chaninit(&zs_soft[channel], 1,
-                                     zs_soft[channel].zs_baud);
        }
 
        for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
        {
+#ifdef CONFIG_KGDB
+               if (info->kgdb_channel) {
+                       continue;
+               }
+#endif
                info->magic = SERIAL_MAGIC;
                info->port = (int) info->zs_channel->control;
                info->line = i;
@@ -1832,84 +1736,212 @@ void unregister_serial(int line)
        return;
 }
 
-extern void register_console(void (*proc)(const char *));
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
 
 /*
- * Initialization values for when a channel is used for
- * a serial console.
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
  */
-static unsigned char cons_init_regs[16] = {
-       0, 0, 0,                /* write 0, 1, 2 */
-       (Rx8 | RxENABLE),       /* write 3 */
-       (X16CLK | SB1),         /* write 4 */
-       (Tx8 | TxENAB | RTS),   /* write 5 */
-       0, 0, 0,                /* write 6, 7, 8 */
-       0,                      /* write 9 */
-       (NRZ),                  /* write 10 */
-       (TCBR | RCBR),          /* write 11 */
-       1, 0,                   /* 38400 baud divisor, write 12 + 13 */
-       (BRENABL),              /* write 14 */
-       0                       /* write 15 */
-};
+static void serial_console_write(struct console *co, const char *s,
+                                unsigned count)
+{
+}
 
 /*
- * Hooks for running a serial console.  con_init() calls this if the
- * console is being run over one of the serial ports.
- * 'channel' is decoded as 1=modem, 2=printer.
+ *     Receive character from the serial port
  */
-void
-rs_cons_hook(int chip, int out, int channel)
+static int serial_console_wait_key(struct console *co)
 {
-       int brg;
+       return 0;
+}
 
-       if (!out)
-               return;
-       if (zs_consinfo != 0) {
-               printk("rs_cons_hook called twice?\n");
-               return;
+static kdev_t serial_console_device(struct console *c)
+{
+       return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *     Setup initial baud/bits/parity. We do two things here:
+ *     - construct a cflag setting for the first rs_open()
+ *     - initialize the serial port
+ *     Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+       struct serial_state *ser;
+       unsigned cval;
+       int     baud = 9600;
+       int     bits = 8;
+       int     parity = 'n';
+       int     cflag = CREAD | HUPCL | CLOCAL;
+       int     quot = 0;
+       char    *s;
+
+       if (options) {
+               baud = simple_strtoul(options, NULL, 10);
+               s = options;
+               while(*s >= '0' && *s <= '9')
+                       s++;
+               if (*s)
+                       parity = *s++;
+               if (*s)
+                       bits   = *s - '0';
        }
-       if (zs_chain == 0)
-               probe_sccs();
-       --channel;
-       if (channel < 0 || channel >= zs_channels_found) {
-               printk("rs_cons_hook: channel = %d?\n", channel);
-               return;
+
+       /*
+        *      Now construct a cflag setting.
+        */
+       switch(baud) {
+       case 1200:
+               cflag |= B1200;
+               break;
+       case 2400:
+               cflag |= B2400;
+               break;
+       case 4800:
+               cflag |= B4800;
+               break;
+       case 19200:
+               cflag |= B19200;
+               break;
+       case 38400:
+               cflag |= B38400;
+               break;
+       case 57600:
+               cflag |= B57600;
+               break;
+       case 115200:
+               cflag |= B115200;
+               break;
+       case 9600:
+       default:
+               cflag |= B9600;
+               break;
+       }
+       switch(bits) {
+       case 7:
+               cflag |= CS7;
+               break;
+       default:
+       case 8:
+               cflag |= CS8;
+               break;
+       }
+       switch(parity) {
+       case 'o': case 'O':
+               cflag |= PARODD;
+               break;
+       case 'e': case 'E':
+               cflag |= PARENB;
+               break;
        }
+       co->cflag = cflag;
 
-       zs_cons_chan = channel;
-       zs_consinfo = &zs_soft[channel];
-       zs_conschan = zs_consinfo->zs_channel;
-       zs_consinfo->clk_divisor = 16;
-       zs_consinfo->zs_baud = 38400;
-       zs_consinfo->is_cons = 1;
-
-       memcpy(zs_consinfo->curregs, cons_init_regs, sizeof(cons_init_regs));
-       brg = BPS_TO_BRG(zs_consinfo->zs_baud, ZS_CLOCK/16);
-       zs_consinfo->curregs[R12] = brg;
-       zs_consinfo->curregs[R13] = brg >> 8;
-       load_zsregs(zs_conschan, zs_consinfo->curregs);
-
-       register_console(zs_console_print);
-       printk("zs%d: console I/O\n", channel);
+       return 0;
 }
 
+static struct console sercons = {
+       "ttyS",
+       serial_console_write,
+       NULL,
+       serial_console_device,
+       serial_console_wait_key,
+       NULL,
+       serial_console_setup,
+       CON_PRINTBUFFER,
+       -1,
+       0,
+       NULL
+};
+
+/*
+ *     Register console.
+ */
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+{
+       register_console(&sercons);
+       return kmem_start;
+}
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+#ifdef CONFIG_KGDB
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+       struct mac_zschannel *chan = zs_kgdbchan;
+       while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+               udelay(5);
+       write_zsdata(chan, kgdb_char);
+}
+char getDebugChar(void)
+{
+       struct mac_zschannel *chan = zs_kgdbchan;
+       while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+               eieio(); /*barrier();*/
+       return read_zsdata(chan);
+}
+void kgdb_interruptible(int yes)
+{
+       struct mac_zschannel *chan = zs_kgdbchan;
+       int one, nine;
+       nine = read_zsreg(chan, 9);
+       if (yes == 1) {
+               one = EXT_INT_ENAB|INT_ALL_Rx;
+               nine |= MIE;
+               printk("turning serial ints on\n");
+       } else {
+               one = RxINT_DISAB;
+               nine &= ~MIE;
+               printk("turning serial ints off\n");
+       }
+       write_zsreg(chan, 1, one);
+       write_zsreg(chan, 9, nine);
+}
+/* This sets up the serial port we're using, and turns on
+ * interrupts for that channel, so kgdb is usable once we're done.
+ */
+static inline void kgdb_chaninit(struct mac_zschannel *ms, int intson, int bps)
+{
+       int brg;
+       int i, x;
+       volatile char *sccc = ms->control;
+       brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+       printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
+       for (i = 20000; i != 0; --i) {
+               x = *sccc; eieio();
+       }
+       for (i = 0; i < sizeof(scc_inittab); ++i) {
+               write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
+               i++;
+       }
+}
 /* This is called at boot time to prime the kgdb serial debugging
- * serial line.  The 'tty_num' argument is 0 for /dev/ttyS0 and 1
- * for /dev/ttyS1 which is determined in setup_arch() from the
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttya and 1
+ * for /dev/ttyb which is determined in setup_arch() from the
  * boot command line flags.
  */
-void
-rs_kgdb_hook(int tty_num)
+__initfunc(void zs_kgdb_hook(int tty_num))
 {
+       /* Find out how many Z8530 SCCs we have */
        if (zs_chain == 0)
                probe_sccs();
+       zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
        zs_kgdbchan = zs_soft[tty_num].zs_channel;
+       zs_soft[tty_num].change_needed = 0;
        zs_soft[tty_num].clk_divisor = 16;
-       zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+       zs_soft[tty_num].zs_baud = 38400;
        zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
        zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
        /* Turn on transmitter/receiver at 8-bits/char */
-       kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
-       ZS_CLEARERR(zs_kgdbchan);
-       ZS_CLEARFIFO(zs_kgdbchan);
+        kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
+       printk("KGDB: on channel %d initialized\n", tty_num);
+       set_debug_traps(); /* init stub */
 }
+#endif /* ifdef CONFIG_KGDB */
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
new file mode 100644 (file)
index 0000000..6e39367
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Driver for the media bay on the PowerBook 3400 and 2400.
+ *
+ * Copyright (C) 1998 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>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/hdreg.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
+
+struct media_bay_hw {
+       unsigned char   b0;
+       unsigned char   contents;
+       unsigned char   b2;
+       unsigned char   b3;
+       unsigned        feature;
+};
+
+static volatile struct media_bay_hw *mb_addr;
+
+#define MB_CONTENTS()  ((in_8(&mb_addr->contents) >> 4) & 7)
+#define SET_FEATURES(set, clr) \
+       out_le32(&mb_addr->feature, \
+                (in_le32(&mb_addr->feature) & ~(clr)) | (set));
+
+static int media_bay_id = -1;
+static int mb_ready;
+static int mb_last_value;
+static int mb_value_count;
+
+int media_bay_present;
+
+#ifdef CONFIG_BLK_DEV_IDE
+unsigned long mb_cd_base;
+int mb_cd_index = -1;
+int mb_cd_irq;
+
+/* check the busy bit in the media-bay ide interface
+   (assumes the media-bay contains an ide device) */
+#define MB_IDE_READY() ((in_8((volatile unsigned char *) \
+                              (mb_cd_base + 0x70)) & 0x80) == 0)
+#endif
+
+/*
+ * Consider the media-bay ID value stable if it is the same for
+ * this many consecutive samples (at intervals of 1/HZ seconds).
+ */
+#define MB_STABLE_COUNT        4
+
+/*
+ * Hold the media-bay reset signal true for this many ticks
+ * after a device is inserted before releasing it.
+ */
+#define MB_RESET_COUNT 10
+
+/*
+ * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
+ * (or until the device is ready) before registering the IDE interface.
+ */
+#define MB_IDE_WAIT    500
+
+static void poll_media_bay(void);
+static void set_media_bay(int id);
+
+/*
+ * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL
+ * register is always set when there is something in the media bay.
+ * This causes problems for the interrupt code if we attach an interrupt
+ * handler to the media-bay interrupt, because it tends to go into
+ * an infinite loop calling the media bay interrupt handler.
+ * Therefore we do it all by polling the media bay once each tick.
+ */
+
+void
+media_bay_init(void)
+{
+       struct device_node *np;
+
+       np = find_devices("media-bay");
+       if (np == NULL || np->n_addrs == 0)
+               return;
+       mb_addr = (volatile struct media_bay_hw *)
+               ioremap(np->addrs[0].address, sizeof(struct media_bay_hw));
+
+#if 0
+       if (np->n_intrs == 0) {
+               printk(KERN_WARNING "No interrupt for media bay?\n");
+       } else {
+               if (request_irq(np->intrs[0].line, media_bay_intr, 0,
+                               "Media bay", NULL))
+                       printk(KERN_WARNING "Couldn't get IRQ %d for "
+                              "media bay\n", np->intrs[0].line);
+       }
+#endif
+
+       media_bay_present = 1;
+       set_media_bay(MB_CONTENTS());
+       if (media_bay_id != MB_NO) {
+               SET_FEATURES(0, OH_BAY_RESET);
+               mb_ready = 1;
+       }
+}
+
+#if 0
+static void
+media_bay_intr(int irq, void *devid, struct pt_regs *regs)
+{
+       int id = MB_CONTENTS();
+
+       if (id == MB_NO)
+               set_media_bay(id);
+}
+#endif
+
+int
+check_media_bay(int what)
+{
+       return what == media_bay_id && mb_ready;
+}
+
+/*
+ * This procedure runs as a kernel thread to poll the media bay
+ * once each tick and register and unregister the IDE interface
+ * with the IDE driver.  It needs to be a thread because
+ * ide_register can't be called from interrupt context.
+ */
+int
+media_bay_task(void *x)
+{
+       int prev = media_bay_id;
+       int reset_timer = 0;
+#ifdef CONFIG_BLK_DEV_IDE
+       int cd_timer = 0;
+#endif
+
+       strcpy(current->comm, "media-bay");
+       for (;;) {
+               poll_media_bay();
+               if (media_bay_id != prev) {
+                       reset_timer = (media_bay_id != MB_NO)?
+                               MB_RESET_COUNT: 0;
+                       mb_ready = 0;
+#ifdef CONFIG_BLK_DEV_IDE
+                       cd_timer = 0;
+                       if (media_bay_id != MB_CD && mb_cd_index >= 0) {
+                               printk(KERN_DEBUG "Unregistering mb ide\n");
+                               ide_unregister(mb_cd_index);
+                               mb_cd_index = -1;
+                       }
+#endif
+               } else if (reset_timer) {
+                       if (--reset_timer == 0) {
+                               SET_FEATURES(0, OH_BAY_RESET);
+                               mb_ready = 1;
+#ifdef CONFIG_BLK_DEV_IDE
+                               if (media_bay_id == MB_CD && mb_cd_base != 0)
+                                       cd_timer = MB_IDE_WAIT;
+#endif
+                       }
+#ifdef CONFIG_BLK_DEV_IDE
+               } else if (cd_timer && (--cd_timer == 0 || MB_IDE_READY())
+                          && mb_cd_index < 0) {
+                       mb_cd_index = ide_register(mb_cd_base, 0, mb_cd_irq);
+                       printk(KERN_DEBUG "media-bay is ide %d\n", mb_cd_index);
+#endif
+               }
+
+               prev = media_bay_id;
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + 1;
+               schedule();
+               if (signal_pending(current))
+                       return 0;
+       }
+}
+
+void
+poll_media_bay(void)
+{
+       int id = MB_CONTENTS();
+
+       if (id == mb_last_value) {
+               if (id != media_bay_id
+                   && ++mb_value_count >= MB_STABLE_COUNT)
+                       set_media_bay(id);
+       } else {
+               mb_last_value = id;
+               mb_value_count = 0;
+       }
+}
+
+static void
+set_media_bay(int id)
+{
+       u32 clr, set;
+
+       media_bay_id = id;
+       mb_last_value = id;
+       clr = OH_FLOPPY_ENABLE | OH_IDECD_POWER;
+       set = 0;
+       switch (id) {
+       case MB_CD:
+               set = OH_BAY_ENABLE | OH_IDECD_POWER | OH_BAY_IDE_ENABLE;
+               printk(KERN_INFO "media bay contains a CD-ROM drive\n");
+               break;
+       case MB_FD:
+               set = OH_BAY_ENABLE | OH_BAY_FLOPPY_ENABLE | OH_FLOPPY_ENABLE;
+               printk(KERN_INFO "media bay contains a floppy disk drive\n");
+               break;
+       case MB_NO:
+               printk(KERN_INFO "media bay is empty\n");
+               break;
+       default:
+               set = OH_BAY_ENABLE;
+               printk(KERN_INFO "media bay contains an unknown device (%d)\n",
+                      id);
+               break;
+       }
+
+       SET_FEATURES(set, clr);
+       printk(KERN_DEBUG "feature reg now %x\n", in_le32(&mb_addr->feature));
+}
index 34f314df7de4af710aac9d6a0e5643c82e58e882..d35961d795cc423c689db2b85278538af1a84005 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/nvram.h>
 #include <asm/prom.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <linux/selection.h>
 #include "pmac-cons.h"
 #include "platinum.h"
@@ -58,6 +59,10 @@ static unsigned char *base_frame_buffer;
 static struct cmap_regs *cmap_regs;
 static volatile struct platinum_regs *plat_regs;
 
+static unsigned long frame_buffer_phys;
+static unsigned long cmap_regs_phys;
+static unsigned long plat_regs_phys;
+
 /*
  * Register initialization tables for the platinum display.
  *
@@ -403,14 +408,17 @@ map_platinum(struct device_node *dp)
                size = dp->addrs[i].size;
                if (size >= 0x400000) {
                        /* frame buffer - map only 4MB */
-                       frame_buffer = ioremap(addr, 0x400000);
+                       frame_buffer_phys = addr;
+                       frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
                        base_frame_buffer = frame_buffer;
                } else {
                        /* registers */
+                       plat_regs_phys = addr;
                        plat_regs = ioremap(addr, size);
                }
        }
-       cmap_regs = ioremap(0xf301b000, 0x1000);        /* XXX not in prom? */
+       cmap_regs_phys = 0xf301b000;    /* XXX not in prom? */
+       cmap_regs = ioremap(cmap_regs_phys, 0x1000);
 
        /* Grok total video ram */
        plat_regs->reg[16].r = (unsigned)frame_buffer;
@@ -560,10 +568,10 @@ platinum_init()
        display_info.pitch = line_pitch;
        display_info.mode = video_mode;
        strncpy(display_info.name, "platinum", sizeof(display_info.name));
-       display_info.fb_address = (unsigned long) frame_buffer + 0x10;
-       display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
-       display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
-       display_info.disp_reg_address = (unsigned long) &plat_regs;
+       display_info.fb_address = frame_buffer_phys + init->fb_offset + 0x10;
+       display_info.cmap_adr_address = cmap_regs_phys;
+       display_info.cmap_data_address = cmap_regs_phys + 0x30;
+       display_info.disp_reg_address = plat_regs_phys;
 }
 
 int
index 8c199e94fb3f5db2429eccff34a44f1c57779d7e..731d19fe21f7d6a0f0684b3aed9a5a6b595849f6 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/selection.h>
 #include <linux/console_struct.h>
 #include <linux/vt_kern.h>
+#include "../char/console_macros.h"
 #include "pmac-cons.h"
 #include "control.h"
 #include "platinum.h"
@@ -95,6 +96,7 @@ struct mon_map {
        {0x72d, VMODE_832_624_75},      /* 16" RGB (Goldfish) */
        {0x730, VMODE_768_576_50I},     /* PAL (Alternate) */
        {0x73a, VMODE_1152_870_75},     /* 3rd party 19" */
+       {0x73f, VMODE_640_480_67},      /* no sense lines connected at all */
        {-1,    VMODE_640_480_60},      /* catch-all, must be last */
 };
 
@@ -183,12 +185,22 @@ struct display_interface {
          aty_setmode, aty_set_palette, aty_set_blanking },
        { "ATY,XCLAIMVR", map_aty_display, aty_init,
          aty_setmode, aty_set_palette, aty_set_blanking },
-       { "ATY,RAGEII_M", map_aty_display, aty_init, // untested!!
+#if 0 /* problematic */
+       { "ATY,RAGEII_M", map_aty_display, aty_init,
+         aty_setmode, aty_set_palette, aty_set_blanking },
+#endif
+       { "ATY,XCLAIMVRPro", map_aty_display, aty_init,
+         aty_setmode, aty_set_palette, aty_set_blanking },
+       { "ATY,mach64_3DU", map_aty_display, aty_init,
          aty_setmode, aty_set_palette, aty_set_blanking },
 #endif
 #ifdef CONFIG_IMSTT_VIDEO
-       { "IMS,tt128mb", map_imstt_display, imstt_init, 
-         imstt_setmode, imstt_set_palette, imstt_set_blanking },
+       { "IMS,tt128mb", map_imstt_display_ibm, imstt_init, 
+         imstt_setmode, imstt_set_palette_ibm, imstt_set_blanking },
+       { "IMS,tt128mb8", map_imstt_display_tvp, imstt_init, 
+         imstt_setmode, imstt_set_palette_tvp, imstt_set_blanking },
+       { "IMS,tt128mb8A", map_imstt_display_tvp, imstt_init, 
+         imstt_setmode, imstt_set_palette_tvp, imstt_set_blanking },
 #endif
        { NULL }
 };
@@ -592,6 +604,16 @@ console_setmode(struct vc_mode *mode, int doit)
        return err;
 }
 
+int
+console_setcmap(int n_entries, unsigned char *red,
+               unsigned char *green, unsigned char *blue)
+{
+       if (current_display == NULL || current_display->set_palette == NULL)
+               return -EOPNOTSUPP;
+       (*current_display->set_palette)(red, green, blue, 0, n_entries);
+       return 0;
+}
+
 int
 console_powermode(int mode)
 {
@@ -600,7 +622,7 @@ console_powermode(int mode)
        if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
                return -EINVAL;
        if (current_display == NULL || current_display->set_blanking == NULL)
-               return -ENXIO;
+               return mode == VESA_NO_BLANKING? 0: -ENXIO;
        (*current_display->set_blanking)(mode);
        vesa_blanked = mode;
        return 0;
@@ -890,6 +912,7 @@ static int unknown_modes[] = {
 static unsigned char *frame_buffer;
 static unsigned char *unknown_cmap_adr;
 static volatile unsigned char *unknown_cmap_data;
+static unsigned long frame_buffer_phys;
 
 static int map_unknown(struct device_node *dp)
 {
@@ -938,7 +961,8 @@ static int map_unknown(struct device_node *dp)
                address = dp->addrs[i].address;
        }
        printk(KERN_INFO "%s: using address %x\n", dp->full_name, address);
-       frame_buffer = ioremap(address, len);
+       frame_buffer_phys = address;
+       frame_buffer = __ioremap(frame_buffer_phys, len, _PAGE_WRITETHRU);
 
        video_mode = 0;
        color_mode = CMODE_8;
@@ -961,15 +985,15 @@ static int map_unknown(struct device_node *dp)
        display_info.pitch = line_pitch;
        display_info.mode = video_mode;
        strncpy(display_info.name, dp->name, sizeof(display_info.name));
-       display_info.fb_address = (unsigned long) frame_buffer;
+       display_info.fb_address = frame_buffer_phys;
        display_info.cmap_adr_address = 0;
        display_info.cmap_data_address = 0;
        unknown_cmap_adr = 0;
        /* XXX kludge for ati */
        if (strncmp(dp->name, "ATY,", 4) == 0) {
-               display_info.disp_reg_address = address + 0x7ffc00;
-               display_info.cmap_adr_address = address + 0x7ffcc0;
-               display_info.cmap_data_address = address + 0x7ffcc1;
+               display_info.disp_reg_address = frame_buffer_phys + 0x7ffc00;
+               display_info.cmap_adr_address = frame_buffer_phys + 0x7ffcc0;
+               display_info.cmap_data_address = frame_buffer_phys + 0x7ffcc1;
                unknown_cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0;
                unknown_cmap_data = unknown_cmap_adr + 1;
        }
index 63c8fe074c41f73781c075eec6e666f6109c4829..02b81ea72c87535dcc66286113b9acb78bd5fa8c 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/io.h>
 #include <asm/adb.h>
 #include <asm/cuda.h>
+#include <asm/pgtable.h>
 #include <linux/selection.h>
 #include "pmac-cons.h"
 #include "valkyrie.h"
@@ -62,6 +63,10 @@ static unsigned char *frame_buffer;
 static struct cmap_regs *cmap_regs;
 static struct valkyrie_regs *disp_regs;
 
+static unsigned long frame_buffer_phys;
+static unsigned long disp_regs_phys;
+static unsigned long cmap_regs_phys;
+
 /*
  * Register initialization tables for the valkyrie display.
  *
@@ -161,7 +166,7 @@ read_valkyrie_sense()
        __delay(20000);
        sense |= (in_8(&disp_regs->msense) & 0x60) >> 5;
 
-       out_8(&disp_regs->msense, 7);
+       out_8(&disp_regs->msense, 0);
        return sense;
 }
 
@@ -178,9 +183,12 @@ map_valkyrie_display(struct device_node *dp)
 
        /* Map in frame buffer and registers */
        addr = dp->addrs[0].address;
-       frame_buffer = ioremap(addr, 0x100000);
-       disp_regs = ioremap(addr + 0x30a000, 4096);
-       cmap_regs = ioremap(addr + 0x304000, 4096);
+       frame_buffer_phys = addr;
+       frame_buffer = __ioremap(addr, 0x100000, _PAGE_WRITETHRU);
+       disp_regs_phys = addr + 0x30a000;
+       disp_regs = ioremap(disp_regs_phys, 4096);
+       cmap_regs_phys = addr + 0x304000;
+       cmap_regs = ioremap(cmap_regs_phys, 4096);
 
        /* Read the monitor sense value and choose the video mode */
        sense = read_valkyrie_sense();
@@ -266,10 +274,10 @@ valkyrie_init()
        display_info.pitch = line_pitch;
        display_info.mode = video_mode;
        strncpy(display_info.name, "valkyrie", sizeof(display_info.name));
-       display_info.fb_address = (unsigned long) frame_buffer + 0x1000;
-       display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
-       display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
-       display_info.disp_reg_address = (unsigned long) &disp_regs;
+       display_info.fb_address = frame_buffer_phys + 0x1000;
+       display_info.cmap_adr_address = cmap_regs_phys;
+       display_info.cmap_data_address = cmap_regs_phys + 8;
+       display_info.disp_reg_address = disp_regs_phys;
 }
 
 int
index 6185e16c50321cf0c8a28bffc75b99174e59faae..55fd8ea920ef6fe4fdeba8c4db6f76f8c9688216 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include <asm/system.h>
 
 static volatile unsigned char *via;
@@ -98,7 +99,7 @@ via_cuda_init()
        printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
     printk(", intrs =");
     for (i = 0; i < vias->n_intrs; ++i)
-       printk(" %x", vias->intrs[i]);
+       printk(" %x", vias->intrs[i].line);
     printk("\n"); }
 #endif
 
@@ -108,7 +109,7 @@ via_cuda_init()
        if (vias->n_addrs < 1 || vias->n_intrs < 1)
            return;
     }
-    via = (volatile unsigned char *) vias->addrs->address;
+    via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
 
     if (!init_via()) {
        printk(KERN_ERR "init_via failed\n");
@@ -117,8 +118,8 @@ via_cuda_init()
 
     cuda_state = idle;
 
-    if (request_irq(vias->intrs[0], via_interrupt, 0, "VIA", (void *)0)) {
-       printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0]);
+    if (request_irq(vias->intrs[0].line, via_interrupt, 0, "VIA", (void *)0)) {
+       printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0].line);
        return;
     }
 
@@ -238,6 +239,14 @@ cuda_send_request(struct adb_request *req)
 {
     unsigned long flags;
 
+    if (via == NULL) {
+       req->complete = 1;
+       return -ENXIO;
+    }
+    if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {
+       req->complete = 1;
+       return -EINVAL;
+    }
     req->next = 0;
     req->sent = 0;
     req->complete = 0;
@@ -388,6 +397,17 @@ via_interrupt(int irq, void *arg, struct pt_regs *regs)
        if (reading_reply) {
            req = current_req;
            req->reply_len = reply_ptr - req->reply;
+           if (req->data[0] == ADB_PACKET) {
+               /* Have to adjust the reply from ADB commands */
+               if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
+                   /* the 0x2 bit indicates no response */
+                   req->reply_len = 0;
+               } else {
+                   /* leave just the command and result bytes in the reply */
+                   req->reply_len -= 2;
+                   memmove(req->reply, req->reply + 2, req->reply_len);
+               }
+           }
            req->complete = 1;
            current_req = req->next;
            if (req->done)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
new file mode 100644 (file)
index 0000000..922aed0
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * Device driver for the via-pmu on Apple Powermacs.
+ *
+ * The VIA (versatile interface adapter) interfaces to the PMU,
+ * a 6805 microprocessor core whose primary function is to control
+ * battery charging and system power on the PowerBook 3400 and 2400.
+ * The PMU also controls the ADB (Apple Desktop Bus) which connects
+ * to the keyboard and mouse, as well as the non-volatile RAM
+ * and the RTC (real time clock) chip.
+ *
+ * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ */
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/prom.h>
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#include <asm/cuda.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS             0x200           /* skip between registers */
+#define B              0               /* B-side data */
+#define A              RS              /* A-side data */
+#define DIRB           (2*RS)          /* B-side direction (1=output) */
+#define DIRA           (3*RS)          /* A-side direction (1=output) */
+#define T1CL           (4*RS)          /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH           (5*RS)          /* Timer 1 counter (high 8 bits) */
+#define T1LL           (6*RS)          /* Timer 1 latch (low 8 bits) */
+#define T1LH           (7*RS)          /* Timer 1 latch (high 8 bits) */
+#define T2CL           (8*RS)          /* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH           (9*RS)          /* Timer 2 counter (high 8 bits) */
+#define SR             (10*RS)         /* Shift register */
+#define ACR            (11*RS)         /* Auxiliary control register */
+#define PCR            (12*RS)         /* Peripheral control register */
+#define IFR            (13*RS)         /* Interrupt flag register */
+#define IER            (14*RS)         /* Interrupt enable register */
+#define ANH            (15*RS)         /* A-side data, no handshake */
+
+/* Bits in B data register: both active low */
+#define TACK           0x08            /* Transfer acknowledge (input) */
+#define TREQ           0x10            /* Transfer request (output) */
+
+/* Bits in ACR */
+#define SR_CTRL                0x1c            /* Shift register control bits */
+#define SR_EXT         0x0c            /* Shift on external clock */
+#define SR_OUT         0x10            /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET                0x80            /* set bits in IER */
+#define IER_CLR                0               /* clear bits in IER */
+#define SR_INT         0x04            /* Shift register full/empty */
+#define CB1_INT                0x10            /* transition on CB1 input */
+
+static enum pmu_state {
+       idle,
+       sending,
+       intack,
+       reading,
+       reading_intr,
+} pmu_state;
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+static struct adb_request *req_awaiting_reply;
+static unsigned char interrupt_data[32];
+static unsigned char *reply_ptr;
+static int data_index;
+static int data_len;
+static int adb_int_pending;
+static int pmu_adb_flags;
+static int adb_dev_map = 0;
+static struct adb_request bright_req_1, bright_req_2;
+
+static int init_pmu(void);
+static int pmu_queue_request(struct adb_request *req);
+static void pmu_start(void);
+static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
+static int pmu_adb_send_request(struct adb_request *req, int sync);
+static int pmu_adb_autopoll(int on);
+static void send_byte(int x);
+static void recv_byte(void);
+static void pmu_sr_intr(struct pt_regs *regs);
+static void pmu_done(struct adb_request *req);
+static void pmu_handle_data(unsigned char *data, int len,
+                           struct pt_regs *regs);
+static void set_brightness(int level);
+static void set_volume(int level);
+
+/*
+ * This table indicates for each PMU opcode:
+ * - the number of data bytes to be sent with the command, or -1
+ *   if a length byte should be sent,
+ * - the number of response bytes which the PMU will return, or
+ *   -1 if it will send a length byte.
+ */
+static s8 pmu_data_len[256][2] = {
+/*        0       1       2       3       4       5       6       7  */
+/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
+/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*28*/ { 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*30*/ { 4, 0},{20, 0},{ 2, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*38*/ { 0, 4},{ 0,20},{ 1, 1},{ 2, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*48*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
+/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
+/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
+/*60*/ { 2, 0},{-1, 0},{ 2, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
+/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 4, 1},{ 4, 1},
+/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
+/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
+/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
+/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+};
+
+void
+via_pmu_init()
+{
+       struct device_node *vias;
+
+       vias = find_devices("via-pmu");
+       if (vias == 0)
+               return;
+       if (vias->next != 0)
+               printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
+
+#if 0
+       { int i;
+
+       printk("via_pmu_init: node = %p, addrs =", vias->node);
+       for (i = 0; i < vias->n_addrs; ++i)
+               printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
+       printk(", intrs =");
+       for (i = 0; i < vias->n_intrs; ++i)
+               printk(" %x", vias->intrs[i].line);
+       printk("\n"); }
+#endif
+
+       if (vias->n_addrs != 1 || vias->n_intrs != 1) {
+               printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
+                      vias->n_addrs, vias->n_intrs);
+               if (vias->n_addrs < 1 || vias->n_intrs < 1)
+                       return;
+       }
+       via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
+
+       out_8(&via[IER], IER_CLR | 0x7f);       /* disable all intrs */
+
+       pmu_state = idle;
+
+       if (!init_pmu())
+               return;
+
+       if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
+                       (void *)0)) {
+               printk(KERN_ERR "VIA-PMU: can't get irq %d\n",
+                      vias->intrs[0].line);
+               return;
+       }
+
+       /* Enable interrupts */
+       out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
+
+       /* Set function pointers */
+       adb_hardware = ADB_VIAPMU;
+       adb_send_request = pmu_adb_send_request;
+       adb_autopoll = pmu_adb_autopoll;
+
+       bright_req_1.complete = 1;
+       bright_req_2.complete = 1;
+}
+
+static int
+init_pmu()
+{
+       int timeout;
+       struct adb_request req;
+
+       out_8(&via[B], via[B] | TREQ);                  /* negate TREQ */
+       out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK);  /* TACK in, TREQ out */
+
+       pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff);
+       timeout = 100000;
+       while (!req.complete) {
+               if (--timeout < 0) {
+                       printk(KERN_ERR "init_pmu: no response from PMU\n");
+                       return 0;
+               }
+               udelay(10);
+               pmu_poll();
+       }
+
+       /* ack all pending interrupts */
+       timeout = 100000;
+       interrupt_data[0] = 1;
+       while (interrupt_data[0] || pmu_state != idle) {
+               if (--timeout < 0) {
+                       printk(KERN_ERR "init_pmu: timed out acking intrs\n");
+                       return 0;
+               }
+               if (pmu_state == idle)
+                       adb_int_pending = 1;
+               via_pmu_interrupt(0, 0, 0);
+               udelay(10);
+       }
+
+       return 1;
+}
+
+/* Send an ADB command */
+static int
+pmu_adb_send_request(struct adb_request *req, int sync)
+{
+       int i;
+
+       for (i = req->nbytes - 1; i > 0; --i)
+               req->data[i+3] = req->data[i];
+       req->data[3] = req->nbytes - 1;
+       req->data[2] = pmu_adb_flags;
+       req->data[1] = req->data[0];
+       req->data[0] = PMU_ADB_CMD;
+       req->nbytes += 3;
+       req->reply_expected = 1;
+       req->reply_len = 0;
+       i = pmu_queue_request(req);
+       if (i)
+               return i;
+       if (sync) {
+               while (!req->complete)
+                       pmu_poll();
+       }
+       return 0;
+}
+
+/* Enable/disable autopolling */
+static int
+pmu_adb_autopoll(int on)
+{
+       struct adb_request req;
+
+       if (on) {
+               pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
+                           adb_dev_map >> 8, adb_dev_map);
+               pmu_adb_flags = 2;
+       } else {
+               pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF);
+               pmu_adb_flags = 0;
+       }
+       while (!req.complete)
+               pmu_poll();
+       return 0;
+}
+
+/* Construct and send a pmu request */
+int
+pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
+           int nbytes, ...)
+{
+       va_list list;
+       int i;
+
+       if (nbytes < 0 || nbytes > 32) {
+               printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
+               req->complete = 1;
+               return -EINVAL;
+       }
+       req->nbytes = nbytes;
+       req->done = done;
+       va_start(list, nbytes);
+       for (i = 0; i < nbytes; ++i)
+               req->data[i] = va_arg(list, int);
+       va_end(list);
+       if (pmu_data_len[req->data[0]][1] != 0) {
+               req->reply[0] = ADB_RET_OK;
+               req->reply_len = 1;
+       } else
+               req->reply_len = 0;
+       req->reply_expected = 0;
+       return pmu_queue_request(req);
+}
+
+/*
+ * This procedure handles requests written to /dev/adb where the
+ * first byte is CUDA_PACKET or PMU_PACKET.  For CUDA_PACKET, we
+ * emulate a few CUDA requests.
+ */
+int
+pmu_send_request(struct adb_request *req)
+{
+       int i;
+
+       switch (req->data[0]) {
+       case PMU_PACKET:
+               for (i = 0; i < req->nbytes - 1; ++i)
+                       req->data[i] = req->data[i+1];
+               --req->nbytes;
+               if (pmu_data_len[req->data[0]][1] != 0) {
+                       req->reply[0] = ADB_RET_OK;
+                       req->reply_len = 1;
+               } else
+                       req->reply_len = 0;
+               return pmu_queue_request(req);
+       case CUDA_PACKET:
+               switch (req->data[1]) {
+               case CUDA_GET_TIME:
+                       if (req->nbytes != 2)
+                               break;
+                       req->data[0] = PMU_READ_RTC;
+                       req->nbytes = 1;
+                       req->reply_len = 3;
+                       req->reply[0] = CUDA_PACKET;
+                       req->reply[1] = 0;
+                       req->reply[2] = CUDA_GET_TIME;
+                       return pmu_queue_request(req);
+               case CUDA_SET_TIME:
+                       if (req->nbytes != 6)
+                               break;
+                       req->data[0] = PMU_SET_RTC;
+                       req->nbytes = 5;
+                       for (i = 1; i <= 4; ++i)
+                               req->data[i] = req->data[i+1];
+                       req->reply_len = 0;
+                       return pmu_queue_request(req);
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
+int
+pmu_queue_request(struct adb_request *req)
+{
+       unsigned long flags;
+       int nsend;
+
+       if (via == NULL) {
+               req->complete = 1;
+               return -ENXIO;
+       }
+       if (req->nbytes <= 0) {
+               req->complete = 1;
+               return 0;
+       }
+       nsend = pmu_data_len[req->data[0]][0];
+       if (nsend >= 0 && req->nbytes != nsend + 1) {
+               req->complete = 1;
+               return -EINVAL;
+       }
+
+       req->next = 0;
+       req->sent = 0;
+       req->complete = 0;
+       save_flags(flags); cli();
+
+       if (current_req != 0) {
+               last_req->next = req;
+               last_req = req;
+       } else {
+               current_req = req;
+               last_req = req;
+               if (pmu_state == idle)
+                       pmu_start();
+       }
+
+       restore_flags(flags);
+       return 0;
+}
+
+static void
+send_byte(int x)
+{
+       out_8(&via[ACR], 0x1c);
+       out_8(&via[SR], x);
+       out_8(&via[B], via[B] & ~0x10);         /* assert TREQ */
+}
+
+static void
+recv_byte()
+{
+       out_8(&via[ACR], 0x0c);
+       in_8(&via[SR]);         /* resets SR */
+       out_8(&via[B], via[B] & ~0x10);
+}
+
+static void
+pmu_start()
+{
+       unsigned long flags;
+       struct adb_request *req;
+
+       /* assert pmu_state == idle */
+       /* get the packet to send */
+       save_flags(flags); cli();
+       req = current_req;
+       if (req == 0 || pmu_state != idle
+           || (req->reply_expected && req_awaiting_reply))
+               goto out;
+
+       pmu_state = sending;
+       data_index = 1;
+       data_len = pmu_data_len[req->data[0]][0];
+
+       /* set the shift register to shift out and send a byte */
+       send_byte(req->data[0]);
+
+out:
+       restore_flags(flags);
+}
+
+void
+pmu_poll()
+{
+       int ie;
+
+       ie = _disable_interrupts();
+       if (via[IFR] & (SR_INT | CB1_INT))
+               via_pmu_interrupt(0, 0, 0);
+       _enable_interrupts(ie);
+}
+
+static void
+via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+       int intr;
+       int nloop = 0;
+
+       while ((intr = (in_8(&via[IFR]) & (SR_INT | CB1_INT))) != 0) {
+               if (++nloop > 1000) {
+                       printk(KERN_DEBUG "PMU: stuck in intr loop, "
+                              "intr=%x pmu_state=%d\n", intr, pmu_state);
+                       break;
+               }
+               if (intr & SR_INT)
+                       pmu_sr_intr(regs);
+               else if (intr & CB1_INT) {
+                       adb_int_pending = 1;
+                       out_8(&via[IFR], CB1_INT);
+               }
+       }
+       if (pmu_state == idle) {
+               if (adb_int_pending) {
+                       pmu_state = intack;
+                       send_byte(PMU_INT_ACK);
+                       adb_int_pending = 0;
+               } else if (current_req) {
+                       pmu_start();
+               }
+       }
+}
+
+static void
+pmu_sr_intr(struct pt_regs *regs)
+{
+       struct adb_request *req;
+       int bite, timeout;
+
+       if (via[B] & TACK)
+               printk(KERN_DEBUG "PMU: sr_intr but ack still high! (%x)\n",
+                      via[B]);
+
+       /* if reading grab the byte, and reset the interrupt */
+       if ((via[ACR] & SR_OUT) == 0)
+               bite = in_8(&via[SR]);
+       out_8(&via[IFR], SR_INT);
+
+       /* reset TREQ and wait for TACK to go high */
+       out_8(&via[B], via[B] | TREQ);
+       timeout = 3200;
+       while ((in_8(&via[B]) & TACK) == 0) {
+               if (--timeout < 0) {
+                       printk(KERN_ERR "PMU not responding (!ack)\n");
+                       return;
+               }
+               udelay(10);
+       }
+
+       switch (pmu_state) {
+       case sending:
+               req = current_req;
+               if (data_len < 0) {
+                       data_len = req->nbytes - 1;
+                       send_byte(data_len);
+                       break;
+               }
+               if (data_index <= data_len) {
+                       send_byte(req->data[data_index++]);
+                       break;
+               }
+               req->sent = 1;
+               data_len = pmu_data_len[req->data[0]][1];
+               if (data_len == 0) {
+                       pmu_state = idle;
+                       current_req = req->next;
+                       if (req->reply_expected)
+                               req_awaiting_reply = req;
+                       else
+                               pmu_done(req);
+               } else {
+                       pmu_state = reading;
+                       data_index = 0;
+                       reply_ptr = req->reply + req->reply_len;
+                       recv_byte();
+               }
+               break;
+
+       case intack:
+               data_index = 0;
+               data_len = -1;
+               pmu_state = reading_intr;
+               reply_ptr = interrupt_data;
+               recv_byte();
+               break;
+
+       case reading:
+       case reading_intr:
+               if (data_len == -1) {
+                       data_len = bite;
+                       if (bite > 32)
+                               printk(KERN_ERR "PMU: bad reply len %d\n",
+                                      bite);
+               } else {
+                       reply_ptr[data_index++] = bite;
+               }
+               if (data_index < data_len) {
+                       recv_byte();
+                       break;
+               }
+
+               if (pmu_state == reading_intr) {
+                       pmu_handle_data(interrupt_data, data_index, regs);
+               } else {
+                       req = current_req;
+                       current_req = req->next;
+                       req->reply_len += data_index;
+                       pmu_done(req);
+               }
+               pmu_state = idle;
+
+               break;
+
+       default:
+               printk(KERN_ERR "via_pmu_interrupt: unknown state %d?\n",
+                      pmu_state);
+       }
+}
+
+static void
+pmu_done(struct adb_request *req)
+{
+       req->complete = 1;
+       if (req->done)
+               (*req->done)(req);
+}
+
+/* Interrupt data could be the result data from an ADB cmd */
+static void
+pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
+{
+       static int show_pmu_ints = 1;
+
+       if (len < 1) {
+               adb_int_pending = 0;
+               return;
+       }
+       if (data[0] & PMU_INT_ADB) {
+               if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
+                       struct adb_request *req = req_awaiting_reply;
+                       if (req == 0) {
+                               printk(KERN_ERR "PMU: extra ADB reply\n");
+                               return;
+                       }
+                       req_awaiting_reply = 0;
+                       if (len <= 2)
+                               req->reply_len = 0;
+                       else {
+                               memcpy(req->reply, data + 1, len - 1);
+                               req->reply_len = len - 1;
+                       }
+                       pmu_done(req);
+               } else {
+                       adb_input(data+1, len-1, regs, 1);
+               }
+       } else {
+               if (data[0] == 0x08 && len == 3) {
+                       /* sound/brightness buttons pressed */
+                       set_brightness(data[1]);
+                       set_volume(data[2]);
+               } else if (show_pmu_ints
+                          && !(data[0] == PMU_INT_TICK && len == 1)) {
+                       int i;
+                       printk(KERN_DEBUG "pmu intr");
+                       for (i = 0; i < len; ++i)
+                               printk(" %.2x", data[i]);
+                       printk("\n");
+               }
+       }
+}
+
+int backlight_bright = -1;
+int backlight_enabled = 0;
+
+#define LEVEL_TO_BRIGHT(lev)   ((lev) < 8? 0x7f: 0x4a - ((lev) >> 2))
+
+void
+pmu_enable_backlight(int on)
+{
+       struct adb_request req;
+
+       if (on) {
+               if (backlight_bright < 0) {
+                       pmu_request(&req, NULL, 2, 0xd9, 0);
+                       while (!req.complete)
+                               pmu_poll();
+                       backlight_bright = LEVEL_TO_BRIGHT(req.reply[1]);
+               }
+               pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+                           backlight_bright);
+               while (!req.complete)
+                       pmu_poll();
+       }
+       pmu_request(&req, NULL, 2, PMU_BACKLIGHT_CTRL, on? 0x81: 1);
+       while (!req.complete)
+               pmu_poll();
+       backlight_enabled = on;
+}
+
+static void
+set_brightness(int level)
+{
+       backlight_bright = LEVEL_TO_BRIGHT(level);
+       if (bright_req_1.complete)
+               pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+                           backlight_bright);
+       if (bright_req_2.complete) {
+               backlight_enabled = backlight_bright < 0x7f;
+               pmu_request(&bright_req_2, NULL, 2, PMU_BACKLIGHT_CTRL,
+                           backlight_enabled? 0x81: 1);
+       }
+}
+
+static void
+set_volume(int level)
+{
+}
index 7ecc021703dc9d1f6f4c05924386fcc37c8962f9..7396e2e11b623b7368572ad6e6dae1c4147ae14c 100644 (file)
@@ -745,7 +745,7 @@ int parport_pc_init(int *io, int *irq, int *dma)
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
 static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
-static char *irq = NULL;
+static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
index 5c582ef47386a5868ec071c5f8245a4ceeda0018..6ce7d69d301f505396ae3fe8f92dcfa6a8cb7380 100644 (file)
@@ -398,6 +398,7 @@ void parport_release(struct pardevice *dev)
 {
        struct parport *port = dev->port;
        struct pardevice *pd;
+       unsigned long flags;
 
        /* Make sure that dev is the current device */
        if (port->cad != dev) {
@@ -405,7 +406,9 @@ void parport_release(struct pardevice *dev)
                       "when not owner\n", port->name, dev->name);
                return;
        }
+       spin_lock_irqsave(&port->lock, flags);
        port->cad = NULL;
+       spin_unlock_irqrestore(&port->lock, flags);
 
        /* Save control registers */
        port->ops->save_state(port, dev->state);
@@ -442,25 +445,23 @@ void parport_release(struct pardevice *dev)
        }
 }
 
-void parport_parse_irqs(int nports, const char *irqstr, int irqval[])
+void parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
 {
        unsigned int i;
-       for (i = 0; i < nports && irqstr; i++) {
-               if (!strncmp(irqstr, "auto", 4))
+       for (i = 0; i < nports && irqstr[i]; i++) {
+               if (!strncmp(irqstr[i], "auto", 4))
                        irqval[i] = PARPORT_IRQ_AUTO;
-               else if (!strncmp(irqstr, "none", 4))
+               else if (!strncmp(irqstr[i], "none", 4))
                        irqval[i] = PARPORT_IRQ_NONE;
                else {
                        char *ep;
-                       unsigned long r = simple_strtoul(irqstr, &ep, 0);
-                       if (ep != irqstr)
+                       unsigned long r = simple_strtoul(irqstr[i], &ep, 0);
+                       if (ep != irqstr[i])
                                irqval[i] = r;
                        else {
-                               printk("parport: bad irq specifier `%s'\n", irqstr);
+                               printk("parport: bad irq specifier `%s'\n", irqstr[i]);
                                return;
                        }
                }
-               irqstr = strchr(irqstr, ',');
-               if (irqstr) irqstr++;
        }
 }
index d85b7c4141e3bad09e49d764be720cd68c0e957f..9d94f7bae172c11471b085dc27996e9a39383526 100644 (file)
@@ -42,7 +42,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       fi
     fi
     tristate '3c509/3c579 support' CONFIG_EL3
-    tristate '3c590 series (592/595/597) "Vortex" support' CONFIG_VORTEX
+    tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
   fi
   bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
   bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
index 25f04ddead35e06906ee2e05e3ec956a1e22f2d5..bd97a51b3af850c1892868febdaf3639c37482ec 100644 (file)
@@ -2,7 +2,7 @@
 ** hp100.c 
 ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
 **
-** $Id: hp100.c,v 1.56 1998/03/04 15:23:59 perex Exp perex $
+** $Id: hp100.c,v 1.57 1998/04/10 16:27:23 perex Exp perex $
 **
 ** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
 ** Extended for new busmaster capable chipsets by 
 **       -  some updates for EISA version of card
 **
 **
-** This source/code is public free; you can distribute it and/or modify 
-** it under terms of the GNU General Public License (published by the
-** Free Software Foundation) either version two of this License, or any 
-** later version.
+**   This code 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.
+**
+**   This code 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; if not, write to the Free Software
+**   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**
+** 1.56 -> 1.57
+**   - updates for new PCI interface for 2.1 kernels
 **
 ** 1.55 -> 1.56
 **   - removed printk in misc. interrupt and update statistics to allow
 #include <linux/config.h>  /* for CONFIG_PCI */
 #include <linux/delay.h>
 
-#if LINUX_VERSION_CODE < 0x020100
+#if LINUX_VERSION_CODE >= 0x020100
+#define LINUX_2_1
+typedef struct net_device_stats hp100_stats_t;
+EXPORT_NO_SYMBOLS;
+#else
+#include <linux/bios32.h>
 #define ioremap vremap
 #define iounmap vfree
 typedef struct enet_statistics hp100_stats_t;
-#else
-#define LINUX_2_1
-typedef struct net_device_stats hp100_stats_t;
 #endif
 
 #ifndef __initfunc
@@ -135,14 +150,14 @@ typedef struct net_device_stats hp100_stats_t;
 #define PCI_DEVICE_ID_COMPEX2_100VG 0x0005
 #endif
 
-#define HP100_REGION_SIZE  0x20 /* for ioports */
+#define HP100_REGION_SIZE      0x20 /* for ioports */
 
-#define HP100_MAX_PACKET_SIZE  (1536+4)
-#define HP100_MIN_PACKET_SIZE  60
+#define HP100_MAX_PACKET_SIZE  (1536+4)
+#define HP100_MIN_PACKET_SIZE  60
 
 #ifndef HP100_DEFAULT_RX_RATIO
 /* default - 75% onboard memory on the card are used for RX packets */
-#define HP100_DEFAULT_RX_RATIO  75
+#define HP100_DEFAULT_RX_RATIO 75
 #endif
 
 #ifndef HP100_DEFAULT_PRIORITY_TX
@@ -175,8 +190,12 @@ struct hp100_private {
   u_short priority_tx;    /* != 0 - priority tx */
   u_short mode;           /* PIO, Shared Mem or Busmaster */
   u_char bus;
+#ifndef LINUX_2_1
   u_char pci_bus;
   u_char pci_device_fn;
+#else
+  struct pci_dev *pci_dev;
+#endif
   short mem_mapped;      /* memory mapped access */
   u_int *mem_ptr_virt;    /* virtual memory mapped area, maybe NULL */
   u_int *mem_ptr_phys;   /* physical memory mapped area */
@@ -281,7 +300,11 @@ MODULE_PARM( hp100_mode, "1i" );
  *  prototypes
  */
 
-static int  hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn  );
+#ifdef LINUX_2_1
+static int  hp100_probe1( struct device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev );
+#else
+static int  hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn );
+#endif
 static int  hp100_open( struct device *dev );
 static int  hp100_close( struct device *dev );
 static int  hp100_start_xmit( struct sk_buff *skb, struct device *dev );
@@ -330,9 +353,6 @@ __initfunc(int hp100_probe( struct device *dev ))
   int ioaddr = 0;
 #ifdef CONFIG_PCI
   int pci_start_index = 0;
-#ifdef LINUX_2_1
-  struct pci_dev *pdev;
-#endif
 #endif
 
 #ifdef HP100_DEBUG_B
@@ -344,12 +364,24 @@ __initfunc(int hp100_probe( struct device *dev ))
     {
       if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL;
       if ( base_addr < 0x400 )
+#ifdef LINUX_2_1
+        return hp100_probe1( dev, base_addr, HP100_BUS_ISA, NULL );
+#else
         return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 );
+#endif
       if ( EISA_bus && base_addr >= 0x1c38 && ( (base_addr - 0x1c38) & 0x3ff ) == 0 )
+#ifdef LINUX_2_1
+        return hp100_probe1( dev, base_addr, HP100_BUS_EISA, NULL );
+#else
         return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 );
+#endif
 #ifdef CONFIG_PCI
+#ifdef LINUX_2_1
+      printk( "hp100: %s: You must specify card # in i/o address parameter for PCI bus...", dev->name );
+#else
       printk( "hp100: %s: You may specify card # in i/o address parameter for PCI bus...", dev->name );
       return hp100_probe1( dev, base_addr, HP100_BUS_PCI, 0, 0 );
+#endif
 #else
       return -ENODEV;
 #endif
@@ -365,13 +397,54 @@ __initfunc(int hp100_probe( struct device *dev ))
   /* at first - scan PCI bus(es) */
 
 #ifdef CONFIG_PCI
-  if ( pci_present() )
+  if ( pcibios_present() )
     {
       int pci_index;
+#ifdef LINUX_2_1
+      struct pci_dev *pci_dev = NULL;
+      int pci_id_index;
+      u_short pci_command;
+#endif
 
 #ifdef HP100_DEBUG_PCI
       printk( "hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name );
 #endif
+#ifdef LINUX_2_1
+      pci_index = 0;
+      for ( pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++ ) {
+        while ( (pci_dev = pci_find_device( hp100_pci_ids[ pci_id_index ].vendor,
+                                           hp100_pci_ids[ pci_id_index ].device,
+                                           pci_dev )) != NULL ) {
+          if ( pci_index < (pci_start_index & 7) ) {
+            pci_index++;
+            continue;
+          }
+          /* found... */
+          ioaddr = pci_dev -> base_address[ 0 ] & ~3;
+          if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
+          pci_read_config_word( pci_dev, PCI_COMMAND, &pci_command );
+          if ( !( pci_command & PCI_COMMAND_IO ) ) {
+#ifdef HP100_DEBUG
+            printk( "hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name );
+#endif
+            pci_command |= PCI_COMMAND_IO;
+            pci_write_config_word( pci_dev, PCI_COMMAND, pci_command );
+          }
+          if ( !( pci_command & PCI_COMMAND_MASTER ) ) {
+#ifdef HP100_DEBUG
+            printk( "hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name );
+#endif
+            pci_command |= PCI_COMMAND_MASTER;
+            pci_write_config_word( pci_dev, PCI_COMMAND, pci_command );
+          }
+#ifdef HP100_DEBUG
+          printk( "hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr );
+#endif
+         if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_dev ) == 0 )
+           return 0;
+        }
+      }      
+#else /* old PCI interface */
       for ( pci_index = pci_start_index & 7; pci_index < 8; pci_index++ )
         {
           u_char pci_bus, pci_device_fn;
@@ -386,14 +459,8 @@ __initfunc(int hp100_probe( struct device *dev ))
           break;
 
          __pci_found:
-
-#ifdef LINUX_2_1
-         pdev = pci_find_slot(pci_bus, pci_device_fn);
-         ioaddr = pdev->base_address[0];
-#else
           pcibios_read_config_dword( pci_bus, pci_device_fn,
                                      PCI_BASE_ADDRESS_0, &ioaddr );
-#endif
 
           ioaddr &= ~3;    /* remove I/O space marker in bit 0. */
 
@@ -425,6 +492,7 @@ __initfunc(int hp100_probe( struct device *dev ))
          if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 )
            return 0;
         }
+#endif
     }
   if ( pci_start_index > 0 ) return -ENODEV;
 #endif /* CONFIG_PCI */
@@ -433,21 +501,33 @@ __initfunc(int hp100_probe( struct device *dev ))
   for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 )
     {
       if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
+#ifdef LINUX_2_1
+      if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, NULL ) == 0 ) return 0;
+#else
       if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0;
+#endif
     }
 
   /* Third Probe all ISA possible port regions */
   for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 )
     {
       if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
+#ifdef LINUX_2_1
+      if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, NULL ) == 0 ) return 0;
+#else
       if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0;
+#endif
     }
 
   return -ENODEV;
 }
 
 \f
+#ifdef LINUX_2_1
+__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev ))
+#else
 __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ))
+#endif
 {
   int i;
 
@@ -711,15 +791,19 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus,
   /* Initialise the "private" data structure for this card. */
   if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL)
     return -ENOMEM;
-  memset( dev->priv, 0, sizeof(struct hp100_private) );
 
   lp = (struct hp100_private *)dev->priv;
+  memset( lp, 0, sizeof( struct hp100_private ) );
   lp->id = eid;
   lp->chip = chip;
   lp->mode = local_mode;
-  lp->pci_bus = pci_bus;
   lp->bus = bus;
+#ifdef LINUX_2_1
+  lp->pci_dev = pci_dev;
+#else
+  lp->pci_bus = pci_bus;
   lp->pci_device_fn = pci_device_fn;
+#endif
   lp->priority_tx = hp100_priority_tx;
   lp->rx_ratio = hp100_rx_ratio;
   lp->mem_ptr_phys = mem_ptr_phys;
@@ -751,10 +835,18 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus,
   dev->set_multicast_list = &hp100_set_multicast_list;
 
   /* Ask the card for which IRQ line it is configured */
-  hp100_page( HW_MAP );
-  dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK;
-  if ( dev->irq == 2 )
-    dev->irq = 9;
+#ifdef LINUX_2_1
+  if ( bus == HP100_BUS_PCI ) {
+    dev->irq = pci_dev->irq;
+  } else {
+#endif
+    hp100_page( HW_MAP );
+    dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK;
+    if ( dev->irq == 2 )
+      dev->irq = 9;
+#ifdef LINUX_2_1
+  }
+#endif
 
   if(lp->mode==1) /* busmaster */
     dev->dma=4; 
index cf1e9e903d336d43539ef16e348ab2357dc683c1..ea836aaa0f43971851ddcce171515d236850e925 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 #include "mace.h"
 
 #define N_RX_RING      8
@@ -117,21 +118,22 @@ mace_probe(struct device *dev)
 
        mp = (struct mace_data *) dev->priv;
        dev->base_addr = maces->addrs[0].address;
-       mp->mace = (volatile struct mace *) maces->addrs[0].address;
-       dev->irq = maces->intrs[0];
+       mp->mace = (volatile struct mace *)
+               ioremap(maces->addrs[0].address, 0x1000);
+       dev->irq = maces->intrs[0].line;
 
        if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
            printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
            return -EAGAIN;
        }
-       if (request_irq(maces->intrs[1], mace_txdma_intr, 0, "MACE-txdma",
+       if (request_irq(maces->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma",
                        dev)) {
-           printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[1]);
+           printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[1].line);
            return -EAGAIN;
        }
-       if (request_irq(maces->intrs[2], mace_rxdma_intr, 0, "MACE-rxdma",
+       if (request_irq(maces->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma",
                        dev)) {
-           printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[2]);
+           printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[2].line);
            return -EAGAIN;
        }
 
@@ -155,10 +157,12 @@ mace_probe(struct device *dev)
 
        mp = (struct mace_data *) dev->priv;
        mp->maccc = ENXMT | ENRCV;
-       mp->tx_dma = (volatile struct dbdma_regs *) maces->addrs[1].address;
-       mp->tx_dma_intr = maces->intrs[1];
-       mp->rx_dma = (volatile struct dbdma_regs *) maces->addrs[2].address;
-       mp->rx_dma_intr = maces->intrs[2];
+       mp->tx_dma = (volatile struct dbdma_regs *)
+               ioremap(maces->addrs[1].address, 0x1000);
+       mp->tx_dma_intr = maces->intrs[1].line;
+       mp->rx_dma = (volatile struct dbdma_regs *)
+               ioremap(maces->addrs[2].address, 0x1000);
+       mp->rx_dma_intr = maces->intrs[2].line;
 
        mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
        mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
@@ -169,8 +173,6 @@ mace_probe(struct device *dev)
        init_timer(&mp->tx_timeout);
        mp->timeout_active = 0;
 
-       mace_reset(dev);
-
        dev->open = mace_open;
        dev->stop = mace_close;
        dev->hard_start_xmit = mace_xmit_start;
@@ -260,6 +262,9 @@ static int mace_open(struct device *dev)
     struct sk_buff *skb;
     unsigned char *data;
 
+    /* reset the chip */
+    mace_reset(dev);
+
     /* initialize list of sk_buffs for receiving and set up recv dma */
     memset((char *)mp->rx_cmds, 0, N_RX_RING * sizeof(struct dbdma_cmd));
     cp = mp->rx_cmds;
@@ -410,6 +415,10 @@ static int mace_xmit_start(struct sk_buff *skb, struct device *dev)
        ++mp->tx_active;
        mace_set_timeout(dev);
     }
+    if (++next >= N_TX_RING)
+       next = 0;
+    if (next == mp->tx_empty)
+       dev->tbusy = 1;
     restore_flags(flags);
 
     return 0;
@@ -520,6 +529,8 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
     i = mp->tx_empty;
     while (mb->pr & XMTSV) {
+       del_timer(&mp->tx_timeout);
+       mp->timeout_active = 0;
        /*
         * Clear any interrupt indication associated with this status
         * word.  This appears to unlatch any error indication from
@@ -533,8 +544,6 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            eieio();
            mp->tx_bad_runt = 0;
            mb->xmtfc = AUTO_PAD_XMIT;
-           del_timer(&mp->tx_timeout);
-           mp->timeout_active = 0;
            continue;
        }
        dstat = ld_le32(&td->status);
@@ -562,7 +571,8 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        }
        fs = mb->xmtfs;
        if ((fs & XMTSV) == 0) {
-           printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat);
+           printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n",
+                  fs, xcount, dstat);
        }
        cp = mp->tx_cmds + NCMDS_TX * i;
        stat = ld_le16(&cp->xfer_status);
@@ -571,6 +581,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
             * Check whether there were in fact 2 bytes written to
             * the transmit FIFO.
             */
+           udelay(1);
            x = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
            if (x != 0) {
                /* there were two bytes with an end-of-packet indication */
@@ -579,17 +590,21 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            } else {
                /*
                 * Either there weren't the two bytes buffered up, or they
-                * didn't have an end-of-packet indication.  Maybe we ought
-                * to flush the transmit FIFO just in case (by setting the
+                * didn't have an end-of-packet indication.
+                * We flush the transmit FIFO just in case (by setting the
                 * XMTFWU bit with the transmitter disabled).
                 */
-               mb->xmtfc = AUTO_PAD_XMIT;
-               eieio();
+               out_8(&mb->maccc, mb->maccc & ~ENXMT);
+               out_8(&mb->fifocc, mb->fifocc | XMTFWU);
+               udelay(1);
+               out_8(&mb->maccc, mb->maccc | ENXMT);
+               out_8(&mb->xmtfc, AUTO_PAD_XMIT);
            }
        }
        /* dma should have finished */
        if (i == mp->tx_fill) {
-           printk(KERN_DEBUG "mace: tx ring ran out? (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat);
+           printk(KERN_DEBUG "mace: tx ring ran out? (fs=%x xc=%d ds=%x)\n",
+                  fs, xcount, dstat);
            continue;
        }
        /* Update stats */
@@ -607,11 +622,9 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            i = 0;
        mace_last_fs = fs;
        mace_last_xcount = xcount;
-       del_timer(&mp->tx_timeout);
-       mp->timeout_active = 0;
     }
 
-    if (i != mp->tx_empty && mp->tx_fullup) {
+    if (i != mp->tx_empty) {
        mp->tx_fullup = 0;
        dev->tbusy = 0;
        mark_bh(NET_BH);
@@ -656,9 +669,6 @@ static void mace_tx_timeout(unsigned long data)
     mace_handle_misc_intrs(mp, mb->ir);
 
     cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
-    printk(KERN_DEBUG "mace: tx dmastat=%x %x bad_runt=%d pr=%x fs=%x fc=%x\n",
-          ld_le32(&td->status), ld_le16(&cp->xfer_status), mp->tx_bad_runt,
-          mb->pr, mb->xmtfs, mb->fifofc);
 
     /* turn off both tx and rx and reset the chip */
     mb->maccc = 0;
@@ -685,11 +695,9 @@ static void mace_tx_timeout(unsigned long data)
            i = 0;
        mp->tx_empty = i;
     }
-    if (mp->tx_fullup) {
-       mp->tx_fullup = 0;
-       dev->tbusy = 0;
-       mark_bh(NET_BH);
-    }
+    mp->tx_fullup = 0;
+    dev->tbusy = 0;
+    mark_bh(NET_BH);
     if (i != mp->tx_fill) {
        cp = mp->tx_cmds + NCMDS_TX * i;
        out_le16(&cp->xfer_status, 0);
index a397c83b4ff541cf2c8c3649667ee6702c872f4c..30b7ec0cedb5e2765eb7ee03f808dd66a961f40a 100644 (file)
@@ -164,7 +164,7 @@ struct mace {
 /* Bits in UTR */
 #define RTRE           0x80    /* reserved test register enable. DON'T SET. */
 #define RTRD           0x40    /* reserved test register disable.  Sticky */
-#define RPA            0x20    /* accept runt packets */
+#define RPAC           0x20    /* accept runt packets */
 #define FCOLL          0x10    /* force collision */
 #define RCVFCSE                0x08    /* receive FCS enable */
 #define LOOP_NONE      0x00    /* no loopback */
index 6c179167414a3d9dde04dcf7e03cfab0378f9aff..ebe502604a8589f1f16ec53dbaba84908bdb2605 100644 (file)
@@ -1408,27 +1408,15 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp,
 {
        int reset = 0;
 
-       printk("%s: Error interrupt for happy meal, status = %08lx\n",
-              hp->dev->name, status);
-
-       if(status &
-          (GREG_STAT_RCNTEXP|GREG_STAT_ACNTEXP|GREG_STAT_CCNTEXP|GREG_STAT_LCNTEXP)) {
-               /* Some stupid counter expired, we should be not
-                * have interrupts for this enabled, but we check
-                * for it anyways.
-                */
-
-               printk("%s: Happy Meal counters expired [ ", hp->dev->name);
-               if(status & GREG_STAT_RCNTEXP)
-                       printk("ReceiveFrame ");
-               if(status & GREG_STAT_ACNTEXP)
-                       printk("AlignError ");
-               if(status & GREG_STAT_CCNTEXP)
-                       printk("CrcError ");
-               if(status & GREG_STAT_LCNTEXP)
-                       printk("LengthError ");
-               printk("]\n");
-       }
+       /* Only print messages for non-counter related interrupts. */
+       if(status & (GREG_STAT_RFIFOVF | GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND |
+                    GREG_STAT_MAXPKTERR | GREG_STAT_NORXD | GREG_STAT_RXERR |
+                    GREG_STAT_RXPERR | GREG_STAT_RXTERR | GREG_STAT_EOPERR |
+                    GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR |
+                    GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR |
+                    GREG_STAT_SLVPERR))
+               printk("%s: Error interrupt for happy meal, status = %08lx\n",
+                      hp->dev->name, status);
 
        if(status & GREG_STAT_RFIFOVF) {
                /* The receive FIFO overflowwed, usually a DMA error. */
@@ -1436,11 +1424,6 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp,
                reset = 1;
        }
 
-       if(status & GREG_STAT_CVCNTEXP) {
-               /* See above about counter expiration... */
-               printk("%s: Code Violation error counter expired.\n", hp->dev->name);
-       }
-
        if(status & GREG_STAT_STSTERR) {
                /* BigMAC SQE link test failed. */
                printk("%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name);
@@ -1462,32 +1445,6 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp,
                reset = 1;
        }
 
-       if(status & (GREG_STAT_NCNTEXP|GREG_STAT_ECNTEXP|GREG_STAT_LCCNTEXP|
-                    GREG_STAT_FCNTEXP)) {
-               /* More stupid error counters... */
-               printk("%s: Happy Meal counters expired [ ", hp->dev->name);
-               if(status & GREG_STAT_NCNTEXP)
-                       printk("NormalCollision ");
-               if(status & GREG_STAT_ECNTEXP)
-                       printk("ExcessCollision ");
-               if(status & GREG_STAT_LCCNTEXP)
-                       printk("LateCollision ");
-               if(status & GREG_STAT_FCNTEXP)
-                       printk("FirstCollision ");
-               printk("]\n");
-       }
-
-       if(status & GREG_STAT_DTIMEXP) {
-               /* Defer-timer expired.  Probably means the happy meal needed
-                * to back off too much before it could transmit one frame.
-                */
-#if 0          /* XXX This isn't worth reporting and is in fact a normal condition. */
-               printk("%s: Transmit defer timer expired, subnet congested?\n",
-                      hp->dev->name);
-               reset = 1;
-#endif
-       }
-
        if(status & GREG_STAT_NORXD) {
                /* AIEEE, out of receive descriptors.  Check out our drop
                 * processing in happy_meal_rx to see how we try very hard
index 093f7a181566d9264d7939bef798e3ee32926b0e..01676c741b43befab48bbbe0ce63da4fed3a4332 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.69 1998/01/09 16:42:52 jj Exp $
+/* $Id: sunlance.c,v 1.74 1998/02/12 07:37:25 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *     Written 1995, 1996 by Miguel de Icaza
@@ -103,6 +103,9 @@ static char *lancedma = "LANCE DMA";
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+#include <asm/idprom.h>
+#include <asm/machines.h>
+
 /* Define: 2^4 Tx buffers and 2^4 Rx buffers */
 #ifndef LANCE_LOG_TX_BUFFERS
 #define LANCE_LOG_TX_BUFFERS 4
@@ -1037,7 +1040,7 @@ sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev,
                                                  "busmaster-regval",
                                                  (LE_C3_BSWP | LE_C3_ACON |
                                                   LE_C3_BCON));
-    
+
        lp->ll = ll;
        lp->name = lancestr;
        lp->ledma = ledma;
@@ -1119,8 +1122,9 @@ no_link_test:
        dev->hard_start_xmit = &lance_start_xmit;
        dev->get_stats = &lance_get_stats;
        dev->set_multicast_list = &lance_set_multicast;
-    
+
        dev->irq = (unsigned char) sdev->irqs [0].pri;
+
        dev->dma = 0;
        ether_setup (dev);
 
@@ -1144,6 +1148,31 @@ find_ledma (struct linux_sbus_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_SUN4
+
+#include <asm/sun4paddr.h>
+
+/* Find all the lance cards on the system and initialize them */
+__initfunc(int sparc_lance_probe (struct device *dev))
+{
+       static struct linux_sbus_device sdev;
+       static int called = 0;
+
+       if(called)
+               return ENODEV;
+       called++;
+
+       if (idprom->id_machtype == (SM_SUN4|SM_4_330)) {
+               memset (&sdev, 0, sizeof(sdev));
+               sdev.reg_addrs[0].phys_addr = SUN4_300_ETH_PHYSADDR;
+               sdev.irqs[0].pri = 6;
+               return sparc_lance_init(dev, &sdev, 0, 0);
+       }
+       return ENODEV;
+}
+
+#else /* !CONFIG_SUN4 */
+
 /* Find all the lance cards on the system and initialize them */
 __initfunc(int sparc_lance_probe (struct device *dev))
 {
@@ -1152,10 +1181,11 @@ __initfunc(int sparc_lance_probe (struct device *dev))
        struct Linux_SBus_DMA *ledma = 0;
        static int called = 0;
        int cards = 0, v;
-    
+
        if(called)
                return ENODEV;
        called++;
+
        for_each_sbus (bus) {
                for_each_sbusdev (sdev, bus) {
                        if (cards) dev = NULL;
@@ -1186,6 +1216,7 @@ __initfunc(int sparc_lance_probe (struct device *dev))
                return ENODEV;
        return 0;
 }
+#endif /* !CONFIG_SUN4 */
 
 #ifdef MODULE
 
index 4ce9459836ce5ed11ae006d85459433b18a16758..ae9315679e290a2daf3492ff76e672289d6c17a5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: pci.c,v 1.71 1998/03/30 11:14:35 mj Exp $
+ *     $Id: pci.c,v 1.79 1998/04/17 16:25:24 mj Exp $
  *
  *     PCI Bus Services
  *
 
 #include <asm/page.h>
 
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
 struct pci_bus pci_root;
 struct pci_dev *pci_devices = NULL;
 static struct pci_dev **pci_last_dev_p = &pci_devices;
 static int pci_reverse __initdata = 0;
 
-#undef DEBUG
-
-const char *pcibios_strerror(int error)
-{
-       static char buf[32];
-
-       switch (error) {
-               case PCIBIOS_SUCCESSFUL:
-               case PCIBIOS_BAD_VENDOR_ID:
-                       return "SUCCESSFUL";
-
-               case PCIBIOS_FUNC_NOT_SUPPORTED:
-                       return "FUNC_NOT_SUPPORTED";
-
-               case PCIBIOS_DEVICE_NOT_FOUND:
-                       return "DEVICE_NOT_FOUND";
-
-               case PCIBIOS_BAD_REGISTER_NUMBER:
-                       return "BAD_REGISTER_NUMBER";
-
-                case PCIBIOS_SET_FAILED:          
-                       return "SET_FAILED";
-
-                case PCIBIOS_BUFFER_TOO_SMALL:    
-                       return "BUFFER_TOO_SMALL";
-
-               default:
-                       sprintf (buf, "PCI ERROR 0x%x", error);
-                       return buf;
-       }
-}
-
-
 struct pci_dev *
 pci_find_slot(unsigned int bus, unsigned int devfn)
 {
@@ -93,6 +68,28 @@ pci_find_class(unsigned int class, struct pci_dev *from)
 }
 
 
+void
+pci_set_master(struct pci_dev *dev)
+{
+       unsigned short cmd;
+       unsigned char lat;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       if (! (cmd & PCI_COMMAND_MASTER)) {
+               printk("PCI: Enabling bus mastering for device %02x:%02x\n",
+                       dev->bus->number, dev->devfn);
+               cmd |= PCI_COMMAND_MASTER;
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       if (lat < 16) {
+               printk("PCI: Increasing latency timer of device %02x:%02x to 64\n",
+                       dev->bus->number, dev->devfn);
+               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+       }
+}
+
+
 __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
 {
        unsigned int devfn, l, max, class;
@@ -101,10 +98,7 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
        struct pci_bus *child;
        int reg;
 
-#ifdef DEBUG
-       printk("pci_scan_bus for bus %d\n", bus->number);
-#endif
-
+       DBG("pci_scan_bus for bus %d\n", bus->number);
        max = bus->secondary;
        for (devfn = 0; devfn < 0xff; ++devfn) {
                if (PCI_FUNC(devfn) && !is_multi) {
@@ -161,6 +155,8 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
                                pcibios_read_config_dword(bus->number, devfn, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
                                dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
                        }
+                       pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l);
+                       dev->rom_address = (l == 0xffffffff) ? 0 : l;
                        break;
                case PCI_HEADER_TYPE_BRIDGE:                /* bridge header */
                        if (class >> 8 != PCI_CLASS_BRIDGE_PCI)
@@ -169,6 +165,8 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
                                pcibios_read_config_dword(bus->number, devfn, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
                                dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
                        }
+                       pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l);
+                       dev->rom_address = (l == 0xffffffff) ? 0 : l;
                        break;
                case PCI_HEADER_TYPE_CARDBUS:               /* CardBus bridge header */
                        if (class >> 16 != PCI_BASE_CLASS_BRIDGE)
@@ -185,10 +183,7 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
                        continue;
                }
 
-#ifdef DEBUG
-               printk("PCI: %02x:%02x [%04x/%04x]\n",
-                      bus->number, dev->devfn, dev->vendor, dev->device);
-#endif
+               DBG("PCI: %02x:%02x [%04x/%04x]\n", bus->number, dev->devfn, dev->vendor, dev->device);
 
                /*
                 * Put it into the global PCI device chain. It's used to
@@ -209,16 +204,15 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
                dev->sibling = bus->devices;
                bus->devices = dev;
 
+#if 0
                /*
-                * In case the latency timer value is less than 32,
-                * which makes everything very sllooowww, set it to
-                * 32. Pciutils should be used to fine-tune it later.
-                * Note that we don't check if the device is a bus-master:
-                * if it isn't, write to the latency timer should be ignored.
+                * Setting of latency timer in case it was less than 32 was
+                * a great idea, but it confused several broken devices. Grrr.
                 */
                pcibios_read_config_byte(bus->number, dev->devfn, PCI_LATENCY_TIMER, &tmp);
                if (tmp < 32)
                        pcibios_write_config_byte(bus->number, dev->devfn, PCI_LATENCY_TIMER, 32);
+#endif
 
                /*
                 * If it's a bridge, scan the bus behind it.
@@ -303,9 +297,7 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
         *
         * Return how far we've got finding sub-buses.
         */
-#ifdef DEBUG
-       printk("PCI: pci_scan_bus returning with max=%02x\n", max);
-#endif
+       DBG("PCI: pci_scan_bus returning with max=%02x\n", max);
        return max;
 }
 
@@ -331,25 +323,19 @@ __initfunc(void pci_init(void))
        pci_quirks_init();
 #endif
 
-#ifdef CONFIG_PROC_FS
-       proc_bus_pci_init();
-#ifdef CONFIG_PCI_OLD_PROC
-       proc_old_pci_init();
-#endif
+#ifdef CONFIG_PROC
+       pci_proc_init();
 #endif
 }
 
 
 __initfunc(void pci_setup (char *str, int *ints))
 {
-       str = pcibios_setup(str);
        while (str) {
                char *k = strchr(str, ',');
                if (k)
                        *k++ = 0;
-               if (*str) {
-                       if (!(str = pcibios_setup(str)) || !*str)
-                               continue;
+               if (*str && (str = pcibios_setup(str)) && *str) {
                        if (!strcmp(str, "reverse"))
                                pci_reverse = 1;
                        else printk(KERN_ERR "PCI: Unknown option `%s'\n", str);
index 2f4501ef982024520042ca245753f388ab08b78a..b0178fdf18a0a0c8b5751703701a04902d330788 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: pcisyms.c,v 1.2 1998/02/16 10:35:57 mj Exp $
+ *     $Id: pcisyms.c,v 1.4 1998/04/17 16:34:19 mj Exp $
  *
  *     PCI Bus Services -- Exported Symbols
  *
@@ -16,11 +16,12 @@ EXPORT_SYMBOL(pcibios_read_config_dword);
 EXPORT_SYMBOL(pcibios_write_config_byte);
 EXPORT_SYMBOL(pcibios_write_config_word);
 EXPORT_SYMBOL(pcibios_write_config_dword);
-EXPORT_SYMBOL(pcibios_strerror);
 EXPORT_SYMBOL(pci_devices);
+EXPORT_SYMBOL(pci_root);
 EXPORT_SYMBOL(pci_find_class);
 EXPORT_SYMBOL(pci_find_device);
 EXPORT_SYMBOL(pci_find_slot);
+EXPORT_SYMBOL(pci_set_master);
 
 /* Backward compatibility */
 
index 452481404bf9405836298261201582c7f1af138d..9ca1a8d0c77f00ce5b573e1e34fc2e1cc5bb6ee1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: proc.c,v 1.8 1998/03/12 14:32:51 mj Exp $
+ *     $Id: proc.c,v 1.10 1998/04/16 20:48:30 mj Exp $
  *
  *     Procfs interface for the PCI bus.
  *
@@ -250,6 +250,13 @@ get_pci_dev_info(char *buf, char **start, off_t pos, int count, int wr)
                                                "\t%016lx",
 #endif
                                        dev->base_address[i]);
+               len += sprintf(buf+len,
+#if BITS_PER_LONG == 32
+                                       "\t%08lx",
+#else
+                                       "\t%016lx",
+#endif
+                              dev->rom_address);
                buf[len++] = '\n';
                at += len;
                if (at >= pos) {
@@ -298,7 +305,7 @@ __initfunc(void proc_bus_pci_add(struct pci_bus *bus, struct proc_dir_entry *pro
        }
 }
 
-__initfunc(void proc_bus_pci_init(void))
+__initfunc(void pci_proc_init(void))
 {
        struct proc_dir_entry *proc_pci;
 
@@ -307,4 +314,8 @@ __initfunc(void proc_bus_pci_init(void))
        proc_pci = create_proc_entry("pci", S_IFDIR, proc_bus);
        proc_register(proc_pci, &proc_pci_devices);
        proc_bus_pci_add(&pci_root, proc_pci);
+
+#ifdef CONFIG_PCI_OLD_PROC
+       proc_old_pci_init();
+#endif
 }
index 5251d5090ba7ce9edfaa1139974f7d166d83606f..84253cf034a1c2fc54d102f4769f0f5ee15edc0f 100644 (file)
@@ -68,6 +68,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ENVCTRL),y)
+O_OBJS += envctrl.o
+else
+  ifeq ($(CONFIG_ENVCTRL),m)
+  M_OBJS += envctrl.o
+  endif
+endif
+
 endif # eq($(CONFIG_PCI,y)
 
 ifeq ($(CONFIG_OBP_FLASH),y)
index 615fef33df267d1513facc5e5b63b11ff696b2ba..c991001c464e1bc3fea0bf6a52e090c6b05844b0 100644 (file)
@@ -1,8 +1,9 @@
-/* $Id: bwtwo.c,v 1.18 1997/07/17 02:21:43 davem Exp $
+/* $Id: bwtwo.c,v 1.20 1998/03/10 20:18:22 jj Exp $
  * bwtwo.c: bwtwo console driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
  * Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
+ * Copyright (C) 1998 Pavel Machek    (pavel@ucw.cz)
  */
 
 #include <linux/kd.h>
@@ -95,7 +96,8 @@ bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
        if (r)
                return -EAGAIN;
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
        return 0;
 }
 
@@ -156,15 +158,17 @@ __initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, u32 bwtwo, int bw2_io,
        fb->loadcmap = 0;
        fb->ioctl = 0;
        fb->reset = 0;
+#ifndef CONFIG_SUN4    
        fb->blank = bwtwo_blank;
        fb->unblank = bwtwo_unblank;
+#endif
 
        fb->info.bwtwo.regs =
                sparc_alloc_io (bwtwo + BWTWO_REGISTER_OFFSET,
                                0, sizeof (struct bwtwo_regs),
                "bwtwo_regs", bw2_io, 0);
 
-       if (!prom_getbool(sbdp->prom_node, "width")) {
+       if (sbdp && !prom_getbool(sbdp->prom_node, "width")) {
                /* Ugh, broken PROM didn't initialize us.
                 * Let's deal with this ourselves.
                 */
index dbe071b982fb3822983357b2df604a55fa8577d4..315d9561f74848d3e940083b13acd401cb778d7c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cgfourteen.c,v 1.25 1997/08/20 07:38:36 davem Exp $
+/* $Id: cgfourteen.c,v 1.26 1998/03/10 20:18:23 jj Exp $
  * cgfourteen.c: Sun SparcStation console support.
  *
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -274,7 +274,8 @@ cg14_mmap (struct inode *inode, struct file *file,
                page += map_size;
        }
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
         return 0;
 }
 
index 4c24a8c0bf9b512baf479a09c5421d21e09c26ff..ca328ee531cd42318326bdc3cce2986f9a853431 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cgsix.c,v 1.37 1997/08/22 15:55:20 jj Exp $
+/* $Id: cgsix.c,v 1.39 1998/03/10 20:18:25 jj Exp $
  * cgsix.c: cgsix frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -326,7 +326,8 @@ cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
                page += map_size;
        }
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
         return 0;
 }
 
@@ -395,11 +396,14 @@ static void
 cg6_blank (fbinfo_t *fb)
 {
        fb->info.cg6.thc->thc_misc &= ~CG6_THC_MISC_VIDEO;
+       /* This should put us in power-save */
+       fb->info.cg6.thc->thc_misc &= ~CG6_THC_MISC_SYNC_ENAB;
 }
 
 static void
 cg6_unblank (fbinfo_t *fb)
 {
+       fb->info.cg6.thc->thc_misc |= CG6_THC_MISC_SYNC_ENAB;
        fb->info.cg6.thc->thc_misc |= CG6_THC_MISC_VIDEO;
 }
 
index 95d8a07f45662da4dd57d579f8f710994ea25f20..568ae99bfd8695e2dbce05f499e61326c1e0267b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cgthree.c,v 1.24 1997/08/20 07:38:37 davem Exp $
+/* $Id: cgthree.c,v 1.25 1998/03/10 20:18:27 jj Exp $
  * cgtree.c: cg3 frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -133,7 +133,8 @@ cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
                page += map_size;
        }
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
         return 0;
 }
 
index 8b6ddf40fd5bd8312fb51351d656e6a52f716e3e..c7935f7130ab95429b00cba47560b7e5280ab344 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: creator.c,v 1.13 1997/10/17 04:14:40 davem Exp $
+/* $Id: creator.c,v 1.14 1998/03/10 20:18:32 jj Exp $
  * creator.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -244,7 +244,8 @@ ffb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
                page += map_size;
        }
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
         return 0;
 }
 
@@ -702,8 +703,8 @@ static void ffb_fill(int attrib, int count, int *boxes)
        while (count-- > 0) {
                ffb->by = boxes[1];
                ffb->bx = boxes[0];
-               ffb->bw = boxes[2];
                ffb->bh = boxes[3];
+               ffb->bw = boxes[2];
                boxes += 4;
        }
        FFB_FILL_END
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
new file mode 100644 (file)
index 0000000..be5bafb
--- /dev/null
@@ -0,0 +1,241 @@
+/* $Id: envctrl.c,v 1.3 1998/04/10 08:42:24 jj Exp $
+ * envctrl.c: Temperature and Fan monitoring on Machines providing it.
+ *
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+
+#include <asm/ebus.h>
+
+#define PCF8584_ADDRESS        0x55
+
+#define CONTROL_PIN    0x80
+#define CONTROL_ES0    0x40
+#define CONTROL_ES1    0x20
+#define CONTROL_ES2    0x10
+#define CONTROL_ENI    0x08
+#define CONTROL_STA    0x04
+#define CONTROL_STO    0x02
+#define CONTROL_ACK    0x01
+
+#define STATUS_PIN     0x80
+#define STATUS_STS     0x20
+#define STATUS_BER     0x10
+#define STATUS_LRB     0x08
+#define STATUS_AD0     0x08
+#define STATUS_AAB     0x04
+#define STATUS_LAB     0x02
+#define STATUS_BB      0x01
+
+/*
+ * CLK Mode Register.
+ */
+#define BUS_CLK_90     0x00
+#define BUS_CLK_45     0x01
+#define BUS_CLK_11     0x02
+#define BUS_CLK_1_5    0x03
+
+#define CLK_3          0x00
+#define CLK_4_43       0x10
+#define CLK_6          0x14
+#define CLK_8          0x18
+#define CLK_12         0x1c
+
+
+#define I2C_WRITE      0x00
+#define I2C_READ       0x01
+
+struct pcf8584_reg
+{
+       __volatile__ unsigned char data;
+       __volatile__ unsigned char csr;
+};
+
+static struct pcf8584_reg *i2c;
+
+
+struct i2c_addr_map {
+       unsigned char addr;
+       unsigned char mask;
+       char *name;
+};
+
+static struct i2c_addr_map devmap[] = {
+       { 0x38, 0x78, "PCF8574A" },
+       { 0x20, 0x78, "TDA8444" },
+       { 0x48, 0x78, "PCF8591" },
+};
+#define NR_DEVMAP (sizeof(devmap) / sizeof(devmap[0]))
+
+static int
+envctrl_read(unsigned char dev, char *buffer, int len)
+{
+       unsigned char dummy;
+       unsigned char stat;
+       int error = -ENODEV;
+       int count = -1;
+
+       if (len == 0)
+               return 0;
+
+       i2c->data = (dev << 1) | I2C_READ;
+
+       while (!(i2c->csr & STATUS_BB))
+               udelay(1);
+
+       i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK;
+
+       do {
+               udelay(1);
+               while ((stat = i2c->csr) & STATUS_PIN)
+                       udelay(1);
+
+               if (stat & STATUS_LRB)
+                       goto stop;
+               error = 0;
+               if (count == (len - 2))
+                       goto final;
+
+               if (++count > 0)
+                       *buffer++ = i2c->data;
+               else
+                       dummy = i2c->data;
+       } while (1);
+
+final:
+       i2c->csr = CONTROL_ES0;
+       if (++count > 0)
+               *buffer++ = i2c->data;
+       else
+               dummy = i2c->data;
+
+       udelay(1);
+       while ((stat = i2c->csr) & STATUS_PIN)
+               udelay(1);
+
+stop:
+       i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK;
+       if (++count > 0)
+               *buffer++ = i2c->data;
+       else
+               dummy = i2c->data;
+
+       if (error)
+               return error;
+       return count;
+}
+
+static int
+envctrl_write(unsigned char dev, char *buffer, int len)
+{
+       int error = -ENODEV;
+       int count = 0;
+
+       while (!(i2c->csr & STATUS_BB))
+               udelay(1);
+
+       i2c->data = (dev << 1) | I2C_WRITE;
+       i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STA | CONTROL_ACK;
+
+       do {
+               unsigned char stat;
+
+               udelay(1);
+               while ((stat = i2c->csr) & STATUS_PIN)
+                       udelay(1);
+
+               if (stat & STATUS_LRB)
+                       goto stop;
+               error = count;
+               if (count == len)
+                       goto stop;
+
+               i2c->data = *buffer++;
+               count++;
+       } while (1);
+
+stop:
+       i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_STO | CONTROL_ACK;
+       return error;
+}
+
+__initfunc(static int scan_bus(void))
+{
+       unsigned char dev;
+       int count = 0;
+       int i;
+
+       /* scan */
+       for (dev = 1; dev < 128; dev++)
+               if (envctrl_write(dev, 0, 0) == 0) {
+                       for (i = 0; i < NR_DEVMAP; i++)
+                               if ((dev & devmap[i].mask) == devmap[i].addr)
+                                       break;
+                       printk("envctrl: i2c device at %02x: %s\n", dev,
+                              i < NR_DEVMAP ? devmap[i].name : "unknown");
+{
+                       unsigned char buf[4];
+                       if (envctrl_read(dev, buf, 4) == 4)
+                               printk("envctrl: read %02x %02x %02x %02x\n",
+                                      buf[0], buf[1], buf[2], buf[3]);
+}
+                       count++;
+               }
+       return count ? 0 : -ENODEV;
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int envctrl_init(void))
+#endif
+{
+#ifdef CONFIG_PCI
+       struct linux_ebus *ebus;
+       struct linux_ebus_device *edev;
+
+       for_all_ebusdev(edev, ebus)
+               if (!strcmp(edev->prom_name, "SUNW,envctrl"))
+                       break;
+
+       if (!edev)
+               return -ENODEV;
+
+       if (check_region(edev->base_address[0], sizeof(*i2c))) {
+               prom_printf("%s: Can't get region %lx, %d\n",
+                           __FUNCTION__, edev->base_address[0],
+                           sizeof(*i2c));
+               prom_halt();
+       }
+
+       request_region(edev->base_address[0],
+                      sizeof(*i2c), "i2c");
+
+       i2c = (struct pcf8584_reg *)edev->base_address[0];
+
+       i2c->csr = CONTROL_PIN;
+       i2c->data = PCF8584_ADDRESS;
+       i2c->csr = CONTROL_PIN | CONTROL_ES1;
+       i2c->data = CLK_4_43 | BUS_CLK_90;
+       i2c->csr = CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK;
+       udelay(10000);
+
+       return scan_bus();
+#else
+       return -ENODEV;
+#endif
+}
+
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+}
+#endif
index ba67381a08c1c2e93aa684c04b87172e40cb45b3..435a0f57bff7b7123f264f2e4b014552f6472495 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.5 1997/11/01 10:22:13 ecd Exp $
+/* $Id: flash.c,v 1.7 1998/03/10 20:19:05 jj Exp $
  * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -71,7 +71,9 @@ flash_mmap(struct file *file, struct vm_area_struct *vma)
 
        if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot))
                return -EAGAIN;
-       vma->vm_dentry = dget(file->f_dentry);
+               
+       vma->vm_file = file;
+       file->f_count++;
        return 0;
 }
 
index e08cf182252d2016898db1578b5d79c07ff8f3c9..fcbbd3e53f29321c9ba2be9be1a6fdb2de9aa030 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: leo.c,v 1.25 1997/08/22 17:33:58 jj Exp $
+/* $Id: leo.c,v 1.26 1998/03/10 20:18:29 jj Exp $
  * leo.c: SUNW,leo 24/8bit frame buffer driver
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -224,7 +224,8 @@ leo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
                page += map_size;
        }
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
         return 0;
 }
 
index 05ed175d31786a78311832f640271aede89a6911..fcce8887d288554eebeee26c97707c82cd9fbcbd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mach64.c,v 1.11 1997/10/17 04:13:35 davem Exp $
+/* $Id: mach64.c,v 1.17 1998/04/06 06:42:23 davem Exp $
  * mach64.c: Ultra/PCI Mach64 console driver.
  *
  * Just about all of this is from the PPC/mac driver, see that for
@@ -12,7 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/string.h>
 #include <linux/tty.h>
 #include <linux/console.h>
@@ -81,8 +80,8 @@ mach64_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma,
        if (vma->vm_offset & ~PAGE_MASK)
                return -ENXIO;
 
-       if (vma->vm_offset == mach64_pci_iobase) {
-               addr = __pa(pcivga_iobase);
+       if (vma->vm_offset == (mach64_pci_iobase & PAGE_MASK)) {
+               addr = __pa((pcivga_iobase & PAGE_MASK));
                size = PAGE_SIZE;
        } else if (vma->vm_offset >= (mach64_pci_membase + 0x800000)) {
                addr = __pa(pcivga_membase) - mach64_pci_membase
@@ -102,7 +101,8 @@ mach64_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma,
        if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot))
                return -EAGAIN;
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
        return 0;
 }
 
@@ -123,6 +123,7 @@ mach64_loadcmap(fbinfo_t *fb, int index, int count)
                pcivga_writeb(fb->color_map CM(i, 1), MACH64_REGOFF + DAC_DATA);
                pcivga_writeb(fb->color_map CM(i, 2), MACH64_REGOFF + DAC_DATA);
        }
+       mach64_idle();
 }
 
 static void
@@ -172,11 +173,11 @@ int mach64_init(fbinfo_t *fb)
        unsigned int tmp;
 
        memset(&mach64, 0, sizeof(mach64));
-       for(pdev = pci_devices; pdev; pdev = pdev->next) {
-               if((pdev->vendor == PCI_VENDOR_ID_ATI) &&
-                  (pdev->device == PCI_DEVICE_ID_ATI_264VT))
-                       break;
-       }
+
+       pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_264VT, 0);
+       if(!pdev)
+               pdev = pci_find_device(PCI_VENDOR_ID_ATI,
+                                      PCI_DEVICE_ID_ATI_215GT, 0);
        if(!pdev)
                return -1;
 
@@ -222,15 +223,15 @@ int mach64_init(fbinfo_t *fb)
        fb->info.private = (void *)&mach64;
        fb->base = pcivga_membase + MACH64_BE_FBOFF;
 
-       if ((pcivga_readl(MACH64_REGOFF + CONFIG_CHIP_ID)
-                                       & CFG_CHIP_TYPE) == MACH64_VT_ID)
-               mach64.flags |= MACH64_MASK_VT;
+       mach64.chip_type = pcivga_readl(MACH64_REGOFF + CONFIG_CHIP_ID)
+                                                       & CFG_CHIP_TYPE;
 
-       /*
-        * Fix the PROM's idea of MEM_CNTL settings...
-        */
-       tmp = pcivga_readl(MACH64_REGOFF + MEM_CNTL);
-       switch (tmp & 0xf) {
+       if (mach64.chip_type == MACH64_VT_ID) {
+               /*
+                * Fix the PROM's idea of MEM_CNTL settings...
+                */
+               tmp = pcivga_readl(MACH64_REGOFF + MEM_CNTL);
+               switch (tmp & 0xf) {
                case 3:
                        tmp = (tmp & ~(0xf)) | 2;
                        break;
@@ -245,11 +246,14 @@ int mach64_init(fbinfo_t *fb)
                        break;
                default:
                        break;
+               }
+               tmp &= ~(0x00f00000);
+               pcivga_writel(tmp, MACH64_REGOFF + MEM_CNTL);
        }
-       tmp &= ~(0x00f00000);
-       pcivga_writel(tmp, MACH64_REGOFF + MEM_CNTL);
 
-       switch(tmp & MEM_SIZE_ALIAS) {
+       tmp = pcivga_readl(MACH64_REGOFF + MEM_CNTL);
+       if (mach64.chip_type != MACH64_GT_ID) {
+               switch(tmp & MEM_SIZE_ALIAS) {
                case MEM_SIZE_512K:
                        mach64.total_vram = 0x80000;
                        break;
@@ -271,10 +275,35 @@ int mach64_init(fbinfo_t *fb)
                default:
                        mach64.total_vram = 0x80000;
                        break;
+               }
+       } else {
+               switch(tmp & MEM_SIZE_ALIAS_GTB) {
+               case MEM_SIZE_512K_GTB:
+                       mach64.total_vram = 0x80000;
+                       break;
+               case MEM_SIZE_1M_GTB:
+                       mach64.total_vram = 0x100000;
+                       break;
+               case MEM_SIZE_2M_GTB:
+                       mach64.total_vram = 0x200000;
+                       break;
+               case MEM_SIZE_4M_GTB:
+                       mach64.total_vram = 0x400000;
+                       break;
+               case MEM_SIZE_6M_GTB:
+                       mach64.total_vram = 0x600000;
+                       break;
+               case MEM_SIZE_8M_GTB:
+                       mach64.total_vram = 0x800000;
+                       break;
+               default:
+                       mach64.total_vram = 0x80000;
+                       break;
+               }
        }
 
-       printk("mach64_init: total_vram[%08x] is_vt_chip[%d]\n",
-               mach64.total_vram, mach64.flags & MACH64_MASK_VT ? 1 : 0);
+       printk("mach64_init: chip_type[%04x], total_vram[%08x]\n",
+               mach64.chip_type, mach64.total_vram);
 
 #if 0
        mach64_test(fb);
index 02593fa7b90e430e4ccd3d7f5f4ea82705fa96e2..2b30888e809588d0be11cc1c8997c34cc0215aee 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mach64.h,v 1.4 1997/10/04 08:51:30 ecd Exp $
+/* $Id: mach64.h,v 1.5 1998/04/01 05:52:58 ecd Exp $
  * mach64.h: Ultra/PCI mach64 driver constants etc.
  *
  * Copyright 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -9,12 +9,10 @@
 
 struct mach64_info {
        unsigned int color_mode;
-       unsigned int flags;
+       unsigned int chip_type;
        unsigned int total_vram;
 };
 
-/* The mach64_info flag bits. */
-#define MACH64_MASK_VT 0x00000001
 
 /* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */
 
@@ -376,15 +374,6 @@ struct mach64_info {
 #define MEM_BNDRY_1M            0x00030000
 #define MEM_BNDRY_EN            0x00040000
 
-/* ATI PCI constants */
-#define PCI_ATI_VENDOR_ID      0x1002
-#define PCI_MACH64_GX          0x4758
-#define PCI_MACH64_CX          0x4358
-#define PCI_MACH64_CT          0x4354
-#define PCI_MACH64_ET          0x4554
-#define PCI_MACH64_VT          0x5654
-#define PCI_MACH64_GT          0x4754
-
 /* CONFIG_CHIP_ID register constants */
 #define CFG_CHIP_TYPE          0x0000FFFF
 #define CFG_CHIP_CLASS         0x00FF0000
index c20796e638d498a21d0135bda9795cbd086e7ab7..5117c2c8e128b867483ec80fc7149dff9679eb52 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pcicons.c,v 1.10 1997/10/04 08:52:57 ecd Exp $
+/* $Id: pcicons.c,v 1.13 1998/04/01 06:55:11 ecd Exp $
  * pcicons.c: PCI specific probing and console operations layer.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -42,6 +42,7 @@ static __u64 cursor_bits[2];
 static int cursor_pos = -1;
 
 extern int serial_console;
+extern struct console vt_console_driver;
 
 static void pci_install_consops(void);
 static int (*fbuf_offset)(int);
@@ -191,24 +192,32 @@ static unsigned short pci_scr_readw(unsigned short *addr)
 
 static void pci_get_scrmem(int currcons)
 {
+       struct vc_data *vcd = vc_cons[currcons].d;
+       
        memcpyw((unsigned short *)vc_scrbuf[currcons],
-               (unsigned short *)origin, video_screen_size);
-       origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
-       scr_end = video_mem_end = video_mem_start + video_screen_size;
-       pos = origin + y * video_size_row + (x << 1);
+               (unsigned short *)vcd->vc_origin, video_screen_size);
+       vcd->vc_origin = vcd->vc_video_mem_start = 
+               (unsigned long)vc_scrbuf[currcons];
+       vcd->vc_scr_end = vcd->vc_video_mem_end = 
+               vcd->vc_video_mem_start + video_screen_size;
+       vcd->vc_pos = 
+               vcd->vc_origin + vcd->vc_y * video_size_row + (vcd->vc_x << 1);
 }
 
 static void pci_set_scrmem(int currcons, long offset)
 {
+       struct vc_data *vcd = vc_cons[currcons].d;
+       
        if (video_mem_term - video_mem_base < offset + video_screen_size)
                offset = 0;
        memcpyw((unsigned short *)(video_mem_base + offset),
-               (unsigned short *) origin, video_screen_size);
-       video_mem_start = video_mem_base;
-       video_mem_end = video_mem_term;
-       origin = video_mem_base + offset;
-       scr_end = origin + video_screen_size;
-       pos = origin + y * video_size_row + (x << 1);
+               (unsigned short *) vcd->vc_origin, video_screen_size);
+       vcd->vc_video_mem_start = video_mem_base;
+       vcd->vc_video_mem_end = video_mem_term;
+       vcd->vc_origin = video_mem_base + offset;
+       vcd->vc_scr_end = vcd->vc_origin + video_screen_size;
+       vcd->vc_pos = 
+               vcd->vc_origin + vcd->vc_y * video_size_row + (vcd->vc_x << 1);
 }
 
 static void pci_invert_cursor(int cpos)
@@ -252,15 +261,17 @@ static void pci_set_cursor(int currcons)
        unsigned long flags;
        int old_cursor;
 
-       if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+       if (currcons != fg_console || console_blanked || 
+           vt_cons[currcons]->vc_mode == KD_GRAPHICS)
                return;
 
        save_flags(flags); cli();
-       if (!deccm) {
+       if (!vc_cons[currcons].d->vc_deccm) {
                pci_hide_cursor();
        } else {
                old_cursor = cursor_pos;
-               cursor_pos = (pos - video_mem_base) >> 1;
+               cursor_pos = 
+                       (vc_cons[currcons].d->vc_pos - video_mem_base) >> 1;
                if (old_cursor != -1)
                        pci_invert_cursor(-1);
                pci_invert_cursor(cursor_pos);
@@ -412,9 +423,12 @@ static void pci_clear_fb(int n)
 {
        fbinfo_t *fb = &fbinfo[n];
 
+#if 0
        if (!n) {
                pci_clear_screen();
-       } else if (fb->base) {
+       } else
+#endif
+       if (fb->base) {
                memset((void *)fb->base,
                       (fb->type.fb_depth == 1) ?
                       ~(0) : reverse_color_table[0],
@@ -545,7 +559,7 @@ __initfunc(static void pci_con_type_init_finish(void))
                                + 10 * (ncpus - 1);
 
        for (p = logo_banner; *p; p++, ush++) {
-               *ush = (attr << 8) + *p;
+               *ush = (vc_cons[currcons].d->vc_attr << 8) + *p;
                pci_blitc(*ush, (unsigned long)ush);
        }
 
@@ -553,6 +567,8 @@ __initfunc(static void pci_con_type_init_finish(void))
                ush = (unsigned short *)video_mem_base + i * video_num_columns;
                memset(ush, 0xff, 20);
        }
+
+       register_console(&vt_console_driver);
 }
 
 unsigned long pcivga_iobase = 0;
index 31485aac8fd09a23ec618db05b1553a2ef7bf3f7..eca0149c5bd5c19618f52973ecfbae2c75c6cbde 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.12 1997/12/27 16:28:27 jj Exp $
+/* $Id: pcikbd.c,v 1.16 1998/04/01 04:12:40 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -953,14 +953,18 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
                return -ENODEV;
 
        len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
-       if (len > 0)
-               kbnode = prom_pathtoinode(prop);
+       if (len > 0) {
+               prop[len] = 0;
+               kbnode = prom_finddevice(prop);
+       }
        if (!kbnode)
                return -ENODEV;
 
        len = prom_getproperty(node, "mouse", prop, sizeof(prop));
-       if (len > 0)
-               msnode = prom_pathtoinode(prop);
+       if (len > 0) {
+               prop[len] = 0;
+               msnode = prom_finddevice(prop);
+       }
        if (!msnode)
                return -ENODEV;
 
@@ -970,6 +974,15 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
         node = prom_getchild(prom_root_node);
        pnode = prom_searchsiblings(node, "pci");
 
+       /*
+        * Check for SUNW,sabre on Ultra5/10/AXi.
+        */
+       len = prom_getproperty(pnode, "model", prop, sizeof(prop));
+       if ((len > 0) && !strncmp(prop, "SUNW,sabre", len)) {
+               pnode = prom_getchild(pnode);
+               pnode = prom_searchsiblings(pnode, "pci");
+       }
+
        /*
         * For each PCI bus...
         */
index 9eed1d7f6de8e60246d685546eaa3ce00af6f9d7..773f69f476b6adc7765e5769b2ec434ea898131c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.13 1997/12/30 09:37:49 ecd Exp $
+/* $Id: sab82532.c,v 1.17 1998/04/01 06:55:12 ecd Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -46,9 +46,10 @@ static int sab82532_refcount;
 
 /* Set of debugging defines */
 #undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_INTR
 #undef SERIAL_DEBUG_FLOW
 #undef SERIAL_DEBUG_WAIT_UNTIL_SENT
+#undef SERIAL_DEBUG_SEND_BREAK
+#undef SERIAL_DEBUG_INTR
 
 static void change_speed(struct sab82532 *info);
 static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -159,6 +160,47 @@ static struct ebrg_struct ebrg_table[] = {
 
 #define NR_EBRG_VALUES (sizeof(ebrg_table)/sizeof(struct ebrg_struct))
 
+#define SAB82532_MAX_TEC_DELAY 2000    /* 2 ms */
+
+static __inline__ void sab82532_tec_wait(struct sab82532 *info)
+{
+       int count = SAB82532_MAX_TEC_DELAY;
+       while ((info->regs->r.star & SAB82532_STAR_TEC) && --count)
+               udelay(1);
+}
+
+static __inline__ void sab82532_start_tx(struct sab82532 *info)
+{
+       unsigned long flags;
+       int i;
+
+       save_flags(flags); cli();
+
+       if (info->xmit_cnt <= 0)
+               goto out;
+
+       if (!(info->regs->r.star & SAB82532_STAR_XFW))
+               goto out;
+
+       info->all_sent = 0;
+       for (i = 0; i < info->xmit_fifo_size; i++) {
+               info->regs->w.xfifo[i] = info->xmit_buf[info->xmit_tail++];
+               info->xmit_tail &= (SERIAL_XMIT_SIZE - 1);
+               info->icount.tx++;
+               if (--info->xmit_cnt <= 0)
+                       break;
+       }
+
+       /* Issue a Transmit Frame command. */
+       if (info->regs->r.star & SAB82532_STAR_CEC)
+               udelay(1);
+       info->regs->w.cmdr = SAB82532_CMDR_XF;
+
+out:
+       restore_flags(flags);
+}
+
+
 /*
  * ------------------------------------------------------------
  * sab82532_stop() and sab82532_start()
@@ -192,6 +234,7 @@ static void sab82532_start(struct tty_struct *tty)
        save_flags(flags); cli();
        info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);
        info->regs->w.imr1 = info->interrupt_mask1;
+       sab82532_start_tx(info);
        restore_flags(flags);
 }
 
@@ -356,6 +399,11 @@ static inline void transmit_chars(struct sab82532 *info,
 {
        int i;
 
+       if (stat->sreg.isr1 & SAB82532_ISR1_ALLS)
+               info->all_sent = 1;
+       if (!(info->regs->r.star & SAB82532_STAR_XFW))
+               return;
+
        if (!info->tty) {
                info->interrupt_mask1 |= SAB82532_IMR1_XPR;
                info->regs->w.imr1 = info->interrupt_mask1;
@@ -364,8 +412,6 @@ static inline void transmit_chars(struct sab82532 *info,
 
        if ((info->xmit_cnt <= 0) || info->tty->stopped ||
            info->tty->hw_stopped) {
-               if (stat->sreg.isr1 & SAB82532_ISR1_ALLS)
-                       info->all_sent = 1;
                info->interrupt_mask1 |= SAB82532_IMR1_XPR;
                info->regs->w.imr1 = info->interrupt_mask1;
                return;
@@ -494,6 +540,7 @@ check_modem:
                                                     RS_EVENT_WRITE_WAKEUP);
                                info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);
                                info->regs->w.imr1 = info->interrupt_mask1;
+                               sab82532_start_tx(info);
                        }
                } else {
                        if (!(info->cts)) {
@@ -641,8 +688,7 @@ sab82532_init_line(struct sab82532 *info)
         */
        if (info->regs->r.star & SAB82532_STAR_CEC)
                udelay(1);
-       while (info->regs->r.star & SAB82532_STAR_TEC)
-               udelay(1);
+       sab82532_tec_wait(info);
 
        /*
         * Clear the FIFO buffers.
@@ -939,8 +985,7 @@ static void change_speed(struct sab82532 *info)
        save_flags(flags); cli();
        if (info->regs->r.star & SAB82532_STAR_CEC)
                udelay(1);
-       while (info->regs->r.star & SAB82532_STAR_TEC)
-               udelay(1);
+       sab82532_tec_wait(info);
        info->regs->w.dafo = dafo;
        info->regs->w.bgr = ebrg & 0xff;
        info->regs->rw.ccr2 &= ~(0xc0);
@@ -996,6 +1041,7 @@ static void sab82532_flush_chars(struct tty_struct *tty)
        save_flags(flags); cli();
        info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);
        info->regs->w.imr1 = info->interrupt_mask1;
+       sab82532_start_tx(info);
        restore_flags(flags);
 }
 
@@ -1044,10 +1090,10 @@ static int sab82532_write(struct tty_struct * tty, int from_user,
        if (from_user)
                up(&tmp_buf_sem);
 
-       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
-           (info->interrupt_mask1 & SAB82532_IMR1_XPR)) {
+       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
                info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);
                info->regs->w.imr1 = info->interrupt_mask1;
+               sab82532_start_tx(info);
        }
 
        restore_flags(flags);
@@ -1098,13 +1144,15 @@ static void sab82532_flush_buffer(struct tty_struct *tty)
 static void sab82532_send_xchar(struct tty_struct *tty, char ch)
 {
        struct sab82532 *info = (struct sab82532 *)tty->driver_data;
+       unsigned long flags;
 
        if (serial_paranoia_check(info, tty->device, "sab82532_send_xchar"))
                return;
 
-       while (info->regs->r.star & SAB82532_STAR_TEC)
-               udelay(1);
+       save_flags(flags); cli();
+       sab82532_tec_wait(info);
        info->regs->w.tic = ch;
+       restore_flags(flags);
 }
 
 /*
@@ -1308,6 +1356,9 @@ static void begin_break(struct sab82532 * info)
        if (!info->regs)
                return;
        info->regs->rw.dafo |= SAB82532_DAFO_XBRK;
+#ifdef SERIAL_DEBUG_SEND_BREAK
+       printk("begin_break: jiffies=%lu\n", jiffies);
+#endif
 }
 
 /*
@@ -1318,6 +1369,9 @@ static void end_break(struct sab82532 * info)
        if (!info->regs)
                return;
        info->regs->rw.dafo &= ~(SAB82532_DAFO_XBRK);
+#ifdef SERIAL_DEBUG_SEND_BREAK
+       printk("end_break: jiffies=%lu\n", jiffies);
+#endif
 }
 
 static int sab82532_ioctl(struct tty_struct *tty, struct file * file,
@@ -1850,6 +1904,7 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp)
 #ifdef SERIAL_DEBUG_OPEN
        printk("sab82532_open: count = %d\n", info->count);
 #endif
+
        line = MINOR(tty->device) - tty->driver.minor_start;
        if ((line < 0) || (line >= NR_PORTS))
                return -ENODEV;
@@ -1991,7 +2046,7 @@ int sab82532_read_proc(char *page, char **start, off_t off, int count,
        int i, len = 0;
        off_t   begin = 0;
 
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.13 $");
+       len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.17 $");
        for (i = 0; i < NR_PORTS && len < 4000; i++) {
                len += line_info(page + len, sab82532_table[i]);
                if (len+begin > off+count)
@@ -2082,7 +2137,7 @@ sab82532_kgdb_hook(int line))
 
 __initfunc(static inline void show_serial_version(void))
 {
-       char *revision = "$Revision: 1.13 $";
+       char *revision = "$Revision: 1.17 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
@@ -2219,10 +2274,21 @@ __initfunc(int sab82532_init(void))
 __initfunc(int sab82532_probe(unsigned long *memory_start))
 {
        int node, enode, snode;
+       char model[32];
+       int len;
 
         node = prom_getchild(prom_root_node);
        node = prom_searchsiblings(node, "pci");
 
+       /*
+        * Check for SUNW,sabre on Ultra 5/10/AXi.
+        */
+       len = prom_getproperty(node, "model", model, sizeof(model));
+       if ((len > 0) && !strncmp(model, "SUNW,sabre", len)) {
+               node = prom_getchild(node);
+               node = prom_searchsiblings(node, "pci");
+       }
+
        /*
         * For each PCI bus...
         */
@@ -2299,12 +2365,15 @@ void cleanup_module(void)
 
 #ifdef CONFIG_SERIAL_CONSOLE
 
-static void
+static __inline__ void
 sab82532_console_putchar(struct sab82532 *info, char c)
 {
-       while (info->regs->r.star & SAB82532_STAR_TEC)
-               udelay(1);
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       sab82532_tec_wait(info);
        info->regs->w.tic = c;
+       restore_flags(flags);
 }
 
 static void
@@ -2320,8 +2389,7 @@ sab82532_console_write(struct console *con, const char *s, unsigned n)
                        sab82532_console_putchar(info, '\r');
                sab82532_console_putchar(info, *s++);
        }
-       while (info->regs->r.star & SAB82532_STAR_TEC)
-               udelay(1);
+       sab82532_tec_wait(info);
 }
 
 static int
@@ -2440,8 +2508,7 @@ sab82532_console_setup(struct console *con, char *options)
        save_flags(flags); cli();
        if (info->regs->r.star & SAB82532_STAR_CEC)
                udelay(1);
-       while (info->regs->r.star & SAB82532_STAR_TEC)
-               udelay(1);
+       sab82532_tec_wait(info);
        info->regs->w.dafo = dafo;
        info->regs->w.bgr = ebrg & 0xff;
        info->regs->rw.ccr2 &= ~(0xc0);
index eda06fa762747a754d3e67d74d36c960618a9544..9273319fcce87230a69bdb59e3aab0463d2ad52a 100644 (file)
@@ -1,11 +1,11 @@
-/* $Id: sbuscons.c,v 1.10 1998/01/07 06:37:22 baccala Exp $
+/* $Id: sbuscons.c,v 1.15 1998/03/31 01:49:50 davem Exp $
  * sbuscons.c: Routines specific to SBUS frame buffer consoles.
  *
  * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
  * Copyright (C) 1995,1996,1997 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
  * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
  *
  * Added font loading Nov/21, Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -72,6 +72,9 @@
 #include <asm/fbio.h>
 #include <asm/io.h>
 #include <asm/smp.h>
+#ifndef __sparc_v9__
+#include <asm/sun4paddr.h>
+#endif
 
 #include <linux/kbd_kern.h>
 #include <linux/vt_kern.h>
@@ -96,7 +99,6 @@ static int sbus_blitc(uint, unsigned long);
 
 static void sbus_install_consops(void);
 
-extern void register_console(void (*proc)(const char *));
 extern void console_print(const char *);
 extern void putconsxy(int, char *);
 extern unsigned char vga_font[];
@@ -277,14 +279,15 @@ static void sbus_set_cursor(int currcons)
        int j, idx, oldpos;
        unsigned long flags;
 
-       if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+       if (currcons != fg_console || console_blanked || 
+           vt_cons[currcons]->vc_mode == KD_GRAPHICS)
                return;
 
        if (fbinfo[0].setcursor) {
-               if (!deccm)
+               if (!vc_cons[currcons].d->vc_deccm)
                        sbus_hide_cursor();
                else {
-                       idx = (pos - video_mem_base) >> 1;
+                       idx = (vc_cons[currcons].d->vc_pos - video_mem_base) >> 1;
                        
                        sbus_hw_set_cursor(x_margin + ((idx % video_num_columns) << 3), y_margin + ((idx / video_num_columns) * CHAR_HEIGHT));
                }
@@ -293,9 +296,9 @@ static void sbus_set_cursor(int currcons)
 
        __save_and_cli(flags);
 
-       idx = (pos - video_mem_base) >> 1;
+       idx = (vc_cons[currcons].d->vc_pos - video_mem_base) >> 1;
        oldpos = cursor_pos;
-       if (!deccm) {
+       if (!vc_cons[currcons].d->vc_deccm) {
                sbus_hide_cursor ();
                __restore_flags (flags);
                return;
@@ -420,7 +423,7 @@ __initfunc(static void sbus_con_type_init_finish(void))
 
        p = logo_banner;
        for (; *p; p++, ush++) {
-               *ush = (attr << 8) + *p;
+               *ush = (vc_cons[currcons].d->vc_attr << 8) + *p;
                sbus_blitc (*ush, (unsigned long) ush);
        }
        for (i = 0; i < 5; i++) {
@@ -435,24 +438,34 @@ __initfunc(static void sbus_con_type_init_finish(void))
  */
 static void sbus_get_scrmem(int currcons)
 {
+       struct vc_data *vcd = vc_cons[currcons].d;
+       
        memcpyw((unsigned short *)vc_scrbuf[currcons],
-               (unsigned short *)origin, video_screen_size);
-       origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
-       scr_end = video_mem_end = video_mem_start + video_screen_size;
-       pos = origin + y*video_size_row + (x<<1);
+               (unsigned short *)vcd->vc_origin, 
+               video_screen_size);
+       vcd->vc_origin = vcd->vc_video_mem_start = 
+               (unsigned long)vc_scrbuf[currcons];
+       vcd->vc_scr_end = vcd->vc_video_mem_end = 
+               vcd->vc_video_mem_start + video_screen_size;
+       vcd->vc_pos = 
+               vcd->vc_origin + vcd->vc_y*video_size_row + (vcd->vc_x<<1);
 }
 
 static void sbus_set_scrmem(int currcons, long offset)
 {
+       struct vc_data *vcd = vc_cons[currcons].d;
+       
        if (video_mem_term - video_mem_base < offset + video_screen_size)
                offset = 0;
        memcpyw((unsigned short *)(video_mem_base + offset),
-               (unsigned short *) origin, video_screen_size);
-       video_mem_start = video_mem_base;
-       video_mem_end = video_mem_term;
-       origin = video_mem_base + offset;
-       scr_end = origin + video_screen_size;
-       pos = origin + y*video_size_row + (x<<1);
+               (unsigned short *) vcd->vc_origin, 
+               video_screen_size);
+       vcd->vc_video_mem_start = video_mem_base;
+       vcd->vc_video_mem_end = video_mem_term;
+       vcd->vc_origin = video_mem_base + offset;
+       vcd->vc_scr_end = vcd->vc_origin + video_screen_size;
+       vcd->vc_pos = 
+               vcd->vc_origin + vcd->vc_y*video_size_row + (vcd->vc_x<<1);
 }
 
 /*
@@ -545,7 +558,20 @@ static int sbus_set_get_cmap(unsigned char * arg, int set)
        return 0;
 }
 
-static void sbus_clear_screen(void)
+#ifdef CONFIG_SUN4
+extern __inline__ void memset_screen(void *s, unsigned c, size_t n)
+{
+       unsigned *p = (unsigned *)s;
+       int i;
+       
+       for (i = n / 4; i > 0; i--)
+               *p++ = c;
+}
+#else
+#define memset_screen memset
+#endif
+
+void sbus_clear_screen(void)
 {
        if (fbinfo[0].fill) {
                int rects [4];
@@ -556,7 +582,7 @@ static void sbus_clear_screen(void)
                rects [3] = con_height;
                (*fbinfo[0].fill)(reverse_color_table[0], 1, rects);
        } else if (fbinfo[0].base && fbinfo[0].base_depth)
-               memset (con_fb_base,
+               memset_screen(con_fb_base,
                        (con_depth == 1) ? ~(0) : reverse_color_table[0],
                        (con_depth * con_height * con_width) / 8);
        /* also clear out the "shadow" screen memory */
@@ -769,8 +795,7 @@ __initfunc(static void
        fbinfo [n].type.fb_height = prom_getintdefault(con_node, "height", 900);
        fbinfo [n].type.fb_width  = prom_getintdefault(con_node, "width", 1152);
        fbinfo [n].type.fb_depth  = (type == FBTYPE_SUN2BW) ? 1 : 8;
-       linebytes = prom_getint(con_node, "linebytes");
-       if (linebytes == -1) linebytes = fbinfo [n].type.fb_width;
+       linebytes = prom_getintdefault(con_node, "linebytes", fbinfo[n].type.fb_width * fbinfo[n].type.fb_depth / 8);
        fbinfo [n].type.fb_size   = PAGE_ALIGN((linebytes) * (fbinfo [n].type.fb_height));
        fbinfo [n].space = io;
        fbinfo [n].blanked = 0;
@@ -925,12 +950,22 @@ __initfunc(int sbus_console_probe(void))
        u32 tmp;
        u32 prom_console_node = 0;
 
-       if(SBus_chain == 0)
-               return -1;
-
-       sbdprom = 0;
-       switch(prom_vers) {
-       case PROM_V0:
+       if(SBus_chain == 0) {
+#ifdef CONFIG_SUN4
+               sparc_framebuffer_setup (1,0,FBTYPE_SUN2BW,NULL,SUN4_300_BWTWO_PHYSADDR,0,0,0);
+#else  
+               creator = creator_present();
+               if (!creator)
+                       return -1;
+               sparc_framebuffer_setup (1, creator, FBTYPE_CREATOR,
+                                        0, 0, 0, 0, prom_root_node);
+#endif
+       } else {
+               sbdprom = 0;
+               
+               switch(prom_vers) {
+               
+               case PROM_V0:
                /* V0 proms are at sun4c only. Can skip many checks. */
                con_type = FBTYPE_NOTYPE;
                for_each_sbusdev(sbdp, SBus_chain) {
@@ -965,9 +1000,10 @@ __initfunc(int sbus_console_probe(void))
                                break;
                }
                break;
-       case PROM_V2:
-       case PROM_V3:
-       case PROM_P1275:
+               
+               case PROM_V2:
+               case PROM_V3:
+               case PROM_P1275:
                if (console_fb_path) {
                        char *q, c;
 
@@ -1073,8 +1109,10 @@ __initfunc(int sbus_console_probe(void))
                                                 prom_root_node);
                }
                break;
-       default:
+               
+               default:
                return -1;
+               }
        }
        
        if (fbinfo [0].type.fb_type == FBTYPE_NOTYPE) {
index beba2e7e6bbfe23fd0f7038ba6699c658ad2c577..42a2337538904dc1abb268b9eeae774d37723d2e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.4 1997/09/07 15:40:19 ecd Exp $
+/* $Id: su.c,v 1.8 1998/04/01 05:07:50 ecd Exp $
  * su.c: Small serial driver for keyboard/mouse interface on Ultra/AX
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -580,7 +580,7 @@ __initfunc(int su_init(void))
 __initfunc(int su_probe (unsigned long *memory_start))
 {
        struct su_struct *info = su_table;
-        int node, enode, sunode;
+        int node, enode, tnode, sunode;
        int kbnode = 0, msnode = 0;
        int devices = 0;
        char prop[128];
@@ -595,14 +595,18 @@ __initfunc(int su_probe (unsigned long *memory_start))
                return -ENODEV;
 
        len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
-       if (len > 0)
-               kbnode = prom_pathtoinode(prop);
+       if (len > 0) {
+               prop[len] = 0;
+               kbnode = prom_finddevice(prop);
+       }
        if (!kbnode)
                return -ENODEV;
 
        len = prom_getproperty(node, "mouse", prop, sizeof(prop));
-       if (len > 0)
-               msnode = prom_pathtoinode(prop);
+       if (len > 0) {
+               prop[len] = 0;
+               msnode = prom_finddevice(prop);
+       }
        if (!msnode)
                return -ENODEV;
 
@@ -612,6 +616,15 @@ __initfunc(int su_probe (unsigned long *memory_start))
         node = prom_getchild(prom_root_node);
        node = prom_searchsiblings(node, "pci");
 
+       /*
+        * Check for SUNW,sabre on Ultra 5/10/AXi.
+        */
+       len = prom_getproperty(node, "model", prop, sizeof(prop));
+       if ((len > 0) && !strncmp(prop, "SUNW,sabre", len)) {
+               node = prom_getchild(node);
+               node = prom_searchsiblings(node, "pci");
+       }
+
        /*
         * For each PCI bus...
         */
@@ -624,7 +637,10 @@ __initfunc(int su_probe (unsigned long *memory_start))
                 */
                while (enode) {
                        sunode = prom_getchild(enode);
-                       sunode = prom_searchsiblings(sunode, "su");
+                       tnode = prom_searchsiblings(sunode, "su");
+                       if (!tnode)
+                               tnode = prom_searchsiblings(sunode, "su_pnp");
+                       sunode = tnode;
 
                        /*
                         * For each 'su' on this EBus...
@@ -651,7 +667,11 @@ __initfunc(int su_probe (unsigned long *memory_start))
                                        goto found;
 
                                sunode = prom_getsibling(sunode);
-                               sunode = prom_searchsiblings(sunode, "su");
+                               tnode = prom_searchsiblings(sunode, "su");
+                               if (!tnode)
+                                       tnode = prom_searchsiblings(sunode,
+                                                                   "su_pnp");
+                               sunode = tnode;
                        }
                        enode = prom_getsibling(enode);
                        enode = prom_searchsiblings(enode, "ebus");
index 586ac28c08aa57be5be3fe06085492ce78768587..32062371ec5ce98a9ac52560fca51222fd778971 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.77 1997/12/19 07:32:59 ecd Exp $
+/* $Id: suncons.c,v 1.79 1998/01/30 10:59:23 jj Exp $
  * suncons.c: Sparc platform console generic layer.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -28,6 +28,9 @@ fbinfo_t *fbinfo;
 int fbinfos;
 unsigned int linux_logo_colors __initdata = LINUX_LOGO_COLORS;
 char logo_banner[] __initdata = linux_logo_banner;
+#ifdef CONFIG_PCI
+static int cons_type __initdata = 0;
+#endif
 
 extern struct console vt_console_driver;
 
@@ -344,6 +347,7 @@ __initfunc(unsigned long sun_console_init(unsigned long memory_start))
 
        if(sbus_console_probe()) {
 #ifdef CONFIG_PCI
+               cons_type = 1;
                pci_console_inithook();
                return memory_start;
 #else
@@ -363,6 +367,11 @@ __initfunc(unsigned long pci_console_init(unsigned long memory_start))
        /* Nothing to do in this case. */
        if (!con_is_present())
                return memory_start;
+               
+       if (!cons_type) {
+               /* Some console was already found on SBUS or UPA */
+               return memory_start;
+       }
 
        if(pci_console_probe()) {
                prom_printf("Could not probe PCI console, bailing out...\n");
index d55fb5ba5b892db2006905aefcc79e6b0f31390c..a0dcb6c74023f84314c3643b30a32e2a65cc8418 100644 (file)
@@ -37,7 +37,6 @@
 
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <asm/pbm.h>
 #include <asm/ebus.h>
 #endif
index ec0736ff00975ac1d417aa732ba64e053acd6779..18533652dd37194b3d33342a264018051ace1137 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.20 1997/08/22 15:55:14 jj Exp $
+/* $Id: tcx.c,v 1.22 1998/03/10 20:18:47 jj Exp $
  * tcx.c: SUNW,tcx 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -33,6 +33,8 @@
 /* THC definitions */
 #define TCX_THC_MISC_REV_SHIFT       16
 #define TCX_THC_MISC_REV_MASK        15
+#define TCX_THC_MISC_VSYNC_DIS       (1 << 25)
+#define TCX_THC_MISC_HSYNC_DIS       (1 << 24)
 #define TCX_THC_MISC_RESET           (1 << 12)
 #define TCX_THC_MISC_VIDEO           (1 << 10)
 #define TCX_THC_MISC_SYNC            (1 << 9)
@@ -174,7 +176,8 @@ tcx_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
                page += map_size;
        }
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
         return 0;
 }
 
@@ -246,11 +249,16 @@ static void
 tcx_blank (fbinfo_t *fb)
 {
        fb->info.tcx.thc->thc_misc &= ~TCX_THC_MISC_VIDEO;
+       /* This should put us in power-save */
+        fb->info.tcx.thc->thc_misc |= TCX_THC_MISC_VSYNC_DIS;
+        fb->info.tcx.thc->thc_misc |= TCX_THC_MISC_HSYNC_DIS;
 }
 
 static void
 tcx_unblank (fbinfo_t *fb)
 {
+        fb->info.tcx.thc->thc_misc &= ~TCX_THC_MISC_VSYNC_DIS;
+        fb->info.tcx.thc->thc_misc &= ~TCX_THC_MISC_HSYNC_DIS;
        fb->info.tcx.thc->thc_misc |= TCX_THC_MISC_VIDEO;
 }
 
index d144c78236776b551ac22fc62874b55d6ce73192..cb822dd2a30d46a33f5396c8cf5891be9367d546 100644 (file)
@@ -582,7 +582,8 @@ static int vfc_mmap(struct inode *inode, struct file *file,
        if(ret)
                return -EAGAIN;
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
        return 0;
 }
 
index 7de26c2f7039df721ef3956330e76a91d63a4ba2..4662bbbb74a88d13ccb2ec1ee228700c0b1cd38a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
+/* $Id: weitek.c,v 1.16 1998/03/10 20:18:54 jj Exp $
  * weitek.c: Tadpole P9100/P9000 console driver
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -84,7 +84,8 @@ weitek_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma,
                page += map_size;
        }
 
-       vma->vm_dentry = dget(file->f_dentry);
+       vma->vm_file = file;
+       file->f_count++;
        return 0;
 }
 #endif
index 6162ed4ad30ef6cd92beb3b2bfe69f7a1c899409..f7c477ea4b708f490437798af6a83c8be9fbc3c6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.15 1997/12/22 16:09:34 jj Exp $
+/* $Id: zs.c,v 1.20 1998/02/25 23:51:57 ecd Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -37,7 +37,7 @@
 #ifdef __sparc_v9__
 #include <asm/fhc.h>
 #ifdef CONFIG_PCI
-#include <linux/bios32.h>
+#include <linux/pci.h>
 #endif
 #endif
 
@@ -70,7 +70,12 @@ struct tty_struct *zs_ttys;
 #ifdef CONFIG_SERIAL_CONSOLE
 static struct console zs_console;
 static int zs_console_init(void);
-#endif
+
+/*
+ * Define this to get the zs_fair_output() functionality.
+ */
+#undef SERIAL_CONSOLE_FAIR_OUTPUT
+#endif /* CONFIG_SERIAL_CONSOLE */
 
 static unsigned char kgdb_regs[16] = {
        0, 0, 0,                     /* write 0, 1, 2 */
@@ -256,14 +261,14 @@ static inline void load_zsregs(struct sun_serial *info, unsigned char *regs)
        restore_flags(flags);
 }
 
+#define ZS_PUT_CHAR_MAX_DELAY  2000    /* 10 ms */
+
 static inline void zs_put_char(struct sun_zschannel *channel, char ch)
 {
-       int loops = 0;
+       int loops = ZS_PUT_CHAR_MAX_DELAY;
 
-       while((channel->control & Tx_BUF_EMP) == 0 && loops < 10000) {
-               loops++;
+       while((channel->control & Tx_BUF_EMP) == 0 && --loops)
                udelay(5);
-       }
        channel->data = ch;
        udelay(5);
 }
@@ -408,6 +413,10 @@ static _INLINE_ void zs_sched_event(struct sun_serial *info,
 extern void breakpoint(void);  /* For the KGDB frame character */
 #endif
 
+#ifdef CONFIG_MAGIC_SYSRQ
+static int serial_sysrq;
+#endif
+
 static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs)
 {
        struct tty_struct *tty = info->tty;
@@ -447,8 +456,6 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs
                }
                if(info->is_cons) {
 #ifdef CONFIG_MAGIC_SYSRQ
-                       static int serial_sysrq;
-
                        if (!ch) {
                                serial_sysrq = 1;
                                return;
@@ -566,8 +573,13 @@ static _INLINE_ void status_handle(struct sun_serial *info)
         * 'break asserted' status change interrupt, call
         * the boot prom.
         */
-       if((status & BRK_ABRT) && info->break_abort)
+       if((status & BRK_ABRT) && info->break_abort) {
+#ifdef CONFIG_MAGIC_SYSRQ
+               serial_sysrq = 1;
+#else
                batten_down_hatches();
+#endif
+       }
 
        /* XXX Whee, put in a buffer somewhere, the status information
         * XXX whee whee whee... Where does the information go...
@@ -1037,12 +1049,12 @@ static void zs_flush_chars(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->device, "zs_flush_chars"))
                return;
 
+       save_flags(flags); cli();
        if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
            !info->xmit_buf)
-               return;
+               goto out;
 
        /* Enable transmitter */
-       save_flags(flags); cli();
        info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
        write_zsreg(info->zs_channel, 1, info->curregs[1]);
        info->curregs[5] |= TxENAB;
@@ -1059,6 +1071,7 @@ static void zs_flush_chars(struct tty_struct *tty)
        info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
        info->xmit_cnt--;
 
+out:
        restore_flags(flags);
 }
 
@@ -1100,21 +1113,21 @@ static int zs_write(struct tty_struct * tty, int from_user,
                total += c;
        }
 
+       cli();          
        if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
                /* Enable transmitter */
                info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
                write_zsreg(info->zs_channel, 1, info->curregs[1]);
                info->curregs[5] |= TxENAB;
                write_zsreg(info->zs_channel, 5, info->curregs[5]);
-       }
 #if 1
-       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
                zs_put_char(info->zs_channel,
                            info->xmit_buf[info->xmit_tail++]);
                info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt--;
-       }
 #endif
+       }
+
        restore_flags(flags);
        return total;
 }
@@ -1819,7 +1832,7 @@ int zs_open(struct tty_struct *tty, struct file * filp)
 
 static void show_serial_version(void)
 {
-       char *revision = "$Revision: 1.15 $";
+       char *revision = "$Revision: 1.20 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
@@ -2220,7 +2233,7 @@ __initfunc(int zs_init(void))
 #endif
 
 #ifdef CONFIG_PCI
-       if (pcibios_present())
+       if (pci_present())
                return 0;
 #endif
 
@@ -2514,6 +2527,7 @@ zs_kgdb_hook(int tty_num))
 static void
 zs_console_putchar(struct sun_serial *info, char ch)
 {
+       int loops = ZS_PUT_CHAR_MAX_DELAY;
        unsigned long flags;
 
        if(!info->zs_channel)
@@ -2521,9 +2535,12 @@ zs_console_putchar(struct sun_serial *info, char ch)
 
        save_flags(flags); cli();
        zs_put_char(info->zs_channel, ch);
+       while (!(read_zsreg(info->zs_channel, R1) & ALL_SNT) && --loops)
+               udelay(5);
        restore_flags(flags);
 }
 
+#ifdef SERIAL_CONSOLE_FAIR_OUTPUT
 /*
  * Fair output driver allows a process to speak.
  */
@@ -2557,6 +2574,7 @@ static void zs_fair_output(struct sun_serial *info)
        restore_flags(flags);
        return;
 }
+#endif
 
 /*
  * zs_console_write is registered for printk.
@@ -2574,9 +2592,10 @@ zs_console_write(struct console *con, const char *s, unsigned count)
                        zs_console_putchar(info, '\r');
                zs_console_putchar(info, *s);
        }
-
+#ifdef SERIAL_CONSOLE_FAIR_OUTPUT
        /* Comment this if you want to have a strict interrupt-driven output */
        zs_fair_output(info);
+#endif
 }
 
 static int
index faa450eebdea1b7f377a14a9dbaa0e72cd48332e..1cd83f0a8db601c8bda679f2e91df7c58e855a98 100644 (file)
@@ -16,7 +16,7 @@
 struct Linux_SBus_DMA *dma_chain;
 
 /* Print out the current values in the DMA control registers */
-static __inline__ void
+extern __inline__ void
 dump_dma_regs(struct sparc_dma_registers *dregs)
 {
        printk("DMA CONTROL<%08lx>  ADDR<%08lx> CNT<%08lx> TEST<%08lx>\n",
@@ -27,6 +27,50 @@ dump_dma_regs(struct sparc_dma_registers *dregs)
        return;
 }
 
+__initfunc(void
+init_one_dvma(struct Linux_SBus_DMA *dma, int num_dma))
+{
+       printk("dma%d: ", num_dma);
+       
+       dma->next = 0;
+       dma->running=0;      /* No transfers going on as of yet */
+       dma->allocated=0;    /* No one has allocated us yet */
+       switch((dma->regs->cond_reg)&DMA_DEVICE_ID) {
+       case DMA_VERS0:
+               dma->revision=dvmarev0;
+               printk("Revision 0 ");
+               break;
+       case DMA_ESCV1:
+               dma->revision=dvmaesc1;
+               printk("ESC Revision 1 ");
+               break;
+       case DMA_VERS1:
+               dma->revision=dvmarev1;
+               printk("Revision 1 ");
+               break;
+       case DMA_VERS2:
+               dma->revision=dvmarev2;
+               printk("Revision 2 ");
+               break;
+       case DMA_VERHME:
+               dma->revision=dvmahme;
+               printk("HME DVMA gate array ");
+               break;
+       case DMA_VERSPLUS:
+               dma->revision=dvmarevplus;
+               printk("Revision 1 PLUS ");
+               break;
+       default:
+               printk("unknown dma version %x",
+                      (dma->regs->cond_reg)&DMA_DEVICE_ID);
+               dma->allocated = 1;
+               break;
+       }
+       printk("\n");
+#if 0 /* Clutters up the screen */
+       dump_dma_regs(dma->regs);
+#endif
+}
 
 /* Probe this SBus DMA module(s) */
 __initfunc(unsigned long
@@ -40,11 +84,11 @@ dvma_init(struct linux_sbus *sbus, unsigned long memory_start))
        for_each_sbusdev(this_dev, sbus) {
                int hme = 0;
 
-               if(!strcmp(this_dev->prom_name, "SUNW,fas")) {
+               if(!strcmp(this_dev->prom_name, "SUNW,fas"))
                        hme = 1;
-               else if(strcmp(this_dev->prom_name, "dma") &&
-                         strcmp(this_dev->prom_name, "ledma") &&
-                         strcmp(this_dev->prom_name, "espdma"))
+               else if(strcmp(this_dev->prom_name, "dma") &&
+                       strcmp(this_dev->prom_name, "ledma") &&
+                       strcmp(this_dev->prom_name, "espdma"))
                        continue;
 
                /* Found one... */
@@ -62,10 +106,6 @@ dvma_init(struct linux_sbus *sbus, unsigned long memory_start))
                        /* We're the first in line */
                        dma_chain=dma;
                }
-               dma->next = 0;
-
-               printk("dma%d: ", num_dma);
-               num_dma++;
 
                /* The constant PAGE_SIZE that is passed to sparc_alloc_io makes the
                 * routine only alloc 1 page, that was what the original code did
@@ -82,45 +122,42 @@ dvma_init(struct linux_sbus *sbus, unsigned long memory_start))
                                        dma->SBus_dev->reg_addrs[0].which_io, 0x0);
 
                dma->node = dma->SBus_dev->prom_node;
-               dma->running=0;      /* No transfers going on as of yet */
-               dma->allocated=0;    /* No one has allocated us yet */
-               switch((dma->regs->cond_reg)&DMA_DEVICE_ID) {
-               case DMA_VERS0:
-                       dma->revision=dvmarev0;
-                       printk("Revision 0 ");
-                       break;
-               case DMA_ESCV1:
-                       dma->revision=dvmaesc1;
-                       printk("ESC Revision 1 ");
-                       break;
-               case DMA_VERS1:
-                       dma->revision=dvmarev1;
-                       printk("Revision 1 ");
-                       break;
-               case DMA_VERS2:
-                       dma->revision=dvmarev2;
-                       printk("Revision 2 ");
-                       break;
-               case DMA_VERHME:
-                       dma->revision=dvmahme;
-                       printk("HME DVMA gate array ");
-                       break;
-               case DMA_VERSPLUS:
-                       dma->revision=dvmarevplus;
-                       printk("Revision 1 PLUS ");
-                       break;
-               default:
-                       printk("unknown dma version %x",
-                              (dma->regs->cond_reg)&DMA_DEVICE_ID);
-                       dma->allocated = 1;
-                       break;
-               }
-               printk("\n");
-#if 0 /* Clutters up the screen */
-               dump_dma_regs(dma->regs);
-#endif
+               
+               init_one_dvma(dma, num_dma++);
+               
        };  /* while(this_dev) */
 
        return memory_start;
 }
 
+#ifdef CONFIG_SUN4
+
+#include <asm/sun4paddr.h>
+
+__initfunc(unsigned long
+sun4_dvma_init(unsigned long memory_start))
+{
+       struct Linux_SBus_DMA *dma;
+       struct Linux_SBus_DMA *dchain;
+
+       dma = (struct Linux_SBus_DMA *) memory_start;
+       memory_start += sizeof(struct Linux_SBus_DMA);
+
+       /* No SBUS */
+       dma->SBus_dev = 0x0;
+
+       /* Only one DMA device */
+       dma_chain=dma;
+
+       dma->regs = (struct sparc_dma_registers *)
+               sparc_alloc_io (SUN4_300_DMA_PHYSADDR, 0,
+                               PAGE_SIZE, "dma", 0x0, 0x0);
+
+       /* No prom node */
+       dma->node = 0x0;
+
+       init_one_dvma(dma, 0);
+       return memory_start;
+}
+
+#endif
index 3f19845424507fa4bc9c5f07f9f741dece7afa67..93713c94f597aceed7ca6f3d0dd25de8b9bd371f 100644 (file)
@@ -186,12 +186,10 @@ extern unsigned long iommu_init(int iommu_node, unsigned long memstart,
                                unsigned long memend, struct linux_sbus *sbus);
 extern unsigned long iounit_init(int sbi_node, int iounit_node, unsigned long memstart,
                                unsigned long memend, struct linux_sbus *sbus);
+unsigned long sun4_init(unsigned long memory_start, unsigned long memory_end);
 #ifdef CONFIG_SUN_OPENPROMIO
 extern int openprom_init(void);
 #endif
-#ifdef CONFIG_SUN_MOSTEK_RTC
-extern int rtc_init(void);
-#endif
 #ifdef CONFIG_SUN_AUXIO
 extern void auxio_probe(void);
 #endif
@@ -234,8 +232,6 @@ sbus_do_child_siblings(unsigned long memory_start, int start_node,
        return memory_start;
 }
 
-/* #define E3000_DEBUG */
-
 __initfunc(unsigned long
 sbus_init(unsigned long memory_start, unsigned long memory_end))
 {
@@ -244,10 +240,11 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
        struct linux_sbus *sbus;
        struct linux_sbus_device *this_dev;
        int num_sbus = 0;  /* How many did we find? */
-
-#ifdef E3000_DEBUG
-       prom_printf("sbus_init: Radek, record following output for me. -DaveM\n");
+       
+#ifdef CONFIG_SUN4
+       return sun4_init(memory_start, memory_end);
 #endif
+
        memory_start = ((memory_start + 7) & (~7));
 
        topnd = prom_getchild(prom_root_node);
@@ -280,9 +277,6 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                }
        }
 
-#ifdef E3000_DEBUG
-       prom_printf("sbus_init: 1st sbus node(%x)\n", nd);
-#endif
        /* Ok, we've found the first one, allocate first SBus struct
         * and place in chain.
         */
@@ -299,9 +293,6 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
        /* Loop until we find no more SBUS's */
        while(this_sbus) {
                /* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */
-#ifdef E3000_DEBUG
-               prom_printf("sbus%d: [ii()", num_sbus);
-#endif
                if(sparc_cpu_model == sun4u)
                        memory_start = iommu_init(this_sbus,
                                                  memory_start, memory_end,
@@ -312,9 +303,6 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                                                   memory_start, memory_end,
                                                   sbus);
 #endif                                            
-#ifdef E3000_DEBUG
-               prom_printf("1");
-#endif
                printk("sbus%d: ", num_sbus);
                sbus_clock = prom_getint(this_sbus, "clock-frequency");
                if(sbus_clock==-1) sbus_clock = (25*1000*1000);
@@ -334,15 +322,9 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                }
 #endif
                
-#ifdef E3000_DEBUG
-               prom_printf("psri()");
-#endif
                prom_sbus_ranges_init (iommund, sbus);
 
                sbus_devs = prom_getchild(this_sbus);
-#ifdef E3000_DEBUG
-               prom_printf("chld(%x)", sbus_devs);
-#endif
 
                sbus->devices = (struct linux_sbus_device *) memory_start;
                memory_start += sizeof(struct linux_sbus_device);
@@ -350,9 +332,6 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                this_dev = sbus->devices;
                this_dev->next = 0;
 
-#ifdef E3000_DEBUG
-               prom_printf("fsd()");
-#endif
                fill_sbus_device(sbus_devs, this_dev);
                this_dev->my_bus = sbus;
 
@@ -362,14 +341,9 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                        this_dev->child = (struct linux_sbus_device *) memory_start;
                        memory_start += sizeof(struct linux_sbus_device);
                        /* Fill it */
-#ifdef E3000_DEBUG
-                       prom_printf("fsd(chld)");
-#endif
+
                        fill_sbus_device(prom_getchild(sbus_devs), this_dev->child);
                        this_dev->child->my_bus = sbus;
-#ifdef E3000_DEBUG
-                       prom_printf("sdcs()");
-#endif
                        memory_start = sbus_do_child_siblings(memory_start,
                                                              prom_getchild(sbus_devs),
                                                              this_dev->child,
@@ -378,9 +352,6 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                        this_dev->child = 0;
                }
 
-#ifdef E3000_DEBUG
-               prom_printf("2");
-#endif
                while((sbus_devs = prom_getsibling(sbus_devs)) != 0) {
                        /* Allocate device node */
                        this_dev->next = (struct linux_sbus_device *) memory_start;
@@ -389,9 +360,6 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                        this_dev->next=0;
 
                        /* Fill it */
-#ifdef E3000_DEBUG
-                       prom_printf("fsd()");
-#endif
                        fill_sbus_device(sbus_devs, this_dev);
                        this_dev->my_bus = sbus;
 
@@ -403,15 +371,9 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                                memory_start += sizeof(struct linux_sbus_device);
 
                                /* Fill it */
-#ifdef E3000_DEBUG
-                               prom_printf("fsd()");
-#endif
                                fill_sbus_device(prom_getchild(sbus_devs),
                                                 this_dev->child);
                                this_dev->child->my_bus = sbus;
-#ifdef E3000_DEBUG
-                               prom_printf("sdcs()");
-#endif
                                memory_start = sbus_do_child_siblings(
                                                     memory_start,
                                                     prom_getchild(sbus_devs),
@@ -422,26 +384,14 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                        }
                }
 
-#ifdef E3000_DEBUG
-               prom_printf("di()");
-#endif
                memory_start = dvma_init(sbus, memory_start);
 
                num_sbus++;
-#ifdef E3000_DEBUG
-               prom_printf("3, off to next sbus\n");
-#endif
                if(sparc_cpu_model == sun4u) {
                        this_sbus = prom_getsibling(this_sbus);
-#ifdef E3000_DEBUG
-                       prom_printf("sbus_init: sibling(%x), ", this_sbus);
-#endif
                        if(!this_sbus)
                                break;
                        this_sbus = prom_searchsiblings(this_sbus, "sbus");
-#ifdef E3000_DEBUG
-                       prom_printf("next sbus node(%x),", this_sbus);
-#endif
                } else if(sparc_cpu_model == sun4d) {
                        iommund = prom_getsibling(iommund);
                        if(!iommund) break;
@@ -454,9 +404,6 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                        this_sbus = prom_searchsiblings(this_sbus, "sbus");
                }
                if(this_sbus) {
-#ifdef E3000_DEBUG
-                       prom_printf(" scanning another sbus\n");
-#endif
                        sbus->next = (struct linux_sbus *) memory_start;
                        memory_start += sizeof(struct linux_sbus);
                        sbus = sbus->next;
@@ -471,19 +418,10 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
                memory_start = sun4d_init_sbi_irq(memory_start);
        }
        
-#ifdef E3000_DEBUG
-       prom_printf("sbus_init: No more sbus's, calling sun_console_init()\n");
-#endif
        memory_start = sun_console_init(memory_start); /* whee... */
-#ifdef E3000_DEBUG
-       prom_printf("sbus_init: back from sun_console_init()\n");
-#endif
 #ifdef CONFIG_SUN_OPENPROMIO
        openprom_init();
 #endif
-#ifdef CONFIG_SUN_MOSTEK_RTC
-       rtc_init();
-#endif
 #ifdef CONFIG_SUN_BPP
        bpp_init();
 #endif
@@ -505,3 +443,20 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
 #endif
        return memory_start;
 }
+
+#ifdef CONFIG_SUN4
+
+extern unsigned long sun4_dvma_init(unsigned long);
+
+__initfunc(unsigned long
+sun4_init(unsigned long memory_start, unsigned long memory_end))
+{
+       memory_start = ((memory_start + 7) & (~7));
+       
+       memory_start = sun_console_init(memory_start);
+       
+       memory_start = sun4_dvma_init(memory_start);
+       
+       return memory_start;
+}
+#endif
index 5bdae66dd4d589f148af3244902b96719f01b476..19e1dfa6a31ff448fd0ab31e16f9fae90000b5ca 100644 (file)
@@ -5143,8 +5143,8 @@ intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
                pci_status &= ~PCI_STATUS_PARITY;
            }
        } else {
-           printk ("scsi%d : couldn't read status register : %s\n",
-               host->host_no, pcibios_strerror (tmp));
+           printk ("scsi%d : couldn't read status register : error %d\n",
+               host->host_no, tmp);
            retry = NEVER;
        }
     }
index ed2d7369d1d9a56ff83a844cce19a2d9b5bca334..d415271cac3edc39f253a26282141cfdc74ac5d0 100644 (file)
@@ -2,7 +2,7 @@
 
   Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
 
-  Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -26,8 +26,8 @@
 */
 
 
-#define BusLogic_DriverVersion         "2.0.12"
-#define BusLogic_DriverDate            "29 March 1998"
+#define BusLogic_DriverVersion         "2.1.13"
+#define BusLogic_DriverDate            "17 April 1998"
 
 
 #include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
-
-#include <linux/blk.h>
-
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/irq.h>
+#include <asm/spinlock.h>
 #include <asm/system.h>
 #include "scsi.h"
 #include "hosts.h"
@@ -114,15 +110,6 @@ static BusLogic_HostAdapter_T
   *BusLogic_LastRegisteredHostAdapter =                NULL;
 
 
-/*
-  BusLogic_RegisteredHostAdapters is an array of linked lists of all the
-  registered BusLogic Host Adapters, indexed by IRQ Channel.
-*/
-
-static BusLogic_HostAdapter_T
-  *BusLogic_RegisteredHostAdapters[NR_IRQS] =  { NULL };
-
-
 /*
   BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList.
 */
@@ -152,16 +139,6 @@ static char
   *BusLogic_CommandFailureReason;
 
 
-/*
-  BusLogic_FirstCompletedCCB and BusLogic_LastCompletedCCB are pointers
-  to the first and last CCBs that are queued for completion processing.
-*/
-
-static BusLogic_CCB_T
-  *BusLogic_FirstCompletedCCB =                        NULL,
-  *BusLogic_LastCompletedCCB =                 NULL;
-
-
 /*
   BusLogic_ProcDirectoryEntry is the BusLogic /proc/scsi directory entry.
 */
@@ -181,7 +158,7 @@ static void BusLogic_AnnounceDriver(BusLogic_HostAdapter_T *HostAdapter)
   BusLogic_Announce("***** BusLogic SCSI Driver Version "
                    BusLogic_DriverVersion " of "
                    BusLogic_DriverDate " *****\n", HostAdapter);
-  BusLogic_Announce("Copyright 1995 by Leonard N. Zubkoff "
+  BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff "
                    "<lnz@dandelion.com>\n", HostAdapter);
 }
 
@@ -206,7 +183,7 @@ const char *BusLogic_DriverInfo(SCSI_Host_T *Host)
 
 static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 {
-  HostAdapter->NextAll = NULL;
+  HostAdapter->Next = NULL;
   if (BusLogic_FirstRegisteredHostAdapter == NULL)
     {
       BusLogic_FirstRegisteredHostAdapter = HostAdapter;
@@ -214,20 +191,9 @@ static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
     }
   else
     {
-      BusLogic_LastRegisteredHostAdapter->NextAll = HostAdapter;
+      BusLogic_LastRegisteredHostAdapter->Next = HostAdapter;
       BusLogic_LastRegisteredHostAdapter = HostAdapter;
     }
-  HostAdapter->Next = NULL;
-  if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != NULL)
-    {
-      BusLogic_HostAdapter_T *LastHostAdapter =
-       BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
-      BusLogic_HostAdapter_T *NextHostAdapter;
-      while ((NextHostAdapter = LastHostAdapter->Next) != NULL)
-       LastHostAdapter = NextHostAdapter;
-      LastHostAdapter->Next = HostAdapter;
-    }
-  else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] = HostAdapter;
 }
 
 
@@ -241,7 +207,7 @@ static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
   if (HostAdapter == BusLogic_FirstRegisteredHostAdapter)
     {
       BusLogic_FirstRegisteredHostAdapter =
-       BusLogic_FirstRegisteredHostAdapter->NextAll;
+       BusLogic_FirstRegisteredHostAdapter->Next;
       if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
        BusLogic_LastRegisteredHostAdapter = NULL;
     }
@@ -249,25 +215,12 @@ static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
     {
       BusLogic_HostAdapter_T *PreviousHostAdapter =
        BusLogic_FirstRegisteredHostAdapter;
-      while (PreviousHostAdapter != NULL &&
-            PreviousHostAdapter->NextAll != HostAdapter)
-       PreviousHostAdapter = PreviousHostAdapter->NextAll;
-      if (PreviousHostAdapter != NULL)
-       PreviousHostAdapter->NextAll = HostAdapter->NextAll;
-    }
-  HostAdapter->NextAll = NULL;
-  if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != HostAdapter)
-    {
-      BusLogic_HostAdapter_T *PreviousHostAdapter =
-       BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
       while (PreviousHostAdapter != NULL &&
             PreviousHostAdapter->Next != HostAdapter)
        PreviousHostAdapter = PreviousHostAdapter->Next;
       if (PreviousHostAdapter != NULL)
        PreviousHostAdapter->Next = HostAdapter->Next;
     }
-  else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] =
-        HostAdapter->Next;
   HostAdapter->Next = NULL;
 }
 
@@ -469,7 +422,7 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
   unsigned char *ReplyPointer = (unsigned char *) ReplyData;
   BusLogic_StatusRegister_T StatusRegister;
   BusLogic_InterruptRegister_T InterruptRegister;
-  unsigned long ProcessorFlags = 0;
+  ProcessorFlags_T ProcessorFlags = 0;
   int ReplyBytes = 0, Result;
   long TimeoutCounter;
   /*
@@ -797,12 +750,7 @@ static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
   boolean ForceBusDeviceScanningOrder = false;
   boolean ForceBusDeviceScanningOrderChecked = false;
   boolean StandardAddressSeen[6];
-  unsigned char Bus, DeviceFunction;
-  unsigned int BaseAddress0, BaseAddress1;
-  unsigned char IRQ_Channel;
-  BusLogic_IO_Address_T IO_Address;
-  BusLogic_PCI_Address_T PCI_Address;
-  unsigned short Index = 0;
+  PCI_Device_T *PCI_Device = NULL;
   int i;
   if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0;
   BusLogic_ProbeInfoCount++;
@@ -821,147 +769,148 @@ static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
     particular standard ISA I/O Address need not be probed.
   */
   PrimaryProbeInfo->IO_Address = 0;
-  while (pcibios_find_device(PCI_VENDOR_ID_BUSLOGIC,
-                            PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
-                            Index++, &Bus, &DeviceFunction) == 0)
-    if (pcibios_read_config_dword(Bus, DeviceFunction,
-                                 PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
-       pcibios_read_config_dword(Bus, DeviceFunction,
-                                 PCI_BASE_ADDRESS_1, &BaseAddress1) == 0 &&
-       pcibios_read_config_byte(Bus, DeviceFunction,
-                                PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
-      {
-       BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
-       BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation;
-       BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
-       unsigned char Device = DeviceFunction >> 3;
-       IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-       PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
-       if ((BaseAddress0 & PCI_BASE_ADDRESS_SPACE)
-           != PCI_BASE_ADDRESS_SPACE_IO)
-         {
-           BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
-                          "MultiMaster Host Adapter\n", NULL, BaseAddress0);
-           BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
-                          NULL, Bus, Device, IO_Address);
-           continue;
-         }
-       if ((BaseAddress1 & PCI_BASE_ADDRESS_SPACE)
-           != PCI_BASE_ADDRESS_SPACE_MEMORY)
-         {
-           BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for "
-                          "MultiMaster Host Adapter\n", NULL, BaseAddress1);
-           BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n",
-                          NULL, Bus, Device, PCI_Address);
-           continue;
-         }
-       if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
-         {
-           BusLogic_Error("BusLogic: IRQ Channel %d illegal for "
-                          "MultiMaster Host Adapter\n", NULL, IRQ_Channel);
-           BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
-                          NULL, Bus, Device, IO_Address);
-           continue;
-         }
-       if (BusLogic_GlobalOptions.TraceProbe)
-         {
-           BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter "
-                           "detected at\n", NULL);
-           BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address "
-                           "0x%X PCI Address 0x%X\n", NULL,
-                           Bus, Device, IO_Address, PCI_Address);
-         }
-       /*
-         Issue the Inquire PCI Host Adapter Information command to determine
-         the ISA Compatible I/O Port.  If the ISA Compatible I/O Port is
-         known and enabled, note that the particular Standard ISA I/O
-         Address should not be probed.
-       */
-       HostAdapter->IO_Address = IO_Address;
-       if (BusLogic_Command(HostAdapter,
-                            BusLogic_InquirePCIHostAdapterInformation,
-                            NULL, 0, &PCIHostAdapterInformation,
-                            sizeof(PCIHostAdapterInformation))
-           == sizeof(PCIHostAdapterInformation))
-         {
-           if (PCIHostAdapterInformation.ISACompatibleIOPort < 6)
-             StandardAddressSeen[PCIHostAdapterInformation
-                                 .ISACompatibleIOPort] = true;
-         }
-       else PCIHostAdapterInformation.ISACompatibleIOPort =
-              BusLogic_IO_Disable;
-       /*
-         Issue the Modify I/O Address command to disable the ISA Compatible
-         I/O Port.
-       */
-       ModifyIOAddressRequest = BusLogic_IO_Disable;
-       BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress,
-                        &ModifyIOAddressRequest,
-                        sizeof(ModifyIOAddressRequest), NULL, 0);
-       /*
-         For the first MultiMaster Host Adapter enumerated, issue the Fetch
-         Host Adapter Local RAM command to read byte 45 of the AutoSCSI area,
-         for the setting of the "Use Bus And Device # For PCI Scanning Seq."
-         option.  Issue the Inquire Board ID command since this option is
-         only valid for the BT-948/958/958D.
-       */
-       if (!ForceBusDeviceScanningOrderChecked)
-         {
-           BusLogic_FetchHostAdapterLocalRAMRequest_T
-             FetchHostAdapterLocalRAMRequest;
-           BusLogic_AutoSCSIByte45_T AutoSCSIByte45;
-           BusLogic_BoardID_T BoardID;
-           FetchHostAdapterLocalRAMRequest.ByteOffset =
-             BusLogic_AutoSCSI_BaseOffset + 45;
-           FetchHostAdapterLocalRAMRequest.ByteCount =
-             sizeof(AutoSCSIByte45);
-           BusLogic_Command(HostAdapter,
-                            BusLogic_FetchHostAdapterLocalRAM,
-                            &FetchHostAdapterLocalRAMRequest,
-                            sizeof(FetchHostAdapterLocalRAMRequest),
-                            &AutoSCSIByte45, sizeof(AutoSCSIByte45));
-           BusLogic_Command(HostAdapter, BusLogic_InquireBoardID,
-                            NULL, 0, &BoardID, sizeof(BoardID));
-           if (BoardID.FirmwareVersion1stDigit == '5')
-             ForceBusDeviceScanningOrder =
-               AutoSCSIByte45.ForceBusDeviceScanningOrder;
-           ForceBusDeviceScanningOrderChecked = true;
-         }
-       /*
-         Determine whether this MultiMaster Host Adapter has its ISA
-         Compatible I/O Port enabled and is assigned the Primary I/O Address.
-         If it does, then it is the Primary MultiMaster Host Adapter and must
-         be recognized first.  If it does not, then it is added to the list
-         for probing after any Primary MultiMaster Host Adapter is probed.
-       */
-       if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330)
-         {
-           PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-           PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
-           PrimaryProbeInfo->IO_Address = IO_Address;
-           PrimaryProbeInfo->PCI_Address = PCI_Address;
-           PrimaryProbeInfo->Bus = Bus;
-           PrimaryProbeInfo->Device = Device;
-           PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
-           PCIMultiMasterCount++;
-         }
-       else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
-         {
-           BusLogic_ProbeInfo_T *ProbeInfo =
-             &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-           ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-           ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
-           ProbeInfo->IO_Address = IO_Address;
-           ProbeInfo->PCI_Address = PCI_Address;
-           ProbeInfo->Bus = Bus;
-           ProbeInfo->Device = Device;
-           ProbeInfo->IRQ_Channel = IRQ_Channel;
-           NonPrimaryPCIMultiMasterCount++;
-           PCIMultiMasterCount++;
-         }
-       else BusLogic_Warning("BusLogic: Too many Host Adapters "
-                             "detected\n", NULL);
-      }
+  while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC,
+                                      PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
+                                      PCI_Device)) != NULL)
+    {
+      BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
+      BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation;
+      BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
+      unsigned char Bus = PCI_Device->bus->number;
+      unsigned char Device = PCI_Device->devfn >> 3;
+      unsigned int IRQ_Channel = PCI_Device->irq;
+      unsigned long BaseAddress0 = PCI_Device->base_address[0];
+      unsigned long BaseAddress1 = PCI_Device->base_address[1];
+      BusLogic_IO_Address_T IO_Address =
+       BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+      BusLogic_PCI_Address_T PCI_Address =
+       BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+      if ((BaseAddress0 & PCI_BASE_ADDRESS_SPACE)
+         != PCI_BASE_ADDRESS_SPACE_IO)
+       {
+         BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
+                        "MultiMaster Host Adapter\n", NULL, BaseAddress0);
+         BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
+                        NULL, Bus, Device, IO_Address);
+         continue;
+       }
+      if ((BaseAddress1 & PCI_BASE_ADDRESS_SPACE)
+         != PCI_BASE_ADDRESS_SPACE_MEMORY)
+       {
+         BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for "
+                        "MultiMaster Host Adapter\n", NULL, BaseAddress1);
+         BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n",
+                        NULL, Bus, Device, PCI_Address);
+         continue;
+       }
+      if (IRQ_Channel == 0)
+       {
+         BusLogic_Error("BusLogic: IRQ Channel %d illegal for "
+                        "MultiMaster Host Adapter\n", NULL, IRQ_Channel);
+         BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
+                        NULL, Bus, Device, IO_Address);
+         continue;
+       }
+      if (BusLogic_GlobalOptions.TraceProbe)
+       {
+         BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter "
+                         "detected at\n", NULL);
+         BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address "
+                         "0x%X PCI Address 0x%X\n", NULL,
+                         Bus, Device, IO_Address, PCI_Address);
+       }
+      /*
+       Issue the Inquire PCI Host Adapter Information command to determine
+       the ISA Compatible I/O Port.  If the ISA Compatible I/O Port is
+       known and enabled, note that the particular Standard ISA I/O
+       Address should not be probed.
+      */
+      HostAdapter->IO_Address = IO_Address;
+      BusLogic_InterruptReset(HostAdapter);
+      if (BusLogic_Command(HostAdapter,
+                          BusLogic_InquirePCIHostAdapterInformation,
+                          NULL, 0, &PCIHostAdapterInformation,
+                          sizeof(PCIHostAdapterInformation))
+         == sizeof(PCIHostAdapterInformation))
+       {
+         if (PCIHostAdapterInformation.ISACompatibleIOPort < 6)
+           StandardAddressSeen[PCIHostAdapterInformation
+                               .ISACompatibleIOPort] = true;
+       }
+      else PCIHostAdapterInformation.ISACompatibleIOPort =
+            BusLogic_IO_Disable;
+      /*
+       Issue the Modify I/O Address command to disable the ISA Compatible
+       I/O Port.
+      */
+      ModifyIOAddressRequest = BusLogic_IO_Disable;
+      BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress,
+                      &ModifyIOAddressRequest,
+                      sizeof(ModifyIOAddressRequest), NULL, 0);
+      /*
+       For the first MultiMaster Host Adapter enumerated, issue the Fetch
+       Host Adapter Local RAM command to read byte 45 of the AutoSCSI area,
+       for the setting of the "Use Bus And Device # For PCI Scanning Seq."
+       option.  Issue the Inquire Board ID command since this option is
+       only valid for the BT-948/958/958D.
+      */
+      if (!ForceBusDeviceScanningOrderChecked)
+       {
+         BusLogic_FetchHostAdapterLocalRAMRequest_T
+           FetchHostAdapterLocalRAMRequest;
+         BusLogic_AutoSCSIByte45_T AutoSCSIByte45;
+         BusLogic_BoardID_T BoardID;
+         FetchHostAdapterLocalRAMRequest.ByteOffset =
+           BusLogic_AutoSCSI_BaseOffset + 45;
+         FetchHostAdapterLocalRAMRequest.ByteCount =
+           sizeof(AutoSCSIByte45);
+         BusLogic_Command(HostAdapter,
+                          BusLogic_FetchHostAdapterLocalRAM,
+                          &FetchHostAdapterLocalRAMRequest,
+                          sizeof(FetchHostAdapterLocalRAMRequest),
+                          &AutoSCSIByte45, sizeof(AutoSCSIByte45));
+         BusLogic_Command(HostAdapter, BusLogic_InquireBoardID,
+                          NULL, 0, &BoardID, sizeof(BoardID));
+         if (BoardID.FirmwareVersion1stDigit == '5')
+           ForceBusDeviceScanningOrder =
+             AutoSCSIByte45.ForceBusDeviceScanningOrder;
+         ForceBusDeviceScanningOrderChecked = true;
+       }
+      /*
+       Determine whether this MultiMaster Host Adapter has its ISA
+       Compatible I/O Port enabled and is assigned the Primary I/O Address.
+       If it does, then it is the Primary MultiMaster Host Adapter and must
+       be recognized first.  If it does not, then it is added to the list
+       for probing after any Primary MultiMaster Host Adapter is probed.
+      */
+      if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330)
+       {
+         PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+         PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+         PrimaryProbeInfo->IO_Address = IO_Address;
+         PrimaryProbeInfo->PCI_Address = PCI_Address;
+         PrimaryProbeInfo->Bus = Bus;
+         PrimaryProbeInfo->Device = Device;
+         PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
+         PCIMultiMasterCount++;
+       }
+      else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
+       {
+         BusLogic_ProbeInfo_T *ProbeInfo =
+           &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+         ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+         ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+         ProbeInfo->IO_Address = IO_Address;
+         ProbeInfo->PCI_Address = PCI_Address;
+         ProbeInfo->Bus = Bus;
+         ProbeInfo->Device = Device;
+         ProbeInfo->IRQ_Channel = IRQ_Channel;
+         NonPrimaryPCIMultiMasterCount++;
+         PCIMultiMasterCount++;
+       }
+      else BusLogic_Warning("BusLogic: Too many Host Adapters "
+                           "detected\n", NULL);
+    }
   /*
     If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option is ON
     for the first enumerated MultiMaster Host Adapter, and if that host adapter
@@ -1027,34 +976,32 @@ static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
     Iterate over the older non-compliant MultiMaster PCI Host Adapters,
     noting the PCI bus location and assigned IRQ Channel.
   */
-  Index = 0;
-  while (pcibios_find_device(PCI_VENDOR_ID_BUSLOGIC,
-                            PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
-                            Index++, &Bus, &DeviceFunction) == 0)
-    if (pcibios_read_config_dword(Bus, DeviceFunction,
-                                 PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
-       pcibios_read_config_byte(Bus, DeviceFunction,
-                                PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
-      {
-       unsigned char Device = DeviceFunction >> 3;
-       IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-       if (IO_Address == 0 || IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
-         continue;
-       for (i = 0; i < BusLogic_ProbeInfoCount; i++)
-         {
-           BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[i];
-           if (ProbeInfo->IO_Address == IO_Address &&
-               ProbeInfo->HostAdapterType == BusLogic_MultiMaster)
-             {
-               ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
-               ProbeInfo->PCI_Address = 0;
-               ProbeInfo->Bus = Bus;
-               ProbeInfo->Device = Device;
-               ProbeInfo->IRQ_Channel = IRQ_Channel;
-               break;
-             }
-         }
-      }
+  PCI_Device = NULL;
+  while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC,
+                                      PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
+                                      PCI_Device)) != NULL)
+    {
+      unsigned char Bus = PCI_Device->bus->number;
+      unsigned char Device = PCI_Device->devfn >> 3;
+      unsigned int IRQ_Channel = PCI_Device->irq;
+      BusLogic_IO_Address_T IO_Address =
+       PCI_Device->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+      if (IO_Address == 0 || IRQ_Channel == 0) continue;
+      for (i = 0; i < BusLogic_ProbeInfoCount; i++)
+       {
+         BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[i];
+         if (ProbeInfo->IO_Address == IO_Address &&
+             ProbeInfo->HostAdapterType == BusLogic_MultiMaster)
+           {
+             ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+             ProbeInfo->PCI_Address = 0;
+             ProbeInfo->Bus = Bus;
+             ProbeInfo->Device = Device;
+             ProbeInfo->IRQ_Channel = IRQ_Channel;
+             break;
+           }
+       }
+    }
   return PCIMultiMasterCount;
 }
 
@@ -1070,87 +1017,82 @@ static int BusLogic_InitializeFlashPointProbeInfo(BusLogic_HostAdapter_T
                                                  *PrototypeHostAdapter)
 {
   int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0;
-  unsigned char Bus, DeviceFunction;
-  unsigned int BaseAddress0, BaseAddress1;
-  unsigned char IRQ_Channel;
-  BusLogic_IO_Address_T IO_Address;
-  BusLogic_PCI_Address_T PCI_Address;
-  unsigned short Index = 0;
+  PCI_Device_T *PCI_Device = NULL;
   /*
     Interrogate PCI Configuration Space for any FlashPoint Host Adapters.
   */
-  while (pcibios_find_device(PCI_VENDOR_ID_BUSLOGIC,
-                            PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
-                            Index++, &Bus, &DeviceFunction) == 0)
-    if (pcibios_read_config_dword(Bus, DeviceFunction,
-                                 PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
-       pcibios_read_config_dword(Bus, DeviceFunction,
-                                 PCI_BASE_ADDRESS_1, &BaseAddress1) == 0 &&
-       pcibios_read_config_byte(Bus, DeviceFunction,
-                                PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
-      {
-       unsigned char Device = DeviceFunction >> 3;
-       IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-       PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+  while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC,
+                                      PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
+                                      PCI_Device)) != NULL)
+    {
+      unsigned char Bus = PCI_Device->bus->number;
+      unsigned char Device = PCI_Device->devfn >> 3;
+      unsigned int IRQ_Channel = PCI_Device->irq;
+      unsigned long BaseAddress0 = PCI_Device->base_address[0];
+      unsigned long BaseAddress1 = PCI_Device->base_address[1];
+      BusLogic_IO_Address_T IO_Address =
+       BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+      BusLogic_PCI_Address_T PCI_Address =
+       BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
 #ifndef CONFIG_SCSI_OMIT_FLASHPOINT
-       if ((BaseAddress0 & PCI_BASE_ADDRESS_SPACE)
-           != PCI_BASE_ADDRESS_SPACE_IO)
-         {
-           BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
-                          "FlashPoint Host Adapter\n", NULL, BaseAddress0);
-           BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
-                          NULL, Bus, Device, IO_Address);
-           continue;
-         }
-       if ((BaseAddress1 & PCI_BASE_ADDRESS_SPACE)
-           != PCI_BASE_ADDRESS_SPACE_MEMORY)
-         {
-           BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for "
-                          "FlashPoint Host Adapter\n", NULL, BaseAddress1);
-           BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n",
-                          NULL, Bus, Device, PCI_Address);
-           continue;
-         }
-       if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
-         {
-           BusLogic_Error("BusLogic: IRQ Channel %d illegal for "
-                          "FlashPoint Host Adapter\n", NULL, IRQ_Channel);
-           BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
-                          NULL, Bus, Device, IO_Address);
-           continue;
-         }
-       if (BusLogic_GlobalOptions.TraceProbe)
-         {
-           BusLogic_Notice("BusLogic: FlashPoint Host Adapter "
-                           "detected at\n", NULL);
-           BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address "
-                           "0x%X PCI Address 0x%X\n", NULL,
-                           Bus, Device, IO_Address, PCI_Address);
-         }
-       if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
-         {
-           BusLogic_ProbeInfo_T *ProbeInfo =
-             &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-           ProbeInfo->HostAdapterType = BusLogic_FlashPoint;
-           ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
-           ProbeInfo->IO_Address = IO_Address;
-           ProbeInfo->PCI_Address = PCI_Address;
-           ProbeInfo->Bus = Bus;
-           ProbeInfo->Device = Device;
-           ProbeInfo->IRQ_Channel = IRQ_Channel;
-           FlashPointCount++;
-         }
-       else BusLogic_Warning("BusLogic: Too many Host Adapters "
-                             "detected\n", NULL);
+      if ((BaseAddress0 & PCI_BASE_ADDRESS_SPACE)
+         != PCI_BASE_ADDRESS_SPACE_IO)
+       {
+         BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for "
+                        "FlashPoint Host Adapter\n", NULL, BaseAddress0);
+         BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
+                        NULL, Bus, Device, IO_Address);
+         continue;
+       }
+      if ((BaseAddress1 & PCI_BASE_ADDRESS_SPACE)
+         != PCI_BASE_ADDRESS_SPACE_MEMORY)
+       {
+         BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for "
+                        "FlashPoint Host Adapter\n", NULL, BaseAddress1);
+         BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n",
+                        NULL, Bus, Device, PCI_Address);
+         continue;
+       }
+      if (IRQ_Channel == 0)
+       {
+         BusLogic_Error("BusLogic: IRQ Channel %d illegal for "
+                        "FlashPoint Host Adapter\n", NULL, IRQ_Channel);
+         BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n",
+                        NULL, Bus, Device, IO_Address);
+         continue;
+       }
+      if (BusLogic_GlobalOptions.TraceProbe)
+       {
+         BusLogic_Notice("BusLogic: FlashPoint Host Adapter "
+                         "detected at\n", NULL);
+         BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address "
+                         "0x%X PCI Address 0x%X\n", NULL,
+                         Bus, Device, IO_Address, PCI_Address);
+       }
+      if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
+       {
+         BusLogic_ProbeInfo_T *ProbeInfo =
+           &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+         ProbeInfo->HostAdapterType = BusLogic_FlashPoint;
+         ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+         ProbeInfo->IO_Address = IO_Address;
+         ProbeInfo->PCI_Address = PCI_Address;
+         ProbeInfo->Bus = Bus;
+         ProbeInfo->Device = Device;
+         ProbeInfo->IRQ_Channel = IRQ_Channel;
+         FlashPointCount++;
+       }
+      else BusLogic_Warning("BusLogic: Too many Host Adapters "
+                           "detected\n", NULL);
 #else
-       BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at "
-                      "PCI Bus %d Device %d\n", NULL, Bus, Device);
-       BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, "
-                      "but FlashPoint\n", NULL, IO_Address, PCI_Address);
-       BusLogic_Error("BusLogic: support was omitted in this kernel "
-                      "configuration.\n", NULL);
+      BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at "
+                    "PCI Bus %d Device %d\n", NULL, Bus, Device);
+      BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, "
+                    "but FlashPoint\n", NULL, IO_Address, PCI_Address);
+      BusLogic_Error("BusLogic: support was omitted in this kernel "
+                    "configuration.\n", NULL);
 #endif
-      }
+    }
   /*
     The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of
     increasing PCI Bus and Device Number, so sort the probe information into
@@ -1482,12 +1424,11 @@ static boolean BusLogic_HardwareResetHostAdapter(BusLogic_HostAdapter_T
 
 /*
   BusLogic_CheckHostAdapter checks to be sure this really is a BusLogic
-  Host Adapter.  It also determines the IRQ Channel for non-PCI Host Adapters.
+  Host Adapter.
 */
 
 static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 {
-  BusLogic_Configuration_T Configuration;
   BusLogic_ExtendedSetupInformation_T ExtendedSetupInformation;
   BusLogic_RequestedReplyLength_T RequestedReplyLength;
   boolean Result = true;
@@ -1495,31 +1436,6 @@ static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
     FlashPoint Host Adapters do not require this protection.
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
-  /*
-    Issue the Inquire Configuration command if the IRQ Channel is unknown.
-  */
-  if (HostAdapter->IRQ_Channel == 0)
-    {
-      if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration,
-                          NULL, 0, &Configuration, sizeof(Configuration))
-         == sizeof(Configuration))
-       {
-         if (Configuration.IRQ_Channel9)
-           HostAdapter->IRQ_Channel = 9;
-         else if (Configuration.IRQ_Channel10)
-           HostAdapter->IRQ_Channel = 10;
-         else if (Configuration.IRQ_Channel11)
-           HostAdapter->IRQ_Channel = 11;
-         else if (Configuration.IRQ_Channel12)
-           HostAdapter->IRQ_Channel = 12;
-         else if (Configuration.IRQ_Channel14)
-           HostAdapter->IRQ_Channel = 14;
-         else if (Configuration.IRQ_Channel15)
-           HostAdapter->IRQ_Channel = 15;
-         else Result = false;
-       }
-      else Result = false;
-    }
   /*
     Issue the Inquire Extended Setup Information command.  Only genuine
     BusLogic Host Adapters and true clones support this command.  Adaptec 1542C
@@ -1746,11 +1662,27 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   */
   HostAdapter->SCSI_ID = Configuration.HostAdapterID;
   /*
-    Determine the Bus Type and save it in the Host Adapter structure,
-    and determine and save the DMA Channel for ISA Host Adapters.
+    Determine the Bus Type and save it in the Host Adapter structure, determine
+    and save the IRQ Channel if necessary, and determine and save the DMA
+    Channel for ISA Host Adapters.
   */
   HostAdapter->HostAdapterBusType =
     BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4'];
+  if (HostAdapter->IRQ_Channel == 0)
+    {
+      if (Configuration.IRQ_Channel9)
+       HostAdapter->IRQ_Channel = 9;
+      else if (Configuration.IRQ_Channel10)
+       HostAdapter->IRQ_Channel = 10;
+      else if (Configuration.IRQ_Channel11)
+       HostAdapter->IRQ_Channel = 11;
+      else if (Configuration.IRQ_Channel12)
+       HostAdapter->IRQ_Channel = 12;
+      else if (Configuration.IRQ_Channel14)
+       HostAdapter->IRQ_Channel = 14;
+      else if (Configuration.IRQ_Channel15)
+       HostAdapter->IRQ_Channel = 15;
+    }
   if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus)
     {
       if (Configuration.DMA_Channel5)
@@ -1893,7 +1825,7 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
   HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8);
   /*
-    Select appropriate values for the Mailbox Count, Driver Queue Depth, 
+    Select appropriate values for the Mailbox Count, Driver Queue Depth,
     Initial CCBs, and Incremental CCBs variables based on whether or not Strict
     Round Robin Mode is supported.  If Strict Round Robin Mode is supported,
     then there is no performance degradation in using the maximum possible
@@ -1985,12 +1917,10 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   */
 Common:
   /*
-    Initialize the Host Adapter Full Model Name and Interrupt Label fields
-    from the Model Name.
+    Initialize the Host Adapter Full Model Name from the Model Name.
   */
   strcpy(HostAdapter->FullModelName, "BusLogic ");
   strcat(HostAdapter->FullModelName, HostAdapter->ModelName);
-  strcpy(HostAdapter->InterruptLabel, HostAdapter->FullModelName);
   /*
     Select an appropriate value for the Tagged Queue Depth either from a
     BusLogic Driver Options specification, or based on whether this Host
@@ -2308,8 +2238,6 @@ static boolean BusLogic_ReportHostAdapterConfiguration(BusLogic_HostAdapter_T
 
 static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
 {
-  BusLogic_HostAdapter_T *FirstHostAdapter =
-    BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
   if (HostAdapter->IRQ_Channel == 0)
     {
       BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n",
@@ -2317,24 +2245,14 @@ static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
       return false;
     }
   /*
-    Acquire exclusive or shared access to the IRQ Channel if necessary.
+    Acquire shared access to the IRQ Channel.
   */
-  if (FirstHostAdapter->Next == NULL)
+  if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
+                 SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0)
     {
-      if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
-                     SA_INTERRUPT | SA_SHIRQ,
-                     HostAdapter->InterruptLabel, NULL) < 0)
-       {
-         BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
-                        HostAdapter, HostAdapter->IRQ_Channel);
-         return false;
-       }
-    }
-  else if (strlen(FirstHostAdapter->InterruptLabel) + 11
-          < sizeof(FirstHostAdapter->InterruptLabel))
-    {
-      strcat(FirstHostAdapter->InterruptLabel, " + ");
-      strcat(FirstHostAdapter->InterruptLabel, HostAdapter->ModelName);
+      BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
+                    HostAdapter, HostAdapter->IRQ_Channel);
+      return false;
     }
   HostAdapter->IRQ_ChannelAcquired = true;
   /*
@@ -2367,14 +2285,11 @@ static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
 
 static void BusLogic_ReleaseResources(BusLogic_HostAdapter_T *HostAdapter)
 {
-  BusLogic_HostAdapter_T *FirstHostAdapter =
-    BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
   /*
-    Release exclusive or shared access to the IRQ Channel.
+    Release shared access to the IRQ Channel.
   */
   if (HostAdapter->IRQ_ChannelAcquired)
-    if (FirstHostAdapter->Next == NULL)
-      free_irq(HostAdapter->IRQ_Channel, NULL);
+    free_irq(HostAdapter->IRQ_Channel, HostAdapter);
   /*
     Release exclusive access to the DMA Channel.
   */
@@ -2396,6 +2311,12 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T
   BusLogic_RoundRobinModeRequest_T RoundRobinModeRequest;
   BusLogic_SetCCBFormatRequest_T SetCCBFormatRequest;
   int TargetID;
+  /*
+    Initialize the pointers to the first and last CCBs that are queued for
+    completion processing.
+  */
+  HostAdapter->FirstCompletedCCB = NULL;
+  HostAdapter->LastCompletedCCB = NULL;
   /*
     Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active,
     Command Successful Flag, Active Commands, and Commands Since Reset
@@ -2776,7 +2697,7 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
   if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
     for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
         HostAdapter != NULL;
-        HostAdapter = HostAdapter->NextAll)
+        HostAdapter = HostAdapter->Next)
       BusLogic_ReportTargetDeviceInfo(HostAdapter);
 }
 
@@ -2878,9 +2799,7 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
       Host->select_queue_depths = BusLogic_SelectQueueDepths;
       /*
        Add Host Adapter to the end of the list of registered BusLogic
-       Host Adapters.  In order for Command Complete Interrupts to be
-       properly dismissed by BusLogic_InterruptHandler, the Host Adapter
-       must be registered.
+       Host Adapters.
       */
       BusLogic_RegisterHostAdapter(HostAdapter);
       /*
@@ -2973,19 +2892,20 @@ int BusLogic_ReleaseHostAdapter(SCSI_Host_T *Host)
 
 static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB)
 {
+  BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
   CCB->Status = BusLogic_CCB_Completed;
   CCB->Next = NULL;
-  if (BusLogic_FirstCompletedCCB == NULL)
+  if (HostAdapter->FirstCompletedCCB == NULL)
     {
-      BusLogic_FirstCompletedCCB = CCB;
-      BusLogic_LastCompletedCCB = CCB;
+      HostAdapter->FirstCompletedCCB = CCB;
+      HostAdapter->LastCompletedCCB = CCB;
     }
   else
     {
-      BusLogic_LastCompletedCCB->Next = CCB;
-      BusLogic_LastCompletedCCB = CCB;
+      HostAdapter->LastCompletedCCB->Next = CCB;
+      HostAdapter->LastCompletedCCB = CCB;
     }
-  CCB->HostAdapter->ActiveCommands[CCB->TargetID]--;
+  HostAdapter->ActiveCommands[CCB->TargetID]--;
 }
 
 
@@ -3108,25 +3028,23 @@ static void BusLogic_ScanIncomingMailboxes(BusLogic_HostAdapter_T *HostAdapter)
 
 
 /*
-  BusLogic_ProcessCompletedCCBs iterates over the completed CCBs setting
-  the SCSI Command Result Codes, deallocating the CCBs, and calling the
-  SCSI Subsystem Completion Routines.  Interrupts should already have been
-  disabled by the caller.
+  BusLogic_ProcessCompletedCCBs iterates over the completed CCBs for Host
+  Adapter setting the SCSI Command Result Codes, deallocating the CCBs, and
+  calling the SCSI Subsystem Completion Routines.  The Host Adapter's Lock
+  should already have been acquired by the caller.
 */
 
-static void BusLogic_ProcessCompletedCCBs(void)
+static void BusLogic_ProcessCompletedCCBs(BusLogic_HostAdapter_T *HostAdapter)
 {
-  static boolean ProcessCompletedCCBsActive = false;
-  if (ProcessCompletedCCBsActive) return;
-  ProcessCompletedCCBsActive = true;
-  while (BusLogic_FirstCompletedCCB != NULL)
+  if (HostAdapter->ProcessCompletedCCBsActive) return;
+  HostAdapter->ProcessCompletedCCBsActive = true;
+  while (HostAdapter->FirstCompletedCCB != NULL)
     {
-      BusLogic_CCB_T *CCB = BusLogic_FirstCompletedCCB;
+      BusLogic_CCB_T *CCB = HostAdapter->FirstCompletedCCB;
       SCSI_Command_T *Command = CCB->Command;
-      BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
-      BusLogic_FirstCompletedCCB = CCB->Next;
-      if (BusLogic_FirstCompletedCCB == NULL)
-       BusLogic_LastCompletedCCB = NULL;
+      HostAdapter->FirstCompletedCCB = CCB->Next;
+      if (HostAdapter->FirstCompletedCCB == NULL)
+       HostAdapter->LastCompletedCCB = NULL;
       /*
        Process the Completed CCB.
       */
@@ -3262,7 +3180,7 @@ static void BusLogic_ProcessCompletedCCBs(void)
          Command->scsi_done(Command);
        }
     }
-  ProcessCompletedCCBsActive = false;
+  HostAdapter->ProcessCompletedCCBsActive = false;
 }
 
 
@@ -3270,129 +3188,91 @@ static void BusLogic_ProcessCompletedCCBs(void)
   BusLogic_InterruptHandler handles hardware interrupts from BusLogic Host
   Adapters.
 */
-static void do_BusLogic_InterruptHandler(int IRQ_Channel,
+
+static void BusLogic_InterruptHandler(int IRQ_Channel,
                                      void *DeviceIdentifier,
                                      Registers_T *InterruptRegisters)
 {
-  BusLogic_HostAdapter_T *FirstHostAdapter =
-    BusLogic_RegisteredHostAdapters[IRQ_Channel];
-  boolean HostAdapterResetRequired = false;
-  BusLogic_HostAdapter_T *HostAdapter;
-  BusLogic_Lock_T Lock;
+  BusLogic_HostAdapter_T *HostAdapter =
+    (BusLogic_HostAdapter_T *) DeviceIdentifier;
+  ProcessorFlags_T ProcessorFlags;
   /*
-    Iterate over the installed BusLogic Host Adapters accepting any Incoming
-    Mailbox entries and saving the completed CCBs for processing.  This
-    interrupt handler is installed as a fast interrupt, so interrupts are
-    disabled when the interrupt handler is entered.
+    Acquire exclusive access to Host Adapter.
   */
-  for (HostAdapter = FirstHostAdapter;
-       HostAdapter != NULL;
-       HostAdapter = HostAdapter->Next)
+  BusLogic_AcquireHostAdapterLockIH(HostAdapter, &ProcessorFlags);
+  /*
+    Handle Interrupts appropriately for each Host Adapter type.
+  */
+  if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
     {
+      BusLogic_InterruptRegister_T InterruptRegister;
       /*
-       Acquire exclusive access to Host Adapter.
-      */
-      BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
-      /*
-       Handle Interrupts appropriately for each Host Adapter type.
+       Read the Host Adapter Interrupt Register.
       */
-      if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
+      InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
+      if (InterruptRegister.Bits.InterruptValid)
        {
-         BusLogic_InterruptRegister_T InterruptRegister;
          /*
-           Read the Host Adapter Interrupt Register.
+           Acknowledge the interrupt and reset the Host Adapter
+           Interrupt Register.
          */
-         InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
-         if (InterruptRegister.Bits.InterruptValid)
-           {
-             /*
-               Acknowledge the interrupt and reset the Host Adapter
-               Interrupt Register.
-             */
-             BusLogic_InterruptReset(HostAdapter);
-             /*
-               Process valid External SCSI Bus Reset and Incoming Mailbox
-               Loaded Interrupts.  Command Complete Interrupts are noted,
-               and Outgoing Mailbox Available Interrupts are ignored, as
-               they are never enabled.
-             */
-             if (InterruptRegister.Bits.ExternalBusReset)
-               {
-                 HostAdapter->HostAdapterExternalReset = true;
-                 HostAdapterResetRequired = true;
-               }
-             else if (InterruptRegister.Bits.IncomingMailboxLoaded)
-               BusLogic_ScanIncomingMailboxes(HostAdapter);
-             else if (InterruptRegister.Bits.CommandComplete)
-               HostAdapter->HostAdapterCommandCompleted = true;
-           }
-       }
-      else
-       {
+         BusLogic_InterruptReset(HostAdapter);
          /*
-           Check if there is a pending interrupt for this Host Adapter.
+           Process valid External SCSI Bus Reset and Incoming Mailbox
+           Loaded Interrupts.  Command Complete Interrupts are noted,
+           and Outgoing Mailbox Available Interrupts are ignored, as
+           they are never enabled.
          */
-         if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
-           switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
-             {
-             case FlashPoint_NormalInterrupt:
-               break;
-             case FlashPoint_ExternalBusReset:
-               HostAdapter->HostAdapterExternalReset = true;
-               HostAdapterResetRequired = true;
-               break;
-             case FlashPoint_InternalError:
-               BusLogic_Warning("Internal FlashPoint Error detected"
-                                " - Resetting Host Adapter\n", HostAdapter);
-               HostAdapter->HostAdapterInternalError = true;
-               HostAdapterResetRequired = true;
-               break;
-             }
+         if (InterruptRegister.Bits.ExternalBusReset)
+           HostAdapter->HostAdapterExternalReset = true;
+         else if (InterruptRegister.Bits.IncomingMailboxLoaded)
+           BusLogic_ScanIncomingMailboxes(HostAdapter);
+         else if (InterruptRegister.Bits.CommandComplete)
+           HostAdapter->HostAdapterCommandCompleted = true;
        }
+    }
+  else
+    {
       /*
-       Release exclusive access to Host Adapter.
+       Check if there is a pending interrupt for this Host Adapter.
       */
-      BusLogic_ReleaseHostAdapterLockID(HostAdapter, &Lock);
+      if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
+       switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
+         {
+         case FlashPoint_NormalInterrupt:
+           break;
+         case FlashPoint_ExternalBusReset:
+           HostAdapter->HostAdapterExternalReset = true;
+           break;
+         case FlashPoint_InternalError:
+           BusLogic_Warning("Internal FlashPoint Error detected"
+                            " - Resetting Host Adapter\n", HostAdapter);
+           HostAdapter->HostAdapterInternalError = true;
+           break;
+         }
     }
   /*
     Process any completed CCBs.
   */
-  if (BusLogic_FirstCompletedCCB != NULL)
-    BusLogic_ProcessCompletedCCBs();
+  if (HostAdapter->FirstCompletedCCB != NULL)
+    BusLogic_ProcessCompletedCCBs(HostAdapter);
   /*
-    Iterate over the Host Adapters performing any requested
-    Host Adapter Resets.
+    Reset the Host Adapter if requested.
   */
-  if (HostAdapterResetRequired)
-    for (HostAdapter = FirstHostAdapter;
-        HostAdapter != NULL;
-        HostAdapter = HostAdapter->Next)
-      if (HostAdapter->HostAdapterExternalReset ||
-         HostAdapter->HostAdapterInternalError)
-       {
-         BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
-         HostAdapter->HostAdapterExternalReset = false;
-         HostAdapter->HostAdapterInternalError = false;
-         scsi_mark_host_reset(HostAdapter->SCSI_Host);
-       }
+  if (HostAdapter->HostAdapterExternalReset ||
+      HostAdapter->HostAdapterInternalError)
+    {
+      BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
+      HostAdapter->HostAdapterExternalReset = false;
+      HostAdapter->HostAdapterInternalError = false;
+      scsi_mark_host_reset(HostAdapter->SCSI_Host);
+    }
+  /*
+    Release exclusive access to Host Adapter.
+  */
+  BusLogic_ReleaseHostAdapterLockIH(HostAdapter, &ProcessorFlags);
 }
 
-/*
- * This is the low-level interrupt handler:
- * we get the io request lock here to guarantee
- * that all of this is atomic wrt the setup
- * functions.
- */
-static void BusLogic_InterruptHandler(int IRQ_Channel,
-                                     void *DeviceIdentifier,
-                                     Registers_T *InterruptRegisters)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&io_request_lock, flags);
-       do_BusLogic_InterruptHandler(IRQ_Channel, DeviceIdentifier, InterruptRegisters);
-       spin_unlock_irqrestore(&io_request_lock, flags);
-}
 
 /*
   BusLogic_WriteOutgoingMailbox places CCB and Action Code into an Outgoing
@@ -3454,7 +3334,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
   void *BufferPointer = Command->request_buffer;
   int BufferLength = Command->request_bufflen;
   int SegmentCount = Command->use_sg;
-  BusLogic_Lock_T Lock;
+  ProcessorFlags_T ProcessorFlags;
   BusLogic_CCB_T *CCB;
   /*
     SCSI REQUEST_SENSE commands will be executed automatically by the Host
@@ -3470,7 +3350,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
   /*
     Acquire exclusive access to Host Adapter.
   */
-  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
   /*
     Allocate a CCB from the Host Adapter's free list.  In the unlikely event
     that there are none available and memory allocation fails, wait 1 second
@@ -3651,13 +3531,13 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
        been called, or it may still be pending.
       */
       if (CCB->Status == BusLogic_CCB_Completed)
-       BusLogic_ProcessCompletedCCBs();
+       BusLogic_ProcessCompletedCCBs(HostAdapter);
     }
   /*
     Release exclusive access to Host Adapter.
   */
 Done:
-  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
   return 0;
 }
 
@@ -3671,7 +3551,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
   int TargetID = Command->target;
-  BusLogic_Lock_T Lock;
+  ProcessorFlags_T ProcessorFlags;
   BusLogic_CCB_T *CCB;
   int Result;
   BusLogic_IncrementErrorCounter(
@@ -3679,7 +3559,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
   /*
     Acquire exclusive access to Host Adapter.
   */
-  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
   /*
     If this Command has already completed, then no Abort is necessary.
   */
@@ -3772,7 +3652,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
       Result = SCSI_ABORT_PENDING;
       if (CCB->Status == BusLogic_CCB_Completed)
        {
-         BusLogic_ProcessCompletedCCBs();
+         BusLogic_ProcessCompletedCCBs(HostAdapter);
          Result = SCSI_ABORT_SUCCESS;
        }
     }
@@ -3780,7 +3660,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
     Release exclusive access to Host Adapter.
   */
 Done:
-  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
   return Result;
 }
 
@@ -3794,7 +3674,7 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
                                     SCSI_Command_T *Command,
                                     unsigned int ResetFlags)
 {
-  BusLogic_Lock_T Lock;
+  ProcessorFlags_T ProcessorFlags;
   BusLogic_CCB_T *CCB;
   int TargetID, Result;
   boolean HardReset;
@@ -3818,7 +3698,7 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
   /*
     Acquire exclusive access to Host Adapter.
   */
-  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
   /*
     If this is an Asynchronous Reset and this Command has already completed,
     then no Reset is necessary.
@@ -3941,7 +3821,7 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
     Release exclusive access to Host Adapter.
   */
 Done:
-  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
   return Result;
 }
 
@@ -3957,14 +3837,14 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
 {
   int TargetID = Command->target;
   BusLogic_CCB_T *CCB, *XCCB;
-  BusLogic_Lock_T Lock;
+  ProcessorFlags_T ProcessorFlags;
   int Result = -1;
   BusLogic_IncrementErrorCounter(
     &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested);
   /*
     Acquire exclusive access to Host Adapter.
   */
-  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
   /*
     If this is an Asynchronous Reset and this Command has already completed,
     then no Reset is necessary.
@@ -4116,7 +3996,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
     if (CCB->Status == BusLogic_CCB_Completed)
       {
-       BusLogic_ProcessCompletedCCBs();
+       BusLogic_ProcessCompletedCCBs(HostAdapter);
        Result = SCSI_RESET_SUCCESS;
       }
   /*
@@ -4129,7 +4009,7 @@ Done:
   /*
     Release exclusive access to Host Adapter.
   */
-  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
   return Result;
 }
 
@@ -4325,7 +4205,7 @@ int BusLogic_ProcDirectoryInfo(char *ProcBuffer, char **StartPointer,
   if (WriteFlag) return 0;
   for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
        HostAdapter != NULL;
-       HostAdapter = HostAdapter->NextAll)
+       HostAdapter = HostAdapter->Next)
     if (HostAdapter->HostNumber == HostNumber) break;
   if (HostAdapter == NULL)
     {
index 0e07abe1f2a81852f4e5f5e35cec1d993c3fc92d..820f6cb81a62ee3da468dd199af1186f82fd94df 100644 (file)
@@ -2,7 +2,7 @@
 
   Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
 
-  Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
 
 typedef kdev_t KernelDevice_T;
 typedef struct proc_dir_entry PROC_DirectoryEntry_T;
+typedef unsigned long ProcessorFlags_T;
 typedef struct pt_regs Registers_T;
 typedef struct partition PartitionTable_T;
+typedef struct pci_dev PCI_Device_T;
 typedef Scsi_Host_Template SCSI_Host_Template_T;
 typedef struct Scsi_Host SCSI_Host_T;
 typedef struct scsi_device SCSI_Device_T;
@@ -965,16 +967,6 @@ BusLogic_SetCCBFormatRequest_T;
 typedef unsigned char BusLogic_RequestedReplyLength_T;
 
 
-/*
-  Define the Lock data structure.  Until a true symmetric multiprocessing
-  kernel with fine grained locking is available, acquiring the lock is
-  implemented as saving the processor flags and disabling interrupts, and
-  releasing the lock restores the saved processor flags.
-*/
-
-typedef unsigned long BusLogic_Lock_T;
-
-
 /*
   Define the Outgoing Mailbox Action Codes.
 */
@@ -1374,7 +1366,6 @@ typedef struct BusLogic_HostAdapter
   unsigned char ModelName[9];
   unsigned char FirmwareVersion[6];
   unsigned char FullModelName[18];
-  unsigned char InterruptLabel[68];
   unsigned char Bus;
   unsigned char Device;
   unsigned char IRQ_Channel;
@@ -1401,7 +1392,8 @@ typedef struct BusLogic_HostAdapter
   boolean HostAdapterInitialized:1;
   boolean HostAdapterExternalReset:1;
   boolean HostAdapterInternalError:1;
-  volatile boolean HostAdapterCommandCompleted:1;
+  boolean ProcessCompletedCCBsActive;
+  volatile boolean HostAdapterCommandCompleted;
   unsigned short HostAdapterScatterGatherLimit;
   unsigned short DriverScatterGatherLimit;
   unsigned short MaxTargetDevices;
@@ -1430,9 +1422,10 @@ typedef struct BusLogic_HostAdapter
   FlashPoint_Info_T FlashPointInfo;
   FlashPoint_CardHandle_T CardHandle;
   struct BusLogic_HostAdapter *Next;
-  struct BusLogic_HostAdapter *NextAll;
   BusLogic_CCB_T *All_CCBs;
   BusLogic_CCB_T *Free_CCBs;
+  BusLogic_CCB_T *FirstCompletedCCB;
+  BusLogic_CCB_T *LastCompletedCCB;
   BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
   BusLogic_ErrorRecoveryStrategy_T
     ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
@@ -1514,10 +1507,8 @@ SCSI_Inquiry_T;
 
 static inline
 void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
-                                    BusLogic_Lock_T *Lock)
+                                    ProcessorFlags_T *ProcessorFlags)
 {
-  save_flags(*Lock);
-  cli();
 }
 
 
@@ -1527,33 +1518,36 @@ void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
 
 static inline
 void BusLogic_ReleaseHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
-                                    BusLogic_Lock_T *Lock)
+                                    ProcessorFlags_T *ProcessorFlags)
 {
-  restore_flags(*Lock);
 }
 
 
 /*
-  BusLogic_AcquireHostAdapterLockID acquires exclusive access to Host Adapter,
-  but is only called when interrupts are disabled.
+  BusLogic_AcquireHostAdapterLockIH acquires exclusive access to Host Adapter,
+  but is only called from the interrupt handler.
 */
 
 static inline
-void BusLogic_AcquireHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
-                                      BusLogic_Lock_T *Lock)
+void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
+                                      ProcessorFlags_T *ProcessorFlags)
 {
+  extern spinlock_t io_request_lock;
+  spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
 }
 
 
 /*
-  BusLogic_ReleaseHostAdapterLockID releases exclusive access to Host Adapter,
-  but is only called when interrupts are disabled.
+  BusLogic_ReleaseHostAdapterLockIH releases exclusive access to Host Adapter,
+  but is only called from the interrupt handler.
 */
 
 static inline
-void BusLogic_ReleaseHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
-                                      BusLogic_Lock_T *Lock)
+void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
+                                      ProcessorFlags_T *ProcessorFlags)
 {
+  extern spinlock_t io_request_lock;
+  spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
 }
 
 
@@ -1685,8 +1679,8 @@ static inline void *Bus_to_Virtual(BusLogic_BusAddress_T BusAddress)
 
 /*
   Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and
-  32 Bit Kernel Virtual Addresses.  This avoids compilation warnings
-  on 64 Bit architectures.
+  32 bit Kernel Virtual Addresses.  This avoids compilation warnings
+  on 64 bit architectures.
 */
 
 static inline
@@ -1750,17 +1744,6 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T
 }
 
 
-/*
-  Define compatibility macros between Linux 2.0 and Linux 2.1.
-*/
-
-#if LINUX_VERSION_CODE < 0x20100
-
-#define MODULE_PARM(Variable, Type)
-
-#endif
-
-
 /*
   Define the version number of the FlashPoint Firmware (SCCB Manager).
 */
index 9c951b966ef672161d1c1ef1cc33c3df71cb5c81..c67a9625861929cdcf9a8dc95f5311cb7d33b642 100644 (file)
      Erik Ratcliffe <erik@caldera.com> has done testing of the
      AdvanSys driver in the Caldera releases.
 
-     Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
+     Rik van Riel <H.H.vanRiel@phys.uu.nl> provided a patch to
      AscWaitTixISRDone() which he found necessary to make the
      driver work with a SCSI-1 disk.
 
index e3afccaace7ef66684e335580f8cc1a19cd516c7..01d0b31e6a2ae6e57c75dde9f1757688163aa35a 100644 (file)
@@ -400,7 +400,7 @@ static int               Write_SCSI_Data_port;
 static int               FIFO_Size = 0x2000; /* 8k FIFO for
                                                pre-tmc18c30 chips */
 
-extern void              fdomain_16x0_intr( int irq, void *dev_id,
+extern void              do_fdomain_16x0_intr( int irq, void *dev_id,
                                            struct pt_regs * regs );
 
 static unsigned long addresses[] = {
@@ -775,7 +775,7 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase )
           PCI_DEVICE_ID_FD_36C70 );
 #endif 
 
-   if ((pdev = pci_find_device(PCI_VENDOR_ID, PCI_DEVICE_ID, pdev)) == NULL)
+   if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
      return 0;
        
 #if DEBUG_DETECT
index c7182feefc39f04cd3eb343f633e1ce9e0939a5c..550ed7df8be59d5bea1206f1dfbd79d2fc700109 100644 (file)
@@ -73,7 +73,7 @@
  * Initial revision
  *
  *
- * $Id: gdth.c,v 1.3 1998/02/25 23:52:32 ecd Exp $ 
+ * $Id: gdth.c,v 1.4 1998/04/15 14:35:26 mj Exp $ 
  ************************************************************************/
 
 #ifdef MODULE
@@ -473,8 +473,7 @@ static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
        if ((error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
                                            PCI_ROM_ADDRESS,
                                            (int *) &pcistr->bios))) {
-               printk("GDT-PCI: error %s reading configuration space",
-                      pcibios_strerror(error));
+               printk("GDT-PCI: error %d reading configuration space", error);
                return -1;
                }
        pcistr->irq = pdev->irq;
@@ -499,8 +498,7 @@ static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
                                            GDTH_BASEP&pcistr->bios)) ||
         (error = pcibios_read_config_byte(pcistr->bus,pcistr->device_fn,
                                           PCI_INTERRUPT_LINE,&pcistr->irq))) {
-        printk("GDT-PCI: error %s reading configuration space",
-               pcibios_strerror(error));
+        printk("GDT-PCI: error %d reading configuration space", error);
         return -1;
     }
 #endif
index 243be1eca8ac0f3dd9286b27bd5e087e57c56382..3a8e941c4559c483e33d409463f649eb8aed0d84 100644 (file)
 #include "psi240i.h"
 #endif
 
+#ifdef CONFIG_SCSI_PLUTO
+#include "pluto.h"
+#endif
+
 #ifdef CONFIG_SCSI_DEBUG
 #include "scsi_debug.h"
 #endif
@@ -382,6 +386,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_MAC53C94
     SCSI_MAC53C94,
 #endif
+#ifdef CONFIG_SCSI_PLUTO
+    PLUTO,
+#endif
 #ifdef CONFIG_SCSI_DEBUG
     SCSI_DEBUG,
 #endif
index 30a780acd87008b4c76c181a149319d718a4faf7..3ca3a92c268428f04202df0f0604ca7d915b1603 100644 (file)
@@ -466,8 +466,15 @@ extern void scsi_unregister_module(int, void *);
  * we need to leave extra room in some of the data structures. Doing a
  * realloc to enlarge the structures would be riddled with race conditions,
  * so until a better solution is discovered, we use this crude approach
+ *
+ * Even bigger hack for SparcSTORAGE arrays. Those are at least 6 disks, but
+ * usually up to 30 disks, so everyone would need to change this. -jj
  */
-#define SD_EXTRA_DEVS 2
+#ifdef CONFIG_SCSI_PLUTO_MODULE
+#define SD_EXTRA_DEVS 40
+#else
+#define SD_EXTRA_DEVS 4
+#endif
 #define ST_EXTRA_DEVS 2
 #define SR_EXTRA_DEVS 2
 #define SG_EXTRA_DEVS (SD_EXTRA_DEVS + SR_EXTRA_DEVS + ST_EXTRA_DEVS)
index 3b4598a3fd0747bd24e3132df082708436989a7f..bfbddd0c97b93e46ab10186d5e6f3a798822b239 100644 (file)
@@ -1,6 +1,7 @@
 /* pluto.c: SparcSTORAGE Array SCSI host adapter driver.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
  */
 
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/init.h>
+#include <linux/config.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 #include <asm/irq.h>
 
@@ -45,9 +50,9 @@ static struct ctrl_inquiry {
        Scsi_Cmnd cmd;
        char inquiry[256];
        fc_channel *fc;
-} *fcs __initdata;
-static int fcscount __initdata;
-static atomic_t fcss __initdata;
+} *fcs __initdata = { 0 };
+static int fcscount __initdata = 0;
+static atomic_t fcss __initdata = ATOMIC_INIT(0);
 static struct timer_list fc_timer __initdata = { 0 };
 struct semaphore fc_sem __initdata = MUTEX_LOCKED;
 
@@ -98,8 +103,16 @@ __initfunc(int pluto_detect(Scsi_Host_Template *tpnt))
        for_each_online_fc_channel(fc)
                fcscount++;
        PLND(("%d channels online\n", fcscount))
-       if (!fcscount)
-               return 0;
+       if (!fcscount) {
+#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KERNELD)
+               request_module("soc");
+               
+               for_each_online_fc_channel(fc)
+                       fcscount++;
+               if (!fcscount)
+#endif
+                       return 0;
+       }
        fcs = (struct ctrl_inquiry *) scsi_init_malloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
        if (!fcs) {
                printk ("PLUTO: Not enough memory to probe\n");
@@ -213,6 +226,8 @@ __initfunc(int pluto_detect(Scsi_Host_Template *tpnt))
                                
                                nplutos++;
                                
+                               if (fc->module) __MOD_INC_USE_COUNT(fc->module);
+                               
                                pluto = (struct pluto *)host->hostdata;
                                
                                host->max_id = inq->targets;
@@ -256,9 +271,13 @@ int pluto_release(struct Scsi_Host *host)
 {
        struct pluto *pluto = (struct pluto *)host->hostdata;
        fc_channel *fc = pluto->fc;
+
+       if (fc->module) __MOD_DEC_USE_COUNT(fc->module);
        
        fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+       PLND((" releasing pluto.\n"));
        kfree (fc->ages);
+       PLND(("released pluto!\n"));
        return 0;
 }
 
@@ -288,7 +307,7 @@ const char *pluto_info(struct Scsi_Host *host)
 static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr)
 {
        PLND(("encode addr %d %d %d\n", SCpnt->channel, SCpnt->target, SCpnt->cmnd[1] & 0xe0))
-       /* We don't support LUNs */
+       /* We don't support LUNs - neither does SSA :) */
        if (SCpnt->cmnd[1] & 0xe0) return -EINVAL;
        if (!SCpnt->channel) {
                if (SCpnt->target) return -EINVAL;
index 6dbda6a576c1df13d1c90661c2a981d0b7703526..e1d2670542f3ab8f197622ad5cb318388fa28406 100644 (file)
@@ -43,17 +43,23 @@ int pluto_release(struct Scsi_Host *);
 const char * pluto_info(struct Scsi_Host *);
 
 #define PLUTO {                                                        \
+       name:                   "Sparc Storage Array 100/200",  \
        detect:                 pluto_detect,                   \
        release:                pluto_release,                  \
        info:                   pluto_info,                     \
        queuecommand:           fcp_scsi_queuecommand,          \
-       abort:                  fcp_scsi_abort,                 \
-       reset:                  fcp_scsi_reset,                 \
        can_queue:              PLUTO_CAN_QUEUE,                \
        this_id:                -1,                             \
        sg_tablesize:           1,                              \
        cmd_per_lun:            1,                              \
-       use_clustering:         ENABLE_CLUSTERING               \
+       use_clustering:         ENABLE_CLUSTERING,              \
+       use_new_eh_code:        FCP_SCSI_USE_NEW_EH_CODE,       \
+       abort:                  fcp_old_abort,                  \
+       eh_abort_handler:       fcp_scsi_abort,                 \
+       eh_device_reset_handler:fcp_scsi_dev_reset,             \
+       eh_bus_reset_handler:   fcp_scsi_bus_reset,             \
+       eh_host_reset_handler:  fcp_scsi_host_reset,            \
 }      
 
 #endif /* !(_PLUTO_H) */
+
index 33ab799edaf95c44d7ed6ffc5359a5eafc332b63..fefbc3b4589af34d65af1304b2e95311505c4830 100644 (file)
@@ -422,36 +422,37 @@ __initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti))
 
        /* Load the firmware. */
 #if !defined(MODULE) && !defined(__sparc_v9__)
-       dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0],
-                                                (sizeof(u_short) * risc_code_length01));
-       param[0] = MBOX_LOAD_RAM;
-       param[1] = risc_code_addr01;
-       param[2] = (dvma_addr >> 16);
-       param[3] = (dvma_addr & 0xffff);
-       param[4] = (sizeof(u_short) * risc_code_length01);
-       if(qlogicpti_mbox_command(qpti, param, 1) ||
-          (param[0] != MBOX_COMMAND_COMPLETE)) {
-               printk(KERN_EMERG "qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
-                      qpti->qpti_id);
-               restore_flags(flags);
-               return 1;
-       }
-       mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length01));
-#else
-       /* We need to do it this slow way always on Ultra. */
-       for(i = 0; i < risc_code_length01; i++) {
-               param[0] = MBOX_WRITE_RAM_WORD;
-               param[1] = risc_code_addr01 + i;
-               param[2] = risc_code01[i];
+       if (sparc_cpu_model != sun4d) {
+               dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0],
+                                                        (sizeof(u_short) * risc_code_length01));
+               param[0] = MBOX_LOAD_RAM;
+               param[1] = risc_code_addr01;
+               param[2] = (dvma_addr >> 16);
+               param[3] = (dvma_addr & 0xffff);
+               param[4] = (sizeof(u_short) * risc_code_length01);
                if(qlogicpti_mbox_command(qpti, param, 1) ||
-                  param[0] != MBOX_COMMAND_COMPLETE) {
-                       printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
+                  (param[0] != MBOX_COMMAND_COMPLETE)) {
+                       printk(KERN_EMERG "qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
                               qpti->qpti_id);
                        restore_flags(flags);
                        return 1;
                }
-       }
+               mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length01));
+       } else
 #endif
+       /* We need to do it this slow way always on Ultra, SS[12]000. */
+               for(i = 0; i < risc_code_length01; i++) {
+                       param[0] = MBOX_WRITE_RAM_WORD;
+                       param[1] = risc_code_addr01 + i;
+                       param[2] = risc_code01[i];
+                       if(qlogicpti_mbox_command(qpti, param, 1) ||
+                          param[0] != MBOX_COMMAND_COMPLETE) {
+                               printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
+                                      qpti->qpti_id);
+                               restore_flags(flags);
+                               return 1;
+                       }
+               }
 
        /* Reset the ISP again. */
        qregs->hcctrl = HCCTRL_RESET;
@@ -584,8 +585,13 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
 
        tpnt->proc_dir = &proc_scsi_qlogicpti;
        qptichain = 0;
-       if(!SBus_chain)
+       if(!SBus_chain) {
+#ifdef __sparc_v9__
+               return 0; /* Could be a PCI-only machine. */
+#else
                panic("No SBUS in qlogicpti_detect()");
+#endif
+       }
        for_each_sbus(sbus) {
                for_each_sbusdev(sbdev_iter, sbus) {
                        qpti_dev = sbdev_iter;
@@ -778,8 +784,9 @@ qpti_irq_acquired:
                        nqptis_in_use++;
                }
        }
-       printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
-              nqptis, nqptis_in_use);
+       if (nqptis)
+               printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
+                      nqptis, nqptis_in_use);
        qptis_running = nqptis_in_use;
        return nqptis;
 }
@@ -931,7 +938,9 @@ static inline u_int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
 
 static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int out_ptr)
 {
-       int num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
+       /* Temporary workaround until bug is found and fixed (one bug has been found
+          already, but fixing it makes things even worse) -jj */
+       int num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr) - 64;
        host->can_queue = host->host_busy + num_free;
        host->sg_tablesize = QLOGICISP_MAX_SG(num_free);
 }
@@ -1256,4 +1265,6 @@ int qlogicpti_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
 Scsi_Host_Template driver_template = QLOGICPTI;
 
 #include "scsi_module.c"
+
+EXPORT_NO_SYMBOLS;
 #endif /* MODULE */
index 7da69373229dcf0efae9cd22a14eb36073b15355..f47f467ecdc1cb209b941f435885893ac836ee2d 100644 (file)
@@ -349,7 +349,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
                return retval;
 
        /* OK, This is the point of no return */
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(__sparc_v9__)
        memcpy(&current->tss.core_exec, &ex, sizeof(struct exec));
 #endif
 
index ad4fa992ac299314499160ff282d2ae3f4b842a0..b2feaeef120c24404a646262b84b4abab25dc67a 100644 (file)
@@ -70,6 +70,13 @@ static void proc_put_inode(struct inode *inode)
 static void proc_delete_inode(struct inode *inode)
 {
        struct proc_dir_entry *de = inode->u.generic_ip;
+
+#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
+       if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
+           (inode->i_ino <  PROC_OPENPROM_FIRST + PROC_NOPENPROM))
+               return;
+#endif 
+
        if (de) {
                /*
                 * Call the fill_inode hook to release module counts.
index aaf53006f3e64dddab8e748eb349e6126d27cb28..0380e18999a6c73d635db00eb5394e9bb226f525 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.21 1997/08/19 02:05:48 davem Exp $
+/* $Id: openpromfs.c,v 1.26 1998/01/28 09:55:32 ecd Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -55,13 +55,14 @@ static struct openpromfs_dev **devices;
 #define NODEP2INO(no) (no + PROC_OPENPROM_FIRST + last_node)
 
 static int openpromfs_create (struct inode *, struct dentry *, int);
-static int openpromfs_readdir(struct inode *, struct file *, void *, filldir_t);
+static int openpromfs_readdir(struct file *, void *, filldir_t);
 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)
+static ssize_t nodenum_read(struct file *file, char *buf,
+                           size_t count, loff_t *ppos)
 {
+       struct inode *inode = file->f_dentry->d_inode;
        char buffer[10];
        
        if (count < 0 || !inode->u.generic_ip)
@@ -76,9 +77,10 @@ static long nodenum_read(struct inode *inode, struct file *file,
        return count;
 }
 
-static long property_read(struct inode *inode, struct file *filp,
-                         char *buf, unsigned long count)
+static ssize_t property_read(struct file *filp, char *buf,
+                            size_t count, loff_t *ppos)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        int i, j, k;
        u32 node;
        char *p;
@@ -212,8 +214,8 @@ static long property_read(struct inode *inode, struct file *filp,
        return count;
 }
 
-static long property_write(struct inode *inode, struct file *filp,
-                          const char *buf, unsigned long count)
+static ssize_t property_write(struct file *filp, const char *buf,
+                             size_t count, loff_t *ppos)
 {
        int i, j, k;
        char *p;
@@ -224,7 +226,7 @@ static long property_write(struct inode *inode, struct file *filp,
        if (filp->f_pos >= 0xffffff)
                return -EINVAL;
        if (!filp->private_data) {
-               i = property_read (inode, filp, NULL, 0);
+               i = property_read (filp, NULL, 0, 0);
                if (i)
                        return i;
        }
@@ -741,9 +743,9 @@ static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
        return 0;
 }
 
-static int openpromfs_readdir(struct inode * inode, struct file * filp,
-       void * dirent, filldir_t filldir)
+static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        unsigned int ino;
        u32 n;
        int i, j;
@@ -1044,10 +1046,6 @@ EXPORT_NO_SYMBOLS;
 int init_module (void)
 #endif
 {
-#ifndef __sparc_v9__
-       if (!romvec->pv_romvers)
-               return RET(ENODEV);
-#endif
        nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0);
        if (!nodes) {
                printk (KERN_WARNING "/proc/openprom: can't get free page\n");
index 6fdccf97461e54d86d9be3d928ac8a5eb4324dc5..c53a440fe3175cf3c63b7aa66c9a50105253bb1e 100644 (file)
@@ -41,8 +41,8 @@ static int property_read_proc(char *page, char **start, off_t off,
  * and "@10" to it.
  */
 
-static int devtree_readlink(struct inode *, char *, int);
-static struct dentry *devtree_follow_link(struct inode *, struct dentry *);
+static int devtree_readlink(struct dentry *, char *, int);
+static struct dentry *devtree_follow_link(struct dentry *, struct dentry *);
 
 struct inode_operations devtree_symlink_inode_operations = {
        NULL,                   /* no file-operations */
@@ -68,21 +68,23 @@ struct inode_operations devtree_symlink_inode_operations = {
 static struct dentry *devtree_follow_link(struct dentry *dentry,
                                          struct dentry *base)
 {
+       struct inode *inode = dentry->d_inode;
        struct proc_dir_entry * de;
        char *link;
 
-       de = (struct proc_dir_entry *) dentry->inode->u.generic_ip;
+       de = (struct proc_dir_entry *) inode->u.generic_ip;
        link = (char *) de->data;
        return lookup_dentry(link, base, 1);
 }
 
 static int devtree_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
+       struct inode *inode = dentry->d_inode;
        struct proc_dir_entry * de;
        char *link;
        int linklen;
 
-       de = (struct proc_dir_entry *) dentry->inode->u.generic_ip;
+       de = (struct proc_dir_entry *) inode->u.generic_ip;
        link = (char *) de->data;
        linklen = strlen(link);
        if (linklen > buflen)
@@ -206,7 +208,8 @@ static void add_node(struct device_node *np, struct proc_dir_entry *de)
 void proc_device_tree_init(void)
 {
        struct device_node *root;
-
+       if ( !have_of )
+               return;
        proc_device_tree = create_proc_entry("device-tree", S_IFDIR, 0);
        if (proc_device_tree == 0)
                return;
index 75f81f9b982c74ddb21964bc4bf91b38d75945a7..6225b3fd946ece35b98191d22b37985aeb3b870c 100644 (file)
@@ -177,14 +177,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_defreaddir_ptr)(struct file *, void *, filldir_t);
 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),
+proc_openprom_register(int (*readdir)(struct file *, void *, filldir_t),
                       int (*lookup)(struct inode *, struct dentry *),
                       void (*use)(struct inode *, int),
                       struct openpromfs_dev ***devices)
@@ -236,14 +236,13 @@ proc_openprom_deregister(void)
 
 #if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KMOD)
 static int 
-proc_openprom_defreaddir(struct inode * inode, struct file * filp,
-                        void * dirent, filldir_t filldir)
+proc_openprom_defreaddir(struct file * filp, void * dirent, filldir_t filldir)
 {
        request_module("openpromfs");
        if ((proc_openprom_inode_operations.default_file_ops)->readdir !=
            proc_openprom_defreaddir)
                return (proc_openprom_inode_operations.default_file_ops)->readdir 
-                               (inode, filp, dirent, filldir);
+                               (filp, dirent, filldir);
        return -EINVAL;
 }
 #define OPENPROM_DEFREADDIR proc_openprom_defreaddir
index e8cc7f961122227afa4aa704b5942acb2c50b7de..7140a14370203e2fba7acf96f543fa52e68c044b 100644 (file)
 
 #endif
 
+static __inline__ int irq_cannonicalize(int irq)
+{
+       /*
+        * XXX is this true for all Alpha's?  The old serial driver
+        * did it this way for years without any complaints, so....
+        */
+       return ((irq == 2) ? 9 : irq);
+}
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff --git a/include/asm-alpha/serial.h b/include/asm-alpha/serial.h
new file mode 100644 (file)
index 0000000..b5e21bd
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * include/asm-alpha/serial.h
+ */
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD ( 1843200 / 16 )
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#endif
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
+#endif
+       
+#define STD_SERIAL_PORT_DEFNS                  \
+       /* UART CLK   PORT IRQ     FLAGS        */                      \
+       { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
+       { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
+       { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
+       { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
+
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define EXTRA_SERIAL_PORT_DEFNS                        \       
+       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
+       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
+       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
+       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
+       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
+       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
+       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
+       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
+       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
+       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
+       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
+       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
+       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
+       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
+       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
+       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
+       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
+       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
+       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
+       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
+       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
+       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
+       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
+       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
+       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
+       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
+       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
+       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
+#else
+#define EXTRA_SERIAL_PORT_DEFNS
+#endif
+
+#define SERIAL_PORT_DFNS               \
+       STD_SERIAL_PORT_DEFNS           \
+       EXTRA_SERIAL_PORT_DEFNS
index aa9b5be37112d8193dc516dd266a19a47d84803f..67b1a59e57667e691c68b21dac55d924ee547c61 100644 (file)
 
 #define TIMER_IRQ 0
 
+static __inline__ int irq_cannonicalize(int irq)
+{
+       return ((irq == 2) ? 9 : irq);
+}
+
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
diff --git a/include/asm-i386/serial.h b/include/asm-i386/serial.h
new file mode 100644 (file)
index 0000000..dcccb47
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * include/asm-i386/serial.h
+ */
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD ( 1843200 / 16 )
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#endif
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
+#define HUB6_FLAGS 0
+#endif
+       
+/*
+ * The following define the access methods for the HUB6 card. All
+ * access is through two ports for all 24 possible chips. The card is
+ * selected through the high 2 bits, the port on that card with the
+ * "middle" 3 bits, and the register on that port with the bottom
+ * 3 bits.
+ *
+ * While the access port and interrupt is configurable, the default
+ * port locations are 0x302 for the port control register, and 0x303
+ * for the data read/write register. Normally, the interrupt is at irq3
+ * but can be anything from 3 to 7 inclusive. Note that using 3 will
+ * require disabling com2.
+ */
+
+#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
+
+#define STD_SERIAL_PORT_DEFNS                  \
+       /* UART CLK   PORT IRQ     FLAGS        */                      \
+       { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },      /* ttyS0 */     \
+       { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },      /* ttyS1 */     \
+       { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },      /* ttyS2 */     \
+       { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },     /* ttyS3 */
+
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define EXTRA_SERIAL_PORT_DEFNS                        \
+       { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS },     /* ttyS4 */     \
+       { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },     /* ttyS5 */     \
+       { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },     /* ttyS6 */     \
+       { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },     /* ttyS7 */     \
+       { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },     /* ttyS8 */     \
+       { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },     /* ttyS9 */     \
+       { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },     /* ttyS10 */    \
+       { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },     /* ttyS11 */    \
+       { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },       /* ttyS12 */    \
+       { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },       /* ttyS13 */    \
+       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS14 (spare) */            \
+       { 0, BASE_BAUD, 0x000, 0, 0 },  /* ttyS15 (spare) */            \
+       { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },        /* ttyS16 */    \
+       { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },        /* ttyS17 */    \
+       { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },        /* ttyS18 */    \
+       { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },        /* ttyS19 */    \
+       { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },        /* ttyS20 */    \
+       { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },        /* ttyS21 */    \
+       { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },        /* ttyS22 */    \
+       { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },        /* ttyS23 */    \
+       { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },        /* ttyS24 */    \
+       { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },        /* ttyS25 */    \
+       { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },        /* ttyS26 */    \
+       { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },        /* ttyS27 */    \
+       { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },        /* ttyS28 */    \
+       { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },        /* ttyS29 */    \
+       { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },        /* ttyS30 */    \
+       { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },        /* ttyS31 */
+#else
+#define EXTRA_SERIAL_PORT_DEFNS
+#endif
+
+/* You can have up to four HUB6's in the system, but I've only
+ * included two cards here for a total of twelve ports.
+ */
+#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
+#define HUB6_SERIAL_PORT_DFNS          \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */ \
+       { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
+#else
+#define HUB6_SERIAL_PORT_DFNS
+#endif
+
+#ifdef CONFIG_MCA
+#define MCA_SERIAL_PORT_DFNS                   \
+       { 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS },     \
+       { 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS },     \
+       { 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS },     \
+       { 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS },     \
+       { 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS },     \
+       { 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS },
+#else
+#define MCA_SERIAL_PORT_DFNS
+#endif
+
+#define SERIAL_PORT_DFNS               \
+       STD_SERIAL_PORT_DEFNS           \
+       EXTRA_SERIAL_PORT_DEFNS         \
+       HUB6_SERIAL_PORT_DFNS           \
+       MCA_SERIAL_PORT_DFNS
+
index 336eae8f50707c1c496012f4f2080e42735bdd4f..93fe104bc4d265045f7ed51d73f04894a3627f8f 100644 (file)
@@ -293,7 +293,7 @@ __asm__ __volatile__ ("movw %3,0(%2)\n\t" \
        "movb $0,6(%2)\n\t" \
        "movb %%ah,7(%2)\n\t" \
        "rorl $16,%%eax" \
-       : "=m"(*(n)) : "a" (addr), "r"(n), "i"(limit), "i"(type))
+       : "=m"(*(n)) : "a" (addr), "r"(n), "g"(limit), "i"(type))
 
 #define set_tss_desc(n,addr) \
        _set_tssldt_desc(((char *) (n)),((int)(addr)),235,0x89)
index 46ad9206278a7a68f42563e1357c8ffcfcac28a2..169fa381cdc5e62513665d21670346df53791f3b 100644 (file)
 
 #define IRQ_SCHED_TIMER        (8)    /* interrupt source for scheduling timer */
 
+static __inline__ int irq_cannonicalize(int irq)
+{
+       return irq;
+}
+
 /*
  * Machine specific interrupt sources.
  *
diff --git a/include/asm-ppc/8xx_immap.h b/include/asm-ppc/8xx_immap.h
new file mode 100644 (file)
index 0000000..7793c20
--- /dev/null
@@ -0,0 +1,414 @@
+
+/*
+ * MPC8xx Internal Memory Map
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * The I/O on the MPC860 is comprised of blocks of special registers
+ * and the dual port ram for the Communication Processor Module.
+ * Within this space are functional units such as the SIU, memory
+ * controller, system timers, and other control functions.  It is
+ * a combination that I found difficult to separate into logical
+ * functional files.....but anyone else is welcome to try.  -- Dan
+ */
+#ifndef __IMMAP_8XX__
+#define __IMMAP_8XX__
+
+/* System configuration registers.
+*/
+typedef        struct sys_conf {
+       uint    sc_siumcr;
+       uint    sc_sypcr;
+       uint    sc_swt;
+       char    res1[2];
+       ushort  sc_swsr;
+       uint    sc_sipend;
+       uint    sc_simask;
+       uint    sc_siel;
+       uint    sc_sivec;
+       uint    sc_tesr;
+       char    res2[0xc];
+       uint    sc_sdcr;
+       char    res3[0x4c];
+} sysconf8xx_t;
+
+/* PCMCIA configuration registers.
+*/
+typedef struct pcmcia_conf {
+       uint    pcmc_pbr0;
+       uint    pcmc_por0;
+       uint    pcmc_pbr1;
+       uint    pcmc_por1;
+       uint    pcmc_pbr2;
+       uint    pcmc_por2;
+       uint    pcmc_pbr3;
+       uint    pcmc_por3;
+       uint    pcmc_pbr4;
+       uint    pcmc_por4;
+       uint    pcmc_pbr5;
+       uint    pcmc_por5;
+       uint    pcmc_pbr6;
+       uint    pcmc_por6;
+       uint    pcmc_pbr7;
+       uint    pcmc_por7;
+       char    res1[0x20];
+       uint    pcmc_pgcra;
+       uint    pcmc_pgcrb;
+       uint    pcmc_pscr;
+       char    res2[4];
+       uint    pcmc_pipr;
+       char    res3[4];
+       uint    pcmc_per;
+       char    res4[4];
+} pcmconf8xx_t;
+
+/* Memory controller registers.
+*/
+typedef struct mem_ctlr {
+       uint    memc_br0;
+       uint    memc_or0;
+       uint    memc_br1;
+       uint    memc_or1;
+       uint    memc_br2;
+       uint    memc_or2;
+       uint    memc_br3;
+       uint    memc_or3;
+       uint    memc_br4;
+       uint    memc_or4;
+       uint    memc_br5;
+       uint    memc_or5;
+       uint    memc_br6;
+       uint    memc_or6;
+       uint    memc_br7;
+       uint    memc_or7;
+       char    res1[0x24];
+       uint    memc_mar;
+       uint    memc_mcr;
+       char    res2[4];
+       uint    memc_mamr;
+       uint    memc_mbmr;
+       ushort  memc_mstat;
+       ushort  memc_mptpr;
+       uint    memc_mdr;
+       char    res3[0x80];
+} memctl8xx_t;
+
+/* System Integration Timers.
+*/
+typedef struct sys_int_timers {
+       ushort  sit_tbscr;
+       uint    sit_tbreff0;
+       uint    sit_tbreff1;
+       char    res1[0x14];
+       ushort  sit_rtcsc;
+       uint    sit_rtc;
+       uint    sit_rtsec;
+       uint    sit_rtcal;
+       char    res2[0x10];
+       ushort  sit_piscr;
+       char    res3[2];
+       uint    sit_pitc;
+       uint    sit_pitr;
+       char    res4[0x34];
+} sit8xx_t;
+
+#define TBSCR_TBIRQ_MASK       ((ushort)0xff00)
+#define TBSCR_REFA             ((ushort)0x0080)
+#define TBSCR_REFB             ((ushort)0x0040)
+#define TBSCR_REFAE            ((ushort)0x0008)
+#define TBSCR_REFBE            ((ushort)0x0004)
+#define TBSCR_TBF              ((ushort)0x0002)
+#define TBSCR_TBE              ((ushort)0x0001)
+
+#define RTCSC_RTCIRQ_MASK      ((ushort)0xff00)
+#define RTCSC_SEC              ((ushort)0x0080)
+#define RTCSC_ALR              ((ushort)0x0040)
+#define RTCSC_38K              ((ushort)0x0010)
+#define RTCSC_SIE              ((ushort)0x0008)
+#define RTCSC_ALE              ((ushort)0x0004)
+#define RTCSC_RTF              ((ushort)0x0002)
+#define RTCSC_RTE              ((ushort)0x0001)
+
+#define PISCR_PIRQ_MASK                ((ushort)0xff00)
+#define PISCR_PS               ((ushort)0x0080)
+#define PISCR_PIE              ((ushort)0x0004)
+#define PISCR_PTF              ((ushort)0x0002)
+#define PISCR_PTE              ((ushort)0x0001)
+
+/* Clocks and Reset.
+*/
+typedef struct clk_and_reset {
+       uint    car_sccr;
+       uint    car_plprcr;
+       uint    car_rsr;
+       char    res[0x74];        /* Reserved area                  */
+} car8xx_t;
+
+/* System Integration Timers keys.
+*/
+typedef struct sitk {
+       uint    sitk_tbscrk;
+       uint    sitk_tbreff0k;
+       uint    sitk_tbreff1k;
+       uint    sitk_tbk;
+       char    res1[0x10];
+       uint    sitk_rtcsck;
+       uint    sitk_rtck;
+       uint    sitk_rtseck;
+       uint    sitk_rtcalk;
+       char    res2[0x10];
+       uint    sitk_piscrk;
+       uint    sitk_pitck;
+       char    res3[0x38];
+} sitk8xx_t;
+
+/* Clocks and reset keys.
+*/
+typedef struct cark {
+       uint    cark_sccrk;
+       uint    cark_plprcrk;
+       uint    cark_rsrk;
+       char    res[0x474];
+} cark8xx_t;
+
+/* The key to unlock registers maintained by keep-alive power.
+*/
+#define KAPWR_KEY      ((unsigned int)0x55ccaa33)
+
+/* LCD interface.  MPC821 Only.
+*/
+typedef struct lcd {
+       ushort  lcd_lcolr[16];
+       char    res[0x20];
+       uint    lcd_lccr;
+       uint    lcd_lchcr;
+       uint    lcd_lcvcr;
+       char    res2[4];
+       uint    lcd_lcfaa;
+       uint    lcd_lcfba;
+       char    lcd_lcsr;
+       char    res3[0x7];
+} lcd8xx_t;
+
+/* I2C
+*/
+typedef struct i2c {
+       u_char  i2c_i2mod;
+       char    res1[3];
+       u_char  i2c_i2add;
+       char    res2[3];
+       u_char  i2c_i2brg;
+       char    res3[3];
+       u_char  i2c_i2com;
+       char    res4[3];
+       u_char  i2c_i2cer;
+       char    res5[3];
+       u_char  i2c_i2cmr;
+       char    res6[0x8b];
+} i2c8xx_t;
+
+/* DMA control/status registers.
+*/
+typedef struct sdma_csr {
+       char    res1[4];
+       uint    sdma_sdar;
+       u_char  sdma_sdsr;
+       char    res3[3];
+       u_char  sdma_sdmr;
+       char    res4[3];
+       u_char  sdma_idsr1;
+       char    res5[3];
+       u_char  sdma_idmr1;
+       char    res6[3];
+       u_char  sdma_idsr2;
+       char    res7[3];
+       u_char  sdma_idmr2;
+       char    res8[0x13];
+} sdma8xx_t;
+
+/* Communication Processor Module Interrupt Controller.
+*/
+typedef struct cpm_ic {
+       ushort  cpic_civr;
+       char    res[0xe];
+       uint    cpic_cicr;
+       uint    cpic_cipr;
+       uint    cpic_cimr;
+       uint    cpic_cisr;
+} cpic8xx_t;
+
+/* Input/Output Port control/status registers.
+*/
+typedef struct io_port {
+       ushort  iop_padir;
+       ushort  iop_papar;
+       ushort  iop_paodr;
+       ushort  iop_padat;
+       char    res1[8];
+       ushort  iop_pcdir;
+       ushort  iop_pcpar;
+       ushort  iop_pcso;
+       ushort  iop_pcdat;
+       ushort  iop_pcint;
+       char    res2[6];
+       ushort  iop_pddir;
+       ushort  iop_pdpar;
+       char    res3[2];
+       ushort  iop_pddat;
+       char    res4[8];
+} iop8xx_t;
+
+/* Communication Processor Module Timers
+*/
+typedef struct cpm_timers {
+       ushort  cpmt_tgcr;
+       char    res1[0xe];
+       ushort  cpmt_tmr1;
+       ushort  cpmt_tmr2;
+       ushort  cpmt_trr1;
+       ushort  cpmt_trr2;
+       ushort  cpmt_tcr1;
+       ushort  cpmt_tcr2;
+       ushort  cpmt_tcn1;
+       ushort  cpmt_tcn2;
+       ushort  cpmt_tmr3;
+       ushort  cpmt_tmr4;
+       ushort  cpmt_trr3;
+       ushort  cpmt_trr4;
+       ushort  cpmt_tcr3;
+       ushort  cpmt_tcr4;
+       ushort  cpmt_tcn3;
+       ushort  cpmt_tcn4;
+       ushort  cpmt_ter1;
+       ushort  cpmt_ter2;
+       ushort  cpmt_ter3;
+       ushort  cpmt_ter4;
+       char    res2[8];
+} cpmtimer8xx_t;
+
+/* Finally, the Communication Processor stuff.....
+*/
+typedef struct scc {           /* Serial communication channels */
+       uint    scc_gsmrl;
+       uint    scc_gsmrh;
+       ushort  scc_pmsr;
+       char    res1[2];
+       ushort  scc_todr;
+       ushort  scc_dsr;
+       ushort  scc_scce;
+       char    res2[2];
+       ushort  scc_sccm;
+       char    res3;
+       u_char  scc_sccs;
+       char    res4[8];
+} scc_t;
+
+typedef struct smc {           /* Serial management channels */
+       char    res1[2];
+       ushort  smc_smcmr;
+       char    res2[2];
+       u_char  smc_smce;
+       char    res3[3];
+       u_char  smc_smcm;
+       char    res4[5];
+} smc_t;
+
+typedef struct comm_proc {
+       /* General control and status registers.
+       */
+       ushort  cp_cpcr;
+       char    res1[2];
+       ushort  cp_rccr;
+       char    res2[6];
+       ushort  cp_cpmcr1;
+       ushort  cp_cpmcr2;
+       ushort  cp_cpmcr3;
+       ushort  cp_cpmcr4;
+       char    res3[2];
+       ushort  cp_rter;
+       char    res4[2];
+       ushort  cp_rtmr;
+       char    res5[0x14];
+
+       /* Baud rate generators.
+       */
+       uint    cp_brgc1;
+       uint    cp_brgc2;
+       uint    cp_brgc3;
+       uint    cp_brgc4;
+
+       /* Serial Communication Channels.
+       */
+       scc_t   cp_scc[4];
+
+       /* Serial Management Channels.
+       */
+       smc_t   cp_smc[2];
+
+       /* Serial Peripheral Interface.
+       */
+       ushort  cp_spmode;
+       char    res6[4];
+       u_char  cp_spie;
+       char    res7[3];
+       u_char  cp_spim;
+       char    res8[2];
+       u_char  cp_spcom;
+       char    res9[2];
+
+       /* Parallel Interface Port.
+       */
+       char    res10[2];
+       ushort  cp_pipc;
+       char    res11[2];
+       ushort  cp_ptpr;
+       uint    cp_pbdir;
+       uint    cp_pbpar;
+       char    res12[2];
+       ushort  cp_pbodr;
+       uint    cp_pbdat;
+       char    res13[0x18];
+
+       /* Serial Interface and Time Slot Assignment.
+       */
+       uint    cp_simode;
+       u_char  cp_sigmr;
+       char    res14;
+       u_char  cp_sistr;
+       u_char  cp_sicmr;
+       char    res15[4];
+       uint    cp_sicr;
+       uint    cp_sirp;
+       char    res16[0x10c];
+       u_char  cp_siram[0x200];
+       char    res17[0x200];
+       char    res18[0x1000];
+
+       /* Dual Ported RAM follows.
+        * There are many different formats for this memory area
+        * depending upon the devices used and options chosen.
+        */
+       u_char  cp_dpmem[0x1000];       /* BD / Data / ucode */
+       u_char  res19[0xc00];
+       u_char  cp_dparam[0x400];       /* Parameter RAM */
+} cpm8xx_t;
+
+/* Internal memory map.
+*/
+typedef struct immap {
+       sysconf8xx_t    im_siu_conf;    /* SIU Configuration */
+       pcmconf8xx_t    im_pcmcia;      /* PCMCIA Configuration */
+       memctl8xx_t     im_memctl;      /* Memory Controller */
+       sit8xx_t        im_sit;         /* System integration timers */
+       car8xx_t        im_clkrst;      /* Clocks and reset */
+       sitk8xx_t       im_sitk;        /* Sys int timer keys */
+       cark8xx_t       im_clkrstk;     /* Clocks and reset keys */
+       lcd8xx_t        im_lcd;         /* LCD (821 only) */
+       i2c8xx_t        im_i2c;         /* I2C control/status */
+       sdma8xx_t       im_sdma;        /* SDMA control/status */
+       cpic8xx_t       im_cpic;        /* CPM Interrupt Controller */
+       iop8xx_t        im_ioport;      /* IO Port control/status */
+       cpmtimer8xx_t   im_cpmtimer;    /* CPM timers */
+       cpm8xx_t        im_cpm;         /* Communication processor */
+} immap_t;
+
+#endif /* __IMMAP_8XX__ */
index 92fd06e02b4203c4d0bf88d369f16ef1fd9b6765..5035139fe0852d35364d0992c6b51395f3073c98 100644 (file)
 #define ADB_MODEM      5
 #define ADB_MISC       7       /* maybe a monitor */
 
+#define ADB_RET_OK     0
+#define ADB_RET_TIMEOUT        3
 
 #ifdef __KERNEL__
 
 struct adb_request {
-    unsigned char data[16];
+    unsigned char data[32];
     int nbytes;
-    unsigned char reply[16];
+    unsigned char reply[32];
     int reply_len;
     unsigned char reply_expected;
     unsigned char sent;
@@ -34,6 +36,11 @@ struct adb_request {
     struct adb_request *next;
 };
 
+struct adb_ids {
+    int nids;
+    unsigned char id[16];
+};
+
 extern enum adb_hw {
        ADB_NONE, ADB_VIACUDA, ADB_VIAPMU, ADB_MACIO
 } adb_hardware;
@@ -48,7 +55,7 @@ extern int (*adb_autopoll)(int on);
 void adb_init(void);
 int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
                int flags, int nbytes, ...);
-int adb_register(int default_id,
+int adb_register(int default_id,int handler_id,struct adb_ids *ids,
                 void (*handler)(unsigned char *, int, struct pt_regs *, int));
 void adb_input(unsigned char *, int, struct pt_regs *, int);
 
index 53bc673e671d19d2eba85340ff21b7d3cc0f82dd..dd91663907963580ae36279ff28e0db0b0d276cd 100644 (file)
@@ -4,9 +4,84 @@
 #ifndef __ARCH_PPC_CACHE_H
 #define __ARCH_PPC_CACHE_H
 
+#include <linux/config.h>
+#include <asm/processor.h>
+/*#include <asm/system.h>*/
+
 /* bytes per L1 cache line */
 #define        L1_CACHE_BYTES  32      
 #define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 #define L1_CACHE_PAGES         8
 
+#ifndef __ASSEMBLY__
+static inline unsigned long unlock_dcache(void)
+{
+#ifndef CONFIG_8xx     
+       ulong hid0 = 0;
+       /* 601 doesn't do this */
+       if ( (ulong) _get_PVR() == 1 )
+               return 0;
+       asm("mfspr %0,1008 \n\t" : "=r" (hid0) );
+       if ( !(hid0 & HID0_DLOCK) )
+               return 0;
+       asm("mtspr 1008,%0 \n\t" :: "r" (hid0 & ~(HID0_DLOCK)));
+       return (hid0 & HID0_DLOCK) ? 1 : 0;
+#else /* ndef CONFIG_8xx */
+       return 0;
+#endif
+}
+
+static inline void lock_dcache(unsigned long lockit)
+{
+#ifndef CONFIG_8xx
+       /* 601 doesn't do this */
+       if ( !lockit || ((ulong) _get_PVR() == 1) )
+               return;
+       asm("mfspr      %0,1008 \n\t"
+           "ori        %0,%0,%2 \n\t"
+           "mtspr      1008,%0 \n\t"
+           "sync \n\t isync \n\t"
+           : "=r" (lockit) : "0" (lockit), "i" (HID0_DLOCK));
+#endif /* ndef CONFIG_8xx */
+}
+
+#endif /* __ASSEMBLY__ */
+         
+#ifdef CONFIG_8xx
+/* Cache control on the MPC8xx is provided through some additional
+ * special purpose registers.
+ */
+#define IC_CST         560     /* Instruction cache control/status */
+#define IC_ADR         561     /* Address needed for some commands */
+#define IC_DAT         562     /* Read-only data register */
+#define DC_CST         568     /* Data cache control/status */
+#define DC_ADR         569     /* Address needed for some commands */
+#define DC_DAT         570     /* Read-only data register */
+
+/* Commands.  Only the first few are available to the instruction cache.
+*/
+#define        IDC_ENABLE      0x02000000      /* Cache enable */
+#define IDC_DISABLE    0x04000000      /* Cache disable */
+#define IDC_LDLCK      0x06000000      /* Load and lock */
+#define IDC_UNLINE     0x08000000      /* Unlock line */
+#define IDC_UNALL      0x0a000000      /* Unlock all */
+#define IDC_INVALL     0x0c000000      /* Invalidate all */
+
+#define DC_FLINE       0x0e000000      /* Flush data cache line */
+#define DC_SFWT                0x01000000      /* Set forced writethrough mode */
+#define DC_CFWT                0x03000000      /* Clear forced writethrough mode */
+#define DC_SLES                0x05000000      /* Set little endian swap mode */
+#define DC_CLES                0x07000000      /* Clear little endian swap mode */
+
+/* Status.
+*/
+#define IDC_ENABLED    0x80000000      /* Cache is enabled */
+#define IDC_CERR1      0x00200000      /* Cache error 1 */
+#define IDC_CERR2      0x00100000      /* Cache error 2 */
+#define IDC_CERR3      0x00080000      /* Cache error 3 */
+
+#define DC_DFWT                0x40000000      /* Data cache is forced write through */
+#define DC_LES         0x20000000      /* Caches are little endian mode */
+#endif /* CONFIG_8xx */
+
 #endif
index 7c6375c9f885818e32a30276f27f5655fff73d59..32011e0cacb9426f6af08156ba606f1a4ae28986 100644 (file)
@@ -12,6 +12,7 @@
 #define TIMER_PACKET   3
 #define POWER_PACKET   4
 #define MACIIC_PACKET  5
+#define PMU_PACKET     6
 
 /* CUDA commands (2nd byte) */
 #define CUDA_WARM_START                0
index fd50bc24120ac1325999adac87c5c74c574e5238..8ee90bdc10baac376d49251a44091dd95884ceb9 100644 (file)
 #define ISA_DMA_THRESHOLD ~0L
 #endif /* CONFIG_PMAC */
 
+#ifdef CONFIG_APUS
+/* This is bogus and should go away. */
+#define ISA_DMA_THRESHOLD (0x00ffffff)
+#endif
+
 #else
 /* in arch/ppc/kernel/setup.c -- Cort */
 extern unsigned long DMA_MODE_WRITE, DMA_MODE_READ;
index 394b9db56ef0a8fee4fd376fdfe6250c701cb7e5..0073612ddd1c7d9794cf4a333d25a0f8593f430c 100644 (file)
@@ -58,22 +58,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
 #define ELF_PLATFORM   (NULL)
 
-#ifdef __KERNEL__
-#define SET_PERSONALITY(ibcs2) current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX)
-#endif
-
-
-/* This yields a mask that user programs can use to figure out what
-   instruction set this cpu supports.  */
-
-#define ELF_HWCAP      (0)
-
-/* This yields a string that ld.so will use to load implementation
-   specific libraries for optimization.  This is more specific in
-   intent than poking at uname or /proc/cpuinfo.  */
-
-#define ELF_PLATFORM   (NULL)
-
 #ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) \
        current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX)
index 14f8d3312bb2704dd96228a5e1830ddfa4a2e032..efbd4b363cdd5eb93a22a0d6a00b8bca4a2a6174 100644 (file)
 
 #define ide_sti()      sti()
 
-typedef unsigned long ide_ioreg_t;
+typedef unsigned int ide_ioreg_t;
 void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
 void prep_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+void mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
 void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+void chrp_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
 void ide_insw(ide_ioreg_t port, void *buf, int ns);
 void ide_outsw(ide_ioreg_t port, void *buf, int ns);
 
+extern int pmac_ide_ports_known;
+extern ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
+extern int pmac_ide_irq[MAX_HWIFS];
+extern void pmac_ide_probe(void);
+
+extern int chrp_ide_ports_known;
+extern ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
+extern ide_ioreg_t chrp_idedma_regbase; /* one for both channels */
+extern unsigned int chrp_ide_irq;
+extern void chrp_ide_probe(void);
+
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
-       if ( _machine == _MACH_Pmac )
+       if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )
                return 0;
+        else if ( _machine == _MACH_chrp) {
+                if (chrp_ide_ports_known == 0) 
+                       chrp_ide_probe();
+                return chrp_ide_irq;
+        }
        switch (base) {
                case 0x1f0: return 13;
                case 0x170: return 13;
@@ -51,8 +69,17 @@ static __inline__ int ide_default_irq(ide_ioreg_t base)
 
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
-       if ( _machine == _MACH_Pmac )
-               return index;
+        if (_machine == _MACH_Pmac) {
+               if (!pmac_ide_ports_known)
+                       pmac_ide_probe();
+               return pmac_ide_regbase[index];
+       }
+       if (_machine == _MACH_mbx) return index;
+        if ( _machine == _MACH_chrp ) {
+                if (chrp_ide_ports_known == 0)
+                        chrp_ide_probe();
+                return chrp_ide_regbase[index];
+        }
        switch (index) {
                case 0: return 0x1f0;
                case 1: return 0x170;
@@ -65,21 +92,21 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index)
 
 static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
-       if ( _machine == _MACH_Pmac )
+       if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx))
                return 0;
        return check_region(from, extent);
 }
 
 static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
-       if ( _machine == _MACH_Pmac )
+       if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )
                return;
        request_region(from, extent, name);
 }
 
 static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
-       if ( _machine == _MACH_Pmac )
+       if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )
                return;
        release_region(from, extent);
 }
@@ -87,7 +114,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 #define ide_fix_driveid(id)    do {                    \
        int nh;                                         \
        unsigned short *p = (unsigned short *) id;      \
-       if ( _machine == _MACH_Pmac )                   \
+       if (( _machine == _MACH_Pmac ) || (_machine == _MACH_chrp)|| (_machine == _MACH_mbx) )  \
                for (nh = SECTOR_WORDS * 2; nh != 0; --nh, ++p) \
                        *p = (*p << 8) + (*p >> 8);     \
 } while (0)
@@ -95,21 +122,40 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 
 #undef insw
 #define insw(port, buf, ns)    do {                    \
-       if ( _machine != _MACH_Pmac )                   \
+       if ( _machine == _MACH_chrp)  {\
+                ide_insw((port)+_IO_BASE, (buf), (ns));  \
+       }\
+       else if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )                 \
+               ide_insw((port), (buf), (ns));          \
+       else                                            \
                /* this must be the same as insw in io.h!! */   \
                _insw((unsigned short *)((port)+_IO_BASE), (buf), (ns)); \
-       else                                            \
-               ide_insw((port), (buf), (ns));          \
 } while (0)
 #undef outsw
+/*     printk("port: %x buf: %p ns: %d\n",port,buf,ns); \ */
 #define outsw(port, buf, ns)   do {                    \
-       if ( _machine != _MACH_Pmac )                   \
+       if ( _machine == _MACH_chrp) {\
+               ide_outsw((port)+_IO_BASE, (buf), (ns)); \
+       }\
+       else if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )                 \
+               ide_outsw((port), (buf), (ns));         \
+       else                                            \
                /* this must be the same as outsw in io.h!! */  \
                _outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns)); \
-       else                                            \
-               ide_outsw((port), (buf), (ns));         \
 } while (0)
 
+#undef inb
+#define inb(port)      \
+       in_8((unsigned char *)((port) + ((_machine==_MACH_Pmac)? 0: _IO_BASE)))
+#undef inb_p
+#define inb_p(port)    inb(port)
+
+#undef outb
+#define outb(val, port)        \
+       out_8((unsigned char *)((port) + ((_machine==_MACH_Pmac)? 0: _IO_BASE)), (val))
+#undef outb_p
+#define outb_p(val, port)      outb(val, port)
+
 typedef union {
        unsigned all                    : 8;    /* all of the bits together */
        struct {
index 9e2f23c3cbd9ff54481dfe6188daef7723d4a637..e52ddf0be79df8b24d780661298bb4623a6ee318 100644 (file)
@@ -5,6 +5,8 @@
 #include <asm/page.h>
 #include <asm/byteorder.h>
 
+#define KERNELBASE     0xc0000000
+
 /* from the Carolina Technical Spec -- Cort */
 #define IBM_ACORN 0x82A
 #define SIO_CONFIG_RA  0x398
@@ -18,7 +20,6 @@
 
 #define SLOW_DOWN_IO
 
-#define PMAC_ISA_IO_BASE       0
 #define PMAC_ISA_MEM_BASE      0
 #define PMAC_PCI_DRAM_OFFSET   0
 #define CHRP_ISA_IO_BASE       0xf8000000
 #endif /* CONFIG_CHRP */
 
 #ifdef CONFIG_PMAC
-#define _IO_BASE       PMAC_ISA_IO_BASE
+extern unsigned long isa_io_base;
+#define _IO_BASE       isa_io_base     /* well, PCI i/o base really */
 #define _ISA_MEM_BASE  PMAC_ISA_MEM_BASE
 #define PCI_DRAM_OFFSET PMAC_PCI_DRAM_OFFSET
 #endif /* CONFIG_PMAC */
 
+#ifdef CONFIG_MBX
+#define _IO_BASE        0
+#define _ISA_MEM_BASE   0
+#define PCI_DRAM_OFFSET 0x80000000
+#endif /* CONFIG_MBX8xx */
+
 #else /* CONFIG_MACH_SPECIFIC */
 extern unsigned long isa_io_base;
 #define _IO_BASE isa_io_base
@@ -122,8 +130,11 @@ extern inline void * bus_to_virt(unsigned long address)
  * Map in an area of physical address space, for accessing
  * I/O devices etc.
  */
+extern void *__ioremap(unsigned long address, unsigned long size,
+                      unsigned long flags);
 extern void *ioremap(unsigned long address, unsigned long size);
-extern void iounmap(unsigned long *addr);
+extern void iounmap(void *addr);
+extern unsigned long iopa(unsigned long addr);
 
 /*
  * Change virtual addresses to physical addresses and vv, for
index efef8c9f2f7dc6ee847603939f383ce3c0c40f75..8785a3a85d26ecabf6e663faeee4a6e2f9042169 100644 (file)
 #define _IOC_NR(nr)            (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
 #define _IOC_SIZE(nr)          (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
 
+/* various drivers, such as the pcmcia stuff, need these... */
+#define IOC_IN         (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT                (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT      ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK   (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT  (_IOC_SIZESHIFT)
+
 #endif
index 26a481e5dd948769677c26075e88f70c805e5327..63f3b93c739867180812dfbda91c40e1d6961d51 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
+#ifndef CONFIG_8xx
 /*
  * this is the # irq's for all ppc arch's (pmac/chrp/prep)
  * so it is the max of them all - which happens to be chrp
 #define irq_to_openpic(n)      ((n)-NUM_8259_INTERRUPTS)
 #define IRQ_8259_CASCADE       NUM_8259_INTERRUPTS
 
+static __inline__ int irq_cannonicalize(int irq)
+{
+       return irq;
+}
+
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
+#else /* CONFIG_8xx */
+
+/* The MPC8xx cores have 16 possible interrupts.  There are eight
+ * possible level sensitive interrupts assigned and generated internally
+ * from such devices as CPM, PCMCIA, RTC, PIT, TimeBase and Decrementer.
+ * There are eight external interrupts (IRQs) that can be configured
+ * as either level or edge sensitive. 
+ * On the MBX implementation, there is also the possibility of an 8259
+ * through the PCI and PCI-ISA bridges.  All 8259 interrupts appear
+ * on the 8xx as IRQ3, but I may eventually add some of the 8259 code
+ * back into this port to handle that controller.
+ */
+#define NR_IRQS        16
+
+#define        SIU_IRQ0        0       /* Highest priority */
+#define        SIU_LEVEL0      1
+#define        SIU_IRQ1        2
+#define        SIU_LEVEL1      3
+#define        SIU_IRQ2        4
+#define        SIU_LEVEL2      5
+#define        SIU_IRQ3        6
+#define        SIU_LEVEL3      7
+#define        SIU_IRQ4        8
+#define        SIU_LEVEL4      9
+#define        SIU_IRQ5        10
+#define        SIU_LEVEL5      11
+#define        SIU_IRQ6        12
+#define        SIU_LEVEL6      13
+#define        SIU_IRQ7        14
+#define        SIU_LEVEL7      15
+
+/* The internal interrupts we can configure as we see fit.
+ * My personal preference is CPM at level 2, which puts it above the
+ * MBX PCI/ISA/IDE interrupts.
+ */
+#define PIT_INTERRUPT  SIU_LEVEL0
+#define CPM_INTERRUPT  SIU_LEVEL2
+#define DEC_INTERRUPT  SIU_LEVEL7
+
+/* Some internal interrupt registers use an 8-bit mask for the interrupt
+ * level instead of a number.
+ */
+#define        mk_int_int_mask(IL) (1 << (7 - (IL/2)))
+
+#ifdef CONFIG_MBX
+/* These are defined (and fixed) by the MBX hardware implementation.*/
+#define POWER_FAIL_INT SIU_IRQ0        /* Power fail */
+#define TEMP_HILO_INT  SIU_IRQ1        /* Temperature sensor */
+#define QSPAN_INT      SIU_IRQ2        /* PCI Bridge (DMA CTLR?) */
+#define ISA_BRIDGE_INT SIU_IRQ3        /* All those PC things */
+#define COMM_L_INT     SIU_IRQ6        /* MBX Comm expansion connector pin */
+#define STOP_ABRT_INT  SIU_IRQ7        /* Stop/Abort header pin */
+#endif /* CONFIG_MBX */
+
+#endif /* CONFIG_8xx */
+
 #endif
index 41fa0c2ca4807a48b195e694ec072e50a5b03e17..ebf7360cbd18ae627c23c8c53fba1fcf22bd89f6 100644 (file)
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <asm/adb.h>
 
-#ifdef CONFIG_MAC_KEYBOARD
+#define KEYBOARD_IRQ                   1
+#define DISABLE_KBD_DURING_INTERRUPTS  0
+#define INIT_KBD
 
 extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int mackbd_getkeycode(unsigned int scancode);
@@ -28,19 +31,6 @@ 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
-
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
@@ -50,16 +40,133 @@ extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
 
-#define kbd_setkeycode         pckbd_setkeycode
-#define kbd_getkeycode         pckbd_getkeycode
-#define kbd_pretranslate       pckbd_pretranslate
-#define kbd_translate          pckbd_translate
-#define kbd_unexpected_up      pckbd_unexpected_up
-#define kbd_leds               pckbd_leds
-#define kbd_init_hw            pckbd_init_hw
+static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+       if ( is_prep )
+               return pckbd_setkeycode(scancode,keycode);
+       else if ( is_chrp )
+#ifndef CONFIG_MAC_KEYBOARD
+               return pckbd_setkeycode(scancode,keycode);
+#else
+               /* I'm not actually sure if it's legal to have a CHRP machine
+                * without an ADB controller. In any case, this should really
+                * be changed to be a test to see if an ADB _keyboard_ exists
+                * (not just a controller), but that's another story for
+                * another night.
+                */
+               if ( adb_hardware == ADB_NONE )
+                       return pckbd_setkeycode(scancode,keycode);
+               else
+                       return mackbd_setkeycode(scancode,keycode);
+#endif
+       else
+               return mackbd_setkeycode(scancode,keycode);
+}
 
-#define INIT_KBD
-#endif /* CONFIG_MAC_KEYBOARD */
+static inline int kbd_getkeycode(unsigned int x)
+{
+       if ( is_prep )
+               return pckbd_getkeycode(x);
+       else if ( is_chrp )
+#ifndef CONFIG_MAC_KEYBOARD
+               return pckbd_getkeycode(x);
+#else
+               if ( adb_hardware == ADB_NONE )
+                       return pckbd_getkeycode(x);
+               else
+                       return mackbd_getkeycode(x);
+#endif
+       else
+               return mackbd_getkeycode(x);
+}
+
+static inline int kbd_pretranslate(unsigned char x,char y)
+{
+       if ( is_prep )
+               return pckbd_pretranslate(x,y);
+       else if ( is_chrp )
+#ifndef CONFIG_MAC_KEYBOARD
+               return pckbd_pretranslate(x,y);
+#else
+               if ( adb_hardware == ADB_NONE )
+                       return pckbd_pretranslate(x,y);
+               else
+                       return mackbd_pretranslate(x,y);
+#endif
+       else
+               return mackbd_pretranslate(x,y);
+}
+
+static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
+                    char raw_mode)
+{
+       if ( is_prep )
+               return pckbd_translate(keycode,keycodep,raw_mode);
+       else if ( is_chrp )
+#ifndef CONFIG_MAC_KEYBOARD
+               return pckbd_translate(keycode,keycodep,raw_mode);
+#else
+               if ( adb_hardware == ADB_NONE )
+                       return pckbd_translate(keycode,keycodep,raw_mode);
+               else
+                       return mackbd_translate(keycode,keycodep,raw_mode);
+#endif
+       else
+               return mackbd_translate(keycode,keycodep,raw_mode);
+       
+}
+
+static inline int kbd_unexpected_up(unsigned char keycode)
+{
+       if ( is_prep )
+               return pckbd_unexpected_up(keycode);
+       else if ( is_chrp )
+#ifndef CONFIG_MAC_KEYBOARD
+               return pckbd_unexpected_up(keycode);
+#else
+               if ( adb_hardware == ADB_NONE )
+                       return pckbd_unexpected_up(keycode);
+               else
+                       return mackbd_unexpected_up(keycode);
+#endif
+       else
+               return mackbd_unexpected_up(keycode);
+       
+}
+
+static inline void kbd_leds(unsigned char leds)
+{
+       if ( is_prep )
+               pckbd_leds(leds);
+       else if ( is_chrp )
+#ifndef CONFIG_MAC_KEYBOARD
+               pckbd_leds(leds);
+#else
+               if ( adb_hardware == ADB_NONE )
+                       pckbd_leds(leds);
+               else
+                       mackbd_leds(leds);
+#endif
+       else
+               mackbd_leds(leds);
+}
+
+static inline void kbd_init_hw(void)
+{
+       if ( is_prep )
+               pckbd_init_hw();
+       else if ( is_chrp )
+#ifndef CONFIG_MAC_KEYBOARD
+               pckbd_init_hw();
+#else
+               if ( adb_hardware == ADB_NONE )
+                       pckbd_init_hw();
+               else
+                       mackbd_init_hw();
+#endif
+       else
+               mackbd_init_hw();
+}
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-ppc/kgdb.h b/include/asm-ppc/kgdb.h
new file mode 100644 (file)
index 0000000..51c868b
--- /dev/null
@@ -0,0 +1,48 @@
+/* $Id: kgdb.h,v 1.2 1998/04/11 17:29:07 geert Exp $
+ * kgdb.h: Defines and declarations for serial line source level
+ *         remote debugging of the Linux kernel using gdb.
+ *
+ * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu)
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _PPC_KGDB_H
+#define _PPC_KGDB_H
+
+#ifndef __ASSEMBLY__
+/* To initialize the serial, first thing called */
+extern void zs_kgdb_hook(int tty_num);
+/* To init the kgdb engine. (called by serial hook)*/
+extern void set_debug_traps(void);
+
+/* To enter the debugger explicitly. */
+extern void breakpoint(void);
+
+/* For taking exceptions
+ * these are defined in traps.c
+ */
+extern void (*debugger)(struct pt_regs *regs);
+extern int (*debugger_bpt)(struct pt_regs *regs);
+extern int (*debugger_sstep)(struct pt_regs *regs);
+extern int (*debugger_iabr_match)(struct pt_regs *regs);
+extern int (*debugger_dabr_match)(struct pt_regs *regs);
+extern void (*debugger_fault_handler)(struct pt_regs *regs);
+
+/* What we bring to the party */
+int kgdb_bpt(struct pt_regs *regs);
+int kgdb_sstep(struct pt_regs *regs);
+void kgdb(struct pt_regs *regs);
+int kgdb_iabr_match(struct pt_regs *regs);
+int kgdb_dabr_match(struct pt_regs *regs);
+static void kgdb_fault_handler(struct pt_regs *regs);
+static void handle_exception (struct pt_regs *regs);
+
+/*
+ * external low-level support routines (ie macserial.c)
+ */
+extern void kgdb_interruptible(int); /* control interrupts from serial */
+extern void putDebugChar(char);   /* write a single character      */
+extern char getDebugChar(void);   /* read and return a single char */
+
+#endif /* !(__ASSEMBLY__) */
+#endif /* !(_PPC_KGDB_H) */
diff --git a/include/asm-ppc/mbx.h b/include/asm-ppc/mbx.h
new file mode 100644 (file)
index 0000000..f81c64b
--- /dev/null
@@ -0,0 +1,62 @@
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Motorola MBX boards.  This was originally created for the
+ * MBX860, and probably needs revisions for other boards (like the 821).
+ * When this file gets out of control, we can split it up into more
+ * meaningful pieces.
+ *
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_MBX_DEFS
+#define __MACH_MBX_DEFS
+
+/* A Board Information structure that is given to a program when
+ * EPPC-Bug starts it up.
+ */
+typedef struct bd_info {
+       unsigned int    bi_tag;         /* Should be 0x42444944 "BDID" */
+       unsigned int    bi_size;        /* Size of this structure */
+       unsigned int    bi_revision;    /* revision of this structure */
+       unsigned int    bi_bdate;       /* EPPCbug date, i.e. 0x11061997 */
+       unsigned int    bi_memstart;    /* Memory start address */
+       unsigned int    bi_memsize;     /* Memory (end) size in bytes */
+       unsigned int    bi_intfreq;     /* Internal Freq, in Hz */
+       unsigned int    bi_busfreq;     /* Bus Freq, in Hz */
+       unsigned int    bi_clun;        /* Boot device controller */
+       unsigned int    bi_dlun;        /* Boot device logical dev */
+} bd_t;
+
+/* Memory map for the MBX as configured by EPPC-Bug.  We could reprogram
+ * The SIU and PCI bridge, and try to use larger MMU pages, but the
+ * performance gain is not measureable and it certainly complicates the
+ * generic MMU model.
+ *
+ * In a effort to minimize memory usage for embedded applications, any
+ * PCI driver or ISA driver must request or map the region required by
+ * the device.  For convenience (and since we can map up to 4 Mbytes with
+ * a single page table page), the MMU initialization will map the
+ * NVRAM, Status/Control registers, CPM Dual Port RAM, and the PCI
+ * Bridge CSRs 1:1 into the kernel address space.
+ */
+#define PCI_ISA_IO_ADDR                ((uint)0x80000000)
+#define PCI_ISA_IO_SIZE                ((uint)(512 * 1024 * 1024))
+#define PCI_ISA_MEM_ADDR       ((uint)0xc0000000)
+#define PCI_ISA_MEM_SIZE       ((uint)(512 * 1024 * 1024))
+#define PCMCIA_MEM_ADDR                ((uint)0xe0000000)
+#define PCMCIA_MEM_SIZE                ((uint)(64 * 1024 * 1024))
+#define PCMCIA_DMA_ADDR                ((uint)0xe4000000)
+#define PCMCIA_DMA_SIZE                ((uint)(64 * 1024 * 1024))
+#define PCMCIA_ATTRB_ADDR      ((uint)0xe8000000)
+#define PCMCIA_ATTRB_SIZE      ((uint)(64 * 1024 * 1024))
+#define PCMCIA_IO_ADDR         ((uint)0xec000000)
+#define PCMCIA_IO_SIZE         ((uint)(64 * 1024 * 1024))
+#define NVRAM_ADDR             ((uint)0xfa000000)
+#define NVRAM_SIZE             ((uint)(1 * 1024 * 1024))
+#define MBX_CSR_ADDR           ((uint)0xfa100000)
+#define MBX_CSR_SIZE           ((uint)(1 * 1024 * 1024))
+#define MBX_IMAP_ADDR          ((uint)0xfa200000)
+#define MBX_IMAP_SIZE          ((uint)(64 * 1024))
+#define PCI_CSR_ADDR           ((uint)0xfa210000)
+#define PCI_CSR_SIZE           ((uint)(64 * 1024))
+#endif
diff --git a/include/asm-ppc/mediabay.h b/include/asm-ppc/mediabay.h
new file mode 100644 (file)
index 0000000..85146e6
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * mediabay.h: definitions for using the media bay
+ * on PowerBook 3400 and similar computers.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ */
+#ifndef _PPC_MEDIABAY_H
+#define _PPC_MEDIABAY_H
+
+#define MB_FD  0               /* media bay contains floppy drive */
+#define MB_CD  3               /* media bay contains ATA drive such as CD */
+#define MB_NO  7               /* media bay contains nothing */
+
+#ifdef __KERNEL__
+
+void media_bay_init(void);
+int check_media_bay(int what);
+int media_bay_task(void *);
+
+extern int media_bay_present;  /* 1 if this machine has a media bay */
+
+/*
+ * The following give information about the IDE interface
+ * of the media bay: the base virtual address and IRQ number,
+ * and the index that the IDE driver has assigned to it
+ * (or -1 if it is not currently registered with the driver).
+ */
+extern unsigned long mb_cd_base;
+extern int mb_cd_irq;
+extern int mb_cd_index;
+
+#endif /* __KERNEL__ */
+#endif /* _PPC_MEDIABAY_H */
index db12454a54a0148102ba859196632e93607763d6..81ced8229357014e1a833f1ac573cf007c02e2f1 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef _PPC_MMU_H_
 #define _PPC_MMU_H_
 
+#ifndef __ASSEMBLY__
 /* Hardware Page Table Entry */
 typedef struct _PTE {
        unsigned long v:1;      /* Entry is valid */
@@ -157,4 +158,136 @@ extern inline void _tlbie(unsigned long va)
 }
 
 extern void _tlbia(void);              /* invalidate all TLB entries */
-#endif
+#endif /* __ASSEMBLY__ */
+
+/* Control/status registers for the MPC8xx.
+ * A write operation to these registers causes serialized access.
+ * During software tablewalk, the registers used perform mask/shift-add
+ * operations when written/read.  A TLB entry is created when the Mx_RPN
+ * is written, and the contents of several registers are used to
+ * create the entry.
+ */
+#define MI_CTR         784     /* Instruction TLB control register */
+#define MI_GPM         0x80000000      /* Set domain manager mode */
+#define MI_PPM         0x40000000      /* Set subpage protection */
+#define MI_CIDEF       0x20000000      /* Set cache inhibit when MMU dis */
+#define MI_RSV4I       0x08000000      /* Reserve 4 TLB entries */
+#define MI_PPCS                0x02000000      /* Use MI_RPN prob/priv state */
+#define MI_IDXMASK     0x00001f00      /* TLB index to be loaded */
+#define MI_RESETVAL    0x00000000      /* Value of register at reset */
+
+/* These are the Ks and Kp from the PowerPC books.  For proper operation,
+ * Ks = 0, Kp = 1.
+ */
+#define MI_AP          786
+#define MI_Ks          0x80000000      /* Should not be set */
+#define MI_Kp          0x40000000      /* Should always be set */
+
+/* The effective page number register.  When read, contains the information
+ * about the last instruction TLB miss.  When MI_RPN is written, bits in
+ * this register are used to create the TLB entry.
+ */
+#define MI_EPN         787
+#define MI_EPNMASK     0xfffff000      /* Effective page number for entry */
+#define MI_EVALID      0x00000200      /* Entry is valid */
+#define MI_ASIDMASK    0x0000000f      /* ASID match value */
+                                       /* Reset value is undefined */
+
+/* A "level 1" or "segment" or whatever you want to call it register.
+ * For the instruction TLB, it contains bits that get loaded into the
+ * TLB entry when the MI_RPN is written.
+ */
+#define MI_TWC         789
+#define MI_APG         0x000001e0      /* Access protection group (0) */
+#define MI_GUARDED     0x00000010      /* Guarded storage */
+#define MI_PSMASK      0x0000000c      /* Mask of page size bits */
+#define MI_PS8MEG      0x0000000c      /* 8M page size */
+#define MI_PS512K      0x00000004      /* 512K page size */
+#define MI_PS4K_16K    0x00000000      /* 4K or 16K page size */
+#define MI_SVALID      0x00000001      /* Segment entry is valid */
+                                       /* Reset value is undefined */
+
+/* Real page number.  Defined by the pte.  Writing this register
+ * causes a TLB entry to be created for the instruction TLB, using
+ * additional information from the MI_EPN, and MI_TWC registers.
+ */
+#define MI_RPN         790
+
+/* Define an RPN value for mapping kernel memory to large virtual
+ * pages for boot initialization.  This has real page number of 0,
+ * large page size, shared page, cache enabled, and valid.
+ * Also mark all subpages valid and write access.
+ */
+#define MI_BOOTINIT    0x000001fd
+
+#define MD_CTR         792     /* Data TLB control register */
+#define MD_GPM         0x80000000      /* Set domain manager mode */
+#define MD_PPM         0x40000000      /* Set subpage protection */
+#define MD_CIDEF       0x20000000      /* Set cache inhibit when MMU dis */
+#define MD_WTDEF       0x10000000      /* Set writethrough when MMU dis */
+#define MD_RSV4I       0x08000000      /* Reserve 4 TLB entries */
+#define MD_TWAM                0x04000000      /* Use 4K page hardware assist */
+#define MD_PPCS                0x02000000      /* Use MI_RPN prob/priv state */
+#define MD_IDXMASK     0x00001f00      /* TLB index to be loaded */
+#define MD_RESETVAL    0x04000000      /* Value of register at reset */
+
+#define M_CASID                793     /* Address space ID (context) to match */
+#define MC_ASIDMASK    0x0000000f      /* Bits used for ASID value */
+
+
+/* These are the Ks and Kp from the PowerPC books.  For proper operation,
+ * Ks = 0, Kp = 1.
+ */
+#define MD_AP          794
+#define MD_Ks          0x80000000      /* Should not be set */
+#define MD_Kp          0x40000000      /* Should always be set */
+
+/* The effective page number register.  When read, contains the information
+ * about the last instruction TLB miss.  When MD_RPN is written, bits in
+ * this register are used to create the TLB entry.
+ */
+#define MD_EPN         795
+#define MD_EPNMASK     0xfffff000      /* Effective page number for entry */
+#define MD_EVALID      0x00000200      /* Entry is valid */
+#define MD_ASIDMASK    0x0000000f      /* ASID match value */
+                                       /* Reset value is undefined */
+
+/* The pointer to the base address of the first level page table.
+ * During a software tablewalk, reading this register provides the address
+ * of the entry associated with MD_EPN.
+ */
+#define M_TWB          796
+#define        M_L1TB          0xfffff000      /* Level 1 table base address */
+#define M_L1INDX       0x00000ffc      /* Level 1 index, when read */
+                                       /* Reset value is undefined */
+
+/* A "level 1" or "segment" or whatever you want to call it register.
+ * For the data TLB, it contains bits that get loaded into the TLB entry
+ * when the MD_RPN is written.  It is also provides the hardware assist
+ * for finding the PTE address during software tablewalk.
+ */
+#define MD_TWC         797
+#define MD_L2TB                0xfffff000      /* Level 2 table base address */
+#define MD_L2INDX      0xfffffe00      /* Level 2 index (*pte), when read */
+#define MD_APG         0x000001e0      /* Access protection group (0) */
+#define MD_GUARDED     0x00000010      /* Guarded storage */
+#define MD_PSMASK      0x0000000c      /* Mask of page size bits */
+#define MD_PS8MEG      0x0000000c      /* 8M page size */
+#define MD_PS512K      0x00000004      /* 512K page size */
+#define MD_PS4K_16K    0x00000000      /* 4K or 16K page size */
+#define MD_WT          0x00000002      /* Use writethrough page attribute */
+#define MD_SVALID      0x00000001      /* Segment entry is valid */
+                                       /* Reset value is undefined */
+
+
+/* Real page number.  Defined by the pte.  Writing this register
+ * causes a TLB entry to be created for the data TLB, using
+ * additional information from the MD_EPN, and MD_TWC registers.
+ */
+#define MD_RPN         798
+
+/* This is a temporary storage register that could be used to save
+ * a processor working register during a tablewalk.
+ */
+#define M_TW           799
+#endif /* _PPC_MMU_H_ */
index 06a7544ecde1b89367366e3abf683c76c0057ec2..8e7e068ebac96a985935bd41621932ad9502cd1a 100644 (file)
@@ -6,21 +6,44 @@
    perhaps I can defer flushing the tlb by keeping a list of
    zombie vsid/context's and handling that through destroy_context
    later -- Cort
+
+   The MPC8xx has only 16 contexts.  We rotate through them on each
+   task switch.  A better way would be to keep track of tasks that
+   own contexts, and implement an LRU usage.  That way very active
+   tasks don't always have to pay the TLB reload overhead.  The
+   kernel pages are mapped shared, so the kernel can run on behalf
+   of any task that makes a kernel entry.  Shared does not mean they
+   are not protected, just that the ASID comparison is not performed.
+        -- Dan
  */
 
-#define NO_CONTEXT     0
-#define LAST_CONTEXT   0xfffff
+#ifdef CONFIG_8xx
+#define NO_CONTEXT      16
+#define LAST_CONTEXT    15
+#else
+#define NO_CONTEXT      0
+#define LAST_CONTEXT    0xfffff
+#endif
 
 extern int next_mmu_context;
 extern void mmu_context_overflow(void);
+
+#ifndef CONFIG_8xx
 extern void set_context(int context);
+#else
+#define set_context(context)    do { } while (0)
+#endif
 
+#ifndef CONFIG_8xx
 /*
  * Allocating context numbers this way tends to spread out
  * the entries in the hash table better than a simple linear
  * allocation.
  */
-#define MUNGE_CONTEXT(n)       (((n) * 897) & LAST_CONTEXT)
+#define MUNGE_CONTEXT(n)        (((n) * 897) & LAST_CONTEXT)
+#else
+#define MUNGE_CONTEXT(n)        (n)
+#endif
 
 /*
  * Get a new mmu context for task tsk if necessary.
@@ -45,7 +68,11 @@ do {                                                                 \
 /*
  * We're finished using the context for an address space.
  */
-#define destroy_context(mm)    do { } while (0)
+#ifdef CONFIG_8xx
+#define destroy_context(mm)     ((mm)->context = NO_CONTEXT)
+#else
+#define destroy_context(mm)     do { } while (0)
+#endif
 
 /*
  * compute the vsid from the context and segment
diff --git a/include/asm-ppc/ohare.h b/include/asm-ppc/ohare.h
new file mode 100644 (file)
index 0000000..094ad05
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * ohare.h: definitions for using the "O'Hare" I/O controller chip.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ */
+
+/* offset from ohare base for feature control register */
+#define OHARE_FEATURE_REG      0x38
+
+/*
+ * Bits in feature control register.
+ * These were mostly derived by experiment on a powerbook 3400
+ * and may differ for other machines.
+ */
+#define OH_SCC_RESET           1
+#define OH_BAY_RESET           2       /* a guess */
+#define OH_BAY_PCI_ENABLE      4       /* a guess */
+#define OH_BAY_IDE_ENABLE      8
+#define OH_BAY_FLOPPY_ENABLE   0x10
+#define OH_IDE_ENABLE          0x20
+#define OH_BAY_ENABLE          0x80
+#define OH_SCC_ENABLE          0x200
+#define OH_MESH_ENABLE         0x400
+#define OH_FLOPPY_ENABLE       0x800
+#define OH_SCCA_IO             0x2000
+#define OH_SCCB_IO             0x4000
+#define OH_VIA_ENABLE          0x10000
+#define OH_IDECD_POWER         0x800000
+
+/*
+ * Bits to set in the feature control register on PowerBooks.
+ */
+#define PBOOK_FEATURES         (OH_IDE_ENABLE | OH_SCC_ENABLE | \
+                                OH_MESH_ENABLE | OH_SCCA_IO | OH_SCCB_IO)
+
+/*
+ * A magic value to put into the feature control register of the
+ * "ohare" I/O controller on Starmaxes to enable the IDE CD interface.
+ * Contributed by Harry Eaton.
+ */
+#define STARMAX_FEATURES       0xbeff7a
index 1b6e92393a76b821bfaa3c03256ed9b6079b5106..de7134aeba9090a31cba542250c98adbd53fda8f 100644 (file)
@@ -6,8 +6,7 @@
 #define PAGE_SIZE      (1UL << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
-/* KERNELBASE comes from arch/ppc/Makefile */
-#define PAGE_OFFSET    KERNELBASE
+#define PAGE_OFFSET    0xc0000000
 
 
 #ifndef __ASSEMBLY__
@@ -66,8 +65,15 @@ typedef unsigned long pgprot_t;
 #define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)     memcpy((void *)(to), (void *)(from), PAGE_SIZE)
 /* map phys->virtual and virtual->phys for RAM pages */
+#ifdef CONFIG_APUS
+#include <asm/amigappc.h>
+/* Word at CYBERBASEp has the value (-KERNELBASE+CYBERBASE). */
+#define __pa(x)                        ((unsigned long)(x)+(*(unsigned long*)CYBERBASEp))
+#define __va(x)                        ((void *)((unsigned long)(x)-(*(unsigned long*)CYBERBASEp)))
+#else
 #define __pa(x)                        ((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)                        ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#endif
 
 #define MAP_NR(addr)           (((unsigned long)addr-PAGE_OFFSET) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED      (1<<15)
index 68a026b6571fc99f8beffafcd0ed1d3b7ba6639b..e3f3c15909b0392a23b3938f84825f10edbd5b6b 100644 (file)
@@ -17,4 +17,14 @@ void *pci_io_base(unsigned int bus);
 int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
                   unsigned char *devfn_ptr);
 
+struct bridge_data {
+       volatile unsigned int *cfg_addr;
+       volatile unsigned char *cfg_data;
+       void *io_base;
+       int bus_number;
+       int max_bus;
+       struct bridge_data *next;
+       struct device_node *node;
+};
+
 #endif
index 3f3c32b9c1d729c408b3f7af42deeb1d7d1983ab..6b73f3dd824be0f34b53cf44c97b10605359fdf4 100644 (file)
@@ -1,7 +1,10 @@
 #ifndef _PPC_PGTABLE_H
 #define _PPC_PGTABLE_H
 
+#ifndef __ASSEMBLY__
 #include <linux/mm.h>
+#include <asm/processor.h>             /* For TASK_SIZE */
+#include <asm/mmu.h>
 
 extern void local_flush_tlb_all(void);
 extern void local_flush_tlb_mm(struct mm_struct *mm);
@@ -36,6 +39,9 @@ extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 extern void flush_icache_range(unsigned long, unsigned long);
 extern void flush_page_to_ram(unsigned long);
 
+extern unsigned long va_to_phys(unsigned long address);
+extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address);
+#endif /* __ASSEMBLY__ */
 /*
  * The PowerPC MMU uses a hash table containing PTEs, together with
  * a set of 16 segment registers (on 32-bit implementations), to define
@@ -48,6 +54,23 @@ extern void flush_page_to_ram(unsigned long);
  * for extracting ptes from the tree and putting them into the hash table
  * when necessary, and updating the accessed and modified bits in the
  * page table tree.
+ *
+ * The PowerPC MPC8xx uses a TLB with hardware assisted, software tablewalk.
+ * We also use the two level tables, but we can put the real bits in them
+ * needed for the TLB and tablewalk.  These definitions require Mx_CTR.PPM = 0,
+ * Mx_CTR.PPCS = 0, and MD_CTR.TWAM = 1.  The level 2 descriptor has
+ * additional page protection (when Mx_CTR.PPCS = 1) that allows TLB hit
+ * based upon user/super access.  The TLB does not have accessed nor write
+ * protect.  We assume that if the TLB get loaded with an entry it is
+ * accessed, and overload the the changed bit for write protect.  We use
+ * two bits in the software pte that are supposed to be set to zero in
+ * the TLB entry (24 and 25) for these indicators.  Although the level 1
+ * descriptor contains the guarded and writethrough/copyback bits, we can
+ * set these at the page level since they get copied from the Mx_TWC
+ * register when the TLB entry is loaded.  We will use bit 27 for guard, since
+ * that is where it exists in the MD_TWC, and bit 26 for writethrough.
+ * These will get masked from the level 2 descriptor at TLB load time, and
+ * copied to the MD_TWC before it gets loaded.
  */
 
 /* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
@@ -67,6 +90,7 @@ extern void flush_page_to_ram(unsigned long);
 #define PTRS_PER_PTE   1024
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   1024
+#define USER_PTRS_PER_PGD      (TASK_SIZE / PGDIR_SIZE)
 
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 64MB value just means that there will be a 64MB "hole" after the
@@ -89,6 +113,7 @@ extern void flush_page_to_ram(unsigned long);
  * Bits in a linux-style PTE.  These match the bits in the
  * (hardware-defined) PowerPC PTE as closely as possible.
  */
+#ifndef CONFIG_8xx
 #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 */
@@ -100,9 +125,34 @@ extern void flush_page_to_ram(unsigned long);
 #define _PAGE_ACCESSED 0x100   /* R: page referenced */
 #define _PAGE_HWWRITE  0x200   /* software: _PAGE_RW & _PAGE_DIRTY */
 
+#else
+#define _PAGE_PRESENT  0x0001  /* Page is valid */
+#define _PAGE_NO_CACHE 0x0002  /* I: cache inhibit */
+#define _PAGE_SHARED   0x0004  /* No ASID (context) compare */
+
+/* These four software bits must be masked out when the entry is loaded
+ * into the TLB.
+ */
+#define _PAGE_GUARDED  0x0010  /* software: guarded access */
+#define _PAGE_WRITETHRU 0x0020 /* software: use writethrough cache */
+#define _PAGE_RW       0x0040  /* software: user write access allowed */
+#define _PAGE_ACCESSED 0x0080  /* software: page referenced */
+
+#define _PAGE_DIRTY    0x0100  /* C: page changed (write protect) */
+#define _PAGE_USER     0x0800  /* One of the PP bits, the other must be 0 */
+
+/* This is used to enable or disable the actual hardware write
+ * protection.
+ */
+#define _PAGE_HWWRITE  _PAGE_DIRTY
+
+#endif /* CONFIG_8xx */
+
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
 #define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+
+#ifndef CONFIG_8xx
 #define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
                                 _PAGE_ACCESSED)
 #define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
@@ -111,7 +161,17 @@ extern void flush_page_to_ram(unsigned long);
                                 _PAGE_HWWRITE | _PAGE_ACCESSED)
 #define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_NO_CACHE | _PAGE_RW | \
                                 _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
-
+#else
+#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
+                                _PAGE_ACCESSED | _PAGE_SHARED)
+#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_SHARED | _PAGE_ACCESSED)
+#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_NO_CACHE | _PAGE_RW | \
+                                _PAGE_SHARED | _PAGE_DIRTY | _PAGE_ACCESSED)
+#endif /* CONFIG_8xx */
+     
 /*
  * 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.
@@ -143,11 +203,12 @@ extern void flush_page_to_ram(unsigned long);
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
+#ifndef __ASSEMBLY__
 extern pte_t __bad_page(void);
 extern pte_t * __bad_pagetable(void);
 
 extern unsigned long empty_zero_page[1024];
-
+#endif __ASSEMBLY__
 #define BAD_PAGETABLE  __bad_pagetable()
 #define BAD_PAGE       __bad_page()
 #define ZERO_PAGE      ((unsigned long) empty_zero_page)
@@ -164,9 +225,19 @@ extern unsigned long empty_zero_page[1024];
 
 /* to set the page-dir */
 /* tsk is a task_struct and pgdir is a pte_t */
+#ifndef CONFIG_8xx
 #define SET_PAGE_DIR(tsk,pgdir)  \
        ((tsk)->tss.pg_tables = (unsigned long *)(pgdir))
-
+#else /* CONFIG_8xx */     
+#define SET_PAGE_DIR(tsk,pgdir)  \
+ do { \
+       unsigned long __pgdir = (unsigned long)pgdir; \
+       ((tsk)->tss.pg_tables = (unsigned long *)(__pgdir)); \
+       asm("mtspr %0,%1 \n\t" :: "i"(M_TWB), "r"(__pa(__pgdir))); \
+ } while (0)
+#endif /* CONFIG_8xx */
+     
+#ifndef __ASSEMBLY__
 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; }
@@ -197,8 +268,8 @@ 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_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 void pte_uncache(pte_t pte)       { pte_val(pte) |= _PAGE_NO_CACHE; }
+extern inline void pte_cache(pte_t pte)         { pte_val(pte) &= ~_PAGE_NO_CACHE; }
 
 extern inline pte_t pte_rdprotect(pte_t pte) {
        pte_val(pte) &= ~_PAGE_USER; return pte; }
@@ -301,70 +372,123 @@ extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
  * used to allocate a kernel page table, but are actually identical
  * to the xxx() versions.
  */
-extern inline void pte_free_kernel(pte_t * pte)
+#ifdef __SMP__
+/* Sliiiicck */
+#define pgd_quicklist           (cpu_data[smp_processor_id()].pgd_quick)
+#define pmd_quicklist           ((unsigned long *)0)
+#define pte_quicklist           (cpu_data[smp_processor_id()].pte_quick)
+#define pgtable_cache_size      (cpu_data[smp_processor_id()].pgtable_cache_sz)
+#else
+extern struct pgtable_cache_struct {
+       unsigned long *pgd_cache;
+       unsigned long *pte_cache;
+       unsigned long pgtable_cache_sz;
+} quicklists;
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+#endif
+
+
+extern __inline__ pgd_t *get_pgd_slow(void)
 {
-       free_page((unsigned long) pte);
+       pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
+
+       if (ret) {
+               init = pgd_offset(&init_mm, 0);
+               memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+               memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+       }
+       return ret;
 }
 
-extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+extern __inline__ pgd_t *get_pgd_fast(void)
 {
-       address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-       if (pmd_none(*pmd)) {
-               pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (pmd_none(*pmd)) {
-                       if (page) {
-                               pmd_val(*pmd) = (unsigned long) page;
-                               return page + address;
-                       }
-                       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) = (unsigned long) BAD_PAGETABLE;
-               return NULL;
-       }
-       return (pte_t *) pmd_page(*pmd) + address;
+        unsigned long *ret;
+
+        if((ret = pgd_quicklist) != NULL) {
+                pgd_quicklist = (unsigned long *)(*ret);
+                ret[0] = ret[1];
+                pgtable_cache_size--;
+        } else
+                ret = (unsigned long *)get_pgd_slow();
+        return (pgd_t *)ret;
 }
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern inline void pmd_free_kernel(pmd_t * pmd)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
+        *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+        pgd_quicklist = (unsigned long *) pgd;
+        pgtable_cache_size++;
 }
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+       free_page((unsigned long)pgd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+        unsigned long *ret;
+
+        if((ret = (unsigned long *)pte_quicklist) != NULL) {
+                pte_quicklist = (unsigned long *)(*ret);
+                ret[0] = ret[1];
+                pgtable_cache_size--;
+        }
+        return (pte_t *)ret;
+}
+
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+        *(unsigned long *)pte = (unsigned long) pte_quicklist;
+        pte_quicklist = (unsigned long *) pte;
+        pgtable_cache_size++;
+}
+
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+       free_page((unsigned long)pte);
+}
+
+/* We don't use pmd cache, so this is a dummy routine */
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+       return (pmd_t *)0;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
 {
-       return (pmd_t *) pgd;
 }
 
-extern inline void pte_free(pte_t * pte)
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
 {
-       free_page((unsigned long) pte);
 }
 
+extern void __bad_pte(pmd_t *pmd);
+
+#define pte_free_kernel(pte)    free_pte_fast(pte)
+#define pte_free(pte)           free_pte_fast(pte)
+#define pgd_free(pgd)           free_pgd_fast(pgd)
+#define pgd_alloc()             get_pgd_fast()
+
 extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 {
        address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
        if (pmd_none(*pmd)) {
-               pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
-               if (pmd_none(*pmd)) {
-                       if (page) {
-                               pmd_val(*pmd) = (unsigned long) page;
-                               return page + address;
-                       }
-                       pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
-                       return NULL;
-               }
-               free_page((unsigned long) page);
+               pte_t * page = (pte_t *) get_pte_fast();
+               
+               if (!page)
+                       return get_pte_slow(pmd, address);
+               pmd_val(*pmd) = (unsigned long) page;
+               return page + address;
        }
        if (pmd_bad(*pmd)) {
-               printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-               pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
+               __bad_pte(pmd);
                return NULL;
        }
        return (pte_t *) pmd_page(*pmd) + address;
@@ -383,18 +507,64 @@ extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
        return (pmd_t *) pgd;
 }
 
-extern inline void pgd_free(pgd_t * pgd)
-{
-       free_page((unsigned long) pgd);
-}
+#define pmd_free_kernel                pmd_free
+#define pmd_alloc_kernel       pmd_alloc
+#define pte_alloc_kernel       pte_alloc
 
-extern inline pgd_t * pgd_alloc(void)
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
 {
-       return (pgd_t *) get_free_page(GFP_KERNEL);
+       struct task_struct * p;
+       pgd_t *pgd;
+#ifdef __SMP__
+       int i;
+#endif 
+        
+       read_lock(&tasklist_lock);
+       for_each_task(p) {
+               if (!p->mm)
+                       continue;
+               *pgd_offset(p->mm,address) = entry;
+       }
+       read_unlock(&tasklist_lock);
+#ifndef __SMP__
+       for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+               pgd[address >> PGDIR_SHIFT] = entry;
+#else
+       /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
+          modify pgd caches of other CPUs as well. -jj */
+       for (i = 0; i < NR_CPUS; i++)
+               for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+                       pgd[address >> PGDIR_SHIFT] = entry;
+#endif
 }
 
 extern pgd_t swapper_pg_dir[1024];
 
+extern __inline__ pte_t *find_pte(struct mm_struct *mm,unsigned long va)
+{
+       pgd_t *dir;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       va &= PAGE_MASK;
+       
+       dir = pgd_offset( mm, va );
+       if (dir)
+       {
+               pmd = pmd_offset(dir, va & PAGE_MASK);
+               if (pmd && pmd_present(*pmd))
+               {
+                       pte = pte_offset(pmd, va);
+                       if (pte && pte_present(*pte))
+                       {                       
+                               pte_uncache(*pte);
+                               flush_tlb_page(find_vma(mm,va),va);
+                       }
+               }
+       }
+       return pte;
+}
+
 /*
  * 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
@@ -416,5 +586,9 @@ extern void flush_hash_page(unsigned context, unsigned long va);
 
 #define module_map      vmalloc
 #define module_unmap    vfree
+#define module_shrink  vshrink
 
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define PageSkip(page)         (0)
+#endif __ASSEMBLY__
 #endif /* _PPC_PGTABLE_H */
diff --git a/include/asm-ppc/pmu.h b/include/asm-ppc/pmu.h
new file mode 100644 (file)
index 0000000..2a2fb1b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Definitions for talking to the PMU.  The PMU is a microcontroller
+ * which controls battery charging and system power on PowerBook 3400
+ * and 2400 models as well as the RTC and various other things.
+ *
+ * Copyright (C) 1998 Paul Mackerras.
+ */
+
+/*
+ * PMU commands
+ */
+#define PMU_BACKLIGHT_CTRL     0x11    /* control backlight */
+#define PMU_ADB_CMD            0x20    /* send ADB packet */
+#define PMU_ADB_POLL_OFF       0x21    /* disable ADB auto-poll */
+#define PMU_WRITE_NVRAM                0x33    /* write non-volatile RAM */
+#define PMU_READ_NVRAM         0x3b    /* read non-volatile RAM */
+#define PMU_SET_RTC            0x30    /* set real-time clock */
+#define PMU_READ_RTC           0x38    /* read real-time clock */
+#define PMU_BACKLIGHT_BRIGHT   0x41    /* set backlight brightness */
+#define PMU_SET_INTR_MASK      0x70    /* set PMU interrupt mask */
+#define PMU_INT_ACK            0x78    /* read interrupt bits */
+#define PMU_SHUTDOWN           0x7e    /* turn power off */
+#define PMU_SLEEP              0x7f    /* put CPU to sleep */
+#define PMU_RESET              0xd0    /* reset CPU */
+
+/* Bits in PMU interrupt and interrupt mask bytes */
+#define PMU_INT_ADB_AUTO       0x04    /* ADB autopoll, when PMU_INT_ADB */
+#define PMU_INT_PCEJECT                0x04    /* PC-card eject buttons */
+#define PMU_INT_SNDBRT         0x08    /* sound/brightness up/down buttons */
+#define PMU_INT_ADB            0x10    /* ADB autopoll or reply data */
+#define PMU_INT_TICK           0x80    /* 1-second tick interrupt */
+
+#ifdef __KERNEL__
+void via_pmu_init(void);
+int pmu_request(struct adb_request *req,
+               void (*done)(struct adb_request *), int nbytes, ...);
+int pmu_send_request(struct adb_request *req);
+void pmu_poll(void);
+
+void pmu_enable_backlight(int on);
+
+#endif /* __KERNEL */
index 051dd863c85f284e681d672b9cf1938126cf0992..5129f37064bae1beb0716cea4bf5e68b19006a5d 100644 (file)
 #define MSR_RI         (1<<1)          /* Recoverable Exception */
 #define MSR_LE         (1<<0)          /* Little-Endian enable */
 
+#ifdef CONFIG_APUS
+#define MSR_           MSR_ME|MSR_FE0|MSR_FE1|MSR_IP|MSR_RI
+#else
 #define MSR_           MSR_ME|MSR_FE0|MSR_FE1|MSR_RI
+#endif
 #define MSR_KERNEL      MSR_|MSR_IR|MSR_DR
 #define MSR_USER       MSR_KERNEL|MSR_PR|MSR_EE
 
@@ -58,6 +62,8 @@
 #define _MACH_prep     1
 #define _MACH_Pmac     2 /* pmac or pmac clone (non-chrp) */
 #define _MACH_chrp     4 /* chrp machine */
+#define _MACH_mbx      8 /* Motorola MBX board */
+#define _MACH_apus    16 /* amiga with phase5 powerup */
 
 /* see residual.h for these */
 #define _PREP_Motorola 0x01  /* motorola prep */
@@ -117,6 +123,18 @@ n:
 #define IABR   1010    /* Instruction Address Breakpoint */
 #define DEC    22      /* Decrementer */
 #define EAR    282     /* External Address Register */
+#define L2CR   1017    /* PPC 750 L2 control register */
+
+#define THRM1  1020
+#define THRM2  1021
+#define THRM3  1022
+#define THRM1_TIN 0x1
+#define THRM1_TIV 0x2
+#define THRM1_THRES (0x7f<<2)
+#define THRM1_TID (1<<29)
+#define THRM1_TIE (1<<30)
+#define THRM1_V   (1<<31)
+#define THRM3_E   (1<<31)
 
 /* Segment Registers */
 #define SR0    0
@@ -146,18 +164,36 @@ n:
 #ifdef CONFIG_PREP
 #define _machine (_MACH_prep)
 #define is_prep (1)
+#define is_chrp (0)
+#define have_of (0)
 #endif /* CONFIG_PREP */
 
 #ifdef CONFIG_CHRP
 #define _machine (_MACH_chrp)
 #define is_prep (0)
+#define is_chrp (1)
+#define have_of (1)
 #endif /* CONFIG_CHRP */
 
 #ifdef CONFIG_PMAC
 #define _machine (_MACH_Pmac)
 #define is_prep (0)
+#define is_chrp (0)
+#define have_of (1)
 #endif /* CONFIG_PMAC */
 
+#ifdef CONFIG_MBX
+#define _machine (_MACH_mbx)
+#define is_prep (0)
+#define is_chrp (0)
+#define have_of (0)
+#endif /* CONFIG_MBX */
+
+#ifdef CONFIG_APUS
+#define _machine (_MACH_apus)
+#define is_prep (0)
+#endif /* CONFIG_APUS */
+
 #else /* CONFIG_MACH_SPECIFIC */
 
 extern int _machine;
@@ -165,10 +201,13 @@ extern int _machine;
 /* if we're a prep machine */
 #define is_prep (_machine == _MACH_prep)
 
-#endif /* CONFIG_MACH_SPECIFIC */
+/* if we're a chrp machine */
+#define is_chrp (_machine == _MACH_chrp)
 
 /* if we have openfirmware */
 extern unsigned long have_of;
+#endif /* CONFIG_MACH_SPECIFIC */
+
 /* what kind of prep workstation we are */
 extern int _prep_type;
 
@@ -216,6 +255,7 @@ struct thread_struct {
        double          fpr[32];        /* Complete floating point set */
        unsigned long   fpscr_pad;      /* fpr ... fpscr must be contiguous */
        unsigned long   fpscr;          /* Floating point status */
+       unsigned long   smp_fork_ret;
 };
 
 #define INIT_SP                (sizeof(init_stack) + (unsigned long) &init_stack)
@@ -227,10 +267,14 @@ struct thread_struct {
        (struct pt_regs *)INIT_SP - 1, /* regs */ \
        KERNEL_DS, /*fs*/ \
        0, /* last_syscall */ \
-       {0}, 0, 0 \
+       {0}, 0, 0, 0 \
 }
 
-#define INIT_MMAP { &init_mm, KERNELBASE/*0*/, 0xffffffff/*0x40000000*/, \
+/*
+ * Note: the vm_start and vm_end fields here should *not*
+ * be in kernel space.  (Could vm_end == vm_start perhaps?)
+ */
+#define INIT_MMAP { &init_mm, 0, 0x1000, \
                      PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
 
 /*
index f0b4c747069c0bb36ca96886ae66472d68b2d944..9dd8609810abcc9ff7791aa8514c8826d9a1900f 100644 (file)
@@ -20,6 +20,11 @@ struct address_range {
        unsigned int size;
 };
 
+struct interrupt_info {
+       int     line;
+       int     sense;          /* +ve/-ve logic, edge or level, etc. */
+};
+
 struct reg_property {
        unsigned int address;
        unsigned int size;
@@ -46,7 +51,7 @@ struct device_node {
        int     n_addrs;
        struct  address_range *addrs;
        int     n_intrs;
-       int     *intrs;
+       struct  interrupt_info *intrs;
        char    *full_name;
        struct  property *properties;
        struct  device_node *parent;
index c46bdb9b79d750e360032171e3d803260ca8e27d..6909d7c3a72b9045e88f0d0e9a7d98dd317d23dd 100644 (file)
@@ -28,6 +28,7 @@ struct pt_regs {
        unsigned long xer;
        unsigned long ccr;
        unsigned long mq;       /* 601 only (not used at present) */
+                               /* Used on APUS to hold IPL value. */
        unsigned long trap;     /* Reason for being here */
        unsigned long dar;      /* Fault registers */
        unsigned long dsisr;
index 02dbd88169c298e8b6a75eef53da93093fa4610f..fcbaa00760ea93aa7f3265de6b2dca016051d35f 100644 (file)
@@ -19,26 +19,34 @@ extern unsigned long cpu_present_map;
 struct cpuinfo_PPC {
        unsigned long loops_per_sec;
        unsigned long pvr;
+       unsigned long *pgd_quick;
+       unsigned long *pte_quick;
+       unsigned long pgtable_cache_sz;
 };
 
 extern struct cpuinfo_PPC cpu_data[NR_CPUS];
 
-struct klock_info {
-       unsigned char kernel_flag;
+struct klock_info_struct {
+       unsigned long kernel_flag;
        unsigned char akp;
 };
 
-extern struct klock_info klock_info;
+extern struct klock_info_struct klock_info;
 
-#define KLOCK_HELD       0xff
-#define KLOCK_CLEAR      0x00
+#define KLOCK_HELD       0xffffffff
+#define KLOCK_CLEAR      0x0
 
-#define PROC_CHANGE_PENALTY     1000 /* don't change cpu's for now */
+#define PROC_CHANGE_PENALTY     20
 
 extern __volatile__ int cpu_number_map[NR_CPUS];
-extern __volatile__ int cpu_logical_map[NR_CPUS];
+extern __volatile__ int __cpu_logical_map[NR_CPUS];
 extern unsigned long smp_proc_in_lock[NR_CPUS];
 
+extern __inline__ int cpu_logical_map(int cpu)
+{
+       return __cpu_logical_map[cpu];
+}
+
 extern __inline__ int hard_smp_processor_id(void)
 {
        int cpuid = 0;
@@ -48,8 +56,17 @@ extern __inline__ int hard_smp_processor_id(void)
 
 #define smp_processor_id() (current->processor)
 
+extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
+
 #endif /* __ASSEMBLY__ */
 
+#else /* !(__SMP__) */
+#ifndef __ASSEMBLY__
+extern __inline__ int cpu_logical_map(int cpu)
+{
+       return cpu;
+}
+#endif
 #endif /* !(__SMP__) */
 
 #define NO_PROC_ID               0xFF            /* No processor magic marker */
index a33aed501616b05b45865a19ee260d9f8941ee58..8a71d5f3d9ec53c47932ad6d99b2120d20a41998 100644 (file)
@@ -41,4 +41,8 @@
 
 #define SO_BINDTODEVICE        25
 
+/* Socket filtering */
+#define SO_ATTACH_FILTER       26
+#define SO_DETACH_FILTER       27
+
 #endif /* _ASM_SOCKET_H */
index e7e2bbb8f8e786f05e99f3b4b77a01c5e706a350..99506983dd678d1fe9d441ff2b52cdc44bd7a64e 100644 (file)
@@ -69,8 +69,8 @@ extern inline void end_bh_atomic(void)
 }
 
 /* These are for the irq's testing the lock */
-#define softirq_trylock()      (__ppc_bh_counter? 0: ((__ppc_bh_counter=1),1))
-#define softirq_endlock()      (__ppc_bh_counter = 0)
+#define softirq_trylock(cpu)   (__ppc_bh_counter? 0: ((__ppc_bh_counter=1),1))
+#define softirq_endlock(cpu)   (__ppc_bh_counter = 0)
 
 #else /* __SMP__ */
 
@@ -129,7 +129,7 @@ do {        unsigned long flags;                            \
        spin_unlock_irqrestore(&global_bh_lock, flags); \
 } while(0)
 
-#define softirq_trylock()                                      \
+#define softirq_trylock(cpu)                                   \
 ({                                                             \
        int ret = 1;                                            \
        if(atomic_add_return(1, &__ppc_bh_counter) != 1) {      \
@@ -138,7 +138,7 @@ do {        unsigned long flags;                            \
        }                                                       \
        ret;                                                    \
 })
-#define softirq_endlock()      atomic_dec(&__ppc_bh_counter)
+#define softirq_endlock(cpu)   atomic_dec(&__ppc_bh_counter)
 #define clear_active_bhs(mask)                         \
 do {   unsigned long flags;                            \
        spin_lock_irqsave(&global_bh_lock, flags);      \
index bb4af6a0c3fe7018f06068bff8fbcd8edcceed7d..00f1de28190c4d60f01a5ef4e5cbb69b84a38277 100644 (file)
@@ -57,27 +57,24 @@ typedef struct { } rwlock_t;
  * We make no fairness assumptions. They have a cost.
  */
 
-struct _spinlock_debug {
+typedef struct {
        volatile unsigned long lock;
        volatile unsigned long owner_pc;
-};
-
-typedef struct _spinlock_debug spinlock_t;
+       volatile unsigned long owner_cpu;
+} spinlock_t;
 
-#define SPIN_LOCK_UNLOCKED { 0, 0 }
-
-#define SPIN_LOCK_UNLOCKED     { 0, 0 }
-#define spin_lock_init(lp)     do { (lp)->owner_pc = 0; (lp)->lock = 0; } while(0)
+#define SPIN_LOCK_UNLOCKED     { 0, 0, 0 }
+#define spin_lock_init(lp) \
+do { spinlock_t *p = (lp); p->owner_pc = p->owner_cpu = p->lock = 0; } while(0)
 #define spin_unlock_wait(lp)   do { barrier(); } while((lp)->lock)
 
 extern void _spin_lock(spinlock_t *lock);
 extern void _spin_unlock(spinlock_t *lock);
+extern int spin_trylock(spinlock_t *lock);
 
 #define spin_lock(lp)                  _spin_lock(lp)
 #define spin_unlock(lp)                        _spin_unlock(lp)
 
-#define spin_trylock(l) (!test_and_set_bit(0, &((l)->lock) ))
-
 #define spin_lock_irq(lock) \
        do { __cli(); spin_lock(lock); } while (0)
 #define spin_unlock_irq(lock) \
index 1c2d4296658f9112ce3784ec353bfb7e43edb0ad..7b1028c3957cd72279dd8375e963214fd6bea870 100644 (file)
@@ -36,4 +36,41 @@ struct stat {
        unsigned long   __unused4;
        unsigned long   __unused5;
 };
+
+typedef struct {
+       unsigned int    major;
+       unsigned int    minor;
+} __new_dev_t;
+
+struct stat64 {
+       __new_dev_t     st_dev;
+       __u64           st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       __new_dev_t     st_rdev;
+       __s64           st_size;
+       __u64           st_blocks;
+       unsigned long   st_atime;
+       unsigned long   __unused1;
+       unsigned long   st_mtime;
+       unsigned long   __unused2;
+       unsigned long   st_ctime;
+       unsigned long   __unused3;
+       unsigned long   st_blksize;
+       unsigned long   __unused4;
+};
+
+#define __XSTAT_VER_1          1
+#define __XSTAT_VER_2          2
+#define __XSTAT_VER_MASK       0xff
+
+#define __XSTAT_VER_XSTAT      0x000
+#define __XSTAT_VER_LXSTAT     0x100
+#define __XSTAT_VER_FXSTAT     0x200
+#define __XSTAT_VER_TYPEMASK   0xff00
+
+#define __XMKNOD_VER_1         1
+
 #endif
index 99fe62999fc068fc7f3a175c1a6cdcc283560800..f0c01623581afdbe474a046221538b6efa318eab 100644 (file)
@@ -72,14 +72,14 @@ extern void show_regs(struct pt_regs * regs);
 extern void flush_instruction_cache(void);
 extern void hard_reset_now(void);
 extern void poweroff_now(void);
-/*extern void note_bootable_part(kdev_t, int);*/
-extern int sd_find_target(void *, int);
 extern int _get_PVR(void);
+extern long _get_L2CR(void);
 extern void via_cuda_init(void);
 extern void pmac_nvram_init(void);
 extern void read_rtc_time(void);
 extern void pmac_find_display(void);
 extern void giveup_fpu(void);
+extern void smp_giveup_fpu(struct task_struct *);
 extern void cvt_fd(float *from, double *to);
 extern void cvt_df(double *from, float *to);
 
@@ -102,6 +102,7 @@ extern void dump_regs(struct pt_regs *);
 #define sti()  __sti()
 #define save_flags(flags)      __save_flags(flags)
 #define restore_flags(flags)   __restore_flags(flags)
+#define save_and_cli(flags)    __save_and_cli(flags)
 
 #else /* __SMP__ */
 
index a03465065078b53eb91fdb08734cb320974bad61..8202dde4e212e8e0357d4c31c8b4b2a347b6b4be 100644 (file)
 #define __NR_setresgid         169
 #define __NR_getresgid         170
 #define __NR_prctl             171
+#define __NR_xstat             172
+#define __NR_xmknod            173
 
 #define __NR(n)        #n
 #define __do_syscall(n) \
@@ -212,10 +214,11 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
 #ifdef __KERNEL_SYSCALLS__
 
 /*
- * 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.
+ * Forking from kernel space will result in the child getting a new,
+ * empty kernel stack area.  Thus the child cannot access automatic
+ * variables set in the parent unless they are in registers, and the
+ * procedure where the fork was done cannot return to its caller in
+ * the child.
  */
 
 /*
@@ -241,6 +244,9 @@ int execve(const char *, char **, char **);
 int open(const char *, int, int);
 int close(int);
 pid_t waitpid(pid_t, int *, int);
+pid_t fork(void);
+void _exit(int);
+int delete_module(const char *);
 
 static inline pid_t wait(int * wait_stat) 
 {
diff --git a/include/asm-ppc/xstat.h b/include/asm-ppc/xstat.h
new file mode 100644 (file)
index 0000000..f489523
--- /dev/null
@@ -0,0 +1,35 @@
+/* $Id: xstat.h,v 1.1 1998/02/06 12:51:55 jj Exp $
+ * xstat.h: sys_xstat/xmknod architecture dependent stuff.
+ *
+ * Copyright (C) 1998  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
+ */
+extern __inline__ int cp_xstat(struct inode *inode, struct stat64 *s, unsigned long blocks, int blksize)
+{
+       struct stat64 tmp;
+       
+       memset (&tmp, 0, sizeof(tmp));
+       tmp.st_dev.major = MAJOR(inode->i_dev);
+       tmp.st_dev.minor = MINOR(inode->i_dev);
+       tmp.st_ino = inode->i_ino;
+       tmp.st_mode = inode->i_mode;
+       tmp.st_nlink = inode->i_nlink;
+       tmp.st_uid = inode->i_uid;
+       tmp.st_gid = inode->i_gid;
+       tmp.st_rdev.major = MAJOR(inode->i_rdev);
+       tmp.st_rdev.minor = MINOR(inode->i_rdev);
+       tmp.st_size = inode->i_size;
+       tmp.st_blksize = blksize;
+       tmp.st_blocks = blocks;
+       tmp.st_atime = inode->i_atime;
+       tmp.st_mtime = inode->i_mtime;
+       tmp.st_ctime = inode->i_ctime;
+       return copy_to_user(s,&tmp,sizeof(tmp));
+}
+
+extern __inline__ int get_user_new_dev_t(kdev_t *kdev, __new_dev_t *udev) {
+       __new_dev_t ndev;
+       if (copy_from_user (&ndev, udev, sizeof(__new_dev_t))) return -EFAULT;
+       *kdev = MKDEV(ndev.major, ndev.minor);
+       return 0;
+}
index cdc3e76cafde3f1fd6c193154537f56460dc6e6e..25ddaf086515261c07dceba11c10c74c34b8b3e4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: a.out.h,v 1.11 1996/12/03 08:44:56 jj Exp $ */
+/* $Id: a.out.h,v 1.12 1998/02/05 14:20:00 jj Exp $ */
 #ifndef __SPARC_A_OUT_H__
 #define __SPARC_A_OUT_H__
 
@@ -89,10 +89,31 @@ struct relocation_info /* used when header.a_machtype == M_SPARC */
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+#include <asm/btfixup.h>
+
+#ifdef CONFIG_SUN4
+
+#define STACK_TOP      (0xefffe000UL)
+
+#else
+
 extern unsigned long   stack_top;
 
-#define STACK_TOP      (stack_top)
+#  ifndef MODULE
+
+    BTFIXUPDEF_SETHI_INIT(stack_top,0xeffff000)
+
+#    define STACK_TOP  ((unsigned long)BTFIXUP_SETHI(stack_top))
+
+#  else /* MODULE */
+
+#    define STACK_TOP  (stack_top)
+
+#  endif /* MODULE */
+
+#endif /* !CONFIG_SUN4 */
 
-#endif
+#endif /* __KERNEL__ */
 
 #endif /* __SPARC_A_OUT_H__ */
index 59fcd4337e7def62c5114ac3e336e159695e76c2..72ccc64ba5608254ad09f1110bc82ecbb0c95c1e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: asi.h,v 1.17 1997/06/24 15:48:10 jj Exp $ */
+/* $Id: asi.h,v 1.18 1998/03/09 14:04:46 jj Exp $ */
 #ifndef _SPARC_ASI_H
 #define _SPARC_ASI_H
 
 
 #define ASI_M_DCDR         0x39   /* Data Cache Diagnostics Register rw, ss */
 
+#define ASI_M_VIKING_TMP1  0x40          /* Emulation temporary 1 on Viking */
+#define ASI_M_VIKING_TMP2  0x41          /* Emulation temporary 2 on Viking */
+
 #define ASI_M_ACTION       0x4c   /* Breakpoint Action Register (GNU/Viking) */
 
 #endif /* _SPARC_ASI_H */
index b3cf79d56a83803d86b7018ab0e4f9dab3eb453e..5e0578bf1a26988ce822d7505a07113843af4b76 100644 (file)
 #ifndef __ASM_OFFSETS_H__
 #define __ASM_OFFSETS_H__
 
+#ifndef __SMP__
+
 #define AOFF_task_state        0x00000000
 #define ASIZ_task_state        0x00000004
-#define AOFF_task_counter      0x00000004
+#define AOFF_task_flags        0x00000004
+#define ASIZ_task_flags        0x00000004
+#define AOFF_task_sigpending   0x00000008
+#define ASIZ_task_sigpending   0x00000004
+#define AOFF_task_addr_limit   0x0000000c
+#define ASIZ_task_addr_limit   0x00000004
+#define AOFF_task_exec_domain  0x00000010
+#define ASIZ_task_exec_domain  0x00000004
+#define AOFF_task_debugreg     0x00000014
+#define ASIZ_task_debugreg     0x00000020
+#define AOFF_task_counter      0x00000034
 #define ASIZ_task_counter      0x00000004
-#define AOFF_task_priority     0x00000008
+#define AOFF_task_priority     0x00000038
 #define ASIZ_task_priority     0x00000004
-#define AOFF_task_flags        0x0000000c
+#define AOFF_task_binfmt       0x0000003c
+#define ASIZ_task_binfmt       0x00000004
+#define AOFF_task_next_task    0x00000040
+#define ASIZ_task_next_task    0x00000004
+#define AOFF_task_prev_task    0x00000044
+#define ASIZ_task_prev_task    0x00000004
+#define AOFF_task_next_run     0x00000048
+#define ASIZ_task_next_run     0x00000004
+#define AOFF_task_prev_run     0x0000004c
+#define ASIZ_task_prev_run     0x00000004
+#define AOFF_task_exit_code    0x00000050
+#define ASIZ_task_exit_code    0x00000004
+#define AOFF_task_exit_signal  0x00000054
+#define ASIZ_task_exit_signal  0x00000004
+#define AOFF_task_pdeath_signal        0x00000058
+#define ASIZ_task_pdeath_signal        0x00000004
+#define AOFF_task_personality  0x0000005c
+#define ASIZ_task_personality  0x00000004
+#define AOFF_task_pid  0x00000064
+#define ASIZ_task_pid  0x00000004
+#define AOFF_task_pgrp 0x00000068
+#define ASIZ_task_pgrp 0x00000004
+#define AOFF_task_tty_old_pgrp 0x0000006c
+#define ASIZ_task_tty_old_pgrp 0x00000004
+#define AOFF_task_session      0x00000070
+#define ASIZ_task_session      0x00000004
+#define AOFF_task_leader       0x00000074
+#define ASIZ_task_leader       0x00000004
+#define AOFF_task_ngroups      0x00000078
+#define ASIZ_task_ngroups      0x00000004
+#define AOFF_task_groups       0x0000007c
+#define ASIZ_task_groups       0x00000040
+#define AOFF_task_p_opptr      0x000000bc
+#define ASIZ_task_p_opptr      0x00000004
+#define AOFF_task_p_pptr       0x000000c0
+#define ASIZ_task_p_pptr       0x00000004
+#define AOFF_task_p_cptr       0x000000c4
+#define ASIZ_task_p_cptr       0x00000004
+#define AOFF_task_p_ysptr      0x000000c8
+#define ASIZ_task_p_ysptr      0x00000004
+#define AOFF_task_p_osptr      0x000000cc
+#define ASIZ_task_p_osptr      0x00000004
+#define AOFF_task_pidhash_next 0x000000d0
+#define ASIZ_task_pidhash_next 0x00000004
+#define AOFF_task_pidhash_pprev        0x000000d4
+#define ASIZ_task_pidhash_pprev        0x00000004
+#define AOFF_task_tarray_ptr   0x000000d8
+#define ASIZ_task_tarray_ptr   0x00000004
+#define AOFF_task_wait_chldexit        0x000000dc
+#define ASIZ_task_wait_chldexit        0x00000004
+#define AOFF_task_uid  0x000000e0
+#define ASIZ_task_uid  0x00000002
+#define AOFF_task_euid 0x000000e2
+#define ASIZ_task_euid 0x00000002
+#define AOFF_task_suid 0x000000e4
+#define ASIZ_task_suid 0x00000002
+#define AOFF_task_fsuid        0x000000e6
+#define ASIZ_task_fsuid        0x00000002
+#define AOFF_task_gid  0x000000e8
+#define ASIZ_task_gid  0x00000002
+#define AOFF_task_egid 0x000000ea
+#define ASIZ_task_egid 0x00000002
+#define AOFF_task_sgid 0x000000ec
+#define ASIZ_task_sgid 0x00000002
+#define AOFF_task_fsgid        0x000000ee
+#define ASIZ_task_fsgid        0x00000002
+#define AOFF_task_timeout      0x000000f0
+#define ASIZ_task_timeout      0x00000004
+#define AOFF_task_policy       0x000000f4
+#define ASIZ_task_policy       0x00000004
+#define AOFF_task_rt_priority  0x000000f8
+#define ASIZ_task_rt_priority  0x00000004
+#define AOFF_task_it_real_value        0x000000fc
+#define ASIZ_task_it_real_value        0x00000004
+#define AOFF_task_it_prof_value        0x00000100
+#define ASIZ_task_it_prof_value        0x00000004
+#define AOFF_task_it_virt_value        0x00000104
+#define ASIZ_task_it_virt_value        0x00000004
+#define AOFF_task_it_real_incr 0x00000108
+#define ASIZ_task_it_real_incr 0x00000004
+#define AOFF_task_it_prof_incr 0x0000010c
+#define ASIZ_task_it_prof_incr 0x00000004
+#define AOFF_task_it_virt_incr 0x00000110
+#define ASIZ_task_it_virt_incr 0x00000004
+#define AOFF_task_real_timer   0x00000114
+#define ASIZ_task_real_timer   0x00000014
+#define AOFF_task_times        0x00000128
+#define ASIZ_task_times        0x00000010
+#define AOFF_task_start_time   0x00000138
+#define ASIZ_task_start_time   0x00000004
+#define AOFF_task_per_cpu_utime        0x0000013c
+#define ASIZ_task_per_cpu_utime        0x00000004
+#define AOFF_task_min_flt      0x00000144
+#define ASIZ_task_min_flt      0x00000004
+#define AOFF_task_maj_flt      0x00000148
+#define ASIZ_task_maj_flt      0x00000004
+#define AOFF_task_nswap        0x0000014c
+#define ASIZ_task_nswap        0x00000004
+#define AOFF_task_cmin_flt     0x00000150
+#define ASIZ_task_cmin_flt     0x00000004
+#define AOFF_task_cmaj_flt     0x00000154
+#define ASIZ_task_cmaj_flt     0x00000004
+#define AOFF_task_cnswap       0x00000158
+#define ASIZ_task_cnswap       0x00000004
+#define AOFF_task_swap_address 0x00000160
+#define ASIZ_task_swap_address 0x00000004
+#define AOFF_task_old_maj_flt  0x00000164
+#define ASIZ_task_old_maj_flt  0x00000004
+#define AOFF_task_dec_flt      0x00000168
+#define ASIZ_task_dec_flt      0x00000004
+#define AOFF_task_swap_cnt     0x0000016c
+#define ASIZ_task_swap_cnt     0x00000004
+#define AOFF_task_rlim 0x00000170
+#define ASIZ_task_rlim 0x00000050
+#define AOFF_task_used_math    0x000001c0
+#define ASIZ_task_used_math    0x00000002
+#define AOFF_task_io_usage     0x000001c4
+#define ASIZ_task_io_usage     0x00000004
+#define AOFF_task_comm 0x000001c8
+#define ASIZ_task_comm 0x00000010
+#define AOFF_task_link_count   0x000001d8
+#define ASIZ_task_link_count   0x00000004
+#define AOFF_task_tty  0x000001dc
+#define ASIZ_task_tty  0x00000004
+#define AOFF_task_semundo      0x000001e0
+#define ASIZ_task_semundo      0x00000004
+#define AOFF_task_semsleeping  0x000001e4
+#define ASIZ_task_semsleeping  0x00000004
+#define AOFF_task_ldt  0x000001e8
+#define ASIZ_task_ldt  0x00000004
+#define AOFF_task_tss  0x000001f0
+#define ASIZ_task_tss  0x00000390
+#define AOFF_task_fs   0x00000580
+#define ASIZ_task_fs   0x00000004
+#define AOFF_task_files        0x00000584
+#define ASIZ_task_files        0x00000004
+#define AOFF_task_mm   0x00000588
+#define ASIZ_task_mm   0x00000004
+#define AOFF_task_sig  0x0000058c
+#define ASIZ_task_sig  0x00000004
+#define AOFF_task_signal       0x00000590
+#define ASIZ_task_signal       0x00000008
+#define AOFF_task_blocked      0x00000598
+#define ASIZ_task_blocked      0x00000008
+#define AOFF_task_sigqueue     0x000005a0
+#define ASIZ_task_sigqueue     0x00000004
+#define AOFF_task_sigqueue_tail        0x000005a4
+#define ASIZ_task_sigqueue_tail        0x00000004
+#define AOFF_task_has_cpu      0x000005a8
+#define ASIZ_task_has_cpu      0x00000004
+#define AOFF_task_processor    0x000005ac
+#define ASIZ_task_processor    0x00000004
+#define AOFF_task_last_processor       0x000005b0
+#define ASIZ_task_last_processor       0x00000004
+#define AOFF_task_lock_depth   0x000005b4
+#define ASIZ_task_lock_depth   0x00000004
+#define AOFF_task_sigmask_lock 0x000005b8
+#define ASIZ_task_sigmask_lock 0x00000000
+#define AOFF_mm_mmap   0x00000000
+#define ASIZ_mm_mmap   0x00000004
+#define AOFF_mm_mmap_cache     0x00000004
+#define ASIZ_mm_mmap_cache     0x00000004
+#define AOFF_mm_pgd    0x00000008
+#define ASIZ_mm_pgd    0x00000004
+#define AOFF_mm_count  0x0000000c
+#define ASIZ_mm_count  0x00000004
+#define AOFF_mm_map_count      0x00000010
+#define ASIZ_mm_map_count      0x00000004
+#define AOFF_mm_mmap_sem       0x00000014
+#define ASIZ_mm_mmap_sem       0x0000000c
+#define AOFF_mm_context        0x00000020
+#define ASIZ_mm_context        0x00000004
+#define AOFF_mm_start_code     0x00000024
+#define ASIZ_mm_start_code     0x00000004
+#define AOFF_mm_end_code       0x00000028
+#define ASIZ_mm_end_code       0x00000004
+#define AOFF_mm_start_data     0x0000002c
+#define ASIZ_mm_start_data     0x00000004
+#define AOFF_mm_end_data       0x00000030
+#define ASIZ_mm_end_data       0x00000004
+#define AOFF_mm_start_brk      0x00000034
+#define ASIZ_mm_start_brk      0x00000004
+#define AOFF_mm_brk    0x00000038
+#define ASIZ_mm_brk    0x00000004
+#define AOFF_mm_start_stack    0x0000003c
+#define ASIZ_mm_start_stack    0x00000004
+#define AOFF_mm_arg_start      0x00000040
+#define ASIZ_mm_arg_start      0x00000004
+#define AOFF_mm_arg_end        0x00000044
+#define ASIZ_mm_arg_end        0x00000004
+#define AOFF_mm_env_start      0x00000048
+#define ASIZ_mm_env_start      0x00000004
+#define AOFF_mm_env_end        0x0000004c
+#define ASIZ_mm_env_end        0x00000004
+#define AOFF_mm_rss    0x00000050
+#define ASIZ_mm_rss    0x00000004
+#define AOFF_mm_total_vm       0x00000054
+#define ASIZ_mm_total_vm       0x00000004
+#define AOFF_mm_locked_vm      0x00000058
+#define ASIZ_mm_locked_vm      0x00000004
+#define AOFF_mm_def_flags      0x0000005c
+#define ASIZ_mm_def_flags      0x00000004
+#define AOFF_mm_cpu_vm_mask    0x00000060
+#define ASIZ_mm_cpu_vm_mask    0x00000004
+#define AOFF_thread_uwinmask   0x00000000
+#define ASIZ_thread_uwinmask   0x00000004
+#define AOFF_thread_kregs      0x00000004
+#define ASIZ_thread_kregs      0x00000004
+#define AOFF_thread_sig_address        0x00000008
+#define ASIZ_thread_sig_address        0x00000004
+#define AOFF_thread_sig_desc   0x0000000c
+#define ASIZ_thread_sig_desc   0x00000004
+#define AOFF_thread_ksp        0x00000010
+#define ASIZ_thread_ksp        0x00000004
+#define AOFF_thread_kpc        0x00000014
+#define ASIZ_thread_kpc        0x00000004
+#define AOFF_thread_kpsr       0x00000018
+#define ASIZ_thread_kpsr       0x00000004
+#define AOFF_thread_kwim       0x0000001c
+#define ASIZ_thread_kwim       0x00000004
+#define AOFF_thread_fork_kpsr  0x00000020
+#define ASIZ_thread_fork_kpsr  0x00000004
+#define AOFF_thread_fork_kwim  0x00000024
+#define ASIZ_thread_fork_kwim  0x00000004
+#define AOFF_thread_reg_window 0x00000028
+#define ASIZ_thread_reg_window 0x00000200
+#define AOFF_thread_rwbuf_stkptrs      0x00000228
+#define ASIZ_thread_rwbuf_stkptrs      0x00000020
+#define AOFF_thread_w_saved    0x00000248
+#define ASIZ_thread_w_saved    0x00000004
+#define AOFF_thread_float_regs 0x00000250
+#define ASIZ_thread_float_regs 0x00000080
+#define AOFF_thread_fsr        0x000002d0
+#define ASIZ_thread_fsr        0x00000004
+#define AOFF_thread_fpqdepth   0x000002d4
+#define ASIZ_thread_fpqdepth   0x00000004
+#define AOFF_thread_fpqueue    0x000002d8
+#define ASIZ_thread_fpqueue    0x00000080
+#define AOFF_thread_sstk_info  0x00000358
+#define ASIZ_thread_sstk_info  0x00000008
+#define AOFF_thread_flags      0x00000360
+#define ASIZ_thread_flags      0x00000004
+#define AOFF_thread_current_ds 0x00000364
+#define ASIZ_thread_current_ds 0x00000004
+#define AOFF_thread_core_exec  0x00000368
+#define ASIZ_thread_core_exec  0x00000020
+#define AOFF_thread_new_signal 0x00000388
+#define ASIZ_thread_new_signal 0x00000004
+
+#else /* __SMP__ */
+
+#define AOFF_task_state        0x00000000
+#define ASIZ_task_state        0x00000004
+#define AOFF_task_flags        0x00000004
 #define ASIZ_task_flags        0x00000004
-#define AOFF_task_addr_limit   0x00000010
-#define ASIZ_task_addr_limit   0x00000004
-#define AOFF_task_sigpending   0x00000014
+#define AOFF_task_sigpending   0x00000008
 #define ASIZ_task_sigpending   0x00000004
-#define AOFF_task_debugreg     0x00000018
-#define ASIZ_task_debugreg     0x00000020
-#define AOFF_task_exec_domain  0x00000038
+#define AOFF_task_addr_limit   0x0000000c
+#define ASIZ_task_addr_limit   0x00000004
+#define AOFF_task_exec_domain  0x00000010
 #define ASIZ_task_exec_domain  0x00000004
+#define AOFF_task_debugreg     0x00000014
+#define ASIZ_task_debugreg     0x00000020
+#define AOFF_task_counter      0x00000034
+#define ASIZ_task_counter      0x00000004
+#define AOFF_task_priority     0x00000038
+#define ASIZ_task_priority     0x00000004
 #define AOFF_task_binfmt       0x0000003c
 #define ASIZ_task_binfmt       0x00000004
 #define AOFF_task_next_task    0x00000040
 #define ASIZ_task_times        0x00000010
 #define AOFF_task_start_time   0x00000138
 #define ASIZ_task_start_time   0x00000004
-#define AOFF_task_min_flt      0x0000013c
+#define AOFF_task_per_cpu_utime        0x0000013c
+#define ASIZ_task_per_cpu_utime        0x00000080
+#define AOFF_task_min_flt      0x0000023c
 #define ASIZ_task_min_flt      0x00000004
-#define AOFF_task_maj_flt      0x00000140
+#define AOFF_task_maj_flt      0x00000240
 #define ASIZ_task_maj_flt      0x00000004
-#define AOFF_task_nswap        0x00000144
+#define AOFF_task_nswap        0x00000244
 #define ASIZ_task_nswap        0x00000004
-#define AOFF_task_cmin_flt     0x00000148
+#define AOFF_task_cmin_flt     0x00000248
 #define ASIZ_task_cmin_flt     0x00000004
-#define AOFF_task_cmaj_flt     0x0000014c
+#define AOFF_task_cmaj_flt     0x0000024c
 #define ASIZ_task_cmaj_flt     0x00000004
-#define AOFF_task_cnswap       0x00000150
+#define AOFF_task_cnswap       0x00000250
 #define ASIZ_task_cnswap       0x00000004
-#define AOFF_task_swap_address 0x00000158
+#define AOFF_task_swap_address 0x00000258
 #define ASIZ_task_swap_address 0x00000004
-#define AOFF_task_old_maj_flt  0x0000015c
+#define AOFF_task_old_maj_flt  0x0000025c
 #define ASIZ_task_old_maj_flt  0x00000004
-#define AOFF_task_dec_flt      0x00000160
+#define AOFF_task_dec_flt      0x00000260
 #define ASIZ_task_dec_flt      0x00000004
-#define AOFF_task_swap_cnt     0x00000164
+#define AOFF_task_swap_cnt     0x00000264
 #define ASIZ_task_swap_cnt     0x00000004
-#define AOFF_task_rlim 0x00000168
+#define AOFF_task_rlim 0x00000268
 #define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math    0x000001b8
+#define AOFF_task_used_math    0x000002b8
 #define ASIZ_task_used_math    0x00000002
-#define AOFF_task_io_usage     0x000001bc
+#define AOFF_task_io_usage     0x000002bc
 #define ASIZ_task_io_usage     0x00000004
-#define AOFF_task_comm 0x000001c0
+#define AOFF_task_comm 0x000002c0
 #define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count   0x000001d0
+#define AOFF_task_link_count   0x000002d0
 #define ASIZ_task_link_count   0x00000004
-#define AOFF_task_tty  0x000001d4
+#define AOFF_task_tty  0x000002d4
 #define ASIZ_task_tty  0x00000004
-#define AOFF_task_semundo      0x000001d8
+#define AOFF_task_semundo      0x000002d8
 #define ASIZ_task_semundo      0x00000004
-#define AOFF_task_semsleeping  0x000001dc
+#define AOFF_task_semsleeping  0x000002dc
 #define ASIZ_task_semsleeping  0x00000004
-#define AOFF_task_ldt  0x000001e0
+#define AOFF_task_ldt  0x000002e0
 #define ASIZ_task_ldt  0x00000004
-#define AOFF_task_tss  0x000001e8
+#define AOFF_task_tss  0x000002e8
 #define ASIZ_task_tss  0x00000390
-#define AOFF_task_fs   0x00000578
+#define AOFF_task_fs   0x00000678
 #define ASIZ_task_fs   0x00000004
-#define AOFF_task_files        0x0000057c
+#define AOFF_task_files        0x0000067c
 #define ASIZ_task_files        0x00000004
-#define AOFF_task_mm   0x00000580
+#define AOFF_task_mm   0x00000680
 #define ASIZ_task_mm   0x00000004
-#define AOFF_task_sig  0x00000584
+#define AOFF_task_sig  0x00000684
 #define ASIZ_task_sig  0x00000004
-#define AOFF_task_signal       0x00000588
+#define AOFF_task_signal       0x00000688
 #define ASIZ_task_signal       0x00000008
-#define AOFF_task_blocked      0x00000590
+#define AOFF_task_blocked      0x00000690
 #define ASIZ_task_blocked      0x00000008
-#define AOFF_task_sigqueue     0x00000598
+#define AOFF_task_sigqueue     0x00000698
 #define ASIZ_task_sigqueue     0x00000004
-#define AOFF_task_sigqueue_tail        0x0000059c
+#define AOFF_task_sigqueue_tail        0x0000069c
 #define ASIZ_task_sigqueue_tail        0x00000004
-#define AOFF_task_has_cpu      0x000005a0
+#define AOFF_task_has_cpu      0x000006a0
 #define ASIZ_task_has_cpu      0x00000004
-#define AOFF_task_processor    0x000005a4
+#define AOFF_task_processor    0x000006a4
 #define ASIZ_task_processor    0x00000004
-#define AOFF_task_last_processor       0x000005a8
+#define AOFF_task_last_processor       0x000006a8
 #define ASIZ_task_last_processor       0x00000004
-#define AOFF_task_lock_depth   0x000005ac
+#define AOFF_task_lock_depth   0x000006ac
 #define ASIZ_task_lock_depth   0x00000004
-#define AOFF_task_sigmask_lock 0x000005b0
-#define ASIZ_task_sigmask_lock 0x00000000
+#define AOFF_task_sigmask_lock 0x000006b0
+#define ASIZ_task_sigmask_lock 0x00000001
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000004
 #define AOFF_mm_mmap_cache     0x00000004
 #define ASIZ_mm_pgd    0x00000004
 #define AOFF_mm_count  0x0000000c
 #define ASIZ_mm_count  0x00000004
-#define AOFF_mm_mmap_sem       0x00000010
+#define AOFF_mm_map_count      0x00000010
+#define ASIZ_mm_map_count      0x00000004
+#define AOFF_mm_mmap_sem       0x00000014
 #define ASIZ_mm_mmap_sem       0x0000000c
-#define AOFF_mm_context        0x0000001c
+#define AOFF_mm_context        0x00000020
 #define ASIZ_mm_context        0x00000004
-#define AOFF_mm_start_code     0x00000020
+#define AOFF_mm_start_code     0x00000024
 #define ASIZ_mm_start_code     0x00000004
-#define AOFF_mm_end_code       0x00000024
+#define AOFF_mm_end_code       0x00000028
 #define ASIZ_mm_end_code       0x00000004
-#define AOFF_mm_start_data     0x00000028
+#define AOFF_mm_start_data     0x0000002c
 #define ASIZ_mm_start_data     0x00000004
-#define AOFF_mm_end_data       0x0000002c
+#define AOFF_mm_end_data       0x00000030
 #define ASIZ_mm_end_data       0x00000004
-#define AOFF_mm_start_brk      0x00000030
+#define AOFF_mm_start_brk      0x00000034
 #define ASIZ_mm_start_brk      0x00000004
-#define AOFF_mm_brk    0x00000034
+#define AOFF_mm_brk    0x00000038
 #define ASIZ_mm_brk    0x00000004
-#define AOFF_mm_start_stack    0x00000038
+#define AOFF_mm_start_stack    0x0000003c
 #define ASIZ_mm_start_stack    0x00000004
-#define AOFF_mm_start_mmap     0x0000003c
-#define ASIZ_mm_start_mmap     0x00000004
 #define AOFF_mm_arg_start      0x00000040
 #define ASIZ_mm_arg_start      0x00000004
 #define AOFF_mm_arg_end        0x00000044
 #define AOFF_thread_new_signal 0x00000388
 #define ASIZ_thread_new_signal 0x00000004
 
+#endif /* __SMP__ */
+
 #endif /* __ASM_OFFSETS_H__ */
index 40c71b0d6cb2ee37725bd7cfc8685bd5bf6d7f69..ed49f6ea033c36faa0367c65cb23fa34949786fd 100644 (file)
@@ -6,11 +6,24 @@
 #ifndef _SPARC_ASMMACRO_H
 #define _SPARC_ASMMACRO_H
 
-#define GET_PROCESSOR_ID(reg) \
+#include <linux/config.h>
+#include <asm/btfixup.h>
+#include <asm/asi.h>
+
+#define GET_PROCESSOR4M_ID(reg) \
        rd      %tbr, %reg; \
        srl     %reg, 12, %reg; \
        and     %reg, 3, %reg;
 
+#define GET_PROCESSOR4D_ID(reg) \
+       lda     [%g0] ASI_M_VIKING_TMP1, %reg;
+
+/* Blackbox */
+#define GET_PROCESSOR_ID(reg) \
+       sethi   %hi(___b_smp_processor_id), %reg; \
+       sethi   %hi(boot_cpu_id), %reg; \
+       ldub    [%reg + %lo(boot_cpu_id)], %reg;
+
 #define GET_PROCESSOR_MID(reg, tmp) \
        rd      %tbr, %reg; \
        sethi   C_LABEL(mid_xlate), %tmp; \
        and     %reg, 3, %reg; \
        ldub    [%tmp + %reg], %reg;
 
-#define GET_PROCESSOR_OFFSET(reg) \
+#define GET_PROCESSOR_OFFSET(reg, tmp) \
        GET_PROCESSOR_ID(reg) \
-       sll     %reg, 2, %reg;
-
-#define PROCESSOR_OFFSET_TO_ID(reg) \
-       srl     %reg, 2, %reg;
+       sethi   C_LABEL(cpu_offset), %tmp; \
+       sll     %reg, 2, %reg; \
+       or      %tmp, %lo(C_LABEL(cpu_offset)), %tmp; \
+       ld      [%tmp + %reg], %reg;
 
-#define PROCESSOR_ID_TO_OFFSET(reg) \
-       sll     %reg, 2, %reg;
+#define GET_PAGE_OFFSET(reg) \
+       sethi   BTFIXUP_SETHI_INIT(page_offset,0xf0000000), %reg;
 
 /* All trap entry points _must_ begin with this macro or else you
  * lose.  It makes sure the kernel has a proper window so that
 /* All traps low-level code here must end with this macro. */
 #define RESTORE_ALL b ret_trap_entry; clr %l6;
 
+/* sun4 probably wants half word accesses to ASI_SEGMAP, while sun4c+
+   likes byte accesses. These are to avoid ifdef mania. */
+
+#ifdef CONFIG_SUN4
+#define lduXa  lduha
+#define stXa   stha
+#else
+#define lduXa  lduba
+#define stXa   stba
+#endif
+
 #endif /* !(_SPARC_ASMMACRO_H) */
index a433b684c5af34623d74441b32d70c049febeffc..dbc259cb6805b4c3e287c32b808a442c356df6b1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.48 1997/12/18 02:44:06 ecd Exp $
+/* $Id: bitops.h,v 1.49 1998/02/23 01:46:44 rth Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -60,7 +60,7 @@ extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
        return (unsigned long) ADDR;
 }
 
-extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
+extern __inline__ void change_bit(unsigned long nr, void *addr)
 {
        int mask;
        unsigned long *ADDR = (unsigned long *) addr;
@@ -76,8 +76,6 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
        : "=&r" (ADDR)
        : "0" (ADDR), "r" (mask)
        : "g2", "g3");
-
-       return (unsigned long) ADDR;
 }
 
 #else /* __KERNEL__ */
@@ -136,7 +134,7 @@ extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, __SMPVOL vo
        return mask;
 }
 
-extern __inline__ unsigned long clear_bit(unsigned long nr, __SMPVOL void *addr)
+extern __inline__ void clear_bit(unsigned long nr, __SMPVOL void *addr)
 {
        (void) test_and_clear_bit(nr, addr);
 }
@@ -159,7 +157,7 @@ extern __inline__ unsigned long test_and_change_bit(unsigned long nr, __SMPVOL v
        return mask;
 }
 
-extern __inline__ unsigned long change_bit(unsigned long nr, __SMPVOL void *addr)
+extern __inline__ void change_bit(unsigned long nr, __SMPVOL void *addr)
 {
        (void) test_and_change_bit(nr, addr);
 }
diff --git a/include/asm-sparc/btfixup.h b/include/asm-sparc/btfixup.h
new file mode 100644 (file)
index 0000000..e2ad321
--- /dev/null
@@ -0,0 +1,219 @@
+/* $Id: btfixup.h,v 1.4 1998/03/09 14:04:43 jj Exp $
+ *  asm-sparc/btfixup.h:    Macros for boot time linking.
+ *
+ *  Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+#ifndef _SPARC_BTFIXUP_H
+#define _SPARC_BTFIXUP_H
+
+#include <linux/init.h>
+
+#ifndef __ASSEMBLY__
+
+#ifdef MODULE
+extern unsigned int ___illegal_use_of_BTFIXUP_SIMM13_in_module(void);
+extern unsigned int ___illegal_use_of_BTFIXUP_SETHI_in_module(void);
+extern unsigned int ___illegal_use_of_BTFIXUP_HALF_in_module(void);
+extern unsigned int ___illegal_use_of_BTFIXUP_INT_in_module(void);
+#endif
+
+/* Fixup call xx */
+
+#define BTFIXUPDEF_CALL(__type, __name, __args...)                                     \
+       extern __type ___f_##__name(__args);                                            \
+       extern unsigned ___fs_##__name[3];
+#define BTFIXUPDEF_CALL_CONST(__type, __name, __args...)                               \
+       extern __type ___f_##__name(__args) __attribute__((const));                     \
+       extern unsigned ___fs_##__name[3];
+#define BTFIXUP_CALL(__name) ___f_##__name
+
+#define BTFIXUPDEF_BLACKBOX(__name)                                                    \
+       extern unsigned ___bs_##__name[2];
+#ifdef MODULE
+#define BTFIXUP_BLACKBOX(__name) ___illegal_use_of_BTFIXUP_BLACKBOX_in_module
+#else
+/* This must be written in assembly and present in a sethi */
+#define BTFIXUP_BLACKBOX(__name) ___b_##__name
+#endif
+
+/* Put bottom 13bits into some register variable */
+
+#define BTFIXUPDEF_SIMM13(__name)                                                      \
+       extern unsigned int ___sf_##__name(void) __attribute__((const));                \
+       extern unsigned ___ss_##__name[2];                                              \
+       extern __inline__ unsigned int ___sf_##__name(void) {                           \
+               unsigned int ret;                                                       \
+               __asm__ ("or %%g0, ___s_" #__name ", %0" : "=r"(ret));                  \
+               return ret;                                                             \
+       }
+#define BTFIXUPDEF_SIMM13_INIT(__name,__val)                                           \
+       extern unsigned int ___sf_##__name(void) __attribute__((const));                \
+       extern unsigned ___ss_##__name[2];                                              \
+       extern __inline__ unsigned int ___sf_##__name(void) {                           \
+               unsigned int ret;                                                       \
+               __asm__ ("or %%g0, ___s_" #__name "__btset_" #__val ", %0" : "=r"(ret));\
+               return ret;                                                             \
+       }
+#ifdef MODULE
+#define BTFIXUP_SIMM13(__name) ___illegal_use_of_BTFIXUP_SIMM13_in_module()
+#else
+#define BTFIXUP_SIMM13(__name) ___sf_##__name()
+#endif
+
+/* Put either bottom 13 bits, or upper 22 bits into some register variable
+ * (depending on the value, this will lead into sethi FIX, reg; or
+ * mov FIX, reg; )
+ */
+
+#define BTFIXUPDEF_HALF(__name)                                                                \
+       extern unsigned int ___af_##__name(void) __attribute__((const));                \
+       extern unsigned ___as_##__name[2];                                              \
+       extern __inline__ unsigned int ___af_##__name(void) {                           \
+               unsigned int ret;                                                       \
+               __asm__ ("or %%g0, ___a_" #__name ", %0" : "=r"(ret));                  \
+               return ret;                                                             \
+       }
+#define BTFIXUPDEF_HALF_INIT(__name,__val)                                             \
+       extern unsigned int ___af_##__name(void) __attribute__((const));                \
+       extern unsigned ___as_##__name[2];                                              \
+       extern __inline__ unsigned int ___af_##__name(void) {                           \
+               unsigned int ret;                                                       \
+               __asm__ ("or %%g0, ___a_" #__name "__btset_" #__val ", %0" : "=r"(ret));\
+               return ret;                                                             \
+       }
+#ifdef MODULE
+#define BTFIXUP_HALF(__name) ___illegal_use_of_BTFIXUP_HALF_in_module()
+#else
+#define BTFIXUP_HALF(__name) ___af_##__name()
+#endif
+
+/* Put upper 22 bits into some register variable */
+
+#define BTFIXUPDEF_SETHI(__name)                                                       \
+       extern unsigned int ___hf_##__name(void) __attribute__((const));                \
+       extern unsigned ___hs_##__name[2];                                              \
+       extern __inline__ unsigned int ___hf_##__name(void) {                           \
+               unsigned int ret;                                                       \
+               __asm__ ("sethi %%hi(___h_" #__name "), %0" : "=r"(ret));               \
+               return ret;                                                             \
+       }
+#define BTFIXUPDEF_SETHI_INIT(__name,__val)                                            \
+       extern unsigned int ___hf_##__name(void) __attribute__((const));                \
+       extern unsigned ___hs_##__name[2];                                              \
+       extern __inline__ unsigned int ___hf_##__name(void) {                           \
+               unsigned int ret;                                                       \
+               __asm__ ("sethi %%hi(___h_" #__name "__btset_" #__val "), %0" :         \
+                        "=r"(ret));                                                    \
+               return ret;                                                             \
+       }
+#ifdef MODULE
+#define BTFIXUP_SETHI(__name) ___illegal_use_of_BTFIXUP_SETHI_in_module()
+#else
+#define BTFIXUP_SETHI(__name) ___hf_##__name()
+#endif
+
+/* Put a full 32bit integer into some register variable */
+
+#define BTFIXUPDEF_INT(__name)                                                         \
+       extern unsigned char ___i_##__name;                                             \
+       extern unsigned ___is_##__name[2];
+#ifdef MODULE
+#define BTFIXUP_INT(__name) ___illegal_use_of_BTFIXUP_INT_in_module()
+#else
+#define BTFIXUP_INT(__name) ((unsigned int)&___i_##__name)
+#endif
+
+#define BTFIXUPCALL_NORM       0x00000000                      /* Always call */
+#define BTFIXUPCALL_NOP                0x01000000                      /* Possibly optimize to nop */
+#define BTFIXUPCALL_RETINT(i)  (0x90102000|((i) & 0x1fff))     /* Possibly optimize to mov i, %o0 */
+#define BTFIXUPCALL_ORINT(i)   (0x90122000|((i) & 0x1fff))     /* Possibly optimize to or %o0, i, %o0 */
+#define BTFIXUPCALL_RETO0      0x01000000                      /* Return first parameter, actually a nop */
+#define BTFIXUPCALL_ANDNINT(i) (0x902a2000|((i) & 0x1fff))     /* Possibly optimize to andn %o0, i, %o0 */
+#define BTFIXUPCALL_SWAPO0O1   0xd27a0000                      /* Possibly optimize to swap [%o0],%o1 */
+#define BTFIXUPCALL_SWAPO0G0   0xc07a0000                      /* Possibly optimize to swap [%o0],%g0 */
+#define BTFIXUPCALL_SWAPG1G2   0xc4784000                      /* Possibly optimize to swap [%g1],%g2 */
+#define BTFIXUPCALL_STG0O0     0xc0220000                      /* Possibly optimize to st %g0,[%o0] */
+#define BTFIXUPCALL_STO1O0     0xd2220000                      /* Possibly optimize to st %o1,[%o0] */
+
+#define BTFIXUPSET_CALL(__name, __addr, __insn)                                                \
+       do {                                                                            \
+               ___fs_##__name[0] |= 1;                                                 \
+               ___fs_##__name[1] = (unsigned long)__addr;                              \
+               ___fs_##__name[2] = __insn;                                             \
+       } while (0)
+       
+#define BTFIXUPSET_BLACKBOX(__name, __func)                                            \
+       do {                                                                            \
+               ___bs_##__name[0] |= 1;                                                 \
+               ___bs_##__name[1] = (unsigned long)__func;                              \
+       } while (0)
+       
+#define BTFIXUPCOPY_CALL(__name, __from)                                               \
+       do {                                                                            \
+               ___fs_##__name[0] |= 1;                                                 \
+               ___fs_##__name[1] = ___fs_##__from[1];                                  \
+               ___fs_##__name[2] = ___fs_##__from[2];                                  \
+       } while (0)
+               
+#define BTFIXUPSET_SIMM13(__name, __val)                                               \
+       do {                                                                            \
+               ___ss_##__name[0] |= 1;                                                 \
+               ___ss_##__name[1] = (unsigned)__val;                                    \
+       } while (0)
+       
+#define BTFIXUPCOPY_SIMM13(__name, __from)                                             \
+       do {                                                                            \
+               ___ss_##__name[0] |= 1;                                                 \
+               ___ss_##__name[1] = ___ss_##__from[1];                                  \
+       } while (0)
+               
+#define BTFIXUPSET_HALF(__name, __val)                                                 \
+       do {                                                                            \
+               ___as_##__name[0] |= 1;                                                 \
+               ___as_##__name[1] = (unsigned)__val;                                    \
+       } while (0)
+       
+#define BTFIXUPCOPY_HALF(__name, __from)                                               \
+       do {                                                                            \
+               ___as_##__name[0] |= 1;                                                 \
+               ___as_##__name[1] = ___as_##__from[1];                                  \
+       } while (0)
+               
+#define BTFIXUPSET_SETHI(__name, __val)                                                        \
+       do {                                                                            \
+               ___hs_##__name[0] |= 1;                                                 \
+               ___hs_##__name[1] = (unsigned)__val;                                    \
+       } while (0)
+       
+#define BTFIXUPCOPY_SETHI(__name, __from)                                              \
+       do {                                                                            \
+               ___hs_##__name[0] |= 1;                                                 \
+               ___hs_##__name[1] = ___hs_##__from[1];                                  \
+       } while (0)
+               
+#define BTFIXUPSET_INT(__name, __val)                                                  \
+       do {                                                                            \
+               ___is_##__name[0] |= 1;                                                 \
+               ___is_##__name[1] = (unsigned)__val;                                    \
+       } while (0)
+       
+#define BTFIXUPCOPY_INT(__name, __from)                                                        \
+       do {                                                                            \
+               ___is_##__name[0] |= 1;                                                 \
+               ___is_##__name[1] = ___is_##__from[1];                                  \
+       } while (0)
+       
+#define BTFIXUPVAL_CALL(__name)                                                                \
+       ((unsigned long)___fs_##__name[1])
+       
+extern void btfixup(void);
+
+#else /* __ASSEMBLY__ */
+
+#define BTFIXUP_SETHI(__name)                  %hi(___h_ ## __name)
+#define BTFIXUP_SETHI_INIT(__name,__val)       %hi(___h_ ## __name ## __btset_ ## __val)
+
+#endif /* __ASSEMBLY__ */
+       
+#endif /* !(_SPARC_BTFIXUP_H) */
index adf4718a29665a40e98dbb84c25ad8a0cadc32d2..1657f7d0bc9aedaaca5cdffbf8d2691c9f6b94ce 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: contregs.h,v 1.6 1995/11/25 02:31:27 davem Exp $ */
+/* $Id: contregs.h,v 1.7 1998/01/30 10:59:48 jj Exp $ */
 #ifndef _SPARC_CONTREGS_H
 #define _SPARC_CONTREGS_H
 
@@ -14,7 +14,7 @@
 #define AC_CONTEXT    0x30000000    /* 4c current mmu-context                */
 #define AC_SENABLE    0x40000000    /* 4c system dvma/cache/reset enable reg */
 #define AC_UDVMA_ENB  0x50000000    /* 4  Not used on Sun boards, byte       */
-#define AC_BUS_ERROR  0x60000000    /* 4  Cleared on read, byte.             */
+#define AC_BUS_ERROR  0x60000000    /* 4  Not cleared on read, byte.         */
 #define AC_SYNC_ERR   0x60000000    /*  c fault type                         */
 #define AC_SYNC_VA    0x60000004    /*  c fault virtual address              */
 #define AC_ASYNC_ERR  0x60000008    /*  c asynchronous fault type            */
index 9c6885d1059409d3b9dab013e72570c88e470cf4..a9f43c03461a7e59e2c4ac9b7cf792c20488f2d9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.24 1997/04/10 05:13:21 davem Exp $
+/* $Id: dma.h,v 1.25 1998/02/09 13:27:01 jj Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
 #ifndef _ASM_SPARC_DMA_H
 #define _ASM_SPARC_DMA_H
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 
@@ -71,7 +72,13 @@ struct Linux_SBus_DMA {
 extern struct Linux_SBus_DMA *dma_chain;
 
 /* Broken hardware... */
+#ifdef CONFIG_SUN4
+/* Have to sort this out. Does rev0 work fine on sun4[cmd] without isbroken?
+ * Or is rev0 present only on sun4 boxes? -jj */
+#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev0 || (dma)->revision == dvmarev1)
+#else
 #define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
+#endif
 #define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
 
 /* Main routines in dma.c */
index 483cd73f200d26ae3cdbd09558298445e347894f..ac1fc83009a88b8f5c2de0ecb12d28d65e1e655c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.11 1997/09/26 18:37:32 tdyas Exp $ */
+/* $Id: elf.h,v 1.15 1998/03/23 08:41:32 jj Exp $ */
 #ifndef __ASMSPARC_ELF_H
 #define __ASMSPARC_ELF_H
 
@@ -6,6 +6,7 @@
  * ELF register definitions..
  */
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/mbus.h>
 
@@ -29,7 +30,12 @@ typedef unsigned long elf_fpregset_t;
 #define ELF_DATA       ELFDATA2MSB
 
 #define USE_ELF_CORE_DUMP
+#ifndef CONFIG_SUN4
 #define ELF_EXEC_PAGESIZE      4096
+#else
+#define ELF_EXEC_PAGESIZE      8192
+#endif
+
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
    use of this is to invoke "./ld.so someprog" to test out a new version of
@@ -45,7 +51,7 @@ typedef unsigned long elf_fpregset_t;
 /* Sun4c has none of the capabilities, most sun4m's have them all.
  * XXX This is gross, set some global variable at boot time. -DaveM
  */
-#define ELF_HWCAP      ((sparc_cpu_model == sun4c) ? 0 : \
+#define ELF_HWCAP      ((ARCH_SUN4C_SUN4) ? 0 : \
                         (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
                          HWCAP_SPARC_SWAP | \
                          ((srmmu_modtype != Cypress && \
@@ -55,7 +61,7 @@ typedef unsigned long elf_fpregset_t;
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
-   intent than poking at uname or /proc/cpuinfo.  */
+   intent than poking at uname or /proc/cpuinfo. */
 
 #define ELF_PLATFORM   (NULL)
 
index 7693be50799bf272a9889b835e47b17ad9e6cd79..94e6b83330eb325f8b516b61a99aaa3ae82f5d2c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.33 1997/10/04 08:54:22 ecd Exp $ */
+/* $Id: head.h,v 1.35 1998/03/18 09:15:40 jj Exp $ */
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
@@ -10,8 +10,7 @@
 
 #define NCPUS            4              /* Architectural limit of sun4m. */
 
-#define SUN4_PROM_VECTOR 0xFFE81000     /* To safely die on a SUN4 */
-#define SUN4_PRINTF      0x84           /* Offset into SUN4_PROM_VECTOR */
+#define SUN4_PROM_VECTOR 0xFFE81000     /* SUN4 PROM needs to be hardwired */
 
 #define WRITE_PAUSE      nop; nop; nop; /* Have to do this after %wim/%psr chg */
 #define NOP_INSN         0x01000000     /* Used to patch sparc_save_state */
 #define BAD_TRAP(num) \
         rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3;
 
+/* This is for traps when we want just skip the instruction which caused it */
+#define SKIP_TRAP(type, name) \
+       jmpl %l2, %g0; rett %l2 + 4; nop; nop;
+
 /* Notice that for the system calls we pull a trick.  We load up a
  * different pointer to the system call vector table in %l7, but call
  * the same generic system call low-level entry point.  The trap table
index 6063469373c7e324e471b1251405d47a4480e04c..d76219df47be05c979f923e05ebd7fa527492670 100644 (file)
@@ -1,6 +1,6 @@
 /* io-unit.h: Definitions for the sun4d IO-UNIT.
  *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 #ifndef _SPARC_IO_UNIT_H
 #define _SPARC_IO_UNIT_H
@@ -22,8 +22,8 @@
  
 #define IOUNIT_DMA_BASE            0xfc000000 /* TOP - 64M */
 #define IOUNIT_DMA_SIZE            0x04000000 /* 64M */
-/* We use last 4M for sparc_dvma_malloc */
-#define IOUNIT_DVMA_SIZE    0x00400000 /* 4M */
+/* We use last 1M for sparc_dvma_malloc */
+#define IOUNIT_DVMA_SIZE    0x00100000 /* 1M */
 
 /* The format of an iopte in the external page tables */
 #define IOUPTE_PAGE          0xffffff00 /* Physical page number (PA[35:12]) */
 #define IOUPTE_PARITY        0x00000001
 
 struct iounit_struct {
-       spinlock_t              iommu_lock;
+       unsigned int            bmap[(IOUNIT_DMA_SIZE >> (PAGE_SHIFT + 3)) / sizeof(unsigned int)];
+       spinlock_t              lock;
        iopte_t                 *page_table;
+       unsigned long           rotor[3];
+       unsigned long           limit[4];
 };
 
+#define IOUNIT_BMAP1_START     0x00000000
+#define IOUNIT_BMAP1_END       (IOUNIT_DMA_SIZE >> (PAGE_SHIFT + 1))
+#define IOUNIT_BMAP2_START     IOUNIT_BMAP1_END
+#define IOUNIT_BMAP2_END       IOUNIT_BMAP2_START + (IOUNIT_DMA_SIZE >> (PAGE_SHIFT + 2))
+#define IOUNIT_BMAPM_START     IOUNIT_BMAP2_END
+#define IOUNIT_BMAPM_END       ((IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE) >> PAGE_SHIFT)
+
 #endif /* !(_SPARC_IO_UNIT_H) */
index b1fb5b30e3252d3111bc2ff8c5ff2ab100f22990..93e5fde773d24982fd588851381a400eee6a64f4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.14 1997/04/10 05:13:22 davem Exp $ */
+/* $Id: io.h,v 1.15 1998/01/30 10:59:51 jj Exp $ */
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
 
@@ -99,6 +99,7 @@ extern __inline__ void mapioaddr(unsigned long physaddr, unsigned long virt_addr
 {
        switch(sparc_cpu_model) {
        case sun4c:
+       case sun4:
                sun4c_mapioaddr(physaddr, virt_addr, bus, rdonly);
                break;
        case sun4m:
@@ -122,6 +123,7 @@ extern __inline__ void unmapioaddr(unsigned long virt_addr)
 {
        switch(sparc_cpu_model) {
        case sun4c:
+       case sun4:
                sun4c_unmapioaddr(virt_addr);
                break;
        case sun4m:
index 60a32809415a1ab9cf2f70e3a0c5690ea25e44bc..526aeef9c43c77e56678748f9ac2315ea67a990e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.21 1997/11/19 15:12:20 jj Exp $
+/* $Id: irq.h,v 1.22 1998/02/05 14:20:05 jj Exp $
  * irq.h: IRQ registers on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -10,6 +10,7 @@
 #include <linux/linkage.h>
 
 #include <asm/system.h>     /* For NCPUS */
+#include <asm/btfixup.h>
 
 /* This is used for sun4d */
 struct devid_cookie {
@@ -66,27 +67,47 @@ extern __inline__ void irq_exit(int cpu, int irq)
 #define irq_exit(cpu, irq)             (local_irq_count[cpu]--)
 #endif
 
+static __inline__ int irq_cannonicalize(int irq)
+{
+       return irq;
+}
+
 /* Dave Redman (djhr@tadpole.co.uk)
  * changed these to function pointers.. it saves cycles and will allow
  * the irq dependencies to be split into different files at a later date
  * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size.
+ * Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Changed these to btfixup entities... It saves cycles :)
  */
-extern void (*disable_irq)(unsigned int);
-extern void (*enable_irq)(unsigned int);
-extern void (*disable_pil_irq)(unsigned int);
-extern void (*enable_pil_irq)(unsigned int);
-extern void (*clear_clock_irq)(void);
-extern void (*clear_profile_irq)(int);
-extern void (*load_profile_irq)(int cpu, unsigned int timeout);
+BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
+BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
+BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
+BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
+BTFIXUPDEF_CALL(void, clear_clock_irq, void)
+BTFIXUPDEF_CALL(void, clear_profile_irq, int)
+BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
+
+#define disable_irq(irq) BTFIXUP_CALL(disable_irq)(irq)
+#define enable_irq(irq) BTFIXUP_CALL(enable_irq)(irq)
+#define disable_pil_irq(irq) BTFIXUP_CALL(disable_pil_irq)(irq)
+#define enable_pil_irq(irq) BTFIXUP_CALL(enable_pil_irq)(irq)
+#define clear_clock_irq() BTFIXUP_CALL(clear_clock_irq)()
+#define clear_profile_irq(cpu) BTFIXUP_CALL(clear_profile_irq)(cpu)
+#define load_profile_irq(cpu,limit) BTFIXUP_CALL(load_profile_irq)(cpu,limit)
+
 extern void (*init_timers)(void (*lvl10_irq)(int, void *, struct pt_regs *));
 extern void claim_ticker14(void (*irq_handler)(int, void *, struct pt_regs *),
                           int irq,
                           unsigned int timeout);
 
 #ifdef __SMP__
-extern void (*set_cpu_int)(int, int);
-extern void (*clear_cpu_int)(int, int);
-extern void (*set_irq_udt)(int);
+BTFIXUPDEF_CALL(void, set_cpu_int, int, int)
+BTFIXUPDEF_CALL(void, clear_cpu_int, int, int)
+BTFIXUPDEF_CALL(void, set_irq_udt, int)
+
+#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
+#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
+#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
 #endif
 
 extern int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, __const__ char *devname);
index d104a758cb0cc1ce094b20edb346047d312c40e1..d6ac7e9229dfb78749983dbe19e274c84fad6ba0 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __SPARC_MMU_CONTEXT_H
 #define __SPARC_MMU_CONTEXT_H
 
+#include <asm/btfixup.h>
+
 /* For now I still leave the context handling in the
  * switch_to() macro, I'll do it right soon enough.
  */
 /* Initialize the context related info for a new mm_struct
  * instance.
  */
-extern void (*init_new_context)(struct mm_struct *mm);
+BTFIXUPDEF_CALL(void, init_new_context, struct mm_struct *)
+
+#define init_new_context(mm) BTFIXUP_CALL(init_new_context)(mm)
 
 /* Destroy context related info for an mm_struct that is about
  * to be put to rest.
  */
-extern void (*destroy_context)(struct mm_struct *mm);
+BTFIXUPDEF_CALL(void, destroy_context, struct mm_struct *)
+
+#define destroy_context(mm) BTFIXUP_CALL(destroy_context)(mm)
 
 #endif /* !(__SPARC_MMU_CONTEXT_H) */
index d166264240f7598c663608244918015e5d0d6a23..401e8082006c534499a977870df50a37b9a1a21d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.10 1997/09/24 16:20:36 jj Exp $
+/* $Id: namei.h,v 1.11 1998/01/15 12:58:24 jj Exp $
  * linux/include/asm-sparc/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -18,8 +18,11 @@ __sparc_lookup_dentry(const char *name, int follow_link)
        char *emul;
 
        switch (current->personality) {
+#if 0
+/* Until we solve, why SunOS apps sometime crash, disable gnemul support for SunOS */
        case PER_BSD:
                emul = SPARC_BSD_EMUL; break;
+#endif
        case PER_SVR4:
                emul = SPARC_SOL_EMUL; break;
        default:
index 171a0a34d39abdec39c025f88eda8020b398f72c..62e1d77965f3fd9a13011ce9dc151dca2b47a7fa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: obio.h,v 1.3 1997/12/18 14:21:41 jj Exp $
+/* $Id: obio.h,v 1.4 1998/03/09 14:04:55 jj Exp $
  * obio.h:  Some useful locations in 0xFXXXXXXXX PA obio space on sun4d.
  *
  * Copyright (C) 1997 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
 /* Boot Bus */
 #define BB_LOCAL_BASE          0xf0000000
 
+#define BB_STAT1               0x00100000
+#define BB_STAT2               0x00120000
+#define BB_STAT3               0x00140000
 #define BB_LEDS                        0x002e0000
 
+/* Bits in BB_STAT2 */
+#define BB_STAT2_AC_INTR       0x04    /* Aiee! 5ms and power is gone... */
+#define BB_STAT2_TMP_INTR      0x10    /* My Penguins are burning. Are you able to smell it? */
+#define BB_STAT2_FAN_INTR      0x20    /* My fan refuses to work */
+#define BB_STAT2_PWR_INTR      0x40    /* On SC2000, one of the two ACs died. Ok, we go on... */
+#define BB_STAT2_MASK          (BB_STAT2_AC_INTR|BB_STAT2_TMP_INTR|BB_STAT2_FAN_INTR|BB_STAT2_PWR_INTR)
+
 /* Cache Controller */
+#define CC_BASE                0x1F00000
 #define CC_DATSTREAM   0x1F00000  /* Data stream register */
 #define CC_DATSIZE     0x1F0003F  /* Size */
 #define CC_SRCSTREAM   0x1F00100  /* Source stream register */
@@ -144,10 +155,13 @@ extern __inline__ void bw_set_ctrl(int cpu, unsigned ctrl)
                              "i" (ASI_M_CTL));
 }
 
-extern __inline__ void show_leds(int cpuid, unsigned char mask)
+extern unsigned char cpu_leds[32];
+
+extern __inline__ void show_leds(int cpuid)
 {
+       cpuid &= 0x1e;
        __asm__ __volatile__ ("stba %0, [%1] %2" : :
-                             "r" (mask),
+                             "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
                              "r" (ECSR_BASE(cpuid) | BB_LEDS),
                              "i" (ASI_M_CTL));
 }
@@ -190,6 +204,25 @@ extern __inline__ void cc_set_imsk(unsigned mask)
                              "i" (ASI_M_MXCC));
 }
 
+extern __inline__ unsigned cc_get_imsk_other(int cpuid)
+{
+       unsigned mask;
+       
+       __asm__ __volatile__ ("lduha [%1] %2, %0" :
+                             "=r" (mask) :
+                             "r" (ECSR_BASE(cpuid) | CC_IMSK),
+                             "i" (ASI_M_CTL));
+       return mask;
+}
+
+extern __inline__ void cc_set_imsk_other(int cpuid, unsigned mask)
+{
+       __asm__ __volatile__ ("stha %0, [%1] %2" : :
+                             "r" (mask),
+                             "r" (ECSR_BASE(cpuid) | CC_IMSK),
+                             "i" (ASI_M_CTL));
+}
+
 extern __inline__ void cc_set_igen(unsigned gen)
 {
        __asm__ __volatile__ ("sta %0, [%1] %2" : :
@@ -198,6 +231,19 @@ extern __inline__ void cc_set_igen(unsigned gen)
                              "i" (ASI_M_MXCC));
 }
 
+/* +-------+-------------+-----------+------------------------------------+
+ * | bcast |  devid      |   sid     |              levels mask           |
+ * +-------+-------------+-----------+------------------------------------+
+ *  31      30         23 22       15 14                                 0
+ */
+#define IGEN_MESSAGE(bcast, devid, sid, levels) \
+       (((bcast) << 31) | ((devid) << 23) | ((sid) << 15) | (levels))
+            
+extern __inline__ void sun4d_send_ipi(int cpu, int level)
+{
+       cc_set_igen(IGEN_MESSAGE(0, cpu << 3, 6 + ((level >> 1) & 7), 1 << (level - 1)));
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* !(_SPARC_OBIO_H) */
index f91394a7f653883dc32adae06aff0ca945123c9e..2d1094b07a0f6fca35a508214e1c1052e12e8f05 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.18 1997/09/24 11:34:18 jj Exp $
+/* $Id: oplib.h,v 1.19 1998/01/30 10:59:53 jj Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -20,6 +20,7 @@ enum prom_major_version {
        PROM_V3,      /* sun4m and later, up to sun4d/sun4e machines V3 */
        PROM_P1275,   /* IEEE compliant ISA based Sun PROM, only sun4u */
         PROM_AP1000,  /* actually no prom at all */
+       PROM_SUN4,    /* Old sun4 proms are totally different, but we'll shoehorn it to make it fit */
 };
 
 extern enum prom_major_version prom_vers;
index 2cd6512b423770195c2bdcfe1c01c600467e964e..922f5e5e9ce7b3d450614164360ca129d46e3d61 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.37 1997/11/28 15:59:21 jj Exp $
+/* $Id: page.h,v 1.40 1998/02/06 14:14:46 jj Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -8,7 +8,12 @@
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
+#include <linux/config.h>
+#ifdef CONFIG_SUN4
+#define PAGE_SHIFT   13
+#else
 #define PAGE_SHIFT   12
+#endif
 #define PAGE_SIZE    (1 << PAGE_SHIFT)
 #define PAGE_MASK    (~(PAGE_SIZE-1))
 
 
 #include <linux/config.h>
 #include <asm/head.h>       /* for KERNBASE */
+#include <asm/btfixup.h>
+
+/* This is always 2048*sizeof(long), doesn't change with PAGE_SIZE */
+#define TASK_UNION_SIZE                8192
 
 #ifndef __ASSEMBLY__
 
 
 extern unsigned long page_offset;
 
-#define PAGE_OFFSET  (page_offset)
+BTFIXUPDEF_SETHI_INIT(page_offset,0xf0000000)
+
+#ifdef MODULE
+#define        PAGE_OFFSET  (page_offset)
+#else
+#define                PAGE_OFFSET  BTFIXUP_SETHI(page_offset)
+#endif
 
 /* translate between physical and virtual addresses */
-extern unsigned long (*mmu_v2p)(unsigned long);
-extern unsigned long (*mmu_p2v)(unsigned long);
+BTFIXUPDEF_CALL_CONST(unsigned long, mmu_v2p, unsigned long)
+BTFIXUPDEF_CALL_CONST(unsigned long, mmu_p2v, unsigned long)
+
+#define mmu_v2p(vaddr) BTFIXUP_CALL(mmu_v2p)(vaddr)
+#define mmu_p2v(paddr) BTFIXUP_CALL(mmu_p2v)(paddr)
 
 #define __pa(x)    (mmu_v2p((unsigned long)(x)))
 #define __va(x)    ((void *)(mmu_p2v((unsigned long)(x))))
@@ -248,7 +266,9 @@ typedef unsigned long iopgprot_t;
 
 extern unsigned long sparc_unmapped_base;
 
-#define TASK_UNMAPPED_BASE     (sparc_unmapped_base)
+BTFIXUPDEF_SETHI(sparc_unmapped_base)
+
+#define TASK_UNMAPPED_BASE     BTFIXUP_SETHI(sparc_unmapped_base)
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
index a8403c5319e0cd3b7adcacd6cb551f63f03c1e7f..11f37e980856476bc46e6799baeacdb1b4fe29bc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.64 1997/11/07 15:01:44 jj Exp $ */
+/* $Id: pgtable.h,v 1.74 1998/03/11 04:08:37 tdyas Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -6,33 +6,42 @@
  *                        with Sparc page tables.
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/mm.h>
+#include <linux/config.h>
 #include <asm/asi.h>
+#ifdef CONFIG_SUN4
+#include <asm/pgtsun4.h>
+#else
 #include <asm/pgtsun4c.h>
+#endif
 #include <asm/pgtsrmmu.h>
 #include <asm/vac-ops.h>
 #include <asm/oplib.h>
 #include <asm/sbus.h>
+#include <asm/btfixup.h>
+#include <asm/spinlock.h>
 
 extern void load_mmu(void);
 extern int io_remap_page_range(unsigned long from, unsigned long to,
                               unsigned long size, pgprot_t prot, int space);
+                              
+BTFIXUPDEF_CALL(void, quick_kernel_fault, unsigned long)
 
-extern void (*quick_kernel_fault)(unsigned long);
+#define quick_kernel_fault(addr) BTFIXUP_CALL(quick_kernel_fault)(addr)
 
 /* Allocate a block of RAM which is aligned to its size.
    This procedure can be used until the call to mem_init(). */
 extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
 
-/* translate between physical and virtual addresses */
-extern unsigned long (*mmu_v2p)(unsigned long);
-extern unsigned long (*mmu_p2v)(unsigned long);
-
 /* Routines for data transfer buffers. */
-extern char *(*mmu_lockarea)(char *, unsigned long);
-extern void  (*mmu_unlockarea)(char *, unsigned long);
+BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
+BTFIXUPDEF_CALL(void,   mmu_unlockarea, char *, unsigned long)
+
+#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
+#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
 
 /* Routines for getting a dvma scsi buffer. */
 struct mmu_sglist {
@@ -41,58 +50,76 @@ struct mmu_sglist {
        unsigned int len;
        __u32 dvma_addr;
 };
-extern __u32 (*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus);
-extern void  (*mmu_get_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus);
-extern void  (*mmu_release_scsi_one)(__u32, unsigned long, struct linux_sbus *sbus);
-extern void  (*mmu_release_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus);
+BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct linux_sbus *sbus)
+BTFIXUPDEF_CALL(void,  mmu_get_scsi_sgl, struct mmu_sglist *, int, struct linux_sbus *sbus)
+BTFIXUPDEF_CALL(void,  mmu_release_scsi_one, __u32, unsigned long, struct linux_sbus *sbus)
+BTFIXUPDEF_CALL(void,  mmu_release_scsi_sgl, struct mmu_sglist *, int, struct linux_sbus *sbus)
+BTFIXUPDEF_CALL(void,  mmu_map_dma_area, unsigned long addr, int len)
 
-extern void  (*mmu_map_dma_area)(unsigned long addr, int len);
+#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus)
+#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus)
+#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus)
+#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus)
 
-extern unsigned int pmd_shift;
-extern unsigned int pmd_size;
-extern unsigned int pmd_mask;
-extern unsigned int (*pmd_align)(unsigned int);
+#define mmu_map_dma_area(addr,len) BTFIXUP_CALL(mmu_map_dma_area)(addr,len)
 
-extern unsigned int pgdir_shift;
-extern unsigned int pgdir_size;
-extern unsigned int pgdir_mask;
-extern unsigned int (*pgdir_align)(unsigned int);
+BTFIXUPDEF_SIMM13(pmd_shift)
+BTFIXUPDEF_SETHI(pmd_size)
+BTFIXUPDEF_SETHI(pmd_mask)
 
-extern unsigned int ptrs_per_pte;
-extern unsigned int ptrs_per_pmd;
-extern unsigned int ptrs_per_pgd;
+extern unsigned int pmd_align(unsigned int addr) __attribute__((const));
+extern __inline__ unsigned int pmd_align(unsigned int addr)
+{
+       return ((addr + ~BTFIXUP_SETHI(pmd_mask)) & BTFIXUP_SETHI(pmd_mask));
+}
+
+BTFIXUPDEF_SIMM13(pgdir_shift)
+BTFIXUPDEF_SETHI(pgdir_size)
+BTFIXUPDEF_SETHI(pgdir_mask)
 
-extern unsigned int ptrs_per_page;
+extern unsigned int pgdir_align(unsigned int addr) __attribute__((const));
+extern __inline__ unsigned int pgdir_align(unsigned int addr)
+{
+       return ((addr + ~BTFIXUP_SETHI(pgdir_mask)) & BTFIXUP_SETHI(pgdir_mask));
+}
 
-extern unsigned long (*(vmalloc_start))(void);
+BTFIXUPDEF_SIMM13(ptrs_per_pte)
+BTFIXUPDEF_SIMM13(ptrs_per_pmd)
+BTFIXUPDEF_SIMM13(ptrs_per_pgd)
+BTFIXUPDEF_SIMM13(user_ptrs_per_pgd)
 
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_START vmalloc_start()
-
-extern pgprot_t page_none;
-extern pgprot_t page_shared;
-extern pgprot_t page_copy;
-extern pgprot_t page_readonly;
-extern pgprot_t page_kernel;
-
-#define PMD_SHIFT      (pmd_shift)
-#define PMD_SIZE       (pmd_size)
-#define PMD_MASK       (pmd_mask)
-#define PMD_ALIGN      (pmd_align)
-#define PGDIR_SHIFT    (pgdir_shift)
-#define PGDIR_SIZE     (pgdir_size)
-#define PGDIR_MASK     (pgdir_mask)
-#define PGDIR_ALIGN    (pgdir_align)
-#define PTRS_PER_PTE   (ptrs_per_pte)
-#define PTRS_PER_PMD   (ptrs_per_pmd)
-#define PTRS_PER_PGD   (ptrs_per_pgd)
-
-#define PAGE_NONE      (page_none)
-#define PAGE_SHARED    (page_shared)
-#define PAGE_COPY      (page_copy)
-#define PAGE_READONLY  (page_readonly)
-#define PAGE_KERNEL    (page_kernel)
-#define PAGE_INVALID   (page_invalid)
+/* This is the same accross all platforms */
+#define VMALLOC_START (0xfe300000)
+
+BTFIXUPDEF_INT(page_none)
+BTFIXUPDEF_INT(page_shared)
+BTFIXUPDEF_INT(page_copy)
+BTFIXUPDEF_INT(page_readonly)
+BTFIXUPDEF_INT(page_kernel)
+
+#define PMD_SHIFT              BTFIXUP_SIMM13(pmd_shift)
+#define PMD_SIZE               BTFIXUP_SETHI(pmd_size)
+#define PMD_MASK               BTFIXUP_SETHI(pmd_mask)
+#define PMD_ALIGN(addr)        pmd_align(addr)
+#define PGDIR_SHIFT            BTFIXUP_SIMM13(pgdir_shift)
+#define PGDIR_SIZE             BTFIXUP_SETHI(pgdir_size)
+#define PGDIR_MASK             BTFIXUP_SETHI(pgdir_mask)
+#define PGDIR_ALIGN            pgdir_align(addr)
+#define PTRS_PER_PTE           BTFIXUP_SIMM13(ptrs_per_pte)
+#define PTRS_PER_PMD           BTFIXUP_SIMM13(ptrs_per_pmd)
+#define PTRS_PER_PGD           BTFIXUP_SIMM13(ptrs_per_pgd)
+#define USER_PTRS_PER_PGD      BTFIXUP_SIMM13(user_ptrs_per_pgd)
+
+#define PAGE_NONE      __pgprot(BTFIXUP_INT(page_none))
+#define PAGE_SHARED    __pgprot(BTFIXUP_INT(page_shared))
+#define PAGE_COPY      __pgprot(BTFIXUP_INT(page_copy))
+#define PAGE_READONLY  __pgprot(BTFIXUP_INT(page_readonly))
+#define PAGE_KERNEL    __pgprot(BTFIXUP_INT(page_kernel))
+
+BTFIXUPDEF_CALL(void, set_pgdir, unsigned long, pgd_t)
+
+#define set_pgdir(address,entry) BTFIXUP_CALL(set_pgdir)(address,entry)
 
 /* Top-level page directory */
 extern pgd_t swapper_pg_dir[1024];
@@ -159,122 +186,250 @@ extern unsigned long empty_zero_page;
 
 #define SIZEOF_PTR_LOG2   2
 
-extern unsigned long (*pte_page)(pte_t);
-extern unsigned long (*pmd_page)(pmd_t);
-extern unsigned long (*pgd_page)(pgd_t);
+BTFIXUPDEF_CALL_CONST(unsigned long, pte_page, pte_t)
+BTFIXUPDEF_CALL_CONST(unsigned long, pmd_page, pmd_t)
+BTFIXUPDEF_CALL_CONST(unsigned long, pgd_page, pgd_t)
 
-extern void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
+#define pte_page(pte) BTFIXUP_CALL(pte_page)(pte)
+#define pmd_page(pmd) BTFIXUP_CALL(pmd_page)(pmd)
+#define pgd_page(pgd) BTFIXUP_CALL(pgd_page)(pgd)
 
-#define SET_PAGE_DIR(tsk,pgdir) sparc_update_rootmmu_dir(tsk, pgdir)
+BTFIXUPDEF_CALL(void, sparc_update_rootmmu_dir, struct task_struct *, pgd_t *pgdir)
+
+#define SET_PAGE_DIR(tsk,pgdir) BTFIXUP_CALL(sparc_update_rootmmu_dir)(tsk, pgdir)
        
 /* to find an entry in a page-table */
 #define PAGE_PTR(address) \
 ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
 
-extern int (*pte_none)(pte_t);
-extern int (*pte_present)(pte_t);
-extern void (*pte_clear)(pte_t *);
+BTFIXUPDEF_SETHI(none_mask)
+BTFIXUPDEF_CALL_CONST(int, pte_present, pte_t)
+BTFIXUPDEF_CALL(void, pte_clear, pte_t *)
+
+extern __inline__ int pte_none(pte_t pte)
+{
+       return !(pte_val(pte) & ~BTFIXUP_SETHI(none_mask));
+}
+
+#define pte_present(pte) BTFIXUP_CALL(pte_present)(pte)
+#define pte_clear(pte) BTFIXUP_CALL(pte_clear)(pte)
+
+BTFIXUPDEF_CALL_CONST(int, pmd_bad, pmd_t)
+BTFIXUPDEF_CALL_CONST(int, pmd_present, pmd_t)
+BTFIXUPDEF_CALL(void, pmd_clear, pmd_t *)
 
-extern int (*pmd_none)(pmd_t);
-extern int (*pmd_bad)(pmd_t);
-extern int (*pmd_present)(pmd_t);
-extern void (*pmd_clear)(pmd_t *);
+extern __inline__ int pmd_none(pmd_t pmd)
+{
+       return !(pmd_val(pmd) & ~BTFIXUP_SETHI(none_mask));
+}
 
-extern int (*pgd_none)(pgd_t);
-extern int (*pgd_bad)(pgd_t);
-extern int (*pgd_present)(pgd_t);
-extern void (*pgd_clear)(pgd_t *);
+#define pmd_bad(pmd) BTFIXUP_CALL(pmd_bad)(pmd)
+#define pmd_present(pmd) BTFIXUP_CALL(pmd_present)(pmd)
+#define pmd_clear(pmd) BTFIXUP_CALL(pmd_clear)(pmd)
+
+BTFIXUPDEF_CALL_CONST(int, pgd_none, pgd_t)
+BTFIXUPDEF_CALL_CONST(int, pgd_bad, pgd_t)
+BTFIXUPDEF_CALL_CONST(int, pgd_present, pgd_t)
+BTFIXUPDEF_CALL(void, pgd_clear, pgd_t *)
+
+#define pgd_none(pgd) BTFIXUP_CALL(pgd_none)(pgd)
+#define pgd_bad(pgd) BTFIXUP_CALL(pgd_bad)(pgd)
+#define pgd_present(pgd) BTFIXUP_CALL(pgd_present)(pgd)
+#define pgd_clear(pgd) BTFIXUP_CALL(pgd_clear)(pgd)
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern int (*pte_write)(pte_t);
-extern int (*pte_dirty)(pte_t);
-extern int (*pte_young)(pte_t);
+BTFIXUPDEF_HALF(pte_writei)
+BTFIXUPDEF_HALF(pte_dirtyi)
+BTFIXUPDEF_HALF(pte_youngi)
+
+extern int pte_write(pte_t pte) __attribute__((const));
+extern __inline__ int pte_write(pte_t pte)
+{
+       return pte_val(pte) & BTFIXUP_HALF(pte_writei);
+}
+
+extern int pte_dirty(pte_t pte) __attribute__((const));
+extern __inline__ int pte_dirty(pte_t pte)
+{
+       return pte_val(pte) & BTFIXUP_HALF(pte_dirtyi);
+}
 
-extern pte_t (*pte_wrprotect)(pte_t);
-extern pte_t (*pte_mkclean)(pte_t);
-extern pte_t (*pte_mkold)(pte_t);
-extern pte_t (*pte_mkwrite)(pte_t);
-extern pte_t (*pte_mkdirty)(pte_t);
-extern pte_t (*pte_mkyoung)(pte_t);
+extern int pte_young(pte_t pte) __attribute__((const));
+extern __inline__ int pte_young(pte_t pte)
+{
+       return pte_val(pte) & BTFIXUP_HALF(pte_youngi);
+}
+
+BTFIXUPDEF_HALF(pte_wrprotecti)
+BTFIXUPDEF_HALF(pte_mkcleani)
+BTFIXUPDEF_HALF(pte_mkoldi)
+
+extern pte_t pte_wrprotect(pte_t pte) __attribute__((const));
+extern __inline__ pte_t pte_wrprotect(pte_t pte)
+{
+       return __pte(pte_val(pte) & ~BTFIXUP_HALF(pte_wrprotecti));
+}
+
+extern pte_t pte_mkclean(pte_t pte) __attribute__((const));
+extern __inline__ pte_t pte_mkclean(pte_t pte)
+{
+       return __pte(pte_val(pte) & ~BTFIXUP_HALF(pte_mkcleani));
+}
+
+extern pte_t pte_mkold(pte_t pte) __attribute__((const));
+extern __inline__ pte_t pte_mkold(pte_t pte)
+{
+       return __pte(pte_val(pte) & ~BTFIXUP_HALF(pte_mkoldi));
+}
+
+BTFIXUPDEF_CALL_CONST(pte_t, pte_mkwrite, pte_t)
+BTFIXUPDEF_CALL_CONST(pte_t, pte_mkdirty, pte_t)
+BTFIXUPDEF_CALL_CONST(pte_t, pte_mkyoung, pte_t)
+
+#define pte_mkwrite(pte) BTFIXUP_CALL(pte_mkwrite)(pte)
+#define pte_mkdirty(pte) BTFIXUP_CALL(pte_mkdirty)(pte)
+#define pte_mkyoung(pte) BTFIXUP_CALL(pte_mkyoung)(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 pte_t (*mk_pte)(unsigned long, pgprot_t);
-extern pte_t (*mk_pte_phys)(unsigned long, pgprot_t);
-extern pte_t (*mk_pte_io)(unsigned long, pgprot_t, int);
+BTFIXUPDEF_CALL_CONST(pte_t, mk_pte, unsigned long, pgprot_t)
+BTFIXUPDEF_CALL_CONST(pte_t, mk_pte_phys, unsigned long, pgprot_t)
+BTFIXUPDEF_CALL_CONST(pte_t, mk_pte_io, unsigned long, pgprot_t, int)
+
+#define mk_pte(page,pgprot) BTFIXUP_CALL(mk_pte)(page,pgprot)
+#define mk_pte_phys(page,pgprot) BTFIXUP_CALL(mk_pte_phys)(page,pgprot)
+#define mk_pte_io(page,pgprot,space) BTFIXUP_CALL(mk_pte_io)(page,pgprot,space)
+
+BTFIXUPDEF_CALL(void, pgd_set, pgd_t *, pmd_t *)
 
-extern void (*pgd_set)(pgd_t *, pmd_t *);
+#define pgd_set(pgdp,pmdp) BTFIXUP_CALL(pgd_set)(pgdp,pmdp)
 
-extern pte_t (*pte_modify)(pte_t, pgprot_t);
+BTFIXUPDEF_INT(pte_modify_mask)
+
+extern pte_t pte_modify(pte_t pte, pgprot_t newprot) __attribute__((const));
+extern __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+       return __pte((pte_val(pte) & BTFIXUP_INT(pte_modify_mask)) |
+               pgprot_val(newprot));
+}
+
+BTFIXUPDEF_CALL(pgd_t *, pgd_offset, struct mm_struct *, unsigned long)
+BTFIXUPDEF_CALL(pmd_t *, pmd_offset, pgd_t *, unsigned long)
+BTFIXUPDEF_CALL(pte_t *, pte_offset, pmd_t *, unsigned long)
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* to find an entry in a page-table-directory */
-extern pgd_t * (*pgd_offset)(struct mm_struct *, unsigned long);
+#define pgd_offset(mm,addr) BTFIXUP_CALL(pgd_offset)(mm,addr)
 
 /* Find an entry in the second-level page table.. */
-extern pmd_t * (*pmd_offset)(pgd_t *, unsigned long);
+#define pmd_offset(dir,addr) BTFIXUP_CALL(pmd_offset)(dir,addr)
 
 /* Find an entry in the third-level page table.. */ 
-extern pte_t * (*pte_offset)(pmd_t *, unsigned long);
+#define pte_offset(dir,addr) BTFIXUP_CALL(pte_offset)(dir,addr)
+
+extern struct pgtable_cache_struct {
+       unsigned long *pgd_cache;
+       unsigned long *pte_cache;
+       unsigned long pgtable_cache_sz;
+       unsigned long pgd_cache_sz;
+       spinlock_t pgd_spinlock;
+       spinlock_t pte_spinlock;
+} pgt_quicklists;
+#define pgd_quicklist           (pgt_quicklists.pgd_cache)
+#define pmd_quicklist           ((unsigned long *)0)
+#define pte_quicklist           (pgt_quicklists.pte_cache)
+#define pgd_spinlock           (pgt_quicklists.pgd_spinlock)
+#define pte_spinlock           (pgt_quicklists.pte_spinlock)
+#define pgtable_cache_size      (pgt_quicklists.pgtable_cache_sz)
+#define pgd_cache_size         (pgt_quicklists.pgd_cache_sz)
+
+BTFIXUPDEF_CALL(pte_t *, get_pte_fast, void)
+BTFIXUPDEF_CALL(pgd_t *, get_pgd_fast, void)
+BTFIXUPDEF_CALL(void,    free_pte_slow, pte_t *)
+BTFIXUPDEF_CALL(void,    free_pgd_slow, pgd_t *)
+
+#define get_pte_fast() BTFIXUP_CALL(get_pte_fast)()
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+       return (pmd_t *)0;
+}
+#define get_pgd_fast() BTFIXUP_CALL(get_pgd_fast)()
+#define free_pte_slow(pte) BTFIXUP_CALL(free_pte_slow)(pte)
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+}
+#define free_pgd_slow(pgd) BTFIXUP_CALL(free_pgd_slow)(pgd)
 
 /*
  * 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.
  */
-extern void (*pte_free_kernel)(pte_t *);
+BTFIXUPDEF_CALL(void,    pte_free_kernel, pte_t *)
+BTFIXUPDEF_CALL(pte_t *, pte_alloc_kernel, pmd_t *, unsigned long)
 
-extern pte_t * (*pte_alloc_kernel)(pmd_t *, unsigned long);
+#define pte_free_kernel(pte) BTFIXUP_CALL(pte_free_kernel)(pte)
+#define pte_alloc_kernel(pmd,addr) BTFIXUP_CALL(pte_alloc_kernel)(pmd,addr)
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern void (*pmd_free_kernel)(pmd_t *);
+BTFIXUPDEF_CALL(void,    pmd_free_kernel, pmd_t *)
+BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_kernel, pgd_t *, unsigned long)
 
-extern pmd_t * (*pmd_alloc_kernel)(pgd_t *, unsigned long);
+#define pmd_free_kernel(pmd) BTFIXUP_CALL(pmd_free_kernel)(pmd)
+#define pmd_alloc_kernel(pgd,addr) BTFIXUP_CALL(pmd_alloc_kernel)(pgd,addr)
 
-extern void (*pte_free)(pte_t *);
+BTFIXUPDEF_CALL(void,    pte_free, pte_t *)
+BTFIXUPDEF_CALL(pte_t *, pte_alloc, pmd_t *, unsigned long)
 
-extern pte_t * (*pte_alloc)(pmd_t *, unsigned long);
+#define pte_free(pte) BTFIXUP_CALL(pte_free)(pte)
+#define pte_alloc(pmd,addr) BTFIXUP_CALL(pte_alloc)(pmd,addr)
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern void (*pmd_free)(pmd_t *);
+BTFIXUPDEF_CALL(void,    pmd_free, pmd_t *)
+BTFIXUPDEF_CALL(pmd_t *, pmd_alloc, pgd_t *, unsigned long)
 
-extern pmd_t * (*pmd_alloc)(pgd_t *, unsigned long);
+#define pmd_free(pmd) BTFIXUP_CALL(pmd_free)(pmd)
+#define pmd_alloc(pgd,addr) BTFIXUP_CALL(pmd_alloc)(pgd,addr)
 
-extern void (*pgd_free)(pgd_t *);
+BTFIXUPDEF_CALL(void,    pgd_free, pgd_t *)
+BTFIXUPDEF_CALL(pgd_t *, pgd_alloc, void)
 
-extern pgd_t * (*pgd_alloc)(void);
+#define pgd_free(pgd) BTFIXUP_CALL(pgd_free)(pgd)
+#define pgd_alloc() BTFIXUP_CALL(pgd_alloc)()
 
 /* Fine grained cache/tlb flushing. */
 
 #ifdef __SMP__
-extern void (*local_flush_cache_all)(void);
-extern void (*local_flush_cache_mm)(struct mm_struct *);
-extern void (*local_flush_cache_range)(struct mm_struct *, unsigned long start,
-                                    unsigned long end);
-extern void (*local_flush_cache_page)(struct vm_area_struct *, unsigned long address);
+BTFIXUPDEF_CALL(void, local_flush_cache_all, void)
+BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *)
+BTFIXUPDEF_CALL(void, local_flush_cache_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, local_flush_cache_page, struct vm_area_struct *, unsigned long)
 
-extern void (*local_flush_tlb_all)(void);
-extern void (*local_flush_tlb_mm)(struct mm_struct *);
-extern void (*local_flush_tlb_range)(struct mm_struct *, unsigned long start,
-                                    unsigned long end);
-extern void (*local_flush_tlb_page)(struct vm_area_struct *, unsigned long address);
+#define local_flush_cache_all() BTFIXUP_CALL(local_flush_cache_all)()
+#define local_flush_cache_mm(mm) BTFIXUP_CALL(local_flush_cache_mm)(mm)
+#define local_flush_cache_range(mm,start,end) BTFIXUP_CALL(local_flush_cache_range)(mm,start,end)
+#define local_flush_cache_page(vma,addr) BTFIXUP_CALL(local_flush_cache_page)(vma,addr)
 
-extern void (*local_flush_page_to_ram)(unsigned long address);
+BTFIXUPDEF_CALL(void, local_flush_tlb_all, void)
+BTFIXUPDEF_CALL(void, local_flush_tlb_mm, struct mm_struct *)
+BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, local_flush_tlb_page, struct vm_area_struct *, unsigned long)
 
-extern void (*local_flush_sig_insns)(struct mm_struct *mm, unsigned long insn_addr);
+#define local_flush_tlb_all() BTFIXUP_CALL(local_flush_tlb_all)()
+#define local_flush_tlb_mm(mm) BTFIXUP_CALL(local_flush_tlb_mm)(mm)
+#define local_flush_tlb_range(mm,start,end) BTFIXUP_CALL(local_flush_tlb_range)(mm,start,end)
+#define local_flush_tlb_page(vma,addr) BTFIXUP_CALL(local_flush_tlb_page)(vma,addr)
+
+BTFIXUPDEF_CALL(void, local_flush_page_to_ram, unsigned long)
+BTFIXUPDEF_CALL(void, local_flush_sig_insns, struct mm_struct *, unsigned long)
+
+#define local_flush_page_to_ram(addr) BTFIXUP_CALL(local_flush_page_to_ram)(addr)
+#define local_flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(local_flush_sig_insns)(mm,insn_addr)
 
 extern void smp_flush_cache_all(void);
 extern void smp_flush_cache_mm(struct mm_struct *mm);
@@ -293,47 +448,62 @@ extern void smp_flush_page_to_ram(unsigned long page);
 extern void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 #endif
 
-extern void (*flush_cache_all)(void);
-extern void (*flush_cache_mm)(struct mm_struct *);
-extern void (*flush_cache_range)(struct mm_struct *, unsigned long start,
-                                unsigned long end);
-extern void (*flush_cache_page)(struct vm_area_struct *, unsigned long address);
+BTFIXUPDEF_CALL(void, flush_cache_all, void)
+BTFIXUPDEF_CALL(void, flush_cache_mm, struct mm_struct *)
+BTFIXUPDEF_CALL(void, flush_cache_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long)
+
+#define flush_cache_all() BTFIXUP_CALL(flush_cache_all)()
+#define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm)
+#define flush_cache_range(mm,start,end) BTFIXUP_CALL(flush_cache_range)(mm,start,end)
+#define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr)
 #define flush_icache_range(start, end)         do { } while (0)
 
-extern void (*flush_tlb_all)(void);
-extern void (*flush_tlb_mm)(struct mm_struct *);
-extern void (*flush_tlb_range)(struct mm_struct *, unsigned long start, unsigned long end);
-extern void (*flush_tlb_page)(struct vm_area_struct *, unsigned long address);
+BTFIXUPDEF_CALL(void, flush_tlb_all, void)
+BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *)
+BTFIXUPDEF_CALL(void, flush_tlb_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, flush_tlb_page, struct vm_area_struct *, unsigned long)
+
+#define flush_tlb_all() BTFIXUP_CALL(flush_tlb_all)()
+#define flush_tlb_mm(mm) BTFIXUP_CALL(flush_tlb_mm)(mm)
+#define flush_tlb_range(mm,start,end) BTFIXUP_CALL(flush_tlb_range)(mm,start,end)
+#define flush_tlb_page(vma,addr) BTFIXUP_CALL(flush_tlb_page)(vma,addr)
 
-extern void (*flush_page_to_ram)(unsigned long page);
+BTFIXUPDEF_CALL(void, flush_page_to_ram, unsigned long)
+BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long)
 
-extern void (*flush_sig_insns)(struct mm_struct *mm, unsigned long insn_addr);
+#define flush_page_to_ram(addr) BTFIXUP_CALL(flush_page_to_ram)(addr)
+#define flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(flush_sig_insns)(mm,insn_addr)
 
 /* The permissions for pgprot_val to make a page mapped on the obio space */
 extern unsigned int pg_iobits;
 
 /* MMU context switching. */
-extern void (*switch_to_context)(struct task_struct *tsk);
+BTFIXUPDEF_CALL(void, switch_to_context, struct task_struct *)
+
+#define switch_to_context(tsk) BTFIXUP_CALL(switch_to_context)(tsk)
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
 
-#if 0 /* XXX try this soon XXX */
-extern void (*set_pte)(struct vm_area_struct *vma, unsigned long address,
-                      pte_t *pteptr, pte_t pteval);
-#else
-extern void (*set_pte)(pte_t *pteptr, pte_t pteval);
-#endif
+BTFIXUPDEF_CALL(void, set_pte, pte_t *, pte_t)
+
+#define set_pte(ptep,pteval) BTFIXUP_CALL(set_pte)(ptep,pteval)
 
-extern char *(*mmu_info)(void);
+BTFIXUPDEF_CALL(int, mmu_info, char *)
+
+#define mmu_info(p) BTFIXUP_CALL(mmu_info)(p)
 
 /* Fault handler stuff... */
 #define FAULT_CODE_PROT     0x1
 #define FAULT_CODE_WRITE    0x2
 #define FAULT_CODE_USER     0x4
-extern void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte);
+
+BTFIXUPDEF_CALL(void, update_mmu_cache, struct vm_area_struct *, unsigned long, pte_t)
+
+#define update_mmu_cache(vma,addr,pte) BTFIXUP_CALL(update_mmu_cache)(vma,addr,pte)
 
 extern int invalid_segment;
 
@@ -373,6 +543,7 @@ extern __inline__ unsigned long
 __get_phys (unsigned long addr)
 {
        switch (sparc_cpu_model){
+       case sun4:
        case sun4c:
                return sun4c_get_pte (addr) << PAGE_SHIFT;
        case sun4m:
@@ -387,6 +558,7 @@ extern __inline__ int
 __get_iospace (unsigned long addr)
 {
        switch (sparc_cpu_model){
+       case sun4:
        case sun4c:
                return -1; /* Don't check iospace on sun4c */
        case sun4m:
@@ -399,5 +571,9 @@ __get_iospace (unsigned long addr)
 
 #define module_map      vmalloc
 #define module_unmap    vfree
+#define module_shrink  vshrink
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define PageSkip(page)         (test_bit(PG_skip, &(page)->flags))
 
 #endif /* !(_SPARC_PGTABLE_H) */
index 4161526c0dc5d0f8983b5bde6ace7cb8a598297a..170465d98d2577a57f5052be670938767393bfcf 100644 (file)
-/* $Id: pgtsun4.h,v 1.2 1995/11/25 02:32:26 davem Exp $
- * pgtsun4.c:  Regular Sun4 MMU support goes in here.
+/* $Id: pgtsun4.h,v 1.3 1998/01/30 11:00:01 jj Exp $
+ * pgtsun4.h:  Sun4 specific pgtable.h defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
+#ifndef _SPARC_PGTSUN4C_H
+#define _SPARC_PGTSUN4C_H
 
-#ifndef _SPARC_PGTSUN4_H
-#define _SPARC_PGTSUN4_H
+#include <asm/contregs.h>
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define SUN4C_PMD_SHIFT       23
+#define SUN4C_PMD_SIZE        (1UL << SUN4C_PMD_SHIFT)
+#define SUN4C_PMD_MASK        (~(SUN4C_PMD_SIZE-1))
+#define SUN4C_PMD_ALIGN(addr) (((addr)+SUN4C_PMD_SIZE-1)&SUN4C_PMD_MASK)
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define SUN4C_PGDIR_SHIFT       23
+#define SUN4C_PGDIR_SIZE        (1UL << SUN4C_PGDIR_SHIFT)
+#define SUN4C_PGDIR_MASK        (~(SUN4C_PGDIR_SIZE-1))
+#define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK)
+
+/* To represent how the sun4c mmu really lays things out. */
+#define SUN4C_REAL_PGDIR_SHIFT       18
+#define SUN4C_REAL_PGDIR_SIZE        (1UL << SUN4C_REAL_PGDIR_SHIFT)
+#define SUN4C_REAL_PGDIR_MASK        (~(SUN4C_REAL_PGDIR_SIZE-1))
+#define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK)
+
+/* 19 bit PFN on sun4 */
+#define SUN4C_PFN_MASK 0x7ffff
+/* Don't increase these unless the structures in sun4c.c are fixed */
+#define SUN4C_MAX_SEGMAPS 256
+#define SUN4C_MAX_CONTEXTS 16
+
+/*
+ * To be efficient, and not have to worry about allocating such
+ * a huge pgd, we make the kernel sun4c tables each hold 1024
+ * entries and the pgd similarly just like the i386 tables.
+ */
+#define SUN4C_PTRS_PER_PTE    1024
+#define SUN4C_PTRS_PER_PMD    1
+#define SUN4C_PTRS_PER_PGD    1024
+
+/* On the sun4 the physical ram limit is 128MB.  We set up our I/O
+ * translations at KERNBASE + 128MB for 1MB, then we begin the VMALLOC
+ * area, makes sense.  This works out to the value below.
+ */
+#define SUN4C_VMALLOC_START   (0xfe300000)
+
+/*
+ * Sparc SUN4C pte fields.
+ */
+#define _SUN4C_PAGE_VALID        0x80000000
+#define _SUN4C_PAGE_SILENT_READ  0x80000000   /* synonym */
+#define _SUN4C_PAGE_DIRTY        0x40000000
+#define _SUN4C_PAGE_SILENT_WRITE 0x40000000   /* synonym */
+#define _SUN4C_PAGE_PRIV         0x20000000   /* privileged page */
+#define _SUN4C_PAGE_NOCACHE      0x10000000   /* non-cacheable page */
+#define _SUN4C_PAGE_PRESENT      0x08000000   /* implemented in software */
+#define _SUN4C_PAGE_IO           0x04000000   /* I/O page */
+#define _SUN4C_PAGE_READ         0x00800000   /* implemented in software */
+#define _SUN4C_PAGE_WRITE        0x00400000   /* implemented in software */
+#define _SUN4C_PAGE_ACCESSED     0x00200000   /* implemented in software */
+#define _SUN4C_PAGE_MODIFIED     0x00100000   /* implemented in software */
+
+#define _SUN4C_READABLE                (_SUN4C_PAGE_READ|_SUN4C_PAGE_SILENT_READ|\
+                                _SUN4C_PAGE_ACCESSED)
+#define _SUN4C_WRITEABLE       (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE|\
+                                _SUN4C_PAGE_MODIFIED)
+
+#define _SUN4C_PAGE_CHG_MASK   (0xffff|_SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_MODIFIED)
+
+#define SUN4C_PAGE_NONE                __pgprot(_SUN4C_PAGE_PRESENT)
+#define SUN4C_PAGE_SHARED      __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE|\
+                                        _SUN4C_PAGE_WRITE)
+#define SUN4C_PAGE_COPY                __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE)
+#define SUN4C_PAGE_READONLY    __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE)
+#define SUN4C_PAGE_KERNEL      __pgprot(_SUN4C_READABLE|_SUN4C_WRITEABLE|\
+                                        _SUN4C_PAGE_DIRTY|_SUN4C_PAGE_PRIV)
+
+#ifndef __ASSEMBLY__
+
+extern __inline__ unsigned long sun4c_get_synchronous_error(void)
+{
+       unsigned long sync_err;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (sync_err) :
+                            "r" (AC_SYNC_ERR), "i" (ASI_CONTROL));
+       return sync_err;
+}
+
+extern __inline__ unsigned long sun4c_get_synchronous_address(void)
+{
+       unsigned long sync_addr;
+
+       __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+                            "=r" (sync_addr) :
+                            "r" (AC_SYNC_VA), "i" (ASI_CONTROL));
+       return sync_addr;
+}
+
+/* SUN4 pte, segmap, and context manipulation */
+extern __inline__ unsigned long sun4c_get_segmap(unsigned long addr)
+{
+  register unsigned long entry;
+
+  __asm__ __volatile__("\n\tlduha [%1] %2, %0\n\t" : 
+                      "=r" (entry) :
+                      "r" (addr), "i" (ASI_SEGMAP));
+  return entry;
+}
+
+extern __inline__ void sun4c_put_segmap(unsigned long addr, unsigned long entry)
+{
+  __asm__ __volatile__("\n\tstha %1, [%0] %2; nop; nop; nop;\n\t" : :
+                      "r" (addr), "r" (entry),
+                      "i" (ASI_SEGMAP));
+}
+
+extern __inline__ unsigned long sun4c_get_pte(unsigned long addr)
+{
+  register unsigned long entry;
+
+  __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : 
+                      "=r" (entry) :
+                      "r" (addr), "i" (ASI_PTE));
+  return entry;
+}
+
+extern __inline__ void sun4c_put_pte(unsigned long addr, unsigned long entry)
+{
+  __asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : :
+                      "r" (addr), 
+                      "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE));
+}
+
+extern __inline__ int sun4c_get_context(void)
+{
+  register int ctx;
+
+  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" :
+                      "=r" (ctx) :
+                      "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+  return ctx;
+}
+
+extern __inline__ int sun4c_set_context(int ctx)
+{
+  __asm__ __volatile__("\n\tstba %0, [%1] %2; nop; nop; nop;\n\t" : :
+                      "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+  return ctx;
+}
+
+#endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC_PGTSUN4_H) */
index 93b00ce72dd9899c233328c4abf4df30ae7d1cba..d23881bfb9ea7bcf6a377a144eb4f7cbf25188a2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtsun4c.h,v 1.34 1997/03/23 03:47:08 davem Exp $
+/* $Id: pgtsun4c.h,v 1.35 1998/01/30 11:00:05 jj Exp $
  * pgtsun4c.h:  Sun4c specific pgtable.h defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 #define SUN4C_REAL_PGDIR_MASK        (~(SUN4C_REAL_PGDIR_SIZE-1))
 #define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK)
 
+/* 16 bit PFN on sun4c */
+#define SUN4C_PFN_MASK 0xffff
+
+/* Don't increase these unless the structures in sun4c.c are fixed */
+#define SUN4C_MAX_SEGMAPS 256
+#define SUN4C_MAX_CONTEXTS 16
+
 /*
  * To be efficient, and not have to worry about allocating such
  * a huge pgd, we make the kernel sun4c tables each hold 1024
index 4a91d99a45c5e4704959307f672ebc02f3498e1c..02333405e5798a1f3cce2996ad4fc35bd8030ae3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.61 1997/10/22 09:25:42 jj Exp $
+/* $Id: processor.h,v 1.62 1998/02/05 14:20:02 jj Exp $
  * include/asm-sparc/processor.h
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
@@ -14,6 +14,8 @@
 #include <asm/head.h>
 #include <asm/signal.h>
 #include <asm/segment.h>
+#include <asm/btfixup.h>
+#include <asm/page.h>
 
 /*
  * Bus types
@@ -33,7 +35,7 @@
  * That one page is used to protect kernel from intruders, so that
  * we can make our access_ok test faster
  */
-#define TASK_SIZE      (page_offset)
+#define TASK_SIZE      PAGE_OFFSET
 
 #define COPY_TASK_STRUCT(dst, src)     \
 do {                                   \
@@ -155,8 +157,11 @@ extern __inline__ void start_thread(struct pt_regs * regs, unsigned long pc,
 #ifdef __KERNEL__
 
 /* Allocation and freeing of basic task resources. */
-extern struct task_struct *(*alloc_task_struct)(void);
-extern void (*free_task_struct)(struct task_struct *tsk);
+BTFIXUPDEF_CALL(struct task_struct *, alloc_task_struct, void)
+BTFIXUPDEF_CALL(void, free_task_struct, struct task_struct *)
+
+#define alloc_task_struct() BTFIXUP_CALL(alloc_task_struct)()
+#define free_task_struct(tsk) BTFIXUP_CALL(free_task_struct)(tsk)
 
 #define init_task      (init_task_union.task)
 #define init_stack     (init_task_union.stack)
index 75aa2598bad2aa531d9a68b61aafd38774f5d188..739ccac5dcf284290cc74fd5990dba8bddc3b60b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sbi.h,v 1.1 1997/11/19 15:12:16 jj Exp $
+/* $Id: sbi.h,v 1.2 1998/03/09 14:04:48 jj Exp $
  * sbi.h:  SBI (Sbus Interface on sun4d) definitions
  *
  * Copyright (C) 1997 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
@@ -83,6 +83,14 @@ extern __inline__ void release_sbi(int devid, int mask)
                              "i" (ASI_M_CTL));
 }
 
+extern __inline__ void set_sbi_tid(int devid, int targetid)
+{
+       __asm__ __volatile__ ("sta %0, [%1] %2" : :
+                             "r" (targetid),
+                             "r" (ECSR_DEV_BASE(devid) | SBI_INTR_TID),
+                             "i" (ASI_M_CTL));
+}
+
 extern __inline__ int get_sbi_ctl(int devid, int cfgno)
 {
        int cfg;
index 5e81311187ed6c425bf4969fbff0a44115801524..96a824dd93bea1c1e4b227c6631d94d39b162fd0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.13 1997/11/19 15:12:18 jj Exp $
+/* $Id: sbus.h,v 1.14 1998/03/09 14:04:56 jj Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -47,8 +47,7 @@ struct linux_sbus_device {
   struct linux_sbus_device *child;     /* For ledma and espdma on sun4m */
   struct linux_sbus *my_bus;           /* Back ptr to sbus */
   int prom_node;                       /* PROM device tree node for this device */
-  char prom_name[64];                  /* PROM device name */
-  char linux_name[64];                 /* Name used internally by Linux */
+  char prom_name[32];                  /* PROM device name */
 
   struct linux_prom_registers reg_addrs[PROMREG_MAX];
   int num_registers, ranges_applied;
index 62a97ed405e6ed964feb3d92a08ec2eaa7acb4ca..8ecf68d08cd8a434b1c78a04e138670de911251e 100644 (file)
@@ -6,7 +6,9 @@
 #ifndef _SPARC_SMP_H
 #define _SPARC_SMP_H
 
+#include <linux/tasks.h>
 #include <asm/head.h>
+#include <asm/btfixup.h>
 
 #ifndef __ASSEMBLY__
 /* PROM provided per-processor information we need
@@ -25,7 +27,10 @@ extern int linux_num_cpus;   /* number of CPUs probed  */
 
 #ifndef __ASSEMBLY__
 
-extern struct prom_cpuinfo linux_cpus[NCPUS];
+#include <asm/ptrace.h>
+#include <asm/asi.h>
+
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 
 /* Per processor Sparc parameters we need. */
 
@@ -36,6 +41,7 @@ struct cpuinfo_sparc {
 };
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+extern unsigned long cpu_offset[NR_CPUS];
 
 struct klock_info {
        unsigned char kernel_flag;
@@ -61,12 +67,28 @@ typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
 /*
  *     General functions that each host system must provide.
  */
+void sun4m_init_smp(void);
+void sun4d_init_smp(void);
+
+void smp_callin(void);
+void smp_boot_cpus(void);
+void smp_store_cpu_info(int);
+
+BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, smp_message_pass, int, int, unsigned long, int)
+BTFIXUPDEF_CALL(int, __smp_processor_id, void)
+BTFIXUPDEF_BLACKBOX(smp_processor_id)
+BTFIXUPDEF_BLACKBOX(load_current)
 
-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);
+#define smp_cross_call(func,arg1,arg2,arg3,arg4,arg5) BTFIXUP_CALL(smp_cross_call)(func,arg1,arg2,arg3,arg4,arg5)
+#define smp_message_pass(target,msg,data,wait) BTFIXUP_CALL(smp_message_pass)(target,msg,data,wait)
+
+BTFIXUPDEF_CALL(int, smp_bogo_info, char *)
+BTFIXUPDEF_CALL(int, smp_info, char *)
+
+#define smp_bogo_info(buf) BTFIXUP_CALL(smp_bogo_info)(buf)
+#define smp_info(buf) BTFIXUP_CALL(smp_info)(buf)
 
 extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); }
 extern __inline__ void xc1(smpfunc_t func, unsigned long arg1)
@@ -84,10 +106,15 @@ extern __inline__ void xc5(smpfunc_t func, unsigned long arg1, unsigned long arg
 { 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 __volatile__ int __cpu_logical_map[NR_CPUS];
 extern unsigned long smp_proc_in_lock[NR_CPUS];
 
-extern __inline__ int hard_smp_processor_id(void)
+extern __inline__ int cpu_logical_map(int cpu)
+{
+       return __cpu_logical_map[cpu];
+}
+
+extern __inline__ int hard_smp4m_processor_id(void)
 {
        int cpuid;
 
@@ -98,6 +125,49 @@ extern __inline__ int hard_smp_processor_id(void)
        return cpuid;
 }
 
+extern __inline__ int hard_smp4d_processor_id(void)
+{
+       int cpuid;
+
+       __asm__ __volatile__("lda [%%g0] %1, %0\n\t" :
+                            "=&r" (cpuid) : "i" (ASI_M_VIKING_TMP1));
+       return cpuid;
+}
+
+#ifndef MODULE
+extern __inline__ int hard_smp_processor_id(void)
+{
+       int cpuid;
+
+       /* Black box - sun4m
+               __asm__ __volatile__("rd %%tbr, %0\n\t"
+                                    "srl %0, 12, %0\n\t"
+                                    "and %0, 3, %0\n\t" :
+                                    "=&r" (cpuid));
+                    - sun4d
+               __asm__ __volatile__("lda [%g0] ASI_M_VIKING_TMP1, %0\n\t"
+                                    "nop; nop" :
+                                    "=&r" (cpuid));
+          See btfixup.h and btfixupprep.c to understand how a blackbox works.
+        */
+       __asm__ __volatile__("sethi %%hi(___b_smp_processor_id), %0\n\t"
+                            "sethi %%hi(boot_cpu_id), %0\n\t"
+                            "ldub [%0 + %%lo(boot_cpu_id)], %0\n\t" :
+                            "=&r" (cpuid));
+       return cpuid;
+}
+#else
+extern __inline__ int hard_smp_processor_id(void)
+{
+       int cpuid __asm__ ("g2");
+       
+       __asm__ __volatile__("mov %%o7, %%g1\n\t"
+                            "call ___f___smp_processor_id\n\t"
+                            " nop\n\t" : "=r"(cpuid) : : "g1");
+       return cpuid;
+}
+#endif
+
 #define smp_processor_id() hard_smp_processor_id()
 
 #endif /* !(__ASSEMBLY__) */
@@ -121,6 +191,13 @@ extern __inline__ int hard_smp_processor_id(void)
 #define SMP_FROM_INT           1
 #define SMP_FROM_SYSCALL       2
 
+#else /* !(__SMP__) */
+#ifndef __ASSEMBLY__ 
+extern __inline__ int cpu_logical_map(int cpu)
+{
+       return cpu;
+}
+#endif 
 #endif /* !(__SMP__) */
 
 #define NO_PROC_ID            0xFF
index 41b72b40aa2da8135bc07564a1799aaf057bacdd..204ad53f8b41fb1045ad03aaa092dd537de04ab4 100644 (file)
@@ -72,7 +72,7 @@ do {  unsigned long flags;                            \
        spin_unlock_irqrestore(&global_bh_lock, flags); \
 } while(0)
 
-#define softirq_trylock()                                      \
+#define softirq_trylock(cpu)                                   \
 ({                                                             \
        int ret = 1;                                            \
        if(atomic_add_return(1, &__sparc_bh_counter) != 1) {    \
@@ -81,7 +81,7 @@ do {  unsigned long flags;                            \
        }                                                       \
        ret;                                                    \
 })
-#define softirq_endlock()      atomic_dec(&__sparc_bh_counter)
+#define softirq_endlock(cpu)   atomic_dec(&__sparc_bh_counter)
 #define clear_active_bhs(mask)                         \
 do {   unsigned long flags;                            \
        spin_lock_irqsave(&global_bh_lock, flags);      \
@@ -96,8 +96,8 @@ extern int __sparc_bh_counter;
 #define start_bh_atomic()      do { __sparc_bh_counter++; barrier(); } while(0)
 #define end_bh_atomic()                do { barrier(); __sparc_bh_counter--; } while(0)
 
-#define softirq_trylock() (__sparc_bh_counter ? 0 : (__sparc_bh_counter=1))
-#define softirq_endlock() (__sparc_bh_counter = 0)
+#define softirq_trylock(cpu) (__sparc_bh_counter ? 0 : (__sparc_bh_counter=1))
+#define softirq_endlock(cpu) (__sparc_bh_counter = 0)
 #define clear_active_bhs(x)    (bh_active &= ~(x))
 
 #define init_bh(nr, routine)   \
index 35f929c56e5fea3b9053c5e57c9ca5527e727bd6..62038a4de395f9646aafdeaed5f1aea4ce2b1f72 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: stat.h,v 1.7 1996/10/27 08:55:48 davem Exp $ */
+/* $Id: stat.h,v 1.8 1998/02/06 12:52:07 jj Exp $ */
 #ifndef _SPARC_STAT_H
 #define _SPARC_STAT_H
 
@@ -38,4 +38,40 @@ struct stat {
        unsigned long  __unused4[2];
 };
 
+typedef struct {
+       __u32           major;
+       __u32           minor;
+} __new_dev_t;
+
+struct stat64 {
+       __new_dev_t     st_dev;
+       __u64           st_ino;
+       __u32           st_mode;
+       __u32           st_nlink;
+       __s32           st_uid;
+       __s32           st_gid;
+       __new_dev_t     st_rdev;
+       __s64           st_size;
+       __u64           st_blocks;
+       __s32           st_atime;
+       __u32           __unused1;
+       __s32           st_mtime;
+       __u32           __unused2;
+       __s32           st_ctime;
+       __u32           __unused3;
+       __u32           st_blksize;
+       __u32           __unused4;
+};
+
+#define __XSTAT_VER_1          1
+#define __XSTAT_VER_2          2
+#define __XSTAT_VER_MASK       0xff
+
+#define __XSTAT_VER_XSTAT      0x000
+#define __XSTAT_VER_LXSTAT     0x100
+#define __XSTAT_VER_FXSTAT     0x200
+#define __XSTAT_VER_TYPEMASK   0xff00
+
+#define __XMKNOD_VER_1         1
+
 #endif
index 6957dde67a0c153f583f7815304d2aaa0ae9ae58..7f8d06587c67ce196bb1a76ad0157e2dcd98cef0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.33 1997/11/19 07:57:48 jj Exp $
+/* $Id: string.h,v 1.34 1998/01/30 10:59:55 jj Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -9,6 +9,8 @@
 #ifndef __SPARC_STRING_H__
 #define __SPARC_STRING_H__
 
+#include <asm/page.h>
+
 /* Really, userland/ksyms should not see any of this stuff. */
 
 #ifdef __KERNEL__
@@ -40,7 +42,7 @@ extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_
                __builtin_memcpy(to, from, n);
        } else {
                switch(n) {
-               case 4096:
+               case PAGE_SIZE:
                        __copy_1page(to, from);
                        break;
                default:
@@ -71,7 +73,7 @@ extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size
        extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
        if(!c) {
-               if(count == 4096)
+               if(count == PAGE_SIZE)
                        bzero_1page(s);
                else
                        __bzero(s, count);
diff --git a/include/asm-sparc/sun4paddr.h b/include/asm-sparc/sun4paddr.h
new file mode 100644 (file)
index 0000000..a2c6ed3
--- /dev/null
@@ -0,0 +1,19 @@
+/* $Id: sun4paddr.h,v 1.2 1998/02/09 13:26:41 jj Exp $
+ * sun4paddr.h:  Various physical addresses on sun4 machines
+ *
+ * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
+ */
+
+#ifndef _SPARC_SUN4PADDR_H
+#define _SPARC_SUN4PADDR_H
+
+#define SUN4_MEMREG_PHYSADDR           0xf4000000
+#define SUN4_IE_PHYSADDR               0xf5000000
+#define SUN4_300_MOSTEK_PHYSADDR       0xf2000000
+#define SUN4_300_TIMER_PHYSADDR                0xef000000
+#define SUN4_300_ETH_PHYSADDR          0xf9000000
+#define SUN4_300_BWTWO_PHYSADDR                0xfb400000
+#define SUN4_300_DMA_PHYSADDR          0xfa001000
+#define SUN4_300_ESP_PHYSADDR          0xfa000000
+
+#endif /* !(_SPARC_SUN4PADDR_H) */
diff --git a/include/asm-sparc/sun4prom.h b/include/asm-sparc/sun4prom.h
new file mode 100644 (file)
index 0000000..3a6167f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * sun4prom.h -- interface to sun4 PROM monitor.  We don't use most of this,
+ *               so most of these are just placeholders.
+ */
+
+#ifndef _SUN4PROM_H_
+#define _SUN4PROM_H_
+
+/*
+ * Although this looks similar to an romvec for a OpenProm machine, it is 
+ * actually closer to what was used in the Sun2 and Sun3.
+ *
+ * V2 entries exist only in version 2 PROMs and later, V3 in version 3 and later.
+ * 
+ * Many of the function prototypes are guesses.  Some are certainly wrong.
+ * Use with care.
+ */
+
+typedef struct {
+       char            *initSP;                /* Initial system stack ptr */
+       void            (*startmon)(void);      /* Initial PC for hardware */
+       int             *diagberr;              /* Bus err handler for diags */
+       struct linux_arguments_v0 **bootParam; /* Info for bootstrapped pgm */
+       unsigned int    *memorysize;            /* Usable memory in bytes */
+       unsigned char   (*getchar)(void);       /* Get char from input device */ 
+       void            (*putchar)(char);       /* Put char to output device */
+       int             (*mayget)(void);        /* Maybe get char, or -1 */
+       int             (*mayput)(void);        /* Maybe put char, or -1 */
+       unsigned char   *echo;                  /* Should getchar echo? */
+       unsigned char   *insource;              /* Input source selector */
+       unsigned char   *outsink;               /* Output sink selector */
+       int             (*getkey)(void);        /* Get next key if one exists */
+       void            (*initgetkey)(void);    /* Initialize get key */
+       unsigned int    *translation;           /* Kbd translation selector */
+       unsigned char   *keybid;                /* Keyboard ID byte */
+       int             *screen_x;              /* V2: Screen x pos (r/o) */
+       int             *screen_y;              /* V2: Screen y pos (r/o) */
+       struct keybuf   *keybuf;                /* Up/down keycode buffer */
+       char            *monid;                 /* Monitor version ID */
+       void            (*fbwritechar)(char);   /* Write a character to FB */
+       int             *fbAddr;                /* Address of frame buffer */
+       char            **font;                 /* Font table for FB */
+       void            (*fbwritestr)(char *);  /* Write string to FB */
+       void            (*reboot)(char *);      /* e.g. reboot("sd()vmlinux") */
+       unsigned char   *linebuf;               /* The line input buffer */
+       unsigned char   **lineptr;              /* Cur pointer into linebuf */
+       int             *linesize;              /* length of line in linebuf */
+       void            (*getline)(char *);     /* Get line from user */
+       unsigned char   (*getnextchar)(void);   /* Get next char from linebuf */
+       unsigned char   (*peeknextchar)(void);  /* Peek at next char */
+       int             *fbthere;               /* =1 if frame buffer there */
+       int             (*getnum)(void);        /* Grab hex num from line */
+       int             (*printf)(char *, ...); /* See prom_printf() instead */ 
+       void            (*printhex)(int);       /* Format N digits in hex */
+       unsigned char   *leds;                  /* RAM copy of LED register */
+       void            (*setLEDs)(unsigned char *);    /* Sets LED's and RAM copy */
+       void            (*NMIaddr)(void *);     /* Addr for level 7 vector */
+       void            (*abortentry)(void);    /* Entry for keyboard abort */
+       int             *nmiclock;              /* Counts up in msec */
+       int             *FBtype;                /* Frame buffer type */
+       unsigned int    romvecversion;          /* Version number for this romvec */
+       struct globram  *globram;               /* monitor global variables ??? */
+       void *          kbdaddr;                /* Addr of keyboard in use */
+       int             *keyrinit;              /* ms before kbd repeat */
+       unsigned char   *keyrtick;              /* ms between repetitions */
+       unsigned int    *memoryavail;           /* V1: Main mem usable size */
+       long            *resetaddr;             /* where to jump on a reset */
+       long            *resetmap;              /* pgmap entry for resetaddr */
+       void            (*exittomon)(void);     /* Exit from user program */
+       unsigned char   **memorybitmap;         /* V1: &{0 or &bits} */
+       void            (*setcxsegmap)(int ctxt, char *va, int pmeg);   /* Set seg in any context */
+       void            (**vector_cmd)(void *); /* V2: Handler for 'v' cmd */
+       unsigned long   *expectedtrapsig;       /* V3: Location of the expected trap signal */
+       unsigned long   *trapvectorbasetable;   /* V3: Address of the trap vector table */
+       int             unused1;
+       int             unused2;
+       int             unused3;
+       int             unused4;
+} linux_sun4_romvec;
+
+extern linux_sun4_romvec *sun4_romvec;
+
+#endif /* _SUN4PROM_H_ */
index 69d7cfe1676259f79b09879e62b8bb4bfa2158b2..0b011fbaa6814926ab7c142a8761134ec10bab3c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.65 1997/05/14 20:47:59 davem Exp $ */
+/* $Id: system.h,v 1.68 1998/03/09 14:04:51 jj Exp $ */
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
@@ -11,6 +11,7 @@
 #include <asm/oplib.h>
 #include <asm/psr.h>
 #include <asm/ptrace.h>
+#include <asm/btfixup.h>
 
 #define EMPTY_PGT       (&empty_bad_page)
 #define EMPTY_PGE      (&empty_bad_page_table)
@@ -37,6 +38,14 @@ enum sparc_cpu {
 
 extern enum sparc_cpu sparc_cpu_model;
 
+#ifndef CONFIG_SUN4
+#define ARCH_SUN4C_SUN4 (sparc_cpu_model==sun4c)
+#define ARCH_SUN4 0
+#else
+#define ARCH_SUN4C_SUN4 1
+#define ARCH_SUN4 1
+#endif
+
 extern unsigned long empty_bad_page;
 extern unsigned long empty_bad_page_table;
 extern unsigned long empty_zero_page;
@@ -98,6 +107,8 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
        "std    %%g4, [%%g6 + %2]\n\t"                                                  \
        "ldd    [%1 + %2], %%g4\n\t"                                                    \
        "mov    %1, %%g6\n\t"                                                           \
+       ".globl patchme_store_new_current\n"                                            \
+"patchme_store_new_current:\n\t"                                                       \
        "st     %1, [%0]\n\t"                                                           \
        "wr     %%g4, 0x20, %%psr\n\t"                                                  \
        "nop\n\t"                                                                       \
@@ -237,9 +248,11 @@ extern void __global_restore_flags(unsigned long flags);
 #define restore_flags(flags)   __global_restore_flags(flags)
 #else
 
+#error For combined sun4[md] smp, we need to get rid of the rdtbr.
+
 /* Visit arch/sparc/lib/irqlock.S for all the fun details... */
 #define cli()      __asm__ __volatile__("mov   %%o7, %%g4\n\t"                 \
-                                       "call   ___global_cli\n\t"              \
+                                       "call   ___f_global_cli\n\t"            \
                                        " rd    %%tbr, %%g7" : :                \
                                        : "g1", "g2", "g3", "g4", "g5", "g7",   \
                                          "memory", "cc")
@@ -248,7 +261,7 @@ extern void __global_restore_flags(unsigned long flags);
 do {   register unsigned long bits asm("g7");                  \
        bits = 0;                                               \
        __asm__ __volatile__("mov       %%o7, %%g4\n\t"         \
-                            "call      ___global_sti\n\t"      \
+                            "call      ___f_global_sti\n\t"    \
                             " rd       %%tbr, %%g2"            \
                             : /* no outputs */                 \
                             : "r" (bits)                       \
@@ -260,7 +273,7 @@ do {        register unsigned long bits asm("g7");                  \
 do {   register unsigned long bits asm("g7");                          \
        bits = flags;                                                   \
        __asm__ __volatile__("mov       %%o7, %%g4\n\t"                 \
-                            "call      ___global_restore_flags\n\t"    \
+                            "call      ___f_global_restore_flags\n\t"  \
                             " andcc    %%g7, 0x1, %%g0"                \
                             : "=&r" (bits)                             \
                             : "0" (bits)                               \
@@ -285,6 +298,11 @@ do {       register unsigned long bits asm("g7");                          \
 
 #define nop() __asm__ __volatile__ ("nop");
 
+/* This has special calling conventions */
+#ifndef __SMP__
+BTFIXUPDEF_CALL(void, ___xchg32, void)
+#endif
+
 extern __inline__ unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val)
 {
 #ifdef __SMP__
@@ -299,10 +317,12 @@ extern __inline__ unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned
        ptr = (unsigned long *) m;
        ret = val;
 
+       /* Note: this is magic and the nop there is
+          really needed. */
        __asm__ __volatile__("
        mov     %%o7, %%g4
-       call    ___xchg32
-        add    %%o7, 8, %%o7
+       call    ___f____xchg32
+        nop
 "      : "=&r" (ret)
        : "0" (ret), "r" (ptr)
        : "g3", "g4", "g7", "memory", "cc");
index 9dcd84decd60ae2e1f428d0d4e27484f44bf4ae7..15a4f2e6445f2ac8a71a0384c0499656dcaf3568 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: timer.h,v 1.15 1997/12/18 14:21:43 jj Exp $
+/* $Id: timer.h,v 1.16 1998/01/30 10:59:59 jj Exp $
  * timer.h:  Definitions for the timer chips on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
 #define _SPARC_TIMER_H
 
 #include <asm/system.h>  /* For NCPUS */
+#include <asm/sun4paddr.h>
 
 /* Timer structures. The interrupt timer has two properties which
  * are the counter (which is handled in do_timer in sched.c) and the limit.
@@ -31,6 +32,11 @@ struct sun4c_timer_info {
 };
 
 #define SUN4C_TIMER_PHYSADDR   0xf3000000
+#ifdef CONFIG_SUN4
+#define SUN_TIMER_PHYSADDR SUN4_300_TIMER_PHYSADDR
+#else
+#define SUN_TIMER_PHYSADDR SUN4C_TIMER_PHYSADDR
+#endif
 
 /* A sun4m has two blocks of registers which are probably of the same
  * structure. LSI Logic's L64851 is told to _decrement_ from the limit
index 3a3940df2dc6a60799122512ff10d69fe026537e..6690ab956ea6ada3997c68be08997e675284d3bb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.h,v 1.8 1996/05/17 10:38:53 davem Exp $
+/* $Id: traps.h,v 1.9 1998/03/09 14:04:53 jj Exp $
  * traps.h:  Format of entries for the Sparc trap table.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -11,7 +11,7 @@
 
 #ifndef __ASSEMBLY__
 
-/* This is for V8 and V9 compliant Sparc CPUS */
+/* This is for V8 compliant Sparc CPUS */
 struct tt_entry {
        unsigned long inst_one;
        unsigned long inst_two;
@@ -22,25 +22,6 @@ struct tt_entry {
 /* We set this to _start in system setup. */
 extern struct tt_entry *sparc_ttable;
 
-/* This for V9 compliant Sparc CPUS */
-struct tt_v9_entry {
-       unsigned long inst_one;
-       unsigned long inst_two;
-       unsigned long inst_three;
-       unsigned long inst_four;
-       unsigned long inst_five;
-       unsigned long inst_six;
-       unsigned long inst_seven;
-       unsigned long inst_eight;
-};
-
-/* V9 has multiple trap tables, which one is used depends
- * upon how deep within multiple traps you are.
- * I believe the UltraSparc supports two levels now.
- */
-extern struct tt_v9_entry *sparc_v9_ttablel0;
-extern struct tt_v9_entry *sparc_v9_ttablel1;
-
 extern __inline__ unsigned long get_tbr(void)
 {
        unsigned long tbr;
index c89ec9c352a4a0f31888c09416de0f98eecddceb..638e234a09594351e85901d460b2df072ab98aed 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.14 1997/09/18 10:42:02 rth Exp $
+/* $Id: uaccess.h,v 1.15 1998/02/05 14:19:54 jj Exp $
  * uaccess.h: User space memore access functions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -39,7 +39,7 @@
  * No one can read/write anything from userland in the kernel space by setting
  * large size and address near to page_offset - a fault will break his intentions.
  */
-#define __user_ok(addr,size) ((addr) < stack_top)
+#define __user_ok(addr,size) ((addr) < STACK_TOP)
 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
 #define __access_ok(addr,size) (__user_ok((addr) & get_fs().seg,(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
index 2b34f42a979153f436483ba37d04d68765e7d2d8..7682680a46b3b00367f88e24ccef2ae43133096a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.36 1997/12/14 23:24:43 ecd Exp $ */
+/* $Id: unistd.h,v 1.38 1998/03/27 07:01:56 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
 #define __NR_unlink              10 /* Common                                      */
 #define __NR_execv               11 /* SunOS Specific                              */
 #define __NR_chdir               12 /* Common                                      */
-/* #define __NR_ni_syscall       13    ENOSYS under SunOS                          */
+#define __NR_xstat              13 /* Linux Specific                              */
 #define __NR_mknod               14 /* Common                                      */
 #define __NR_chmod               15 /* Common                                      */
 #define __NR_chown               16 /* Common                                      */
 #define __NR_brk                 17 /* Common                                      */
-/* #define __NR_ni_syscall       18    ENOSYS under SunOS                          */
+#define __NR_xmknod             18 /* Linux Specific                              */
 #define __NR_lseek               19 /* Common                                      */
 #define __NR_getpid              20 /* Common                                      */
 /* #define __NR_ni_syscall       21    ENOSYS under SunOS                          */
index 7306b0d1090c95e2eca4b282f0ffd2172ada0630..b5f1abf733d5251f3aa7ec8e4d5b5821420fa89e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: user.h,v 1.4 1996/07/24 23:17:14 miguel Exp $
+/* $Id: user.h,v 1.5 1998/02/23 01:49:22 rth Exp $
  * asm-sparc/user.h: Core file definitions for the Sparc.
  *
  * Keep in sync with reg.h.  Actually, we could get rid of this
@@ -50,11 +50,11 @@ struct user {
        unsigned long sigcode;   /* Special sigcontext subcode, if any */
 };
 
-#define NBPG                   PAGE_SIZE
+#define NBPG                   0x2000
 #define UPAGES                 1
 #define HOST_TEXT_START_ADDR   (u.start_code)
-#define HOST_DATA_START_ADDR   (u.start_data)
-#define HOST_STACK_END_ADDR    (u.start_stack + u.u_ssize * NBPG)
+#define HOST_DATA_START_ADDR   (u.uexec.a_data)
+#define HOST_STACK_END_ADDR    (- u.u_ssize * NBPG)
 #define SUNOS_CORE_MAGIC       0x080456
 
 #endif /* !(_SPARC_USER_H) */
index d963a7fa3ac194b536a5524a69ef292d67e0959c..eafe7a45287a17bbecd62a749b3dafbe534180c7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: vac-ops.h,v 1.12 1996/07/08 15:12:30 ecd Exp $ */
+/* $Id: vac-ops.h,v 1.13 1998/01/30 10:59:59 jj Exp $ */
 #ifndef _SPARC_VAC_OPS_H
 #define _SPARC_VAC_OPS_H
 
@@ -8,6 +8,7 @@
  * Copyright (C) 1994, David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <asm/sysen.h>
 #include <asm/contregs.h>
 #include <asm/asi.h>
 #define S4CVACTAG_TID      0x0000fffc
 
 /* Sun4c VAC Virtual Address */
+/* These aren't used, why bother? (Anton) */
+#if 0
 #define S4CVACVA_TID       0x3fff0000
 #define S4CVACVA_LINE      0x0000fff0
 #define S4CVACVA_BIL       0x0000000f
+#endif
 
 /* The indexing of cache lines creates a problem.  Because the line
  * field of a virtual address extends past the page offset within
  * not the case, and thus is a 'bad alias' we must turn off the
  * cacheable bit in the pte's of all such pages.
  */
-#define S4CVAC_BADBITS     0x0000f000
+
+#ifdef CONFIG_SUN4
+#define S4CVAC_BADBITS     0x0001e000
+#else
+#define S4CVAC_BADBITS    0x0000f000
+#endif
 
 /* The following is true if vaddr1 and vaddr2 would cause
  * a 'bad alias'.
@@ -89,6 +98,8 @@ struct sun4c_vac_props {
        unsigned int num_bytes;     /* Size of the cache */
        unsigned int num_lines;     /* Number of cache lines */
        unsigned int do_hwflushes;  /* Hardware flushing available? */
+       enum { NONE, WRITE_THROUGH,
+           WRITE_BACK } type;      /* What type of VAC? */
        unsigned int linesize;      /* Size of each line in bytes */
        unsigned int log2lsize;     /* log2(linesize) */
        unsigned int on;            /* VAC is enabled */
index cb2f4e73b43010fd4377e38d1919efd991451e6d..f31322e8e91ba229eb0ccf5ca4d3f62b223dc428 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: winmacro.h,v 1.19 1997/05/01 01:42:05 davem Exp $
+/* $Id: winmacro.h,v 1.20 1998/03/09 14:04:54 jj Exp $
  * winmacro.h: Window loading-unloading macros.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
         st       %scratch, [%cur_reg + AOFF_task_tss + AOFF_thread_w_saved];
 
 #ifdef __SMP__
-#define LOAD_CURRENT(dest_reg, idreg) \
+#define LOAD_CURRENT4M(dest_reg, idreg) \
         rd       %tbr, %idreg; \
        sethi    %hi(C_LABEL(current_set)), %dest_reg; \
         srl      %idreg, 10, %idreg; \
        or       %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \
        and      %idreg, 0xc, %idreg; \
        ld       [%idreg + %dest_reg], %dest_reg;
+
+/* Sliiick. We have a Linux current register :) -jj */
+#define LOAD_CURRENT4D(dest_reg) \
+       lda      [%g0] ASI_M_VIKING_TMP2, %dest_reg;
+
+/* Blackbox - take care with this... - check smp4m and smp4d before changing this. */
+#define LOAD_CURRENT(dest_reg, idreg)                                  \
+       sethi    %hi(___b_load_current), %idreg;                        \
+       sethi    %hi(C_LABEL(current_set)), %dest_reg;                  \
+       sethi    %hi(C_LABEL(boot_cpu_id4)), %idreg;                    \
+       or       %dest_reg, %lo(C_LABEL(current_set)), %dest_reg;       \
+       ldub     [%idreg + %lo(C_LABEL(boot_cpu_id4))], %idreg;         \
+       ld       [%idreg + %dest_reg], %dest_reg;
 #else
 #define LOAD_CURRENT(dest_reg, idreg) \
         sethi    %hi(C_LABEL(current_set)), %idreg; \
diff --git a/include/asm-sparc/xstat.h b/include/asm-sparc/xstat.h
new file mode 100644 (file)
index 0000000..53b1d59
--- /dev/null
@@ -0,0 +1,35 @@
+/* $Id: xstat.h,v 1.1 1998/02/06 12:52:08 jj Exp $
+ * xstat.h: sys_xstat/xmknod architecture dependent stuff.
+ *
+ * Copyright (C) 1998  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
+ */
+extern __inline__ int cp_xstat(struct inode *inode, struct stat64 *s, unsigned long blocks, int blksize)
+{
+       struct stat64 tmp;
+       
+       memset (&tmp, 0, sizeof(tmp));
+       tmp.st_dev.major = MAJOR(inode->i_dev);
+       tmp.st_dev.minor = MINOR(inode->i_dev);
+       tmp.st_ino = inode->i_ino;
+       tmp.st_mode = inode->i_mode;
+       tmp.st_nlink = inode->i_nlink;
+       tmp.st_uid = inode->i_uid;
+       tmp.st_gid = inode->i_gid;
+       tmp.st_rdev.major = MAJOR(inode->i_rdev);
+       tmp.st_rdev.minor = MINOR(inode->i_rdev);
+       tmp.st_size = inode->i_size;
+       tmp.st_blksize = blksize;
+       tmp.st_blocks = blocks;
+       tmp.st_atime = inode->i_atime;
+       tmp.st_mtime = inode->i_mtime;
+       tmp.st_ctime = inode->i_ctime;
+       return copy_to_user(s,&tmp,sizeof(tmp));
+}
+
+extern __inline__ int get_user_new_dev_t(kdev_t *kdev, __new_dev_t *udev) {
+       __new_dev_t ndev;
+       if (copy_from_user (&ndev, udev, sizeof(__new_dev_t))) return -EFAULT;
+       *kdev = MKDEV(ndev.major, ndev.minor);
+       return 0;
+}
diff --git a/include/asm-sparc64/apb.h b/include/asm-sparc64/apb.h
new file mode 100644 (file)
index 0000000..80f0df2
--- /dev/null
@@ -0,0 +1,36 @@
+/* $Id: apb.h,v 1.2 1998/04/01 20:41:49 ecd Exp $
+ * apb.h: Advanced PCI Bridge Configuration Registers and Bits
+ *
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#ifndef _SPARC64_APB_H
+#define _SPARC64_APB_H
+
+#define APB_TICK_REGISTER                      0xb0
+#define APB_INT_ACK                            0xb8
+#define APB_PRIMARY_MASTER_RETRY_LIMIT         0xc0
+#define APB_DMA_ASFR                           0xc8
+#define APB_DMA_AFAR                           0xd0
+#define APB_PIO_TARGET_RETRY_LIMIT             0xd8
+#define APB_PIO_TARGET_LATENCY_TIMER           0xd9
+#define APB_DMA_TARGET_RETRY_LIMIT             0xda
+#define APB_DMA_TARGET_LATENCY_TIMER           0xdb
+#define APB_SECONDARY_MASTER_RETRY_LIMIT       0xdc
+#define APB_SECONDARY_CONTROL                  0xdd
+#define APB_IO_ADDRESS_MAP                     0xde
+#define APB_MEM_ADDRESS_MAP                    0xdf
+
+#define APB_PCI_CONTROL_LOW                    0xe0
+#  define APB_PCI_CTL_LOW_ARB_PARK                     (1 << 21)
+#  define APB_PCI_CTL_LOW_ERRINT_EN                    (1 << 8)
+
+#define APB_PCI_CONTROL_HIGH                   0xe4
+#  define APB_PCI_CTL_HIGH_SERR                                (1 << 2)
+#  define APB_PCI_CTL_HIGH_ARBITER_EN                  (1 << 0)
+
+#define APB_PIO_ASFR                           0xe8
+#define APB_PIO_AFAR                           0xf0
+#define APB_DIAG_REGISTER                      0xf8
+
+#endif /* !(_SPARC64_APB_H) */
index 5dac7041897cd4908ecfef6be68595ec8c02c38b..36b684ae6ce3ad3894cfcc8ab2420c54c8805efe 100644 (file)
 #ifndef __ASM_OFFSETS_H__
 #define __ASM_OFFSETS_H__
 
+#ifndef __SMP__
+
 #define AOFF_task_state        0x00000000
 #define ASIZ_task_state        0x00000008
-#define AOFF_task_counter      0x00000008
+#define AOFF_task_flags        0x00000008
+#define ASIZ_task_flags        0x00000008
+#define AOFF_task_sigpending   0x00000010
+#define ASIZ_task_sigpending   0x00000004
+#define AOFF_task_addr_limit   0x00000018
+#define ASIZ_task_addr_limit   0x00000008
+#define AOFF_task_exec_domain  0x00000020
+#define ASIZ_task_exec_domain  0x00000008
+#define AOFF_task_debugreg     0x00000028
+#define ASIZ_task_debugreg     0x00000040
+#define AOFF_task_counter      0x00000068
 #define ASIZ_task_counter      0x00000008
-#define AOFF_task_priority     0x00000010
+#define AOFF_task_priority     0x00000070
 #define ASIZ_task_priority     0x00000008
-#define AOFF_task_flags        0x00000018
+#define AOFF_task_binfmt       0x00000078
+#define ASIZ_task_binfmt       0x00000008
+#define AOFF_task_next_task    0x00000080
+#define ASIZ_task_next_task    0x00000008
+#define AOFF_task_prev_task    0x00000088
+#define ASIZ_task_prev_task    0x00000008
+#define AOFF_task_next_run     0x00000090
+#define ASIZ_task_next_run     0x00000008
+#define AOFF_task_prev_run     0x00000098
+#define ASIZ_task_prev_run     0x00000008
+#define AOFF_task_exit_code    0x000000a0
+#define ASIZ_task_exit_code    0x00000004
+#define AOFF_task_exit_signal  0x000000a4
+#define ASIZ_task_exit_signal  0x00000004
+#define AOFF_task_pdeath_signal        0x000000a8
+#define ASIZ_task_pdeath_signal        0x00000004
+#define AOFF_task_personality  0x000000b0
+#define ASIZ_task_personality  0x00000008
+#define AOFF_task_pid  0x000000bc
+#define ASIZ_task_pid  0x00000004
+#define AOFF_task_pgrp 0x000000c0
+#define ASIZ_task_pgrp 0x00000004
+#define AOFF_task_tty_old_pgrp 0x000000c4
+#define ASIZ_task_tty_old_pgrp 0x00000004
+#define AOFF_task_session      0x000000c8
+#define ASIZ_task_session      0x00000004
+#define AOFF_task_leader       0x000000cc
+#define ASIZ_task_leader       0x00000004
+#define AOFF_task_ngroups      0x000000d0
+#define ASIZ_task_ngroups      0x00000004
+#define AOFF_task_groups       0x000000d4
+#define ASIZ_task_groups       0x00000080
+#define AOFF_task_p_opptr      0x00000158
+#define ASIZ_task_p_opptr      0x00000008
+#define AOFF_task_p_pptr       0x00000160
+#define ASIZ_task_p_pptr       0x00000008
+#define AOFF_task_p_cptr       0x00000168
+#define ASIZ_task_p_cptr       0x00000008
+#define AOFF_task_p_ysptr      0x00000170
+#define ASIZ_task_p_ysptr      0x00000008
+#define AOFF_task_p_osptr      0x00000178
+#define ASIZ_task_p_osptr      0x00000008
+#define AOFF_task_pidhash_next 0x00000180
+#define ASIZ_task_pidhash_next 0x00000008
+#define AOFF_task_pidhash_pprev        0x00000188
+#define ASIZ_task_pidhash_pprev        0x00000008
+#define AOFF_task_tarray_ptr   0x00000190
+#define ASIZ_task_tarray_ptr   0x00000008
+#define AOFF_task_wait_chldexit        0x00000198
+#define ASIZ_task_wait_chldexit        0x00000008
+#define AOFF_task_uid  0x000001a0
+#define ASIZ_task_uid  0x00000004
+#define AOFF_task_euid 0x000001a4
+#define ASIZ_task_euid 0x00000004
+#define AOFF_task_suid 0x000001a8
+#define ASIZ_task_suid 0x00000004
+#define AOFF_task_fsuid        0x000001ac
+#define ASIZ_task_fsuid        0x00000004
+#define AOFF_task_gid  0x000001b0
+#define ASIZ_task_gid  0x00000004
+#define AOFF_task_egid 0x000001b4
+#define ASIZ_task_egid 0x00000004
+#define AOFF_task_sgid 0x000001b8
+#define ASIZ_task_sgid 0x00000004
+#define AOFF_task_fsgid        0x000001bc
+#define ASIZ_task_fsgid        0x00000004
+#define AOFF_task_timeout      0x000001c0
+#define ASIZ_task_timeout      0x00000008
+#define AOFF_task_policy       0x000001c8
+#define ASIZ_task_policy       0x00000008
+#define AOFF_task_rt_priority  0x000001d0
+#define ASIZ_task_rt_priority  0x00000008
+#define AOFF_task_it_real_value        0x000001d8
+#define ASIZ_task_it_real_value        0x00000008
+#define AOFF_task_it_prof_value        0x000001e0
+#define ASIZ_task_it_prof_value        0x00000008
+#define AOFF_task_it_virt_value        0x000001e8
+#define ASIZ_task_it_virt_value        0x00000008
+#define AOFF_task_it_real_incr 0x000001f0
+#define ASIZ_task_it_real_incr 0x00000008
+#define AOFF_task_it_prof_incr 0x000001f8
+#define ASIZ_task_it_prof_incr 0x00000008
+#define AOFF_task_it_virt_incr 0x00000200
+#define ASIZ_task_it_virt_incr 0x00000008
+#define AOFF_task_real_timer   0x00000208
+#define ASIZ_task_real_timer   0x00000028
+#define AOFF_task_times        0x00000230
+#define ASIZ_task_times        0x00000020
+#define AOFF_task_start_time   0x00000250
+#define ASIZ_task_start_time   0x00000008
+#define AOFF_task_per_cpu_utime        0x00000258
+#define ASIZ_task_per_cpu_utime        0x00000008
+#define AOFF_task_min_flt      0x00000268
+#define ASIZ_task_min_flt      0x00000008
+#define AOFF_task_maj_flt      0x00000270
+#define ASIZ_task_maj_flt      0x00000008
+#define AOFF_task_nswap        0x00000278
+#define ASIZ_task_nswap        0x00000008
+#define AOFF_task_cmin_flt     0x00000280
+#define ASIZ_task_cmin_flt     0x00000008
+#define AOFF_task_cmaj_flt     0x00000288
+#define ASIZ_task_cmaj_flt     0x00000008
+#define AOFF_task_cnswap       0x00000290
+#define ASIZ_task_cnswap       0x00000008
+#define AOFF_task_swap_address 0x000002a0
+#define ASIZ_task_swap_address 0x00000008
+#define AOFF_task_old_maj_flt  0x000002a8
+#define ASIZ_task_old_maj_flt  0x00000008
+#define AOFF_task_dec_flt      0x000002b0
+#define ASIZ_task_dec_flt      0x00000008
+#define AOFF_task_swap_cnt     0x000002b8
+#define ASIZ_task_swap_cnt     0x00000008
+#define AOFF_task_rlim 0x000002c0
+#define ASIZ_task_rlim 0x000000a0
+#define AOFF_task_used_math    0x00000360
+#define ASIZ_task_used_math    0x00000002
+#define AOFF_task_io_usage     0x00000368
+#define ASIZ_task_io_usage     0x00000008
+#define AOFF_task_comm 0x00000370
+#define ASIZ_task_comm 0x00000010
+#define AOFF_task_link_count   0x00000380
+#define ASIZ_task_link_count   0x00000004
+#define AOFF_task_tty  0x00000388
+#define ASIZ_task_tty  0x00000008
+#define AOFF_task_semundo      0x00000390
+#define ASIZ_task_semundo      0x00000008
+#define AOFF_task_semsleeping  0x00000398
+#define ASIZ_task_semsleeping  0x00000008
+#define AOFF_task_ldt  0x000003a0
+#define ASIZ_task_ldt  0x00000008
+#define AOFF_task_tss  0x000003b0
+#define ASIZ_task_tss  0x00000490
+#define AOFF_task_fs   0x00000840
+#define ASIZ_task_fs   0x00000008
+#define AOFF_task_files        0x00000848
+#define ASIZ_task_files        0x00000008
+#define AOFF_task_mm   0x00000850
+#define ASIZ_task_mm   0x00000008
+#define AOFF_task_sig  0x00000858
+#define ASIZ_task_sig  0x00000008
+#define AOFF_task_signal       0x00000860
+#define ASIZ_task_signal       0x00000008
+#define AOFF_task_blocked      0x00000868
+#define ASIZ_task_blocked      0x00000008
+#define AOFF_task_sigqueue     0x00000870
+#define ASIZ_task_sigqueue     0x00000008
+#define AOFF_task_sigqueue_tail        0x00000878
+#define ASIZ_task_sigqueue_tail        0x00000008
+#define AOFF_task_has_cpu      0x00000880
+#define ASIZ_task_has_cpu      0x00000004
+#define AOFF_task_processor    0x00000884
+#define ASIZ_task_processor    0x00000004
+#define AOFF_task_last_processor       0x00000888
+#define ASIZ_task_last_processor       0x00000004
+#define AOFF_task_lock_depth   0x0000088c
+#define ASIZ_task_lock_depth   0x00000004
+#define AOFF_task_sigmask_lock 0x00000890
+#define ASIZ_task_sigmask_lock 0x00000000
+#define AOFF_mm_mmap   0x00000000
+#define ASIZ_mm_mmap   0x00000008
+#define AOFF_mm_mmap_cache     0x00000008
+#define ASIZ_mm_mmap_cache     0x00000008
+#define AOFF_mm_pgd    0x00000010
+#define ASIZ_mm_pgd    0x00000008
+#define AOFF_mm_count  0x00000018
+#define ASIZ_mm_count  0x00000004
+#define AOFF_mm_map_count      0x0000001c
+#define ASIZ_mm_map_count      0x00000004
+#define AOFF_mm_mmap_sem       0x00000020
+#define ASIZ_mm_mmap_sem       0x00000010
+#define AOFF_mm_context        0x00000030
+#define ASIZ_mm_context        0x00000008
+#define AOFF_mm_start_code     0x00000038
+#define ASIZ_mm_start_code     0x00000008
+#define AOFF_mm_end_code       0x00000040
+#define ASIZ_mm_end_code       0x00000008
+#define AOFF_mm_start_data     0x00000048
+#define ASIZ_mm_start_data     0x00000008
+#define AOFF_mm_end_data       0x00000050
+#define ASIZ_mm_end_data       0x00000008
+#define AOFF_mm_start_brk      0x00000058
+#define ASIZ_mm_start_brk      0x00000008
+#define AOFF_mm_brk    0x00000060
+#define ASIZ_mm_brk    0x00000008
+#define AOFF_mm_start_stack    0x00000068
+#define ASIZ_mm_start_stack    0x00000008
+#define AOFF_mm_arg_start      0x00000070
+#define ASIZ_mm_arg_start      0x00000008
+#define AOFF_mm_arg_end        0x00000078
+#define ASIZ_mm_arg_end        0x00000008
+#define AOFF_mm_env_start      0x00000080
+#define ASIZ_mm_env_start      0x00000008
+#define AOFF_mm_env_end        0x00000088
+#define ASIZ_mm_env_end        0x00000008
+#define AOFF_mm_rss    0x00000090
+#define ASIZ_mm_rss    0x00000008
+#define AOFF_mm_total_vm       0x00000098
+#define ASIZ_mm_total_vm       0x00000008
+#define AOFF_mm_locked_vm      0x000000a0
+#define ASIZ_mm_locked_vm      0x00000008
+#define AOFF_mm_def_flags      0x000000a8
+#define ASIZ_mm_def_flags      0x00000008
+#define AOFF_mm_cpu_vm_mask    0x000000b0
+#define ASIZ_mm_cpu_vm_mask    0x00000008
+#define AOFF_thread_ksp        0x00000000
+#define ASIZ_thread_ksp        0x00000008
+#define AOFF_thread_kpc        0x00000008
+#define ASIZ_thread_kpc        0x00000004
+#define AOFF_thread_wstate     0x0000000c
+#define ASIZ_thread_wstate     0x00000002
+#define AOFF_thread_cwp        0x0000000e
+#define ASIZ_thread_cwp        0x00000002
+#define AOFF_thread_flags      0x00000010
+#define ASIZ_thread_flags      0x00000002
+#define AOFF_thread_ctx        0x00000012
+#define ASIZ_thread_ctx        0x00000002
+#define AOFF_thread_w_saved    0x00000014
+#define ASIZ_thread_w_saved    0x00000002
+#define AOFF_thread_new_signal 0x00000016
+#define ASIZ_thread_new_signal 0x00000002
+#define AOFF_thread_current_ds 0x00000018
+#define ASIZ_thread_current_ds 0x00000008
+#define AOFF_thread_kregs      0x00000020
+#define ASIZ_thread_kregs      0x00000008
+#define AOFF_thread_utraps     0x00000028
+#define ASIZ_thread_utraps     0x00000008
+#define AOFF_thread_reg_window 0x00000030
+#define ASIZ_thread_reg_window 0x00000400
+#define AOFF_thread_rwbuf_stkptrs      0x00000430
+#define ASIZ_thread_rwbuf_stkptrs      0x00000040
+#define AOFF_thread_sig_address        0x00000470
+#define ASIZ_thread_sig_address        0x00000008
+#define AOFF_thread_sig_desc   0x00000478
+#define ASIZ_thread_sig_desc   0x00000008
+#define AOFF_thread_sstk_info  0x00000480
+#define ASIZ_thread_sstk_info  0x00000010
+
+#else /* __SMP__ */
+
+#define AOFF_task_state        0x00000000
+#define ASIZ_task_state        0x00000008
+#define AOFF_task_flags        0x00000008
 #define ASIZ_task_flags        0x00000008
-#define AOFF_task_addr_limit   0x00000020
-#define ASIZ_task_addr_limit   0x00000008
-#define AOFF_task_sigpending   0x00000028
+#define AOFF_task_sigpending   0x00000010
 #define ASIZ_task_sigpending   0x00000004
-#define AOFF_task_debugreg     0x00000030
-#define ASIZ_task_debugreg     0x00000040
-#define AOFF_task_exec_domain  0x00000070
+#define AOFF_task_addr_limit   0x00000018
+#define ASIZ_task_addr_limit   0x00000008
+#define AOFF_task_exec_domain  0x00000020
 #define ASIZ_task_exec_domain  0x00000008
+#define AOFF_task_debugreg     0x00000028
+#define ASIZ_task_debugreg     0x00000040
+#define AOFF_task_counter      0x00000068
+#define ASIZ_task_counter      0x00000008
+#define AOFF_task_priority     0x00000070
+#define ASIZ_task_priority     0x00000008
 #define AOFF_task_binfmt       0x00000078
 #define ASIZ_task_binfmt       0x00000008
 #define AOFF_task_next_task    0x00000080
 #define ASIZ_task_times        0x00000020
 #define AOFF_task_start_time   0x00000250
 #define ASIZ_task_start_time   0x00000008
-#define AOFF_task_min_flt      0x00000258
+#define AOFF_task_per_cpu_utime        0x00000258
+#define ASIZ_task_per_cpu_utime        0x00000100
+#define AOFF_task_min_flt      0x00000458
 #define ASIZ_task_min_flt      0x00000008
-#define AOFF_task_maj_flt      0x00000260
+#define AOFF_task_maj_flt      0x00000460
 #define ASIZ_task_maj_flt      0x00000008
-#define AOFF_task_nswap        0x00000268
+#define AOFF_task_nswap        0x00000468
 #define ASIZ_task_nswap        0x00000008
-#define AOFF_task_cmin_flt     0x00000270
+#define AOFF_task_cmin_flt     0x00000470
 #define ASIZ_task_cmin_flt     0x00000008
-#define AOFF_task_cmaj_flt     0x00000278
+#define AOFF_task_cmaj_flt     0x00000478
 #define ASIZ_task_cmaj_flt     0x00000008
-#define AOFF_task_cnswap       0x00000280
+#define AOFF_task_cnswap       0x00000480
 #define ASIZ_task_cnswap       0x00000008
-#define AOFF_task_swap_address 0x00000290
+#define AOFF_task_swap_address 0x00000490
 #define ASIZ_task_swap_address 0x00000008
-#define AOFF_task_old_maj_flt  0x00000298
+#define AOFF_task_old_maj_flt  0x00000498
 #define ASIZ_task_old_maj_flt  0x00000008
-#define AOFF_task_dec_flt      0x000002a0
+#define AOFF_task_dec_flt      0x000004a0
 #define ASIZ_task_dec_flt      0x00000008
-#define AOFF_task_swap_cnt     0x000002a8
+#define AOFF_task_swap_cnt     0x000004a8
 #define ASIZ_task_swap_cnt     0x00000008
-#define AOFF_task_rlim 0x000002b0
+#define AOFF_task_rlim 0x000004b0
 #define ASIZ_task_rlim 0x000000a0
-#define AOFF_task_used_math    0x00000350
+#define AOFF_task_used_math    0x00000550
 #define ASIZ_task_used_math    0x00000002
-#define AOFF_task_io_usage     0x00000358
+#define AOFF_task_io_usage     0x00000558
 #define ASIZ_task_io_usage     0x00000008
-#define AOFF_task_comm 0x00000360
+#define AOFF_task_comm 0x00000560
 #define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count   0x00000370
+#define AOFF_task_link_count   0x00000570
 #define ASIZ_task_link_count   0x00000004
-#define AOFF_task_tty  0x00000378
+#define AOFF_task_tty  0x00000578
 #define ASIZ_task_tty  0x00000008
-#define AOFF_task_semundo      0x00000380
+#define AOFF_task_semundo      0x00000580
 #define ASIZ_task_semundo      0x00000008
-#define AOFF_task_semsleeping  0x00000388
+#define AOFF_task_semsleeping  0x00000588
 #define ASIZ_task_semsleeping  0x00000008
-#define AOFF_task_ldt  0x00000390
+#define AOFF_task_ldt  0x00000590
 #define ASIZ_task_ldt  0x00000008
-#define AOFF_task_tss  0x000003a0
+#define AOFF_task_tss  0x000005a0
 #define ASIZ_task_tss  0x00000490
-#define AOFF_task_fs   0x00000830
+#define AOFF_task_fs   0x00000a30
 #define ASIZ_task_fs   0x00000008
-#define AOFF_task_files        0x00000838
+#define AOFF_task_files        0x00000a38
 #define ASIZ_task_files        0x00000008
-#define AOFF_task_mm   0x00000840
+#define AOFF_task_mm   0x00000a40
 #define ASIZ_task_mm   0x00000008
-#define AOFF_task_sig  0x00000848
+#define AOFF_task_sig  0x00000a48
 #define ASIZ_task_sig  0x00000008
-#define AOFF_task_signal       0x00000850
+#define AOFF_task_signal       0x00000a50
 #define ASIZ_task_signal       0x00000008
-#define AOFF_task_blocked      0x00000858
+#define AOFF_task_blocked      0x00000a58
 #define ASIZ_task_blocked      0x00000008
-#define AOFF_task_sigqueue     0x00000860
+#define AOFF_task_sigqueue     0x00000a60
 #define ASIZ_task_sigqueue     0x00000008
-#define AOFF_task_sigqueue_tail        0x00000868
+#define AOFF_task_sigqueue_tail        0x00000a68
 #define ASIZ_task_sigqueue_tail        0x00000008
-#define AOFF_task_has_cpu      0x00000870
+#define AOFF_task_has_cpu      0x00000a70
 #define ASIZ_task_has_cpu      0x00000004
-#define AOFF_task_processor    0x00000874
+#define AOFF_task_processor    0x00000a74
 #define ASIZ_task_processor    0x00000004
-#define AOFF_task_last_processor       0x00000878
+#define AOFF_task_last_processor       0x00000a78
 #define ASIZ_task_last_processor       0x00000004
-#define AOFF_task_lock_depth   0x0000087c
+#define AOFF_task_lock_depth   0x00000a7c
 #define ASIZ_task_lock_depth   0x00000004
-#define AOFF_task_sigmask_lock 0x00000880
-#define ASIZ_task_sigmask_lock 0x00000000
+#define AOFF_task_sigmask_lock 0x00000a80
+#define ASIZ_task_sigmask_lock 0x00000001
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define AOFF_mm_mmap_cache     0x00000008
 #define ASIZ_mm_pgd    0x00000008
 #define AOFF_mm_count  0x00000018
 #define ASIZ_mm_count  0x00000004
+#define AOFF_mm_map_count      0x0000001c
+#define ASIZ_mm_map_count      0x00000004
 #define AOFF_mm_mmap_sem       0x00000020
 #define ASIZ_mm_mmap_sem       0x00000010
 #define AOFF_mm_context        0x00000030
 #define ASIZ_mm_brk    0x00000008
 #define AOFF_mm_start_stack    0x00000068
 #define ASIZ_mm_start_stack    0x00000008
-#define AOFF_mm_start_mmap     0x00000070
-#define ASIZ_mm_start_mmap     0x00000008
-#define AOFF_mm_arg_start      0x00000078
+#define AOFF_mm_arg_start      0x00000070
 #define ASIZ_mm_arg_start      0x00000008
-#define AOFF_mm_arg_end        0x00000080
+#define AOFF_mm_arg_end        0x00000078
 #define ASIZ_mm_arg_end        0x00000008
-#define AOFF_mm_env_start      0x00000088
+#define AOFF_mm_env_start      0x00000080
 #define ASIZ_mm_env_start      0x00000008
-#define AOFF_mm_env_end        0x00000090
+#define AOFF_mm_env_end        0x00000088
 #define ASIZ_mm_env_end        0x00000008
-#define AOFF_mm_rss    0x00000098
+#define AOFF_mm_rss    0x00000090
 #define ASIZ_mm_rss    0x00000008
-#define AOFF_mm_total_vm       0x000000a0
+#define AOFF_mm_total_vm       0x00000098
 #define ASIZ_mm_total_vm       0x00000008
-#define AOFF_mm_locked_vm      0x000000a8
+#define AOFF_mm_locked_vm      0x000000a0
 #define ASIZ_mm_locked_vm      0x00000008
-#define AOFF_mm_def_flags      0x000000b0
+#define AOFF_mm_def_flags      0x000000a8
 #define ASIZ_mm_def_flags      0x00000008
-#define AOFF_mm_cpu_vm_mask    0x000000b8
+#define AOFF_mm_cpu_vm_mask    0x000000b0
 #define ASIZ_mm_cpu_vm_mask    0x00000008
 #define AOFF_thread_ksp        0x00000000
 #define ASIZ_thread_ksp        0x00000008
 #define AOFF_thread_sstk_info  0x00000480
 #define ASIZ_thread_sstk_info  0x00000010
 
+#endif /* __SMP__ */
+
 #endif /* __ASM_OFFSETS_H__ */
index 4337c0193db02eedb5ae06ed57c9eb0c7a3a806e..333f7affeb30c242ad6b7667dfe346a46322fddc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ebus.h,v 1.4 1998/01/10 18:26:08 ecd Exp $
+/* $Id: ebus.h,v 1.5 1998/03/15 10:14:46 ecd Exp $
  * ebus.h: PCI to Ebus pseudo driver software state.
  *
  * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -42,6 +42,9 @@ struct linux_ebus {
        char                             prom_name[64];
        struct linux_prom_ebus_ranges    ebus_ranges[PROMREG_MAX];
        int                              num_ebus_ranges;
+       struct linux_prom_ebus_intmap    ebus_intmap[PROMREG_MAX];
+       int                              num_ebus_intmap;
+       struct linux_prom_ebus_intmask   ebus_intmask;
 };
 
 struct linux_ebus_dma {
index a6891d6810182fe5252f339af81c484ea9c1eaec..509d5c25465e54d5348c67f01f8fd32c13a69c1c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.13 1997/10/03 18:44:14 davem Exp $ */
+/* $Id: elf.h,v 1.17 1998/03/23 10:07:06 jj Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -20,7 +20,7 @@ typedef unsigned long elf_fpregset_t;
  * These are used to set parameters in the core dumps.
  */
 #ifndef ELF_ARCH
-#define ELF_ARCH               EM_SPARC64
+#define ELF_ARCH               EM_SPARCV9
 #define ELF_CLASS              ELFCLASS64
 #define ELF_DATA               ELFDATA2MSB
 #endif
@@ -29,7 +29,7 @@ typedef unsigned long elf_fpregset_t;
  * This is used to ensure we don't load something for the wrong architecture.
  */
 #ifndef elf_check_arch
-#define elf_check_arch(x) ((x) == ELF_ARCH)    /* Might be EM_SPARC64 or EM_SPARC */
+#define elf_check_arch(x) ((x) == ELF_ARCH)    /* Might be EM_SPARCV9 or EM_SPARC */
 #endif
 
 #define USE_ELF_CORE_DUMP
@@ -50,7 +50,8 @@ typedef unsigned long elf_fpregset_t;
 
 /* On Ultra, we support all of the v8 capabilities. */
 #define ELF_HWCAP      (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
-                        HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV)
+                        HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \
+                        HWCAP_SPARC_V9)
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
index e305ccf914a1d67ced486e3c21cff79771d819ab..f72c264c8b0cf4e393bec497b6ed89315b9940e0 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: ide.h,v 1.4 1997/08/30 16:29:29 davem Exp $
+/* $Id: ide.h,v 1.6 1998/03/15 13:29:13 ecd Exp $
  * ide.h: Ultra/PCI specific IDE glue.
  *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998  Eddie C. Dost   (ecd@skynet.be)
  */
 
 #ifndef _SPARC64_IDE_H
@@ -14,42 +15,31 @@ typedef unsigned long ide_ioreg_t;
 #undef  MAX_HWIFS
 #define MAX_HWIFS      2
 
-extern int sparc64_ide_ports_known;
-extern ide_ioreg_t sparc64_ide_regbase[MAX_HWIFS];
-extern ide_ioreg_t sparc64_idedma_regbase; /* one for both channels */
-extern unsigned int sparc64_ide_irq;
-
-extern void sparc64_ide_probe(void);
-
 #define        ide_sti()       sti()
 
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
-       if(sparc64_ide_ports_known == 0)
-               sparc64_ide_probe();
-       return sparc64_ide_irq;
+       return 0;
 }
 
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
-       if(sparc64_ide_ports_known == 0)
-               sparc64_ide_probe();
-       return sparc64_ide_regbase[index];
+       return 0;
 }
 
 static __inline__ void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
 {
-       ide_ioreg_t port = base;
-       int i = 9;
-
-       while(i--)
-               *p++ = port++;
-       if(base == sparc64_ide_regbase[0])
-               *p = sparc64_idedma_regbase + 0x2;
-       else
-               *p = sparc64_idedma_regbase + 0xa;
+       int i;
+
+       /* These are simply offsets from base. */
+       for (i = 0; i < 8; i++)
+               *p++ = base++;
+       /* PCI code needs to figure out these. */
+       for ( ; i < 10; i++)
+               *p++ = 0;
+       /* PCI code needs to figure out this. */
        if(irq != NULL)
-               *irq = sparc64_ide_irq;
+               *irq = 0;
 }
 
 typedef union {
@@ -102,13 +92,7 @@ static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size)
 
 static __inline__ int ide_ack_intr(ide_ioreg_t status_port, ide_ioreg_t irq_port)
 {
-       unsigned char stat = inb(irq_port);
-
-       if(stat & 0x4) {
-               outb((inb(irq_port) & 0x60) | 4, irq_port);
-               return 1;
-       }
-       return 0;
+       return 1;
 }
 
 /* From m68k code... */
index 3316c0c1d77750a17dcd59a4cb5e387f9eb21536..3b8502189c4d8d8cf45bcdb49debba79b0e30e65 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.14 1997/11/01 10:23:58 ecd Exp $ */
+/* $Id: io.h,v 1.16 1998/03/24 05:54:40 ecd Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
 #define __SLOW_DOWN_IO do { } while (0)
 #define SLOW_DOWN_IO   do { } while (0)
 
+extern unsigned long pci_dvma_offset;
+extern unsigned long pci_dvma_mask;
+
 extern __inline__ unsigned long virt_to_phys(volatile void *addr)
 {
-       return ((((unsigned long)addr) - PAGE_OFFSET) | 0x80000000UL);
+       unsigned long vaddr = (unsigned long)addr;
+
+       /* Handle kernel variable pointers... */
+       if (vaddr < PAGE_OFFSET)
+               vaddr += PAGE_OFFSET - (unsigned long)&empty_zero_page;
+       return ((vaddr - PAGE_OFFSET) | pci_dvma_offset);
 }
 
 extern __inline__ void *phys_to_virt(unsigned long addr)
 {
-       return ((void *)((addr & ~0x80000000) + PAGE_OFFSET));
+       return ((void *)((addr & pci_dvma_mask) + PAGE_OFFSET));
 }
 
 #define virt_to_bus virt_to_phys
@@ -91,9 +99,9 @@ extern void insw(unsigned long addr, void *dst, unsigned long count);
 extern void insl(unsigned long addr, void *dst, unsigned long count);
 
 /* Memory functions, same as I/O accesses on Ultra. */
-#define readb(addr)            inb((unsigned long)addr)
-#define readw(addr)            inw((unsigned long)addr)
-#define readl(addr)            inl((unsigned long)addr)
+#define readb(addr)            inb((unsigned long)(addr))
+#define readw(addr)            inw((unsigned long)(addr))
+#define readl(addr)            inl((unsigned long)(addr))
 #define writeb(b, addr)                outb((b), (unsigned long)(addr))
 #define writew(w, addr)                outw((w), (unsigned long)(addr))
 #define writel(l, addr)                outl((l), (unsigned long)(addr))
index c06f75ad072511b53ea5a9bb089901eb1e5569ff..f385ef9beee130e2b42cc1cf847772dabecf17ed 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctls.h,v 1.6 1997/12/16 19:20:58 davem Exp $ */
+/* $Id: ioctls.h,v 1.7 1998/02/23 02:49:41 davem Exp $ */
 #ifndef _ASM_SPARC64_IOCTLS_H
 #define _ASM_SPARC64_IOCTLS_H
 
index 1b36e2323f9caf756dbbab3a46ffe4d68f15293e..b7e6f2d23d860b8e26105c6a02bfddd8d085a46a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.7 1997/09/07 02:56:44 davem Exp $
+/* $Id: irq.h,v 1.8 1998/03/15 17:23:51 ecd Exp $
  * irq.h: IRQ registers on the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -39,7 +39,8 @@ struct devid_cookie {
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
-extern void init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *));
+extern void init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *),
+                       unsigned long *);
 
 #ifdef __SMP__
 extern void set_cpu_int(int, int);
@@ -75,4 +76,9 @@ extern __inline__ unsigned long get_softint(void)
        return retval;
 }
 
+static __inline__ int irq_cannonicalize(int irq)
+{
+       return irq;
+}
+
 #endif
index 453f73217cd18aa473c2f71903fe843468ca1649..2c9c88ce2bdd237a9197eea2ca4e8031082f642d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.10 1997/09/24 16:20:41 jj Exp $
+/* $Id: namei.h,v 1.12 1998/03/13 17:38:13 jj Exp $
  * linux/include/asm-sparc64/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -10,7 +10,6 @@
 
 #define SPARC_BSD_EMUL "usr/gnemul/sunos/"
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
-#define SPARC_LIN_EMUL "usr/gnemul/linux32/"
 
 static inline struct dentry *
 __sparc64_lookup_dentry(const char *name, int follow_link)
@@ -19,12 +18,13 @@ __sparc64_lookup_dentry(const char *name, int follow_link)
        char *emul;
 
        switch (current->personality) {
+#if 0
+/* Until we solve, why SunOS apps sometime crash, disable gnemul support for SunOS */
        case PER_BSD:
                emul = SPARC_BSD_EMUL; break;
+#endif         
        case PER_SVR4:
                emul = SPARC_SOL_EMUL; break;
-       case PER_LINUX32:
-               emul = SPARC_LIN_EMUL; break;
        default:
                return NULL;
        }
index 5855ddfec14b7bbe9da8ae28f207454127065c7c..3218e00dd54bc9f9f14e14eb1bbb4d9f604aae66 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.6 1997/08/17 22:40:09 ecd Exp $ */
+/* $Id: openprom.h,v 1.7 1998/03/15 10:14:47 ecd Exp $ */
 #ifndef __SPARC64_OPENPROM_H
 #define __SPARC64_OPENPROM_H
 
@@ -232,6 +232,24 @@ struct linux_prom_pci_ranges {
        unsigned int size_lo;
 };
 
+struct linux_prom_pci_intmap {
+       unsigned int phys_hi;
+       unsigned int phys_mid;
+       unsigned int phys_lo;
+
+       unsigned int interrupt;
+
+       int          cnode;
+       unsigned int cinterrupt;
+};
+
+struct linux_prom_pci_intmask {
+       unsigned int phys_hi;
+       unsigned int phys_mid;
+       unsigned int phys_lo;
+       unsigned int interrupt;
+};
+
 struct linux_prom_ebus_ranges {
        unsigned int child_phys_hi;
        unsigned int child_phys_lo;
@@ -243,6 +261,21 @@ struct linux_prom_ebus_ranges {
        unsigned int size;
 };
 
+struct linux_prom_ebus_intmap {
+       unsigned int phys_hi;
+       unsigned int phys_lo;
+
+       unsigned int interrupt;
+
+       int          cnode;
+       unsigned int cinterrupt;
+};
+
+struct linux_prom_ebus_intmask {
+       unsigned int phys_hi;
+       unsigned int phys_lo;
+       unsigned int interrupt;
+};
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC64_OPENPROM_H) */
index 70b787ced557e1a17b46af656859997864d940ba..86ec1477d4d9bed90f7f2cebf76604042dba7077 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.16 1997/11/28 15:59:34 jj Exp $ */
+/* $Id: page.h,v 1.17 1998/01/14 17:16:28 jj Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -31,16 +31,16 @@ extern void copy_page(unsigned long to, unsigned long from);
 /* These are used to make use of C type-checking.. */
 typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long iopte; } iopte_t;
-typedef struct { unsigned long pmd; } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned int pmd; } pmd_t;
+typedef struct { unsigned int pgd; } pgd_t;
 typedef struct { unsigned long ctxd; } ctxd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 typedef struct { unsigned long iopgprot; } iopgprot_t;
 
 #define pte_val(x)     ((x).pte)
 #define iopte_val(x)   ((x).iopte)
-#define pmd_val(x)      ((x).pmd)
-#define pgd_val(x)     ((x).pgd)
+#define pmd_val(x)      ((unsigned long)(x).pmd)
+#define pgd_val(x)     ((unsigned long)(x).pgd)
 #define ctxd_val(x)    ((x).ctxd)
 #define pgprot_val(x)  ((x).pgprot)
 #define iopgprot_val(x)        ((x).iopgprot)
@@ -57,16 +57,16 @@ typedef struct { unsigned long iopgprot; } iopgprot_t;
 /* .. while these make it easier on the compiler */
 typedef unsigned long pte_t;
 typedef unsigned long iopte_t;
-typedef unsigned long pmd_t;
-typedef unsigned long pgd_t;
+typedef unsigned int pmd_t;
+typedef unsigned int pgd_t;
 typedef unsigned long ctxd_t;
 typedef unsigned long pgprot_t;
 typedef unsigned long iopgprot_t;
 
 #define pte_val(x)     (x)
 #define iopte_val(x)   (x)
-#define pmd_val(x)      (x)
-#define pgd_val(x)     (x)
+#define pmd_val(x)      ((unsigned long)(x))
+#define pgd_val(x)     ((unsigned long)(x))
 #define ctxd_val(x)    (x)
 #define pgprot_val(x)  (x)
 #define iopgprot_val(x)        (x)
@@ -83,7 +83,7 @@ typedef unsigned long iopgprot_t;
 
 #define TASK_UNMAPPED_BASE     ((current->tss.flags & SPARC_FLAG_32BIT) ? \
                                 (0x0000000070000000UL) : \
-                                (0x0000030000000000UL))
+                                (0xfffff80000000000UL))
 
 #endif /* !(__ASSEMBLY__) */
 
index 0c09bd338688d901d4c6dae75cc4c5fedcb1cfdf..3adcc9583f055a1da71c04b881476d67ec00177e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pbm.h,v 1.8 1998/01/10 18:26:10 ecd Exp $
+/* $Id: pbm.h,v 1.12 1998/04/10 12:29:55 ecd Exp $
  * pbm.h: U2P PCI bus module pseudo driver software state.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -7,7 +7,6 @@
 #ifndef __SPARC64_PBM_H
 #define __SPARC64_PBM_H
 
-#include <linux/bios32.h>
 #include <linux/pci.h>
 
 #include <asm/psycho.h>
@@ -25,7 +24,7 @@ struct pci_vma {
        struct linux_pbm_info           *pbm;
        unsigned int                    start;
        unsigned int                    end;
-       unsigned int                    base_reg;
+       unsigned int                    offset;
        unsigned int                    _pad;
 };
 
@@ -39,6 +38,9 @@ struct linux_pbm_info {
        char                            prom_name[64];
        struct linux_prom_pci_ranges    pbm_ranges[PROMREG_MAX];
        int                             num_pbm_ranges;
+       struct linux_prom_pci_intmap    pbm_intmap[PROMREG_MAX];
+       int                             num_pbm_intmap;
+       struct linux_prom_pci_intmask   pbm_intmask;
 
        /* Now things for the actual PCI bus probes. */
        unsigned int                    pci_first_busno;
@@ -56,6 +58,11 @@ struct linux_psycho {
        int                             index;
        struct linux_pbm_info           pbm_A;
        struct linux_pbm_info           pbm_B;
+
+       /* Now things for the actual PCI bus probes. */
+       unsigned int                    pci_first_busno;
+       unsigned int                    pci_last_busno;
+       struct pci_bus                  *pci_bus;
 };
 
 /* PCI devices which are not bridges have this placed in their pci_dev
@@ -86,7 +93,7 @@ psycho_by_index(int index)
 #define PCI_IRQ_IDENT          0x80000000      /* This tells irq.c what we are        */
 #define PCI_IRQ_IMAP_OFF       0x7ff00000      /* Offset from first PSYCHO imap       */
 #define PCI_IRQ_IMAP_OFF_SHFT  20
-#define PCI_IRQ_BUSNO          0x000fc000      /* PSYCHO instance, currently unused   */
+#define PCI_IRQ_BUSNO          0x000fc000      /* PSYCHO instance                     */
 #define PCI_IRQ_BUSNO_SHFT     14
 #define PCI_IRQ_IGN            0x000007c0      /* PSYCHO "Int Group Number"           */
 #define PCI_IRQ_INO            0x0000003f      /* PSYCHO INO                          */
index c8457175284a981ec27019a3a07266512cea5696..c57eb06cfc840a0e931e781a0e15415292adae0a 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: pgtable.h,v 1.59 1997/10/12 06:20:43 davem Exp $
+/* $Id: pgtable.h,v 1.64 1998/02/16 14:06:44 jj Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #ifndef _SPARC64_PGTABLE_H
 #define PMD_MASK       (~(PMD_SIZE-1))
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT    (PAGE_SHIFT + 2*(PAGE_SHIFT-3))
+#define PGDIR_SHIFT    (PAGE_SHIFT + (PAGE_SHIFT-3) + (PAGE_SHIFT-2))
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
 /* Entries per page directory level. */
-#define PTRS_PER_PTE   (1UL << (PAGE_SHIFT-3))
-#define PTRS_PER_PMD   (1UL << (PAGE_SHIFT-3))
-#define PTRS_PER_PGD   (1UL << (PAGE_SHIFT-3))
+#define PTRS_PER_PTE           (1UL << (PAGE_SHIFT-3))
+#define PTRS_PER_PMD           (1UL << (PAGE_SHIFT-2))
+/* We cannot use the top 16G because a half of mm/ would break, so why to check it */
+#define PTRS_PER_PGD           ((1UL << (PAGE_SHIFT-3))-1)
+#define USER_PTRS_PER_PGD      PTRS_PER_PGD    /* Kernel has a separate 44bit address space */
 
 #define PTE_TABLE_SIZE 0x2000  /* 1024 entries 8 bytes each */
-#define PMD_TABLE_SIZE 0x2000  /* 1024 entries 8 bytes each */
-#define PGD_TABLE_SIZE 0x2000  /* 1024 entries 8 bytes each */
+#define PMD_TABLE_SIZE 0x2000  /* 2048 entries 4 bytes each */
+#define PGD_TABLE_SIZE 0x1000  /* 1024 entries 4 bytes each */
 
 /* the no. of pointers that fit on a page */
 #define PTRS_PER_PAGE  (1UL << (PAGE_SHIFT-3))
@@ -141,7 +144,7 @@ extern pte_t *__bad_pte(void);
 #define BAD_PTE                __bad_pte()
 #define BAD_PAGE       __bad_page()
 
-/* First phsical page can be anywhere, the following is needed so that
+/* First physical page can be anywhere, the following is needed so that
  * va-->pa and vice versa conversions work properly without performance
  * hit for all __pa()/__va() operations.
  */
@@ -149,8 +152,8 @@ extern unsigned long phys_base;
 #define ZERO_PAGE      ((unsigned long)__va(phys_base))
 
 /* This is for making TLB miss faster to process. */
-extern unsigned long null_pmd_table;
-extern unsigned long null_pte_table;
+#define null_pmd_table (null_pte_table - PAGE_SIZE)
+extern unsigned int null_pte_table;
 
 /* Allocate a block of RAM which is aligned to its size.
    This procedure can be used until the call to mem_init(). */
@@ -198,7 +201,7 @@ extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long
        struct mm_struct *mm = vma->vm_mm;
 
        if(mm->context != NO_CONTEXT)
-               __flush_tlb_page(mm->context & 0x1fff, page);
+               __flush_tlb_page(mm->context & 0x1fff, page & PAGE_MASK);
 }
 
 #else /* __SMP__ */
@@ -260,7 +263,7 @@ extern inline unsigned long pmd_page(pmd_t pmd)
 extern inline unsigned long pgd_page(pgd_t pgd)
 { return (unsigned long) __va(pgd_val(pgd)); }
 
-#define PMD_NONE_MAGIC         0x80
+#define PMD_NONE_MAGIC         0x40
 #define PGD_NONE_MAGIC         0x40
 
 extern inline int pte_none(pte_t pte)          { return !pte_val(pte); }
@@ -323,18 +326,18 @@ extern inline pte_t pte_mkyoung(pte_t pte)
 
 /* to find an entry in a page-table-directory. */
 extern inline pgd_t *pgd_offset(struct mm_struct *mm, unsigned long address)
-{ return mm->pgd + ((address >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1)); }
+{ return mm->pgd + ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD)); }
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* Find an entry in the second-level page table.. */
 extern inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
-{ return (pmd_t *) pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1)); }
+{ return (pmd_t *) pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); }
 
 /* Find an entry in the third-level page table.. */
 extern inline pte_t *pte_offset(pmd_t *dir, unsigned long address)
-{ return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1)); }
+{ return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); }
 
 /* Very stupidly, we used to get new pgd's and pmd's, init their contents
  * to point to the NULL versions of the next level page table, later on
@@ -345,79 +348,97 @@ extern inline pte_t *pte_offset(pmd_t *dir, unsigned long address)
 
 #ifdef __SMP__
 /* Sliiiicck */
-#define pgd_quicklist          (cpu_data[smp_processor_id()].pgd_cache)
-#define pmd_quicklist          (cpu_data[smp_processor_id()].pmd_cache)
-#define pte_quicklist          (cpu_data[smp_processor_id()].pte_cache)
-#define pgtable_cache_size     (cpu_data[smp_processor_id()].pgcache_size)
+#define pgt_quicklists cpu_data[smp_processor_id()]
 #else
-extern unsigned long *pgd_quicklist;
-extern unsigned long *pmd_quicklist;
-extern unsigned long *pte_quicklist;
-extern unsigned long pgtable_cache_size;
+extern struct pgtable_cache_struct {
+       unsigned long *pgd_cache;
+       unsigned long *pmd_cache;
+       unsigned long *pte_cache;
+       unsigned long pgcache_size;
+} pgt_quicklists;
 #endif
+#define pgd_quicklist          (pgt_quicklists.pgd_cache)
+#define pmd_quicklist          (pgt_quicklists.pmd_cache)
+#define pte_quicklist          (pgt_quicklists.pte_cache)
+#define pgtable_cache_size     (pgt_quicklists.pgcache_size)
 
 extern pgd_t *get_pgd_slow(void);
 
 extern __inline__ pgd_t *get_pgd_fast(void)
 {
-       pgd_t *ret;
+       unsigned long *ret;
 
-       if((ret = (pgd_t *)pgd_quicklist) != NULL) {
-               pgd_quicklist = (unsigned long *)pgd_val(*ret);
-               pgd_val(ret[0]) = pgd_val(ret[1]);
-               (pgtable_cache_size)--;
+       if((ret = pgd_quicklist) != NULL) {
+               pgd_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
        } else
-               ret = get_pgd_slow();
-       return ret;
+               ret = (unsigned long *)get_pgd_slow();
+       return (pgd_t *)ret;
 }
 
 extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
-       pgd_val(*pgd) = (unsigned long) pgd_quicklist;
+       *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
        pgd_quicklist = (unsigned long *) pgd;
-       (pgtable_cache_size)++;
+       pgtable_cache_size++;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+       free_page((unsigned long)pgd);
 }
 
 extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
 
 extern __inline__ pmd_t *get_pmd_fast(void)
 {
-       pmd_t *ret;
+       unsigned long *ret;
 
-       if((ret = (pmd_t *)pmd_quicklist) != NULL) {
-               pmd_quicklist = (unsigned long *)pmd_val(*ret);
-               pmd_val(ret[0]) = pmd_val(ret[1]);
-               (pgtable_cache_size)--;
+       if((ret = (unsigned long *)pmd_quicklist) != NULL) {
+               pmd_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
        }
-       return ret;
+       return (pmd_t *)ret;
 }
 
 extern __inline__ void free_pmd_fast(pgd_t *pmd)
 {
-       pmd_val(*pmd) = (unsigned long) pmd_quicklist;
+       *(unsigned long *)pmd = (unsigned long) pmd_quicklist;
        pmd_quicklist = (unsigned long *) pmd;
-       (pgtable_cache_size)++;
+       pgtable_cache_size++;
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+       free_page((unsigned long)pmd);
 }
 
 extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
 
 extern __inline__ pte_t *get_pte_fast(void)
 {
-       pte_t *ret;
+       unsigned long *ret;
 
-       if((ret = (pte_t *)pte_quicklist) != NULL) {
-               pte_quicklist = (unsigned long *)pte_val(*ret);
-               pte_val(ret[0]) = pte_val(ret[1]);
-               (pgtable_cache_size)--;
+       if((ret = (unsigned long *)pte_quicklist) != NULL) {
+               pte_quicklist = (unsigned long *)(*ret);
+               ret[0] = ret[1];
+               pgtable_cache_size--;
        }
-       return ret;
+       return (pte_t *)ret;
 }
 
 extern __inline__ void free_pte_fast(pte_t *pte)
 {
-       pte_val(*pte) = (unsigned long) pte_quicklist;
+       *(unsigned long *)pte = (unsigned long) pte_quicklist;
        pte_quicklist = (unsigned long *) pte;
-       (pgtable_cache_size)++;
+       pgtable_cache_size++;
+}
+
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+       free_page((unsigned long)pte);
 }
 
 #define pte_free_kernel(pte)   free_pte_fast(pte)
@@ -458,6 +479,11 @@ extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
 #define pte_alloc_kernel(pmd, addr)    pte_alloc(pmd, addr)
 #define pmd_alloc_kernel(pgd, addr)    pmd_alloc(pgd, addr)
 
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+       /* Nothing to do on sparc64 :) */
+}
+
 extern pgd_t swapper_pg_dir[1024];
 
 extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir)
@@ -570,6 +596,10 @@ __get_iospace (unsigned long addr)
 
 extern void * module_map (unsigned long size);
 extern void module_unmap (void *addr);
+extern void module_shrink (void *addr, unsigned long size);
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define PageSkip(page)         (test_bit(PG_skip, &(page)->flags))
 
 #endif /* !(__ASSEMBLY__) */
 
index ba2ab11b072b8c2ee5ecbcca37b39cdf571de1a5..fd1a5fc9a5979f1e03b994f0fcaf04bd340fe851 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.40 1997/10/24 11:57:59 jj Exp $
+/* $Id: processor.h,v 1.42 1998/01/28 10:00:04 ecd Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
 
 /* User lives in his very own context, and cannot reference us. */
-#define TASK_SIZE      ((1UL << (PAGE_SHIFT - 3)) * PGDIR_SIZE)
+#ifndef __ASSEMBLY__
+#define TASK_SIZE      ((unsigned long)-PGDIR_SIZE)
+#else
+#define TASK_SIZE      0xfffffffc00000000
+#endif
 
 #define COPY_TASK_STRUCT(dst, src)                                                                             \
 do {                                                                                                           \
index 46bcd464062f032c06744b8b6909c4b94f9fb493..35c5c89c3d291e966c28fae06198f9f333b61c80 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: psycho.h,v 1.2 1997/08/11 14:35:40 davem Exp $
+/* $Id: psycho.h,v 1.3 1998/03/15 13:24:28 ecd Exp $
  * psycho.h: UltraSparc AX specific PCI definitions.
  *
  * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -42,47 +42,47 @@ struct psycho_regs {
                u64     __pad4[0x13d];
 
                /* Interrupt mapping/control registers */
-/*0x0c00*/     u64     imap_a_slot0;   /* PCI A Slot 0 Int Mapping */
-/*0x0c08*/     u64     imap_a_slot1;   /* PCI A Slot 1 Int Mapping */
+/*0x0c00*/     u64     imap_a_slot0;   /* PCI A Slot 0 Int Mapping     */
+/*0x0c08*/     u64     imap_a_slot1;   /* PCI A Slot 1 Int Mapping     */
+/*0x0c10*/     u64     imap_a_slot2;   /* PCI A Slot 2 Int Mapping (IIi only)*/
+/*0x0c18*/     u64     imap_a_slot3;   /* PCI A Slot 3 Int Mapping (IIi only)*/
 
-               u64     __pad5[0x2];
-
-/*0x0c20*/     u64     imap_b_slot0;   /* PCI B Slot 0 Int Mapping */
-/*0x0c28*/     u64     imap_b_slot1;   /* PCI B Slot 1 Int Mapping */
-/*0x0c30*/     u64     imap_b_slot2;   /* PCI B Slot 2 Int Mapping */
-/*0x0c38*/     u64     imap_b_slot3;   /* PCI B Slot 3 Int Mapping */
+/*0x0c20*/     u64     imap_b_slot0;   /* PCI B Slot 0 Int Mapping     */
+/*0x0c28*/     u64     imap_b_slot1;   /* PCI B Slot 1 Int Mapping     */
+/*0x0c30*/     u64     imap_b_slot2;   /* PCI B Slot 2 Int Mapping     */
+/*0x0c38*/     u64     imap_b_slot3;   /* PCI B Slot 3 Int Mapping     */
 
                u64     __pad6[0x78];
 
-/*0x1000*/     u64     imap_scsi;      /* SCSI Int Mapping     */
-/*0x1008*/     u64     imap_eth;       /* Ethernet Int Mapping */
-/*0x1010*/     u64     imap_bpp;       /* Parallel Port Int Mapping */
-/*0x1018*/     u64     imap_au_rec;    /* Audio Record Int Mapping */
-/*0x1020*/     u64     imap_au_play;   /* Audio Playback Int Mapping */
-/*0x1028*/     u64     imap_pfail;     /* Power Fail Int Mapping */
-/*0x1030*/     u64     imap_kms;       /* Kbd/Mouse/Ser Int Mapping */
-/*0x1038*/     u64     imap_flpy;      /* Floppy Int Mapping    */
-/*0x1040*/     u64     imap_shw;       /* Spare HW Int Mapping */
-/*0x1048*/     u64     imap_kbd;       /* Kbd Only Int Mapping */
-/*0x1050*/     u64     imap_ms;        /* Mouse Only Int Mapping */
-/*0x1058*/     u64     imap_ser;       /* Serial Only Int Mapping */
-/*0x1060*/     u64     imap_tim0;      /* Timer 0 Int Mapping  */
-/*0x1068*/     u64     imap_tim1;      /* Timer 1 Int Mapping  */
-/*0x1070*/     u64     imap_ue;        /* UE Int Mapping       */
-/*0x1078*/     u64     imap_ce;        /* CE Int Mapping       */
-/*0x1080*/     u64     imap_a_err;     /* PCI A Err Int Mapping */
-/*0x1088*/     u64     imap_b_err;     /* PCI B Err Int Mapping */
-/*0x1090*/     u64     imap_pmgmt;     /* Power Mgmt Int Mapping */
-/*0x1098*/     u64     imap_gfx;       /* OB Graphics Int Mapping */
-/*0x10a0*/     u64     imap_eupa;      /* UPA Expansion Int Mapping */
+/*0x1000*/     u64     imap_scsi;      /* SCSI Int Mapping             */
+/*0x1008*/     u64     imap_eth;       /* Ethernet Int Mapping         */
+/*0x1010*/     u64     imap_bpp;       /* Parallel Port Int Mapping    */
+/*0x1018*/     u64     imap_au_rec;    /* Audio Record Int Mapping     */
+/*0x1020*/     u64     imap_au_play;   /* Audio Playback Int Mapping   */
+/*0x1028*/     u64     imap_pfail;     /* Power Fail Int Mapping       */
+/*0x1030*/     u64     imap_kms;       /* Kbd/Mouse/Ser Int Mapping    */
+/*0x1038*/     u64     imap_flpy;      /* Floppy Int Mapping           */
+/*0x1040*/     u64     imap_shw;       /* Spare HW Int Mapping         */
+/*0x1048*/     u64     imap_kbd;       /* Kbd Only Int Mapping         */
+/*0x1050*/     u64     imap_ms;        /* Mouse Only Int Mapping       */
+/*0x1058*/     u64     imap_ser;       /* Serial Only Int Mapping      */
+/*0x1060*/     u64     imap_tim0;      /* Timer 0 Int Mapping          */
+/*0x1068*/     u64     imap_tim1;      /* Timer 1 Int Mapping          */
+/*0x1070*/     u64     imap_ue;        /* UE Int Mapping               */
+/*0x1078*/     u64     imap_ce;        /* CE Int Mapping               */
+/*0x1080*/     u64     imap_a_err;     /* PCI A Err Int Mapping        */
+/*0x1088*/     u64     imap_b_err;     /* PCI B Err Int Mapping        */
+/*0x1090*/     u64     imap_pmgmt;     /* Power Mgmt Int Mapping       */
+/*0x1098*/     u64     imap_gfx;       /* OB Graphics Int Mapping      */
+/*0x10a0*/     u64     imap_eupa;      /* UPA Expansion Int Mapping    */
 
                u64     __pad7[0x6b];
 
                /* Interrupt Clear Registers */
 /*0x1400*/     u64     iclr_a_slot0[4];        /* PCI A Slot 0 Clear Int Reg */
 /*0x1420*/     u64     iclr_a_slot1[4];        /* PCI A Slot 1 Clear Int Reg */
-
-               u64     __pad8[0x8];
+/*0x1440*/     u64     iclr_a_slot2[4];        /* PCI A Slot 2 Clear Int Reg */
+/*0x1460*/     u64     iclr_a_slot3[4];        /* PCI A Slot 3 Clear Int Reg */
 
 /*0x1480*/     u64     iclr_b_slot0[4];        /* PCI B Slot 0 Clear Int Reg */
 /*0x14a0*/     u64     iclr_b_slot1[4];        /* PCI B Slot 1 Clear Int Reg */
@@ -123,8 +123,9 @@ struct psycho_regs {
 /*0x1c08*/     u64     tim0_lim;
 /*0x1c10*/     u64     tim1_cnt;
 /*0x1c18*/     u64     tim1_lim;
+/*0x1c20*/     u64     pci_dma_wsync;  /* PCI DMA Write Sync Register (IIi) */
 
-               u64     __pad12[0x7c];
+               u64     __pad12[0x7b];
 
                /* PCI Bus A Registers */
 /*0x2000*/     u64     pci_a_control;  /* PCI Bus A Control Register   */
@@ -132,8 +133,9 @@ struct psycho_regs {
 /*0x2010*/     u64     pci_a_afsr;     /* PCI Bus A Async Fault Status */
 /*0x2018*/     u64     pci_a_afar;     /* PCI Bus A Async Fault Address*/
 /*0x2020*/     u64     pci_a_diag;     /* PCI Bus A Diag Register      */
+/*0x2028*/     u64     pci_tasr;       /* PCI Target Address Space Reg (IIi) */
 
-               u64     __pad14[0xfb];
+               u64     __pad14[0xfa];
 
                /* PCI Bus A/IOMMU Streaming Buffer Registers */
 /*0x2800*/     u64     sbuf_a_control; /* StrBuffer Control            */
index 2c89a84ba5d909b9a1bc9c953c7cfc4cca7178bb..95aa09edea4d90fbfca9c8501a09060f86d80322 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.5 1997/08/12 04:13:16 ecd Exp $
+/* $Id: sbus.h,v 1.6 1998/03/09 14:05:03 jj Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -49,8 +49,7 @@ struct linux_sbus_device {
   struct linux_sbus_device *child;     /* For ledma and espdma on sun4m */
   struct linux_sbus *my_bus;           /* Back ptr to sbus */
   int prom_node;                       /* PROM device tree node for this device */
-  char prom_name[64];                  /* PROM device name */
-  char linux_name[64];                 /* Name used internally by Linux */
+  char prom_name[32];                  /* PROM device name */
 
   struct linux_prom_registers reg_addrs[PROMREG_MAX];
   int num_registers, ranges_applied;
index 363be0fe9715ee08c02ec97df9a8192b59eb1b4b..53121ff1c76a5a34e0e7d567a09f325cf8d01933 100644 (file)
@@ -74,7 +74,12 @@ extern void smp_boot_cpus(void);
 extern void smp_store_cpu_info(int id);
 
 extern __volatile__ int cpu_number_map[NR_CPUS];
-extern __volatile__ int cpu_logical_map[NR_CPUS];
+extern __volatile__ int __cpu_logical_map[NR_CPUS];
+
+extern __inline__ int cpu_logical_map(int cpu)
+{
+       return __cpu_logical_map[cpu];
+}
 
 extern __inline__ int hard_smp_processor_id(void)
 {
@@ -88,10 +93,19 @@ extern __inline__ int hard_smp_processor_id(void)
 
 #define smp_processor_id() (current->processor)
 
+extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
+
 #endif /* !(__ASSEMBLY__) */
 
 #define PROC_CHANGE_PENALTY    20
 
+#else /* !(__SMP__) */
+#ifndef __ASSEMBLY__ 
+extern __inline__ int cpu_logical_map(int cpu)
+{
+       return cpu;
+}
+#endif 
 #endif /* !(__SMP__) */
 
 #define NO_PROC_ID             0xFF
index 397d6bf50e099e9da06cf173437de2c432bb7981..1357489b45a41a57f588fdca58f71d99ef0ed29c 100644 (file)
@@ -20,8 +20,8 @@
 
 extern int __sparc64_bh_counter;
 
-#define softirq_trylock()      (__sparc64_bh_counter ? 0 : (__sparc64_bh_counter=1))
-#define softirq_endlock()      (__sparc64_bh_counter = 0)
+#define softirq_trylock(cpu)   (__sparc64_bh_counter ? 0 : (__sparc64_bh_counter=1))
+#define softirq_endlock(cpu)   (__sparc64_bh_counter = 0)
 #define clear_active_bhs(x)    (bh_active &= ~(x))
 
 #define init_bh(nr, routine)   \
@@ -114,7 +114,7 @@ do {        unsigned long flags;                            \
        spin_unlock_irqrestore(&global_bh_lock, flags); \
 } while(0)
 
-#define softirq_trylock()                                      \
+#define softirq_trylock(cpu)                                   \
 ({                                                             \
        int ret = 1;                                            \
        if(atomic_add_return(1, &__sparc64_bh_counter) != 1) {  \
@@ -123,7 +123,7 @@ do {        unsigned long flags;                            \
        }                                                       \
        ret;                                                    \
 })
-#define softirq_endlock()      atomic_dec(&__sparc64_bh_counter)
+#define softirq_endlock(cpu)   atomic_dec(&__sparc64_bh_counter)
 #define clear_active_bhs(mask)                         \
 do {   unsigned long flags;                            \
        spin_lock_irqsave(&global_bh_lock, flags);      \
index 0d832252564b573cbe8cbaff61ada1c624f2d8b1..05853d3b5438266937fc67657c2b96ea00f98a25 100644 (file)
@@ -1,8 +1,9 @@
-/* $Id: stat.h,v 1.3 1997/04/18 14:34:43 jj Exp $ */
+/* $Id: stat.h,v 1.4 1998/02/06 12:52:14 jj Exp $ */
 #ifndef _SPARC64_STAT_H
 #define _SPARC64_STAT_H
 
 #include <linux/types.h>
+#include <linux/time.h>
 
 struct stat32 {
        __kernel_dev_t32   st_dev;
@@ -41,4 +42,54 @@ struct stat {
        unsigned long  __unused4[2];
 };
 
+typedef __u64  __new_dev_t;
+
+struct stat64 {
+       __new_dev_t     st_dev;
+       __u64           st_ino;
+       __u32           st_mode;
+       __u32           st_nlink;
+       __s32           st_uid;
+       __s32           st_gid;
+       __new_dev_t     st_rdev;
+       __s64           st_size;
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+       int             st_blksize;
+       long            st_blocks;
+       char            st_fstype[16];
+};
+
+struct stat64_32 {
+       __new_dev_t     st_dev;
+       __u64           st_ino;
+       __u32           st_mode;
+       __u32           st_nlink;
+       __s32           st_uid;
+       __s32           st_gid;
+       __new_dev_t     st_rdev;
+       __s64           st_size;
+       __u64           st_blocks;
+       __s32           st_atime;
+       __u32           __unused1;
+       __s32           st_mtime;
+       __u32           __unused2;
+       __s32           st_ctime;
+       __u32           __unused3;
+       __u32           st_blksize;
+       __u32           __unused4;
+};
+
+#define __XSTAT_VER_1          1
+#define __XSTAT_VER_2          2
+#define __XSTAT_VER_MASK       0xff
+
+#define __XSTAT_VER_XSTAT      0x000
+#define __XSTAT_VER_LXSTAT     0x100
+#define __XSTAT_VER_FXSTAT     0x200
+#define __XSTAT_VER_TYPEMASK   0xff00
+
+#define __XMKNOD_VER_1         1
+
 #endif
index a1dd295130e398c3ae3c6eabc21f3de9258cfbed..5bec8802889accb515d19ee2ffce478a8aaf28f5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.37 1997/10/20 00:14:22 davem Exp $ */
+/* $Id: system.h,v 1.38 1998/01/30 11:00:11 jj Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -22,7 +22,10 @@ enum sparc_cpu {
 };
                   
 #define sparc_cpu_model sun4u
-                  
+
+/* This cannot ever be a sun4c nor sun4 :) That's just history. */
+#define ARCH_SUN4C_SUN4 0
+#define ARCH_SUN4 0
 
 extern unsigned long empty_bad_page;
 extern unsigned long empty_bad_pmd_table;
index 860ae6db4b698dea043e7332fdd25383e5d244ba..2d1067c7d875539bab997bccf710010016868730 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: timer.h,v 1.1 1997/07/23 10:38:00 davem Exp $
+/* $Id: timer.h,v 1.2 1998/03/15 17:23:52 ecd Exp $
  * timer.h: System timer definitions for sun5.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -48,4 +48,9 @@ struct sun5_timer {
  */
 #define SUN5_HZ_TO_LIMIT(__hz)  (1000000/(__hz))
 
+#ifdef __SMP__
+extern unsigned long timer_tick_offset;
+extern void timer_tick_interrupt(struct pt_regs *);
+#endif
+
 #endif /* _SPARC64_TIMER_H */
index 10840dc579670177ccbc57abf591a41e272f2813..82e3600429d24a939042a2e24040ff41dacce305 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.5 1997/10/14 16:21:34 jj Exp $ */
+/* $Id: ttable.h,v 1.6 1998/03/15 17:23:54 ecd Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
         add    %sp, STACK_BIAS + REGWIN_SZ, %o1;       \
        ba,a,pt %xcc, rtrap_clr_l6;
 
-#ifdef __SMP__
-#define TRAP_TICK                                      \
-       rdpr    %pil, %g2;                              \
-       wrpr    %g0, 15, %pil;                          \
-       b,pt    %xcc, etrap_irq;                        \
-        rd     %pc, %g7;                               \
-       call    smp_percpu_timer_interrupt;             \
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       b,pt    %xcc, rtrap;                            \
-        clr    %l6;
-#else
-#define TRAP_TICK      TRAP_IRQ(handler_irq, 14)
-#endif
-
 #define TRAP_IVEC TRAP_NOSAVE(do_ivec)
 
 #define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
index 70b12d890e6be1df9f48c86c086aa96953a04b97..ca749ffd9e209d96121f3f94f63522ceecef5c14 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.14 1997/12/11 15:16:08 jj Exp $ */
+/* $Id: unistd.h,v 1.17 1998/03/29 12:57:54 ecd Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
 #define __NR_unlink              10 /* Common                                      */
 #define __NR_execv               11 /* SunOS Specific                              */
 #define __NR_chdir               12 /* Common                                      */
-/* #define __NR_ni_syscall       13    ENOSYS under SunOS                          */
+#define __NR_xstat              13 /* Linux Specific                              */
 #define __NR_mknod               14 /* Common                                      */
 #define __NR_chmod               15 /* Common                                      */
 #define __NR_chown               16 /* Common                                      */
 #define __NR_brk                 17 /* Common                                      */
-/* #define __NR_ni_syscall       18    ENOSYS under SunOS                          */
+#define __NR_xmknod             18 /* Linux Specific                              */
 #define __NR_lseek               19 /* Common                                      */
 #define __NR_getpid              20 /* Common                                      */
 /* #define __NR_ni_syscall       21    ENOSYS under SunOS                          */
 /* #define __NR_ni_syscall       22    ENOSYS under SunOS                          */
 #define __NR_setuid              23 /* Implemented via setreuid in SunOS           */
 #define __NR_getuid              24 /* Common                                      */
-/* #define __NR_ni_syscall       25    ENOSYS under SunOS                          */
+/* #define __NR_time alias      25    ENOSYS under SunOS                          */
 #define __NR_ptrace              26 /* Common                                      */
 #define __NR_alarm               27 /* Implemented via setitimer in SunOS          */
 /* #define __NR_ni_syscall       28    ENOSYS under SunOS                          */
@@ -418,6 +418,7 @@ static __inline__ _syscall1(int,setup,int,magic)
 static __inline__ _syscall0(int,sync)
 static __inline__ _syscall0(pid_t,setsid)
 static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count)
+static __inline__ _syscall3(int,read,int,fd,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)
@@ -443,24 +444,56 @@ static __inline__ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned lo
 {
        long retval;
 
-       __asm__ __volatile("mov %4, %%g2\n\t"    /* Set aside fn ptr... */
-                          "mov %5, %%g3\n\t"    /* and arg. */
-                          "mov %1, %%g1\n\t"
-                          "mov %2, %%o0\n\t"    /* Clone flags. */
-                          "mov 0, %%o1\n\t"     /* usp arg == 0 */
-                          "t 0x6d\n\t"          /* Linux/Sparc clone(). */
-                          "brz,a,pn %%o1, 1f\n\t"           /* The parent, just return. */
+       __asm__ __volatile("mov %1, %%g1\n\t"
+                          "mov %2, %%o0\n\t"      /* Clone flags. */
+                          "mov 0, %%o1\n\t"       /* usp arg == 0 */
+                          "t 0x6d\n\t"            /* Linux/Sparc clone(). */
+                          "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
                           " mov %%o0, %0\n\t"
-                          "jmpl %%g2, %%o7\n\t" /* Call the function. */
-                          " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
+                          "jmpl %4, %%o7\n\t"     /* Call the function. */
+                          " mov %5, %%o0\n\t"     /* Set arg in delay. */
                           "mov %3, %%g1\n\t"
-                          "t 0x6d\n\t"          /* Linux/Sparc exit(). */
+                          "t 0x6d\n\t"            /* Linux/Sparc exit(). */
                           /* Notreached by child. */
                           "1:" :
                           "=r" (retval) :
                           "i" (__NR_clone), "r" (flags | CLONE_VM),
                           "i" (__NR_exit),  "r" (fn), "r" (arg) :
-                          "g1", "g2", "g3", "o0", "o1", "memory", "cc");
+                          "g1", "o0", "o1", "memory", "cc");
+       return retval;
+}
+
+static __inline__ pid_t fork(void)
+{
+       long retval;
+
+       __asm__ __volatile("mov %1, %%g1\n\t"
+                          "t 0x6d\n\t"
+                          "brz,a,pn %%o1, 1f\n\t"
+                          " mov %%o0, %0\n\t"
+                          "mov %%g0, %0\n\t"
+                          "1:" :
+                          "=r" (retval) :
+                          "i" (__NR_fork) :
+                          "g1", "o0", "o1", "memory", "cc");
+       return retval;
+}
+
+static __inline__ pid_t clone(unsigned long flags, char *ksp)
+{
+       long retval;
+
+       __asm__ __volatile("mov %1, %%g1\n\t"
+                          "mov %2, %%o0\n\t"
+                          "mov %3, %%o1\n\t"
+                          "t 0x6d\n\t"
+                          "brz,a,pn %%o1, 1f\n\t"
+                          " mov %%o0, %0\n\t"
+                          "mov %%g0, %0\n\t"
+                          "1:" :
+                          "=r" (retval) :
+                          "i" (__NR_fork), "r" (flags), "r" (ksp) :
+                          "g1", "o0", "o1", "memory", "cc");
        return retval;
 }
 
diff --git a/include/asm-sparc64/xstat.h b/include/asm-sparc64/xstat.h
new file mode 100644 (file)
index 0000000..f73a1b9
--- /dev/null
@@ -0,0 +1,58 @@
+/* $Id: xstat.h,v 1.1 1998/02/06 12:52:18 jj Exp $
+ * xstat.h: sys_xstat/xmknod architecture dependent stuff.
+ *
+ * Copyright (C) 1998  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
+ */
+extern __inline__ int cp_xstat32(struct inode *inode, struct stat64_32 *s, unsigned long blocks, int blksize)
+{
+       struct stat64_32 tmp;
+       
+       memset (&tmp, 0, sizeof(tmp));
+       tmp.st_dev = (((__u64)MAJOR(inode->i_dev)) << 32) | MINOR(inode->i_dev);
+       tmp.st_ino = inode->i_ino;
+       tmp.st_mode = inode->i_mode;
+       tmp.st_nlink = inode->i_nlink;
+       tmp.st_uid = inode->i_uid;
+       tmp.st_gid = inode->i_gid;
+       tmp.st_rdev = (((__u64)MAJOR(inode->i_rdev)) << 32) | MINOR(inode->i_rdev);
+       tmp.st_size = inode->i_size;
+       tmp.st_blocks = blocks;
+       tmp.st_atime = inode->i_atime;
+       tmp.st_mtime = inode->i_mtime;
+       tmp.st_ctime = inode->i_ctime;
+       tmp.st_blksize = blksize;
+       return copy_to_user(s,&tmp,sizeof(tmp));
+}
+
+extern __inline__ int cp_xstat(struct inode *inode, struct stat64 *s, unsigned long blocks, int blksize)
+{
+       struct stat64 tmp;
+       if (current->tss.flags & SPARC_FLAG_32BIT)
+               return cp_xstat32(inode, (struct stat64_32 *)s, blocks, blksize);
+       memset (&tmp, 0, sizeof(tmp));
+       tmp.st_dev = (((__u64)MAJOR(inode->i_dev)) << 32) | MINOR(inode->i_dev);
+       tmp.st_ino = inode->i_ino;
+       tmp.st_mode = inode->i_mode;
+       tmp.st_nlink = inode->i_nlink;
+       tmp.st_uid = inode->i_uid;
+       tmp.st_gid = inode->i_gid;
+       tmp.st_rdev = (((__u64)MAJOR(inode->i_rdev)) << 32) | MINOR(inode->i_rdev);
+       tmp.st_size = inode->i_size;
+       tmp.st_atim.tv_sec = inode->i_atime;
+       tmp.st_mtim.tv_sec = inode->i_mtime;
+       tmp.st_ctim.tv_sec = inode->i_ctime;
+       tmp.st_blksize = blksize;
+       tmp.st_blocks = blocks;
+       /* Should I check if all fs names are < 16? All in the kernel tree are */
+       if (inode->i_sb)
+               strcpy(tmp.st_fstype, inode->i_sb->s_type->name);
+       return copy_to_user(s,&tmp,sizeof(tmp));
+}
+
+extern __inline__ int get_user_new_dev_t(kdev_t *kdev, __new_dev_t *udev) {
+       __new_dev_t ndev;
+       if (copy_from_user (&ndev, udev, sizeof(__new_dev_t))) return -EFAULT;
+       *kdev = MKDEV((ndev >> 32), (__u32)ndev);
+       return 0;
+}
index b2b0f76aebc6b551f7f102fb85163ed24ea05bf4..e98d755c29c61fb7b695eb665e0ad0611d7939bd 100644 (file)
@@ -283,6 +283,7 @@ extern __inline__ unsigned int parport_yield_blocking(struct pardevice *dev)
        if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
                return 0;
        parport_release(dev);
+       schedule();
        return parport_claim_or_block(dev);
 }
 
@@ -292,7 +293,7 @@ extern __inline__ unsigned int parport_yield_blocking(struct pardevice *dev)
 
 #define PARPORT_FLAG_COMA              1
 
-extern void parport_parse_irqs(int, const char *, int irqval[]);
+extern void parport_parse_irqs(int, const char *[], int irqval[]);
 extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
 extern int parport_wait_peripheral(struct parport *, unsigned char, unsigned
                                   char);
index fac49e39670611f147130507ff36bb721b144b14..054215546e656f68b0f269b330c3a70bf6ca4b45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: pci.h,v 1.62 1998/03/15 13:50:05 ecd Exp $
+ *     $Id: pci.h,v 1.67 1998/04/16 20:48:33 mj Exp $
  *
  *     PCI defines and function prototypes
  *     Copyright 1994, Drew Eckhardt
 #define PCI_CARDBUS_CIS                0x28
 #define PCI_SUBSYSTEM_VENDOR_ID        0x2c
 #define PCI_SUBSYSTEM_ID       0x2e  
-#define PCI_ROM_ADDRESS                0x30    /* 32 bits */
-#define  PCI_ROM_ADDRESS_ENABLE        0x01    /* Write 1 to enable ROM,
-                                          bits 31..11 are address,
-                                          10..2 are reserved */
+#define PCI_ROM_ADDRESS                0x30    /* Bits 31..11 are address, 10..1 reserved */
+#define  PCI_ROM_ADDRESS_ENABLE        0x01
+#define PCI_ROM_ADDRESS_MASK   (~0x7ffUL)
+
 /* 0x34-0x3b are reserved */
 #define PCI_INTERRUPT_LINE     0x3c    /* 8 bits */
 #define PCI_INTERRUPT_PIN      0x3d    /* 8 bits */
 #define PCI_CB_IO_LIMIT_1_HI   0x3a
 /* 0x3c-0x3d are same as for htype 0 */
 /* 0x3e-0x3f are same as for htype 1 */
-#define PCI_CB_SUBSYSTEM_ID    0x40
-#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x42
+#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
+#define PCI_CB_SUBSYSTEM_ID    0x42
 #define PCI_CB_LEGACY_MODE_BASE        0x44    /* 16-bit PC Card legacy mode base address (ExCa) */
 /* 0x48-0x7f reserved */
 
 #ifdef __KERNEL__
 
 /*
- * Error values that may be returned by the PCI bios.  Use
- * pcibios_strerror() to convert to a printable string.
+ * Error values that may be returned by the PCI bios.
  */
 #define PCIBIOS_SUCCESSFUL             0x00
 #define PCIBIOS_FUNC_NOT_SUPPORTED     0x81
@@ -1008,7 +1007,6 @@ int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
                               unsigned char where, unsigned short val);
 int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
                                unsigned char where, unsigned int val);
-const char *pcibios_strerror (int error);
 
 /* Don't use these in new code, use pci_find_... instead */
 
@@ -1051,6 +1049,7 @@ struct pci_dev {
         * pcibios_fixup() as necessary.
         */
        unsigned long   base_address[6];
+       unsigned long   rom_address;
 };
 
 struct pci_bus {
@@ -1076,8 +1075,9 @@ void pci_init(void);
 void pci_setup(char *str, int *ints);
 void pci_quirks_init(void);
 unsigned int pci_scan_bus(struct pci_bus *bus);
-void proc_bus_pci_init(void);
+void pci_proc_init(void);
 void proc_old_pci_init(void);
+int get_pci_list(char *buf);
 
 struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
 struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from);
@@ -1090,8 +1090,7 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 #define pci_write_config_byte(dev, where, val) pcibios_write_config_byte(dev->bus->number, dev->devfn, where, val)
 #define pci_write_config_word(dev, where, val) pcibios_write_config_word(dev->bus->number, dev->devfn, where, val)
 #define pci_write_config_dword(dev, where, val) pcibios_write_config_dword(dev->bus->number, dev->devfn, where, val)
-
-int get_pci_list (char *buf);
+void pci_set_master(struct pci_dev *);
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
index 076fbd6613d80d2d70923a25e661a076d9025fef..47a2423102b93c996f5e76906ba19dba3dec185c 100644 (file)
@@ -182,6 +182,7 @@ enum scsi_directory_inos {
        PROC_SCSI_IDESCSI,
        PROC_SCSI_MESH,
        PROC_SCSI_53C94,
+       PROC_SCSI_PLUTO,
        PROC_SCSI_SCSI_DEBUG,   
        PROC_SCSI_NOT_PRESENT,
        PROC_SCSI_FILE,                        /* I'm assuming here that we */
@@ -350,7 +351,7 @@ struct openpromfs_dev {
        char name[32];
 };
 extern struct inode_operations *
-proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
+proc_openprom_register(int (*readdir)(struct file *, void *, filldir_t),
                       int (*lookup)(struct inode *, struct dentry *),
                       void (*use)(struct inode *, int),
                       struct openpromfs_dev ***);
index 7dd531688bd7fd782c8d490b90c47c5e1abb5e10..463350f5c7d298784fd8dcea4c503399d8ae89a3 100644 (file)
@@ -8,6 +8,7 @@
 #define        LINUX_REBOOT_MAGIC1     0xfee1dead
 #define        LINUX_REBOOT_MAGIC2     672274793
 #define        LINUX_REBOOT_MAGIC2A    85072278
+#define        LINUX_REBOOT_MAGIC2B    369367448
 
 
 /*
index 32448833107778264bbb010bd1395dd8177e9816..cee1fc11f1495d402398bcb9339c5a24d5924225 100644 (file)
@@ -85,8 +85,10 @@ struct serial_uart_config {
 #define ASYNC_SPD_SHI  0x1000  /* Use 230400 instead of 38400 bps */
 #define ASYNC_SPD_WARP 0x1010  /* Use 460800 instead of 38400 bps */
 
-#define ASYNC_FLAGS    0x1FFF  /* Possible legal async flags */
-#define ASYNC_USR_MASK 0x1430  /* Legal flags that non-privileged
+#define ASYNC_LOW_LATENCY 0x2000 /* Request low latency behaviour */
+
+#define ASYNC_FLAGS    0x2FFF  /* Possible legal async flags */
+#define ASYNC_USR_MASK 0x3430  /* Legal flags that non-privileged
                                 * users can set or reset */
 
 /* Internal flags used only by kernel/chr_drv/serial.c */
index e86d18c09e6fc3d03f8dc100aaa35fa86b50c83d..aadb3ab5fc1a5f868e87cf9a5339250abe056e8e 100644 (file)
@@ -177,7 +177,8 @@ asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg)
 
        /* For safety, we require "magic" arguments. */
        if (magic1 != LINUX_REBOOT_MAGIC1 ||
-           (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A))
+           (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A &&
+                       magic2 != LINUX_REBOOT_MAGIC2B))
                return -EINVAL;
 
        lock_kernel();
index 21205362f6195e231f722490611406fdfb4e83b0..1641e5c3d098055869692d321ee9fa7476247ed4 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The IP fragmentation functionality.
  *             
- * Version:    $Id: ip_fragment.c,v 1.33 1998/03/19 08:34:08 davem Exp $
+ * Version:    $Id: ip_fragment.c,v 1.36 1998/04/18 02:13:07 davem Exp $
  *
  * Authors:    Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *             Alan Cox <Alan.Cox@linux.org>
@@ -346,10 +346,9 @@ static struct sk_buff *ip_glue(struct ipq *qp)
        memcpy(ptr, qp->iph, qp->ihlen);
        ptr += qp->ihlen;
 
-       count = 0;
-
        /* Copy the data portions of all fragments into the new buffer. */
        fp = qp->fragments;
+       count = qp->ihlen;
        while(fp) {
                if (fp->len < 0 || count+fp->len > skb->len) {
                        NETDEBUG(printk(KERN_ERR "Invalid fragment list: "
@@ -360,7 +359,7 @@ static struct sk_buff *ip_glue(struct ipq *qp)
                        return NULL;
                }
                memcpy((ptr + fp->offset), fp->ptr, fp->len);
-               if (!count) {
+               if (count == qp->ihlen) {
                        skb->dst = dst_clone(fp->skb->dst);
                        skb->dev = fp->skb->dev;
                }
@@ -376,7 +375,7 @@ static struct sk_buff *ip_glue(struct ipq *qp)
        /* Done with all fragments. Fixup the new IP header. */
        iph = skb->nh.iph;
        iph->frag_off = 0;
-       iph->tot_len = htons((iph->ihl * 4) + count);
+       iph->tot_len = htons(count);
 
        ip_statistics.IpReasmOKs++;
        return skb;