summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/sparc/Makefile14
-rw-r--r--sys/arch/sparc/conf/GENERIC337
-rw-r--r--sys/arch/sparc/conf/GENERIC_SCSI3338
-rw-r--r--sys/arch/sparc/conf/Makefile.sparc169
-rw-r--r--sys/arch/sparc/conf/files.sparc176
-rw-r--r--sys/arch/sparc/dev/amd7930.c69
-rw-r--r--sys/arch/sparc/dev/amd7930var.h6
-rw-r--r--sys/arch/sparc/dev/bt_subr.c5
-rw-r--r--sys/arch/sparc/dev/btreg.h62
-rw-r--r--sys/arch/sparc/dev/bwtwo.c380
-rw-r--r--sys/arch/sparc/dev/bwtworeg.h17
-rw-r--r--sys/arch/sparc/dev/cgeight.c383
-rw-r--r--sys/arch/sparc/dev/cgfour.c346
-rw-r--r--sys/arch/sparc/dev/cgsix.c216
-rw-r--r--sys/arch/sparc/dev/cgsixreg.h5
-rw-r--r--sys/arch/sparc/dev/cgthree.c143
-rw-r--r--sys/arch/sparc/dev/cgthreereg.h6
-rw-r--r--sys/arch/sparc/dev/cgtwo.c118
-rw-r--r--sys/arch/sparc/dev/cons.c226
-rw-r--r--sys/arch/sparc/dev/dma.c628
-rw-r--r--sys/arch/sparc/dev/dmareg.h104
-rw-r--r--sys/arch/sparc/dev/dmavar.h93
-rw-r--r--sys/arch/sparc/dev/esp.c2560
-rw-r--r--sys/arch/sparc/dev/espreg.h255
-rw-r--r--sys/arch/sparc/dev/espvar.h335
-rw-r--r--sys/arch/sparc/dev/fb.c275
-rw-r--r--sys/arch/sparc/dev/fd.c367
-rw-r--r--sys/arch/sparc/dev/fdreg.h4
-rw-r--r--sys/arch/sparc/dev/fdvar.h10
-rw-r--r--sys/arch/sparc/dev/if_ie.c191
-rw-r--r--sys/arch/sparc/dev/if_le.c157
-rw-r--r--sys/arch/sparc/dev/if_levar.h39
-rw-r--r--sys/arch/sparc/dev/kbd.c99
-rw-r--r--sys/arch/sparc/dev/ms.c21
-rw-r--r--sys/arch/sparc/dev/obio.c361
-rw-r--r--sys/arch/sparc/dev/pfourreg.h21
-rw-r--r--sys/arch/sparc/dev/power.c103
-rw-r--r--sys/arch/sparc/dev/power.h60
-rw-r--r--sys/arch/sparc/dev/rcons_font.h2
-rw-r--r--sys/arch/sparc/dev/sbus.c132
-rw-r--r--sys/arch/sparc/dev/sbusvar.h7
-rw-r--r--sys/arch/sparc/dev/si.c160
-rw-r--r--sys/arch/sparc/dev/xd.c176
-rw-r--r--sys/arch/sparc/dev/xdreg.h10
-rw-r--r--sys/arch/sparc/dev/xdvar.h20
-rw-r--r--sys/arch/sparc/dev/xio.h6
-rw-r--r--sys/arch/sparc/dev/xy.c245
-rw-r--r--sys/arch/sparc/dev/xyreg.h6
-rw-r--r--sys/arch/sparc/dev/xyvar.h8
-rw-r--r--sys/arch/sparc/dev/zs.c274
-rw-r--r--sys/arch/sparc/dev/zsvar.h28
-rw-r--r--sys/arch/sparc/fpu/fpu.c5
-rw-r--r--sys/arch/sparc/fpu/fpu_add.c7
-rw-r--r--sys/arch/sparc/fpu/fpu_explode.c4
-rw-r--r--sys/arch/sparc/fpu/fpu_extern.h76
-rw-r--r--sys/arch/sparc/fpu/fpu_implode.c9
-rw-r--r--sys/arch/sparc/fpu/fpu_subr.c7
-rw-r--r--sys/arch/sparc/include/ansi.h5
-rw-r--r--sys/arch/sparc/include/autoconf.h107
-rw-r--r--sys/arch/sparc/include/bsd_openprom.h60
-rw-r--r--sys/arch/sparc/include/cdefs.h2
-rw-r--r--sys/arch/sparc/include/conf.h81
-rw-r--r--sys/arch/sparc/include/cpu.h88
-rw-r--r--sys/arch/sparc/include/ctlreg.h246
-rw-r--r--sys/arch/sparc/include/db_machdep.h22
-rw-r--r--sys/arch/sparc/include/eeprom.h450
-rw-r--r--sys/arch/sparc/include/endian.h10
-rw-r--r--sys/arch/sparc/include/exec.h7
-rw-r--r--sys/arch/sparc/include/fbio.h10
-rw-r--r--sys/arch/sparc/include/fbvar.h16
-rw-r--r--sys/arch/sparc/include/ieeefp.h2
-rw-r--r--sys/arch/sparc/include/kbd.h11
-rw-r--r--sys/arch/sparc/include/kbio.h18
-rw-r--r--sys/arch/sparc/include/oldmon.h135
-rw-r--r--sys/arch/sparc/include/param.h106
-rw-r--r--sys/arch/sparc/include/pmap.h230
-rw-r--r--sys/arch/sparc/include/profile.h31
-rw-r--r--sys/arch/sparc/include/psl.h76
-rw-r--r--sys/arch/sparc/include/pte.h213
-rw-r--r--sys/arch/sparc/include/signal.h10
-rw-r--r--sys/arch/sparc/include/sun_disklabel.h10
-rw-r--r--sys/arch/sparc/include/svr4_machdep.h10
-rw-r--r--sys/arch/sparc/include/trap.h10
-rw-r--r--sys/arch/sparc/include/types.h6
-rw-r--r--sys/arch/sparc/include/vmparam.h6
-rw-r--r--sys/arch/sparc/sparc/amd7930intr.s13
-rw-r--r--sys/arch/sparc/sparc/autoconf.c1018
-rw-r--r--sys/arch/sparc/sparc/auxreg.c33
-rw-r--r--sys/arch/sparc/sparc/auxreg.h6
-rw-r--r--sys/arch/sparc/sparc/bsd_fdintr.s9
-rw-r--r--sys/arch/sparc/sparc/cache.c239
-rw-r--r--sys/arch/sparc/sparc/cache.h82
-rw-r--r--sys/arch/sparc/sparc/clock.c760
-rw-r--r--sys/arch/sparc/sparc/conf.c144
-rw-r--r--sys/arch/sparc/sparc/cpu.c228
-rw-r--r--sys/arch/sparc/sparc/db_disasm.c75
-rw-r--r--sys/arch/sparc/sparc/db_interface.c112
-rw-r--r--sys/arch/sparc/sparc/db_trace.c37
-rw-r--r--sys/arch/sparc/sparc/disksubr.c107
-rw-r--r--sys/arch/sparc/sparc/genassym.c26
-rw-r--r--sys/arch/sparc/sparc/in_cksum.c143
-rw-r--r--sys/arch/sparc/sparc/intersil7170.h66
-rw-r--r--sys/arch/sparc/sparc/intr.c66
-rw-r--r--sys/arch/sparc/sparc/intreg.h39
-rw-r--r--sys/arch/sparc/sparc/iommu.c352
-rw-r--r--sys/arch/sparc/sparc/iommureg.h93
-rw-r--r--sys/arch/sparc/sparc/kgdb_proto.h10
-rw-r--r--sys/arch/sparc/sparc/kgdb_stub.c131
-rw-r--r--sys/arch/sparc/sparc/locore.s1382
-rw-r--r--sys/arch/sparc/sparc/locore2.c6
-rw-r--r--sys/arch/sparc/sparc/machdep.c161
-rw-r--r--sys/arch/sparc/sparc/mem.c12
-rw-r--r--sys/arch/sparc/sparc/memreg.c196
-rw-r--r--sys/arch/sparc/sparc/memreg.h12
-rw-r--r--sys/arch/sparc/sparc/openprom.c17
-rw-r--r--sys/arch/sparc/sparc/pmap.c3676
-rw-r--r--sys/arch/sparc/sparc/process_machdep.c3
-rw-r--r--sys/arch/sparc/sparc/svr4_machdep.c221
-rw-r--r--sys/arch/sparc/sparc/swapgeneric.c4
-rw-r--r--sys/arch/sparc/sparc/sys_machdep.c5
-rw-r--r--sys/arch/sparc/sparc/timerreg.h57
-rw-r--r--sys/arch/sparc/sparc/trap.c447
-rw-r--r--sys/arch/sparc/sparc/vaddrs.h52
-rw-r--r--sys/arch/sparc/sparc/vm_machdep.c171
-rw-r--r--sys/arch/sparc/stand/Makefile.inc4
-rw-r--r--sys/arch/sparc/stand/binstall.sh6
-rw-r--r--sys/arch/sparc/stand/boot.c6
-rw-r--r--sys/arch/sparc/stand/bootxx/Makefile2
-rw-r--r--sys/arch/sparc/stand/installboot.c2
-rw-r--r--sys/arch/sparc/stand/net.c6
-rw-r--r--sys/arch/sparc/stand/promdev.c2
-rw-r--r--sys/arch/sparc/stand/srt0.S9
-rw-r--r--sys/arch/sparc/stand/version.c2
133 files changed, 15391 insertions, 6718 deletions
diff --git a/sys/arch/sparc/Makefile b/sys/arch/sparc/Makefile
index 2dd71ec7454..88ba39ae50c 100644
--- a/sys/arch/sparc/Makefile
+++ b/sys/arch/sparc/Makefile
@@ -1,23 +1,24 @@
-# $NetBSD: Makefile,v 1.3 1994/11/20 20:51:32 deraadt Exp $
+# $NetBSD: Makefile,v 1.4 1996/03/25 22:48:09 mrg Exp $
# from: @(#)Makefile 8.1 (Berkeley) 6/11/93
#
# Makefile for sparc links, tags file
+SUBDIR= stand
+
NOPROG= noprog
NOMAN= noman
NOOBJ= noobj
-SUBDIR= stand
-
-DIRS= conf dev fpu include sparc
+DIRS= conf dev fpu include rcons sbus sparc
links::
-for i in ${DIRS}; do \
(cd $$i && { rm -f tags; ln -s ${SYSTAGS} tags; }) done
SPARC= /sys/arch/sparc/dev/*.[ch] /sys/arch/sparc/fpu/*.[ch] \
- /sys/arch/sparc/include/*.[ch] /sys/arch/sparc/sparc/*.[ch]
+ /sys/arch/sparc/include/*.[ch] /sys/arch/sparc/rcons/*.[ch] \
+ /sys/arch/sparc/sbus/*.[ch] /sys/arch/sparc/sparc/*.[ch]
ASPARC= /sys/arch/sparc/sparc/*.s
tags:
@@ -27,6 +28,5 @@ tags:
>> tags
sort -o tags tags
-obj: _SUBDIRUSE
-
.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
diff --git a/sys/arch/sparc/conf/GENERIC b/sys/arch/sparc/conf/GENERIC
index 61af08d2ad3..47b14c74271 100644
--- a/sys/arch/sparc/conf/GENERIC
+++ b/sys/arch/sparc/conf/GENERIC
@@ -1,32 +1,55 @@
-# $NetBSD: GENERIC,v 1.19 1995/10/08 11:45:39 pk Exp $
+# $NetBSD: GENERIC,v 1.28.2.1 1996/07/02 23:55:22 jtc Exp $
+# Machine architecture; required by config(8)
machine sparc
-options SUN4, SUN4C, SUN4M
-#options MMU_3L
-#options DDB,DEBUG,DIAGNOSTIC
-# obsolete timezone spec
-options TIMEZONE=0, DST=0
+# Options for variants of the Sun SPARC architecure.
+# At least one is required.
+options SUN4 # sun4/100, sun4/200, sun4/300
+options SUN4C # sun4c - SS1, 1+, 2, ELC, SLC, IPC, IPX, etc.
+options SUN4M # sun4m - SS10, SS20, Classic, etc.
+
+#options MMU_3L # 3-level MMU on sun4/400
+
+# obsolete timezone spec; optional
+#options TIMEZONE=0, DST=0
# Standard system options
-options SWAPPAGER, VNODEPAGER, DEVPAGER # paging
-#options DEBUG, DIAGNOSTIC # extra kernel debugging
-options KTRACE # system call tracing support
-#options KGDB # support for kernel gdb
-#options KGDBDEV=0xc01, KGDBRATE=38400 # device & baud rate
-options RASTERCONSOLE # fast rasterop console
-options SYSVMSG,SYSVSEM,SYSVSHM
-options COMPAT_09, COMPAT_10
+options SWAPPAGER # swap and anonymous memory; required
+options VNODEPAGER # mapped files; required
+options DEVPAGER # mapped devices; required
+options KTRACE # system call tracing
+options SYSVMSG # System V message queues
+options SYSVSEM # System V semaphores
+options SYSVSHM # System V shared memory
+#options SHMMAXPGS=1024 # 1024 pages is the default
+options LKM # loadable kernel modules
+#options INSECURE # disable kernel security level
+#options UCONSOLE # allow anyone to steal the virtual console
+
+# Debugging options
+#options DDB # kernel dynamic debugger
+#options DEBUG # kernel debugging code
+#options DIAGNOSTIC # extra kernel sanity checking
+#options KGDB # support for kernel gdb
+#options KGDBDEV=0xc01 # kgdb device number (dev_t)
+#options KGDBRATE=38400 # baud rate
+
+# Compatibility options
+options COMPAT_43 # 4.3BSD system interfaces
+options COMPAT_10 # NetBSD 1.0 binary compatibility
+options COMPAT_11 # NetBSD 1.1 binary compatibility
+options COMPAT_SUNOS # SunOS 4.x binary compatibility
+options COMPAT_SVR4 # SunOS 5.x binary compatibility
# Filesystem options
-options FFS
-options NFSSERVER # Sun NFS-compatible filesystem
-options NFSCLIENT # Sun NFS-compatible filesystem
+options FFS # Berkeley Fast Filesystem
+options QUOTA # FFS quotas
+options NFSSERVER # Sun NFS-compatible filesystem server
+options NFSCLIENT # Sun NFS-compatible filesystem client
options KERNFS # kernel data-structure filesystem
-options FIFO # POSIX fifo support (in all filesystems)
-options QUOTA # fast filesystem with user and group quotas
+options NULLFS # NULL layered filesystem
options MFS # memory-based filesystem
-options LOFS # Loop-back filesystem
options FDESC # user file descriptor filesystem
options UMAPFS # uid/gid remapping filesystem
options LFS # Log-based filesystem (still experimental)
@@ -34,131 +57,229 @@ options PORTAL # portal filesystem (still experimental)
options PROCFS # /proc
options CD9660 # ISO 9660 + Rock Ridge file system
options UNION # union file system
+options FIFO # POSIX fifo support (in all filesystems)
# Networking options
-options INET
+options INET # IP stack
options TCP_COMPAT_42 # compatibility with 4.2BSD TCP/IP
#options GATEWAY # IP packet forwarding
-#options ISO # OSI networking
-#options TPIP
-#options EON
-options COMPAT_43
-
-options LKM
+#options ISO,TPIP # OSI networking
+#options EON # OSI tunneling over IP
+#options CCITT,LLC,HDLC # X.25
# Options for SPARCstation hardware
-options COMPAT_SUNOS # compatibility with SunOS binaries
-options COMPAT_SVR4 # compatibility with SVR4 binaries
+options RASTERCONSOLE # fast rasterop console
-config bsd swap generic
+# Generic swap; second partition of root disk or network.
+config netbsd swap generic
+# Main bus and CPU .. all systems.
mainbus0 at root
cpu0 at mainbus0
-sbus0 at mainbus0
-obio0 at mainbus0
-vmes0 at mainbus0
-vmel0 at mainbus0
-
-audio0 at mainbus0
-auxreg0 at mainbus0
-clock0 at mainbus0
-clock0 at obio0 addr 0xf2000000
-oclock0 at obio0 addr 0xf3000000
-oclock0 at obio0 addr 0x03000000 # 4/100
-memreg0 at mainbus0
-memreg0 at obio0 addr 0xf4000000
-memreg0 at obio0 addr 0x04000000 # 4/100
-timer0 at mainbus0
-timer0 at obio0 addr 0xef000000
-eeprom0 at obio0 addr 0xf2000000
-eeprom0 at obio0 addr 0x02000000 # 4/100
-
-zs0 at mainbus0
-zs0 at obio0 addr 0xf1000000 level 12 flags 0x103
-zs0 at obio0 addr 0x01000000 level 12 flags 0x103 # 4/100
-zs1 at mainbus0
-zs1 at obio0 addr 0xf0000000 level 12 flags 0x103
-zs1 at obio0 addr 0x00000000 level 12 flags 0x103 # 4/100
-zs2 at obio0 addr 0xe0000000 level 12 flags 0x103
-
-# FSBE/S or sun4m
-espdma0 at sbus0 slot ? offset ?
-espdma* at sbus0 slot ? offset ?
-esp0 at espdma? slot ? offset ?
-esp* at espdma? slot ? offset ?
-
-# old sun4c SCSI
-dma0 at sbus0 slot ? offset ?
-dma* at sbus0 slot ? offset ?
-dma0 at obio0 addr 0xfa001000 level 4
-esp0 at sbus0 slot ? offset ?
-esp* at sbus0 slot ? offset ?
-esp0 at obio0 addr 0xfa000000 level 4
-
-# old sun4c
-le0 at sbus? slot ? offset ?
+# Bus types found on SPARC systems.
+sbus0 at mainbus0 # sun4c
+obio0 at mainbus0 # sun4 and sun4m
+vmes0 at mainbus0 # sun4
+vmel0 at mainbus0 # sun4
+iommu0 at mainbus0 # sun4m
+sbus0 at iommu0 # sun4m
+
+audio0 at mainbus0 # sun4c
+audio0 at obio0 # sun4m
+
+auxreg0 at mainbus0 # sun4c
+auxreg0 at obio0 # sun4m
+
+# Power status and control register found on Sun4m systems
+power0 at obio0
+
+# Mostek clock found on 4/300, sun4c, and sun4m systems.
+# The Mostek clock NVRAM is the "eeprom" on sun4/300 systems.
+clock0 at mainbus0 # sun4c
+clock0 at obio0 # sun4m
+clock0 at obio0 addr 0xf2000000 # sun4/300
+
+# Intersil clock found on 4/100 and 4/200 systems.
+oclock0 at obio0 addr 0xf3000000 # sun4/200
+oclock0 at obio0 addr 0x03000000 # sun4/100
+
+# Memory error registers.
+memreg0 at mainbus0 # sun4c
+memreg0 at obio0 # sun4m
+memreg0 at obio0 addr 0xf4000000 # sun4/200 and sun4/300
+memreg0 at obio0 addr 0x04000000 # sun4/100
+
+# Timer chip found on 4/300, sun4c, and sun4m systems.
+timer0 at mainbus0 # sun4c
+timer0 at obio0 # sun4m
+timer0 at obio0 addr 0xef000000 # sun4/300
+
+# EEPROM found on 4/100 and 4/200 systems. Note that the 4/300
+# doesn't use this driver; the `EEPROM' is in the NVRAM on the
+# Mostek clock chip on 4/300 systems.
+eeprom0 at obio0 addr 0xf2000000 # sun4/200
+eeprom0 at obio0 addr 0x02000000 # sun4/100
+
+# Zilog 8530 serial chips. Each has two-channels.
+# zs0 is ttya and ttyb. zs1 is the keyboard and mouse.
+zs0 at mainbus0 # sun4c
+zs0 at obio0 # sun4m
+zs0 at obio0 addr 0xf1000000 level 12 flags 0x103 # sun4/200 and sun4/300
+zs0 at obio0 addr 0x01000000 level 12 flags 0x103 # sun4/100
+zs1 at mainbus0 # sun4c
+zs1 at obio0 # sun4m
+zs1 at obio0 addr 0xf0000000 level 12 flags 0x103 # sun4/200 and sun4/300
+zs1 at obio0 addr 0x00000000 level 12 flags 0x103 # sun4/100
+zs2 at obio0 addr 0xe0000000 level 12 flags 0x103 # sun4/300
+
+#
+# Note the flags on the esp entries below, that work around
+# deficiencies in the current driver:
+# bits 0-7: disable disconnect/reselect for the corresponding target
+# bits 8-15: disable synch negotiation for target [bit-8]
+# Note: targets 4-7 have disconnect/reselect enabled on the premise
+# that tape devices normally have one of these targets. Tape
+# devices should be allowed to disconnect for the SCSI bus
+# to operate acceptably.
+#
+
+# sun4/300 SCSI - an NCR53c94 or equivalent behind
+# an LSI Logic DMA controller
+dma0 at obio0 addr 0xfa001000 level 4 # sun4/300
+esp0 at obio0 addr 0xfa000000 level 4 flags 0xff0f #
+
+# sun4c or sun4m SCSI - an NCR53c94 or equivalent behind
+# specialized DMA glue
+dma0 at sbus0 slot ? offset ? # on-board SCSI
+esp0 at sbus0 slot ? offset ? flags 0xff0f # sun4c
+esp0 at dma0 flags 0xff0f # sun4m
+
+# FSBE/S SCSI - an NCR53c94 or equivalent behind
+dma* at sbus? slot ? offset ? # SBus SCSI
+esp* at sbus? slot ? offset ? flags 0xff0f # two flavours
+esp* at dma? flags 0xff0f # depending on model
+
+# sun4m Ethernet - an AMD 7990 LANCE behind
+# specialized DMA glue
+ledma0 at sbus0 slot ? offset ? # sun4m on-board
+le0 at ledma0 #
+
+# Additional SBus LANCE devices - glued on by lebuffer (not yet implemented)
+#lebuffer* at sbus0 slot ? offset ? # sun4m SBus
+#le* at lebuffer? #
+
+# sun4/300 and sun4c Ethernet - an AMD 7990 LANCE
+le0 at sbus0 slot ? offset ? # sun4c on-board
le* at sbus? slot ? offset ?
-le0 at obio0 addr 0xf9000000 level 6
-ie0 at obio0 addr 0xf6000000 level 6
-ie0 at obio0 addr 0x06000000 level 6 # 4/100
+le0 at obio0 addr 0xf9000000 level 6 # sun4/300
+
+# sun4/100 and sun4/200 Ethernet - an Intel 82586 on-board
+# or on a Multibus/VME card.
+ie0 at obio0 addr 0xf6000000 level 6 # sun4/200 on-board
+ie0 at obio0 addr 0x06000000 level 6 # sun4/100 on-board
+
ie1 at vmes0 addr 0xffe88000 level 5 vect 0x75
ie2 at vmes0 addr 0xff31ff02 level 5 vect 0x76
ie3 at vmes0 addr 0xff35ff02 level 5 vect 0x77
ie4 at vmes0 addr 0xff2dff02 level 5 vect 0x7c
+# Xylogics 753 or 7053 VME SMD disk controllers and disks, found
+# on sun4 systems.
xdc0 at vmel0 addr 0xffffee80 level 3 vect 0x44
xdc1 at vmel0 addr 0xffffee90 level 3 vect 0x45
xdc2 at vmel0 addr 0xffffeea0 level 3 vect 0x46
xdc3 at vmel0 addr 0xffffeeb0 level 3 vect 0x47
xd* at xdc? drive ?
+# Xylogics 451 or 451 VME SMD disk controllers and disks, found
+# on sun4 systems.
xyc0 at vmes0 addr 0xffffee40 level 3 vect 0x48
xyc1 at vmes0 addr 0xffffee48 level 3 vect 0x49
xy* at xyc? drive ?
+# NCR5380-based "Sun SCSI 3" VME SCSI controller.
+# This driver has several flags which may be enabled by OR'ing
+# the values and using the "flags" directive.
+# Valid flags are:
+#
+# 0x01 Use DMA (may be polled)
+# 0x02 Use DMA completion interrupts
+# 0x04 Allow disconnect/reselect
+#
+# E.g. the following would enable DMA, interrupts, and reselect:
+# si0 at vmes0 addr 0xff200000 level 3 vect 0x40 flags 0x07
+#
+# By default, DMA is enabled in the driver.
si0 at vmes0 addr 0xff200000 level 3 vect 0x40
-si1 at vmes0 addr 0xff204000 level 3 vect 0x41
+
+# NCR5380-based "SCSI Weird" on-board SCSI interface found
+# on sun4/100 systems. The flags are the same as the "si"
+# controller. Note, while DMA is enabled by default, only
+# polled DMA works at this time, and reselects do not work
+# on this particular controller.
sw0 at obio0 addr 0x0a000000 level 3
-bwtwo0 at sbus? slot ? offset ?
-bwtwo* at sbus? slot ? offset ?
-bwtwo0 at obio0 addr 0xfd000000 level 4 # 4/260
-bwtwo0 at obio0 addr 0xfb300000 level 4 # 4/{300/400} ??
+# Sun "bwtwo" black and white framebuffer, found on sun4, sun4c, and sun4m
+# systems. If your sun4 system has a cgfour installed in the P4 slot,
+# the P4 entries for "bwtwo" will attach to the overlay plane of the
+# "cgfour".
+bwtwo0 at sbus0 slot ? offset ? # sun4c on-board
+bwtwo* at sbus? slot ? offset ? # sun4c and sun4m
+bwtwo0 at obio0 addr 0xfd000000 level 4 # sun4/200
+bwtwo0 at obio0 addr 0xfb300000 level 4 # sun4/300 in P4 slot
+bwtwo0 at obio0 addr 0x0b300000 level 4 # sun4/100 in P4 slot
+
+# Sun "cgtwo" VME color framebuffer
cgtwo0 at vmes0 addr 0xff400000 level 4 vect 0xa8
-#cgnine0 at vmel0 addr 0x08000000 level 4
+
+# Sun "cgthree" Sbus color framebuffer
cgthree0 at sbus? slot ? offset ?
cgthree* at sbus? slot ? offset ?
-cgsix0 at sbus? slot ? offset ?
-cgsix* at sbus? slot ? offset ?
+#cgthree0 at obio? slot ? offset ? # sun4m
+#cgthree* at obio? slot ? offset ? # sun4m
-pfour0 at obio0 addr 0xfb000000
-pfour0 at obio0 addr 0x0b000000 # 4/100
-bwtwo0 at pfour0
-cgfour0 at pfour0
-cgeight0 at pfour0
-cgsix0 at pfour0
+# Sun "cgfour" color framebuffer with overlay plane. See above comment
+# regarding overlay plane.
+cgfour0 at obio0 addr 0xfb300000 level 4 # sun4/300 P4
+cgfour0 at obio0 addr 0x0b300000 level 4 # sun4/100 P4
+# Sun "cgsix" accelerated color framebuffer.
+cgsix0 at sbus? slot ? offset ?
+cgsix* at sbus? slot ? offset ?
+cgsix0 at obio0 addr 0xfb000000 level 4 # sun4/300 P4
+cgsix0 at obio0 addr 0x0b000000 level 4 # sun4/100 P4
+
+# Sun "cgeight" 24-bit framebuffer
+cgeight0 at obio0 addr 0xfb300000 level 4 # sun4/300 P4
+cgeight0 at obio0 addr 0x0b300000 level 4 # sun4/100 P4
+
+# SCSI bus layer. SCSI devices attach to the SCSI bus, which attaches
+# to the underlying hardware controller.
scsibus* at esp?
scsibus* at si?
scsibus* at sw?
-sd* at scsibus? target ? lun ?
-st* at scsibus? target ? lun ?
-cd* at scsibus? target ? lun ?
-ch* at scsibus? target ? lun ?
-ss* at scsibus? target ? lun ?
-uk* at scsibus? target ? lun ?
-
-fdc0 at mainbus0
-fd* at fdc0
-
-pseudo-device loop
-pseudo-device pty 32
-pseudo-device sl 2
-pseudo-device kbd
-pseudo-device ppp 2
-pseudo-device tun 4
-pseudo-device vnd 3
-pseudo-device bpfilter 16
+# These entries find devices on all SCSI busses and assign
+# unit numers dynamically.
+sd* at scsibus? target ? lun ? # SCSI disks
+st* at scsibus? target ? lun ? # SCSI tapes
+cd* at scsibus? target ? lun ? # SCSI CD-ROMs
+ch* at scsibus? target ? lun ? # SCSI changer devices
+
+# Floppy controller and drive found on SPARCstations.
+fdc0 at mainbus0 # sun4c controller
+fdc0 at obio0 # sun4m controller
+fd* at fdc0 # the drive itself
+
+pseudo-device loop # loopback interface; required
+pseudo-device pty 32 # pseudo-ttys (for network, etc.)
+pseudo-device sl 2 # SLIP interfaces
+pseudo-device kbd # Sun keyboard
+pseudo-device ppp 2 # PPP interfaces
+pseudo-device tun 4 # Network "tunnel" device
+pseudo-device bpfilter 16 # Berkeley Packet Filter
+pseudo-device vnd 4 # disk-like interface to files
+pseudo-device ccd 4 # concatenated and striped disks
+#pseudo-device strip 1 # radio clock
diff --git a/sys/arch/sparc/conf/GENERIC_SCSI3 b/sys/arch/sparc/conf/GENERIC_SCSI3
index dd784f33ec5..a160b2c2a29 100644
--- a/sys/arch/sparc/conf/GENERIC_SCSI3
+++ b/sys/arch/sparc/conf/GENERIC_SCSI3
@@ -1,32 +1,55 @@
-# $NetBSD: GENERIC,v 1.19 1995/10/08 11:45:39 pk Exp $
+# $NetBSD: GENERIC_SCSI3,v 1.28.2.1 1996/07/02 23:55:24 jtc Exp $
+# Machine architecture; required by config(8)
machine sparc
-options SUN4, SUN4C, SUN4M
-#options MMU_3L
-#options DDB,DEBUG,DIAGNOSTIC
-# obsolete timezone spec
-options TIMEZONE=0, DST=0
+# Options for variants of the Sun SPARC architecure.
+# At least one is required.
+options SUN4 # sun4/100, sun4/200, sun4/300
+options SUN4C # sun4c - SS1, 1+, 2, ELC, SLC, IPC, IPX, etc.
+options SUN4M # sun4m - SS10, SS20, Classic, etc.
+
+#options MMU_3L # 3-level MMU on sun4/400
+
+# obsolete timezone spec; optional
+#options TIMEZONE=0, DST=0
# Standard system options
-options SWAPPAGER, VNODEPAGER, DEVPAGER # paging
-#options DEBUG, DIAGNOSTIC # extra kernel debugging
-options KTRACE # system call tracing support
-#options KGDB # support for kernel gdb
-#options KGDBDEV=0xc01, KGDBRATE=38400 # device & baud rate
-options RASTERCONSOLE # fast rasterop console
-options SYSVMSG,SYSVSEM,SYSVSHM
-options COMPAT_09, COMPAT_10
+options SWAPPAGER # swap and anonymous memory; required
+options VNODEPAGER # mapped files; required
+options DEVPAGER # mapped devices; required
+options KTRACE # system call tracing
+options SYSVMSG # System V message queues
+options SYSVSEM # System V semaphores
+options SYSVSHM # System V shared memory
+#options SHMMAXPGS=1024 # 1024 pages is the default
+options LKM # loadable kernel modules
+#options INSECURE # disable kernel security level
+#options UCONSOLE # allow anyone to steal the virtual console
+
+# Debugging options
+#options DDB # kernel dynamic debugger
+#options DEBUG # kernel debugging code
+#options DIAGNOSTIC # extra kernel sanity checking
+#options KGDB # support for kernel gdb
+#options KGDBDEV=0xc01 # kgdb device number (dev_t)
+#options KGDBRATE=38400 # baud rate
+
+# Compatibility options
+options COMPAT_43 # 4.3BSD system interfaces
+options COMPAT_10 # NetBSD 1.0 binary compatibility
+options COMPAT_11 # NetBSD 1.1 binary compatibility
+options COMPAT_SUNOS # SunOS 4.x binary compatibility
+options COMPAT_SVR4 # SunOS 5.x binary compatibility
# Filesystem options
-options FFS
-options NFSSERVER # Sun NFS-compatible filesystem
-options NFSCLIENT # Sun NFS-compatible filesystem
+options FFS # Berkeley Fast Filesystem
+options QUOTA # FFS quotas
+options NFSSERVER # Sun NFS-compatible filesystem server
+options NFSCLIENT # Sun NFS-compatible filesystem client
options KERNFS # kernel data-structure filesystem
-options FIFO # POSIX fifo support (in all filesystems)
-options QUOTA # fast filesystem with user and group quotas
+options NULLFS # NULL layered filesystem
options MFS # memory-based filesystem
-options LOFS # Loop-back filesystem
options FDESC # user file descriptor filesystem
options UMAPFS # uid/gid remapping filesystem
options LFS # Log-based filesystem (still experimental)
@@ -34,132 +57,231 @@ options PORTAL # portal filesystem (still experimental)
options PROCFS # /proc
options CD9660 # ISO 9660 + Rock Ridge file system
options UNION # union file system
+options FIFO # POSIX fifo support (in all filesystems)
# Networking options
-options INET
+options INET # IP stack
options TCP_COMPAT_42 # compatibility with 4.2BSD TCP/IP
#options GATEWAY # IP packet forwarding
-#options ISO # OSI networking
-#options TPIP
-#options EON
-options COMPAT_43
-
-options LKM
+#options ISO,TPIP # OSI networking
+#options EON # OSI tunneling over IP
+#options CCITT,LLC,HDLC # X.25
# Options for SPARCstation hardware
-options COMPAT_SUNOS # compatibility with SunOS binaries
-options COMPAT_SVR4 # compatibility with SVR4 binaries
+options RASTERCONSOLE # fast rasterop console
-config bsd swap generic
+# Generic swap; second partition of root disk or network.
+config netbsd swap generic
+# Main bus and CPU .. all systems.
mainbus0 at root
cpu0 at mainbus0
-sbus0 at mainbus0
-obio0 at mainbus0
-vmes0 at mainbus0
-vmel0 at mainbus0
-
-audio0 at mainbus0
-auxreg0 at mainbus0
-clock0 at mainbus0
-clock0 at obio0 addr 0xf2000000
-oclock0 at obio0 addr 0xf3000000
-oclock0 at obio0 addr 0x03000000 # 4/100
-memreg0 at mainbus0
-memreg0 at obio0 addr 0xf4000000
-memreg0 at obio0 addr 0x04000000 # 4/100
-timer0 at mainbus0
-timer0 at obio0 addr 0xef000000
-eeprom0 at obio0 addr 0xf2000000
-eeprom0 at obio0 addr 0x02000000 # 4/100
-
-zs0 at mainbus0
-zs0 at obio0 addr 0xf1000000 level 12 flags 0x103
-zs0 at obio0 addr 0x01000000 level 12 flags 0x103 # 4/100
-zs1 at mainbus0
-zs1 at obio0 addr 0xf0000000 level 12 flags 0x103
-zs1 at obio0 addr 0x00000000 level 12 flags 0x103 # 4/100
-zs2 at obio0 addr 0xe0000000 level 12 flags 0x103
-
-# FSBE/S or sun4m
-espdma0 at sbus0 slot ? offset ?
-espdma* at sbus0 slot ? offset ?
-esp0 at espdma? slot ? offset ?
-esp* at espdma? slot ? offset ?
-
-# old sun4c SCSI
-dma0 at sbus0 slot ? offset ?
-dma* at sbus0 slot ? offset ?
-dma0 at obio0 addr 0xfa001000 level 4
-esp0 at sbus0 slot ? offset ?
-esp* at sbus0 slot ? offset ?
-esp0 at obio0 addr 0xfa000000 level 4
-
-# old sun4c
-le0 at sbus? slot ? offset ?
+# Bus types found on SPARC systems.
+sbus0 at mainbus0 # sun4c
+obio0 at mainbus0 # sun4 and sun4m
+vmes0 at mainbus0 # sun4
+vmel0 at mainbus0 # sun4
+iommu0 at mainbus0 # sun4m
+sbus0 at iommu0 # sun4m
+
+audio0 at mainbus0 # sun4c
+audio0 at obio0 # sun4m
+
+auxreg0 at mainbus0 # sun4c
+auxreg0 at obio0 # sun4m
+
+# Power status and control register found on Sun4m systems
+power0 at obio0
+
+# Mostek clock found on 4/300, sun4c, and sun4m systems.
+# The Mostek clock NVRAM is the "eeprom" on sun4/300 systems.
+clock0 at mainbus0 # sun4c
+clock0 at obio0 # sun4m
+clock0 at obio0 addr 0xf2000000 # sun4/300
+
+# Intersil clock found on 4/100 and 4/200 systems.
+oclock0 at obio0 addr 0xf3000000 # sun4/200
+oclock0 at obio0 addr 0x03000000 # sun4/100
+
+# Memory error registers.
+memreg0 at mainbus0 # sun4c
+memreg0 at obio0 # sun4m
+memreg0 at obio0 addr 0xf4000000 # sun4/200 and sun4/300
+memreg0 at obio0 addr 0x04000000 # sun4/100
+
+# Timer chip found on 4/300, sun4c, and sun4m systems.
+timer0 at mainbus0 # sun4c
+timer0 at obio0 # sun4m
+timer0 at obio0 addr 0xef000000 # sun4/300
+
+# EEPROM found on 4/100 and 4/200 systems. Note that the 4/300
+# doesn't use this driver; the `EEPROM' is in the NVRAM on the
+# Mostek clock chip on 4/300 systems.
+eeprom0 at obio0 addr 0xf2000000 # sun4/200
+eeprom0 at obio0 addr 0x02000000 # sun4/100
+
+# Zilog 8530 serial chips. Each has two-channels.
+# zs0 is ttya and ttyb. zs1 is the keyboard and mouse.
+zs0 at mainbus0 # sun4c
+zs0 at obio0 # sun4m
+zs0 at obio0 addr 0xf1000000 level 12 flags 0x103 # sun4/200 and sun4/300
+zs0 at obio0 addr 0x01000000 level 12 flags 0x103 # sun4/100
+zs1 at mainbus0 # sun4c
+zs1 at obio0 # sun4m
+zs1 at obio0 addr 0xf0000000 level 12 flags 0x103 # sun4/200 and sun4/300
+zs1 at obio0 addr 0x00000000 level 12 flags 0x103 # sun4/100
+zs2 at obio0 addr 0xe0000000 level 12 flags 0x103 # sun4/300
+
+#
+# Note the flags on the esp entries below, that work around
+# deficiencies in the current driver:
+# bits 0-7: disable disconnect/reselect for the corresponding target
+# bits 8-15: disable synch negotiation for target [bit-8]
+# Note: targets 4-7 have disconnect/reselect enabled on the premise
+# that tape devices normally have one of these targets. Tape
+# devices should be allowed to disconnect for the SCSI bus
+# to operate acceptably.
+#
+
+# sun4/300 SCSI - an NCR53c94 or equivalent behind
+# an LSI Logic DMA controller
+dma0 at obio0 addr 0xfa001000 level 4 # sun4/300
+esp0 at obio0 addr 0xfa000000 level 4 flags 0xff0f #
+
+# sun4c or sun4m SCSI - an NCR53c94 or equivalent behind
+# specialized DMA glue
+dma0 at sbus0 slot ? offset ? # on-board SCSI
+esp0 at sbus0 slot ? offset ? flags 0xff0f # sun4c
+esp0 at dma0 flags 0xff0f # sun4m
+
+# FSBE/S SCSI - an NCR53c94 or equivalent behind
+dma* at sbus? slot ? offset ? # SBus SCSI
+esp* at sbus? slot ? offset ? flags 0xff0f # two flavours
+esp* at dma? flags 0xff0f # depending on model
+
+# sun4m Ethernet - an AMD 7990 LANCE behind
+# specialized DMA glue
+ledma0 at sbus0 slot ? offset ? # sun4m on-board
+le0 at ledma0 #
+
+# Additional SBus LANCE devices - glued on by lebuffer (not yet implemented)
+#lebuffer* at sbus0 slot ? offset ? # sun4m SBus
+#le* at lebuffer? #
+
+# sun4/300 and sun4c Ethernet - an AMD 7990 LANCE
+le0 at sbus0 slot ? offset ? # sun4c on-board
le* at sbus? slot ? offset ?
-le0 at obio0 addr 0xf9000000 level 6
-ie0 at obio0 addr 0xf6000000 level 6
-ie0 at obio0 addr 0x06000000 level 6 # 4/100
+le0 at obio0 addr 0xf9000000 level 6 # sun4/300
+
+# sun4/100 and sun4/200 Ethernet - an Intel 82586 on-board
+# or on a Multibus/VME card.
+ie0 at obio0 addr 0xf6000000 level 6 # sun4/200 on-board
+ie0 at obio0 addr 0x06000000 level 6 # sun4/100 on-board
+
ie1 at vmes0 addr 0xffe88000 level 5 vect 0x75
ie2 at vmes0 addr 0xff31ff02 level 5 vect 0x76
ie3 at vmes0 addr 0xff35ff02 level 5 vect 0x77
ie4 at vmes0 addr 0xff2dff02 level 5 vect 0x7c
+# Xylogics 753 or 7053 VME SMD disk controllers and disks, found
+# on sun4 systems.
xdc0 at vmel0 addr 0xffffee80 level 3 vect 0x44
xdc1 at vmel0 addr 0xffffee90 level 3 vect 0x45
xdc2 at vmel0 addr 0xffffeea0 level 3 vect 0x46
xdc3 at vmel0 addr 0xffffeeb0 level 3 vect 0x47
xd* at xdc? drive ?
+# Xylogics 451 or 451 VME SMD disk controllers and disks, found
+# on sun4 systems.
xyc0 at vmes0 addr 0xffffee40 level 3 vect 0x48
xyc1 at vmes0 addr 0xffffee48 level 3 vect 0x49
xy* at xyc? drive ?
+# NCR5380-based "Sun SCSI 3" VME SCSI controller.
+# This driver has several flags which may be enabled by OR'ing
+# the values and using the "flags" directive.
+# Valid flags are:
+#
+# 0x01 Use DMA (may be polled)
+# 0x02 Use DMA completion interrupts
+# 0x04 Allow disconnect/reselect
+#
+# E.g. the following would enable DMA, interrupts, and reselect:
+# si0 at vmes0 addr 0xff200000 level 3 vect 0x40 flags 0x07
+#
+# By default, DMA is enabled in the driver.
si0 at vmes0 addr 0xff200000 level 3 vect 0x40
-si1 at vmes0 addr 0xff204000 level 3 vect 0x41
+
+# NCR5380-based "SCSI Weird" on-board SCSI interface found
+# on sun4/100 systems. The flags are the same as the "si"
+# controller. Note, while DMA is enabled by default, only
+# polled DMA works at this time, and reselects do not work
+# on this particular controller.
sw0 at obio0 addr 0x0a000000 level 3
-bwtwo0 at sbus? slot ? offset ?
-bwtwo* at sbus? slot ? offset ?
-bwtwo0 at obio0 addr 0xfd000000 level 4 # 4/260
-bwtwo0 at obio0 addr 0xfb300000 level 4 # 4/{300/400} ??
+# Sun "bwtwo" black and white framebuffer, found on sun4, sun4c, and sun4m
+# systems. If your sun4 system has a cgfour installed in the P4 slot,
+# the P4 entries for "bwtwo" will attach to the overlay plane of the
+# "cgfour".
+bwtwo0 at sbus0 slot ? offset ? # sun4c on-board
+bwtwo* at sbus? slot ? offset ? # sun4c and sun4m
+bwtwo0 at obio0 addr 0xfd000000 level 4 # sun4/200
+bwtwo0 at obio0 addr 0xfb300000 level 4 # sun4/300 in P4 slot
+bwtwo0 at obio0 addr 0x0b300000 level 4 # sun4/100 in P4 slot
+
+# Sun "cgtwo" VME color framebuffer
cgtwo0 at vmes0 addr 0xff400000 level 4 vect 0xa8
-#cgnine0 at vmel0 addr 0x08000000 level 4
+
+# Sun "cgthree" Sbus color framebuffer
cgthree0 at sbus? slot ? offset ?
cgthree* at sbus? slot ? offset ?
-cgsix0 at sbus? slot ? offset ?
-cgsix* at sbus? slot ? offset ?
+#cgthree0 at obio? slot ? offset ? # sun4m
+#cgthree* at obio? slot ? offset ? # sun4m
-pfour0 at obio0 addr 0xfb000000
-pfour0 at obio0 addr 0x0b000000 # 4/100
-bwtwo0 at pfour0
-cgfour0 at pfour0
-cgeight0 at pfour0
-cgsix0 at pfour0
+# Sun "cgfour" color framebuffer with overlay plane. See above comment
+# regarding overlay plane.
+cgfour0 at obio0 addr 0xfb300000 level 4 # sun4/300 P4
+cgfour0 at obio0 addr 0x0b300000 level 4 # sun4/100 P4
+# Sun "cgsix" accelerated color framebuffer.
+cgsix0 at sbus? slot ? offset ?
+cgsix* at sbus? slot ? offset ?
+cgsix0 at obio0 addr 0xfb000000 level 4 # sun4/300 P4
+cgsix0 at obio0 addr 0x0b000000 level 4 # sun4/100 P4
+
+# Sun "cgeight" 24-bit framebuffer
+cgeight0 at obio0 addr 0xfb300000 level 4 # sun4/300 P4
+cgeight0 at obio0 addr 0x0b300000 level 4 # sun4/100 P4
+
+# SCSI bus layer. SCSI devices attach to the SCSI bus, which attaches
+# to the underlying hardware controller.
scsibus* at esp?
scsibus* at si?
scsibus* at sw?
-# Map scsi-id 3 to sd0; no questions asked. Map the remaining drives
-# in the default order. This is because SunOS's rom swaps scsi-id 3 to
-# sd0, and scsi-id 0 to sd3.
+# These entries find devices on all SCSI busses and assign
+# unit numers dynamically.
+# Map the SCSI disk at target 3 to unit 0, a'la SunOS.
sd0 at scsibus? target 3 lun ?
-sd* at scsibus? target ? lun ?
-st* at scsibus? target ? lun ?
-cd* at scsibus? target ? lun ?
-
-fdc0 at mainbus0
-fd* at fdc0
-
-pseudo-device loop
-pseudo-device pty 32
-pseudo-device sl 2
-pseudo-device kbd
-pseudo-device ppp 2
-pseudo-device tun 4
-pseudo-device vnd 3
-pseudo-device bpfilter 16
+sd* at scsibus? target ? lun ? # SCSI disks
+st* at scsibus? target ? lun ? # SCSI tapes
+cd* at scsibus? target ? lun ? # SCSI CD-ROMs
+ch* at scsibus? target ? lun ? # SCSI changer devices
+
+# Floppy controller and drive found on SPARCstations.
+fdc0 at mainbus0 # sun4c controller
+fdc0 at obio0 # sun4m controller
+fd* at fdc0 # the drive itself
+
+pseudo-device loop # loopback interface; required
+pseudo-device pty 32 # pseudo-ttys (for network, etc.)
+pseudo-device sl 2 # SLIP interfaces
+pseudo-device kbd # Sun keyboard
+pseudo-device ppp 2 # PPP interfaces
+pseudo-device tun 4 # Network "tunnel" device
+pseudo-device bpfilter 16 # Berkeley Packet Filter
+pseudo-device vnd 4 # disk-like interface to files
+pseudo-device ccd 4 # concatenated and striped disks
+#pseudo-device strip 1 # radio clock
diff --git a/sys/arch/sparc/conf/Makefile.sparc b/sys/arch/sparc/conf/Makefile.sparc
index b812cd783b7..f22d4eef230 100644
--- a/sys/arch/sparc/conf/Makefile.sparc
+++ b/sys/arch/sparc/conf/Makefile.sparc
@@ -1,16 +1,15 @@
-# $NetBSD: Makefile.sparc,v 1.22 1995/09/19 23:26:58 thorpej Exp $
+# $NetBSD: Makefile.sparc,v 1.32.4.1 1996/06/12 20:26:32 pk Exp $
-# @(#)Makefile.sparc 8.1 (Berkeley) 7/19/93
-# Makefile for 4.4 BSD
+# Makefile for NetBSD
#
# This makefile is constructed from a machine description:
# config machineid
# Most changes should be made in the machine description
-# /sys/conf/``machineid''
+# /sys/arch/sparc/conf/``machineid''
# after which you should do
-# config machineid
+# config machineid
# Machine generic makefile changes should be made in
-# /sys/conf/Makefile.``machinetype''
+# /sys/arch/sparc/conf/Makefile.sparc
# after which config should be rerun for all machines of that type.
#
# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
@@ -23,20 +22,24 @@
# PROF is set to -pg if profiling.
AS?= as
-
-CC= cc ${DEBUG}
-CPP= cpp
-LD= ld
-TOUCH= touch -f -c
-AWK= awk
+CC?= cc
+CPP?= cpp
+LD?= ld
+STRIP?= strip -d
+TOUCH?= touch -f -c
# source tree is located via $S relative to the compilation directory
S= ../../../..
SPARC= ../..
-INCLUDES= -I. -I$S/arch -I$S -I$S/sys
-COPTS= ${INCLUDES} ${IDENT} -D_KERNEL
-CFLAGS= ${COPTS} -O2 -Werror
+INCLUDES= -I. -I$S/arch -I$S
+CPPFLAGS= ${INCLUDES} ${IDENT} -D_KERNEL
+GCCWFLAGS=-Werror -Wall -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS= ${DEBUG} -O2 ${GCCWFLAGS}
+# add `-mno-fpu' to work around gcc (last noticed in v2.7.2) bug
+CFLAGS+= -mno-fpu
+AFLAGS= -x assembler-with-cpp -traditional-cpp -D_LOCORE
+LINKFLAGS= -N -p -Ttext F8004000 -e start
### find out what to use for libkern
.include "$S/lib/libkern/Makefile.inc"
@@ -59,109 +62,117 @@ LIBCOMPAT= ${COMPATLIB_PROF}
# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file
# is marked as config-dependent.
-# sparc kernel uses volatile, rather than heavy "device-driver"s.
+NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
+NORMAL_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<
-NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $<
-NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+DRIVER_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
+DRIVER_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<
-# optimizer breaks sometimes; temporary workaround uses ${NOOPT_C}
-NOOPT_C= ${CC} -c ${COPTS} ${PROF} ${PARAM} $<
-
-NORMAL_S= rm -f $*.c; ln -s $< $*.c; \
- ${CC} ${COPTS} -I${SPARC}/sparc -E $*.c > $*.i; \
- ${AS} -o $@ $*.i; rm -f $*.c $*.i
-NORMAL_S_C= rm -f $*.c; ln -s $< $*.c; \
- ${CC} ${COPTS} ${PARAM} -I${SPARC}/sparc -E $*.c > $*.i; \
- ${AS} -o $@ $*.i; rm -f $*.c $*.i
+NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} -c $<
+NORMAL_S_C= ${CC} ${AFLAGS} ${CPPFLAGS} ${PARAM} -c $<
%OBJS
%CFILES
+%SFILES
+
# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP} swapxxx.o
# ${SYSTEM_LD_HEAD}
# ${SYSTEM_LD} swapxxx.o
# ${SYSTEM_LD_TAIL}
+SYSTEM_OBJ= locore.o \
+ param.o ioconf.o ${OBJS} ${LIBKERN} ${LIBCOMPAT}
+SYSTEM_DEP= Makefile ${SYSTEM_OBJ}
+SYSTEM_LD_HEAD= @rm -f $@
+SYSTEM_LD= @echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_OBJ}' vers.o; \
+ ${LD} ${LINKFLAGS} -o $@ ${SYSTEM_OBJ} vers.o
+SYSTEM_LD_TAIL= @size $@; chmod 755 $@
+
DEBUG?=
.if ${DEBUG} == "-g"
-LDX=-X
+LINKFLAGS+= -X
+SYSTEM_LD_TAIL+=; \
+ echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \
+ echo ${STRIP} $@; ${STRIP} $@
.else
-LDX=-x
+LINKFLAGS+= -x
.endif
-SYSTEM_OBJ= locore.o vnode_if.o ${OBJS} param.o ioconf.o \
- ${LIBKERN} ${LIBCOMPAT}
-SYSTEM_DEP= Makefile ${SYSTEM_OBJ}
-SYSTEM_LD_HEAD= @echo loading $@; rm -f $@
-SYSTEM_LD= @${LD} ${LDX} -N -e start -Ttext f8004000 -o $@ \
- ${SYSTEM_OBJ} vers.o
-SYSTEM_LD_TAIL= @echo rearranging symbols; size $@; chmod 755 $@
-#.if ${DEBUG} == "-g"
-#SYSTEM_LD_TAIL+=; echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \
-# echo strip -d $@; strip -d $@
-#.endif
%LOAD
-newvers: vers.o
+assym.h: genassym
+ ./genassym >assym.h
-vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
- sh $S/conf/newvers.sh
- ${CC} ${CFLAGS} -c vers.c
+genassym: genassym.o
+ ${CC} -o $@ genassym.o
-clean::
- rm -f eddep bsd bsd.gdb tags vnode_if.[ch] tags1 *.[io] \
- [a-z]*.s Errs errs linterrs makelinks genassym
+genassym.o: ${SPARC}/sparc/genassym.c
+ ${NORMAL_C_C:S/^-pg$//:S/^-p$//}
-locore.o: ${SPARC}/sparc/locore.s assym.s
- ${NORMAL_S}
+param.c: $S/conf/param.c
+ rm -f param.c
+ cp $S/conf/param.c .
-# depend on maxusers
-assym.s: Makefile
+param.o: param.c Makefile
+ ${NORMAL_C_C}
-./assym.s: assym.s
-assym.s: genassym
- ./genassym >assym.s
+ioconf.o: ioconf.c
+ ${NORMAL_C}
+
+newvers: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
+ sh $S/conf/newvers.sh
+ ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c
-genassym: genassym.o
- ${CC} -static -o $@ genassym.o
-genassym.o: ${SPARC}/sparc/genassym.c Makefile
- ${CC} -c ${CFLAGS} ${PARAM} $<
+clean::
+ rm -f eddep *netbsd netbsd.gdb tags *.[io] [a-z]*.s \
+ [Ee]rrs linterrs makelinks genassym genassym.o assym.h
+
+lint:
+ @lint -hbxncez -DGENERIC -Dvolatile= ${CPPFLAGS} ${PARAM} -UKGDB \
+ ${SPARC}/sparc/Locore.c ${CFILES} ${SPARC}/sparc/swapgeneric.c \
+ ioconf.c param.c | \
+ grep -v 'static function .* unused'
-SRCS= ${CFILES} ioconf.c param.c vnode_if.c
-depend: .depend
-.depend: ${SRCS} assym.s
- mkdep ${COPTS} ${SRCS}
- mkdep -a -p ${COPTS} ${SPARC}/sparc/genassym.c
+tags:
+ @echo "see $S/kern/Makefile for tags"
links:
egrep '#if' ${CFILES} | sed -f $S/conf/defines | \
sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
sort -u | comm -23 - dontlink | \
- sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+ sed 's,../.*/\(.*.o\),rm -f \1; ln -s ../GENERIC/\1 \1,' > makelinks
sh makelinks && rm -f dontlink
-tags: depend
- sh $S/conf/systags.sh
- rm -f tags1
- sed -e 's, ../, ,' tags > tags1
+SRCS= ${SPARC}/sparc/locore.s \
+ param.c ioconf.c ${CFILES} ${SFILES}
+depend:: .depend
+.depend: ${SRCS} assym.h param.c
+ mkdep ${AFLAGS} ${CPPFLAGS} ${SPARC}/sparc/locore.s
+ mkdep -a ${CFLAGS} ${CPPFLAGS} param.c ioconf.c ${CFILES}
+ mkdep -a ${AFLAGS} ${CPPFLAGS} ${SFILES}
+ mkdep -a ${CFLAGS} ${CPPFLAGS} ${PARAM} ${SPARC}/sparc/genassym.c
-ioconf.o: ioconf.c
- ${CC} -c ${CFLAGS} ioconf.c
-param.c: $S/conf/param.c
- rm -f param.c
- cp $S/conf/param.c .
+# depend on root or device configuration
+autoconf.o conf.o: Makefile
+
+# depend on network or filesystem configuration
+uipc_proto.o vfs_conf.o: Makefile
-param.o: param.c Makefile
- ${CC} -c ${CFLAGS} ${PARAM} param.c
+# depend on maxusers
+genassym.o machdep.o: Makefile
-vnode_if.c vnode_if.h: $S/kern/vnode_if.sh $S/kern/vnode_if.src
- AWK="${AWK}" sh $S/kern/vnode_if.sh $S/kern/vnode_if.src
+# depend on CPU configuration
+bwtwo.o cgsix.o cgthree.o cgtwo.o cons.o dma.o esp.o fb.o if_ie.o: Makefile
+ms.c obio.o zs.c autoconf.o clock.o cpu.o disksubr.o locore.o: Makefile
+machdep.o mem.o openprom.o pmap.o vm_machdep.o: Makefile
-%RULES
-# DO NOT DELETE THIS LINE -- make depend uses it
+locore.o: ${SPARC}/sparc/locore.s assym.h
+ ${NORMAL_S}
+%RULES
diff --git a/sys/arch/sparc/conf/files.sparc b/sys/arch/sparc/conf/files.sparc
index 3a6851377c8..43a0adeb80a 100644
--- a/sys/arch/sparc/conf/files.sparc
+++ b/sys/arch/sparc/conf/files.sparc
@@ -1,112 +1,152 @@
-# $NetBSD: files.sparc,v 1.12 1995/10/05 00:21:35 pk Exp $
+# $NetBSD: files.sparc,v 1.23 1996/05/21 19:06:26 pk Exp $
# @(#)files.sparc 8.1 (Berkeley) 7/19/93
# sparc-specific configuration info
-# maxpartitions must be first item in files.${ARCH}
+# maxpartitions must be first item in files.${ARCH}.newconf
maxpartitions 8
maxusers 2 8 64
-device mainbus at root {}
+device mainbus {}
+attach mainbus at root
-device obio at mainbus { [addr = -1], [level = -1] }
-device vmel at mainbus { [addr = -1], [level = -1], [vect = -1] }
-device vmes at mainbus { [addr = -1], [level = -1], [vect = -1] }
-file arch/sparc/dev/obio.c obio vmel vmes
+device obio { [addr = -1], [level = -1] }
+attach obio at mainbus
+device vmel { [addr = -1], [level = -1], [vect = -1] }
+attach vmel at mainbus
+device vmes { [addr = -1], [level = -1], [vect = -1] }
+attach vmes at mainbus
+file arch/sparc/dev/obio.c obio | vmel | vmes
-device pfour at obio {}
-file arch/sparc/dev/pfour.c pfour needs-count
+device audio
+attach audio at mainbus, obio
+file arch/sparc/dev/amd7930.c audio
-device audio at mainbus
-file arch/sparc/dev/amd7930.c audio needs-flag
-file arch/sparc/sparc/amd7930intr.s audio
-
-device auxreg at mainbus
+device auxreg
+attach auxreg at mainbus, obio
file arch/sparc/sparc/auxreg.c
-device clock at mainbus, obio
-device oclock at obio
-device timer at mainbus, obio
-device eeprom at obio
+device clock
+attach clock at mainbus, obio
+
+device oclock
+attach oclock at obio
+
+device timer
+attach timer at mainbus, obio
+
+device eeprom
+attach eeprom at obio
file arch/sparc/sparc/clock.c
-device cpu at mainbus
+device power
+attach power at obio
+file arch/sparc/dev/power.c power
+
+device cpu
+attach cpu at mainbus
file arch/sparc/sparc/cpu.c
-device memreg at mainbus, obio
+device memreg
+attach memreg at mainbus, obio
file arch/sparc/sparc/memreg.c
-device zs at mainbus, obio
-file arch/sparc/dev/zs.c zs needs-count
+device zs
+attach zs at mainbus, obio
+file arch/sparc/dev/zs.c zs needs-count
+
+device fdc {}
+attach fdc at mainbus, obio
+device fd: disk
+attach fd at fdc
+file arch/sparc/dev/fd.c fdc | fd needs-flag
+file arch/sparc/sparc/bsd_fdintr.s fdc
+
+device iommu {}
+attach iommu at mainbus
+file arch/sparc/sparc/iommu.c iommu
-device fdc at mainbus {}
-device fd at fdc: disk
-file arch/sparc/dev/fd.c fd needs-flag
-file arch/sparc/sparc/bsd_fdintr.s fd
+device sbus { slot = -1, offset = -1 }
+attach sbus at mainbus, iommu
+file arch/sparc/dev/sbus.c sbus
-device sbus at mainbus { slot = -1, offset = -1 }
-file arch/sparc/dev/sbus.c sbus
+#
+# Machine-independent SCSI drivers
+#
include "../../../scsi/files.scsi"
major { sd = 7 }
major { vnd = 8 }
major { cd = 18 }
-device dma at sbus, obio
-device espdma at sbus { slot = -1, offset = -1 }
-device ledma at sbus { slot = -1, offset = -1 }
-file arch/sparc/dev/dma.c dma espdma ledma needs-flag
+device dma {}
+attach dma at sbus, obio
+device ledma {}
+attach ledma at sbus
+file arch/sparc/dev/dma.c dma | ledma
-device esp at sbus, espdma, obio: scsi
+device esp: scsi
+attach esp at sbus, dma, obio
file arch/sparc/dev/esp.c esp
-device bwtwo at sbus, obio, vmes, vmel, pfour
+# Brooktree DAC attribute
+define bt_dac
+
+device bwtwo
+attach bwtwo at sbus, obio, vmes, vmel
file arch/sparc/dev/bwtwo.c bwtwo needs-flag
-device cgtwo at vmes
+device cgtwo
+attach cgtwo at sbus, obio, vmes
file arch/sparc/dev/cgtwo.c cgtwo needs-flag
-device cgthree at sbus
+device cgthree: bt_dac
+attach cgthree at sbus
file arch/sparc/dev/cgthree.c cgthree needs-flag
-device cgfour at pfour
+device cgfour: bt_dac
+attach cgfour at obio
file arch/sparc/dev/cgfour.c cgfour needs-flag
-device cgsix at sbus, pfour
+device cgsix: bt_dac
+attach cgsix at sbus, obio
file arch/sparc/dev/cgsix.c cgsix needs-flag
-device cgeight at pfour
+device cgeight: bt_dac
+attach cgeight at obio
file arch/sparc/dev/cgeight.c cgeight needs-flag
-file arch/sparc/dev/bt_subr.c cgsix cgthree cgfour
+file arch/sparc/dev/bt_subr.c bt_dac
-device le at sbus, ledma, obio: ifnet, ether
+# device definition in sys/conf/files
+attach le at sbus, ledma, obio
file arch/sparc/dev/if_le.c le
-device ie at obio, vmes, vmel: ifnet, ether
+device ie: ifnet, ether
+attach ie at obio, vmes, vmel
file arch/sparc/dev/if_ie.c ie
-device xdc at vmel {drive = -1}
-device xd at xdc: disk
+device xdc {drive = -1}
+attach xdc at vmel
+device xd: disk
+attach xd at xdc
file arch/sparc/dev/xd.c xd needs-flag
-major { xd = 10 }
+major {xd = 10}
-device xyc at vmes {drive = -1}
-device xy at xyc: disk
+device xyc {drive = -1}
+attach xyc at vmes
+device xy: disk
+attach xy at xyc
file arch/sparc/dev/xy.c xy needs-flag
-major { xy = 3 }
-
-device si at vmes: scsi, ncr5380sbc
-device sw at obio: scsi, ncr5380sbc
-file arch/sparc/dev/si.c si sw
+major {xy = 3}
-# ENI ATM driver
-device en: atm, ifnet
-attach en at sbus with en_sbus
-file arch/sparc/dev/if_en_sbus.c en
-file dev/ic/midway.c en
+device si: scsi, ncr5380sbc
+attach si at vmes
+device sw: scsi, ncr5380sbc
+attach sw at obio
+file arch/sparc/dev/si.c si | sw
pseudo-device kbd
@@ -126,7 +166,10 @@ file arch/sparc/fpu/fpu_mul.c
file arch/sparc/fpu/fpu_sqrt.c
file arch/sparc/fpu/fpu_subr.c
+# N.B.: optimizer breaks pmap.c and/or cache.c somehow -- have not
+# identified the exact problem yet. NOOPT_C suffices for now.
file arch/sparc/sparc/autoconf.c
+file arch/sparc/sparc/amd7930intr.s audio
file arch/sparc/sparc/cache.c
file arch/sparc/sparc/conf.c
file arch/sparc/sparc/in_cksum.c
@@ -140,21 +183,36 @@ file arch/sparc/sparc/process_machdep.c
file arch/sparc/sparc/mem.c
file arch/sparc/sparc/openprom.c
file arch/sparc/sparc/pmap.c
+# the following overrides the generic "sys_process.c"
+# commented out by deraadt
+#file arch/sparc/sparc/sys_process.c
file arch/sparc/sparc/sys_machdep.c
file arch/sparc/sparc/trap.c
file arch/sparc/sparc/vm_machdep.c
file arch/sparc/sparc/disksubr.c
-file arch/sparc/sparc/db_interface.c ddb
+file kludge_for_in_proto.c hy needs-flag
+
+file arch/sparc/sparc/db_interface.c ddb
file arch/sparc/sparc/db_trace.c ddb
file arch/sparc/sparc/db_disasm.c ddb
+#
+# Raster Console
+#
include "../../../dev/rcons/files.rcons"
+#
+# Compatibility modules
+#
+
# SVR4 Binary Compatibility (COMPAT_SVR4)
include "../../../compat/svr4/files.svr4"
file arch/sparc/sparc/svr4_machdep.c compat_svr4
+file arch/sparc/sparc/sunos_machdep.c compat_sunos
# SunOS Binary Compatibility (COMPAT_SUNOS)
include "../../../compat/sunos/files.sunos"
-file arch/sparc/sparc/sunos_machdep.c compat_sunos
+
+# Miscellaneous
+file netns/ns_cksum.c ns
diff --git a/sys/arch/sparc/dev/amd7930.c b/sys/arch/sparc/dev/amd7930.c
index c7a133e3eaf..d2af316243d 100644
--- a/sys/arch/sparc/dev/amd7930.c
+++ b/sys/arch/sparc/dev/amd7930.c
@@ -1,4 +1,4 @@
-/* $NetBSD: amd7930.c,v 1.2 1995/05/04 19:43:27 pk Exp $ */
+/* $NetBSD: amd7930.c,v 1.10 1996/03/31 22:38:29 pk Exp $ */
/*
* Copyright (c) 1995 Rolf Grossmann
@@ -69,7 +69,7 @@ struct amd7930_softc {
int sc_open; /* single use device */
int sc_locked; /* true when transfering data */
struct mapreg sc_map; /* current contents of map registers */
-
+
u_char sc_rlevel; /* record level */
u_char sc_plevel; /* play level */
u_char sc_mlevel; /* monitor level */
@@ -83,7 +83,7 @@ struct amd7930_softc {
/* sc_au is special in that the hardware interrupt handler uses it */
struct auio sc_au; /* recv and xmit buffers, etc */
-#define sc_intrcnt sc_au.au_intrcnt
+#define sc_intrcnt sc_au.au_intrcnt /* statistics */
};
/* interrupt interfaces */
@@ -92,7 +92,6 @@ int amd7930hwintr __P((void *));
#define AUDIO_SET_SWINTR ienab_bis(IE_L4)
#else
struct auio *auiop;
-extern void amd7930_trap();
#endif
int amd7930swintr __P((void *));
@@ -101,12 +100,15 @@ void audio_setmap __P((volatile struct amd7930 *, struct mapreg *));
static void init_amd __P((volatile struct amd7930 *));
/* autoconfiguration driver */
-void amd9730attach __P((struct device *, struct device *, void *));
-int amd9730match __P((struct device *, void *, void *));
+void amd7930attach __P((struct device *, struct device *, void *));
+int amd7930match __P((struct device *, void *, void *));
+
+struct cfattach audio_ca = {
+ sizeof(struct amd7930_softc), amd7930match, amd7930attach
+};
-struct cfdriver audiocd = {
- NULL, "audio", amd9730match, amd9730attach,
- DV_DULL, sizeof(struct amd7930_softc)
+struct cfdriver audio_cd = {
+ NULL, "audio", DV_DULL
};
struct audio_device amd7930_device = {
@@ -212,8 +214,10 @@ int amd7930_set_in_port __P((void *, int));
int amd7930_get_in_port __P((void *));
int amd7930_commit_settings __P((void *));
u_int amd7930_get_silence __P((int));
-int amd7930_start_output __P((void *, void *, int, void (*)(), void *));
-int amd7930_start_input __P((void *, void *, int, void (*)(), void *));
+int amd7930_start_output __P((void *, void *, int, void (*)(void *),
+ void *));
+int amd7930_start_input __P((void *, void *, int, void (*)(void *),
+ void *));
int amd7930_halt_output __P((void *));
int amd7930_halt_input __P((void *));
int amd7930_cont_output __P((void *));
@@ -268,7 +272,7 @@ struct audio_hw_if sa_hw_if = {
/* autoconfig routines */
int
-amd9730match(parent, vcf, aux)
+amd7930match(parent, vcf, aux)
struct device *parent;
void *vcf, *aux;
{
@@ -276,7 +280,7 @@ amd9730match(parent, vcf, aux)
register struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
- if (cputyp==CPU_SUN4)
+ if (CPU_ISSUN4)
return (0);
return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
}
@@ -285,7 +289,7 @@ amd9730match(parent, vcf, aux)
* Audio chip found.
*/
void
-amd9730attach(parent, self, args)
+amd7930attach(parent, self, args)
struct device *parent, *self;
void *args;
{
@@ -301,8 +305,9 @@ amd9730attach(parent, self, args)
}
pri = ra->ra_intr[0].int_pri;
printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT);
- amd = (volatile struct amd7930 *)(ra->ra_vaddr ? ra->ra_vaddr :
- mapiodev(ra->ra_reg, 0, sizeof (*amd), ca->ca_bustype));
+ amd = (volatile struct amd7930 *)(ra->ra_vaddr ?
+ ra->ra_vaddr : mapiodev(ra->ra_reg, 0, sizeof (*amd),
+ ca->ca_bustype));
sc->sc_map.mr_mmr1 = AMD_MMR1_GX | AMD_MMR1_GER |
AMD_MMR1_GR | AMD_MMR1_STG;
@@ -312,7 +317,7 @@ amd9730attach(parent, self, args)
sc->sc_plevel = 128;
sc->sc_mlevel = 0;
sc->sc_out_port = SUNAUDIO_SPEAKER;
-
+
init_amd(amd);
#ifndef AUDIO_C_HANDLER
@@ -360,14 +365,13 @@ amd7930_open(dev, flags)
int flags;
{
register struct amd7930_softc *sc;
- register volatile struct amd7930 *amd;
int unit = AUDIOUNIT(dev);
DPRINTF(("sa_open: unit %d\n",unit));
- if (unit >= audiocd.cd_ndevs)
+ if (unit >= audio_cd.cd_ndevs)
return (ENODEV);
- if ((sc = audiocd.cd_devs[unit]) == NULL)
+ if ((sc = audio_cd.cd_devs[unit]) == NULL)
return (ENXIO);
if (sc->sc_open)
return (EBUSY);
@@ -410,7 +414,7 @@ amd7930_set_in_sr(addr, sr)
{
if (sr != 8000)
return EINVAL;
-
+
return(0); /* no other sampling rates supported by amd chip */
}
@@ -463,7 +467,7 @@ amd7930_set_encoding(addr, enc)
{
if (enc != AUDIO_ENCODING_ULAW)
return(EINVAL);
-
+
return(0); /* no other encoding supported by amd chip */
}
@@ -571,7 +575,7 @@ amd7930_commit_settings(addr)
register struct mapreg *map;
register volatile struct amd7930 *amd;
register int s, level;
-
+
DPRINTF(("sa_commit.\n"));
map = &sc->sc_map;
@@ -579,7 +583,7 @@ amd7930_commit_settings(addr)
map->mr_gx = gx_coeff[sc->sc_rlevel];
map->mr_stgr = gx_coeff[sc->sc_mlevel];
-
+
level = (sc->sc_plevel * (256 + NGER)) >> 8;
if (level >= 256) {
map->mr_ger = ger_coeff[level - 256];
@@ -593,9 +597,9 @@ amd7930_commit_settings(addr)
map->mr_mmr2 |= AMD_MMR2_LS;
else
map->mr_mmr2 &= ~AMD_MMR2_LS;
-
+
s = splaudio();
-
+
amd->cr = AMDR_MAP_MMR1;
amd->dr = map->mr_mmr1;
amd->cr = AMDR_MAP_GX;
@@ -625,7 +629,7 @@ amd7930_start_output(addr, p, cc, intr, arg)
void *addr;
void *p;
int cc;
- void (*intr)();
+ void (*intr) __P((void *));
void *arg;
{
register struct amd7930_softc *sc = addr;
@@ -657,7 +661,7 @@ amd7930_start_input(addr, p, cc, intr, arg)
void *addr;
void *p;
int cc;
- void (*intr)();
+ void (*intr) __P((void *));
void *arg;
{
register struct amd7930_softc *sc = addr;
@@ -760,7 +764,7 @@ amd7930_set_port(addr, cp)
if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1)
return(EINVAL);
-
+
switch(cp->dev) {
case SUNAUDIO_MIC_PORT:
sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
@@ -790,7 +794,7 @@ amd7930_get_port(addr, cp)
if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1)
return(EINVAL);
-
+
switch(cp->dev) {
case SUNAUDIO_MIC_PORT:
cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
@@ -814,8 +818,6 @@ amd7930_query_devinfo(addr, dip)
void *addr;
register mixer_devinfo_t *dip;
{
- register struct amd7930_softc *sc = addr;
-
switch(dip->index) {
case SUNAUDIO_MIC_PORT:
dip->type = AUDIO_MIXER_VALUE;
@@ -867,7 +869,7 @@ amd7930_query_devinfo(addr, dip)
}
DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
-
+
return(0);
}
@@ -913,7 +915,6 @@ amd7930hwintr(au0)
}
}
- *(au->au_intrcnt)++;
return (1);
}
#endif /* AUDIO_C_HANDLER */
diff --git a/sys/arch/sparc/dev/amd7930var.h b/sys/arch/sparc/dev/amd7930var.h
index 0faaf75c41e..2d2e5f28257 100644
--- a/sys/arch/sparc/dev/amd7930var.h
+++ b/sys/arch/sparc/dev/amd7930var.h
@@ -1,4 +1,4 @@
-/* $NetBSD: amd7930var.h,v 1.2 1995/05/04 19:43:32 pk Exp $ */
+/* $NetBSD: amd7930var.h,v 1.3 1996/02/01 22:32:25 mycroft Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -44,7 +44,7 @@
* @(#)bsd_audiovar.h 8.1 (Berkeley) 6/11/93
*/
-#ifndef LOCORE
+#ifndef _LOCORE
/* XXX I think these defines should go into some other header file */
#define SUNAUDIO_MIC_PORT 0
@@ -80,4 +80,4 @@ struct mapreg {
u_char mr_mmr2;
};
-#endif /* !LOCORE */
+#endif /* !_LOCORE */
diff --git a/sys/arch/sparc/dev/bt_subr.c b/sys/arch/sparc/dev/bt_subr.c
index c7ba266d197..2a1df0ad71b 100644
--- a/sys/arch/sparc/dev/bt_subr.c
+++ b/sys/arch/sparc/dev/bt_subr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: bt_subr.c,v 1.4 1994/11/20 20:51:54 deraadt Exp $ */
+/* $NetBSD: bt_subr.c,v 1.5 1996/03/14 19:44:32 christos Exp $ */
/*
* Copyright (c) 1993
@@ -45,9 +45,12 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/errno.h>
+#include <vm/vm.h>
+
#include <machine/fbio.h>
#include <sparc/dev/btreg.h>
diff --git a/sys/arch/sparc/dev/btreg.h b/sys/arch/sparc/dev/btreg.h
index a1f4692da60..aa3f5fbc0db 100644
--- a/sys/arch/sparc/dev/btreg.h
+++ b/sys/arch/sparc/dev/btreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: btreg.h,v 1.2 1994/11/20 20:51:55 deraadt Exp $ */
+/* $NetBSD: btreg.h,v 1.4 1996/02/27 22:09:21 thorpej Exp $ */
/*
* Copyright (c) 1993
@@ -78,3 +78,63 @@ struct bt_regs {
u_int bt_ctrl; /* control register */
u_int bt_omap; /* overlay (cursor) map register */
};
+#define BT_INIT(bt, shift) do { /* whatever this means.. */ \
+ (bt)->bt_addr = 0x06 << (shift); /* command reg */ \
+ (bt)->bt_ctrl = 0x73 << (shift); /* overlay plane */ \
+ (bt)->bt_addr = 0x04 << (shift); /* read mask */ \
+ (bt)->bt_ctrl = 0xff << (shift); /* color planes */ \
+} while(0)
+#define BT_UNBLANK(bt, x, shift) do { \
+ /* restore color 0 (and R of color 1) */ \
+ (bt)->bt_addr = 0 << (shift); \
+ (bt)->bt_cmap = (x); \
+ if ((shift)) { \
+ (bt)->bt_cmap = (x) << 8; \
+ (bt)->bt_cmap = (x) << 16; \
+ /* restore read mask */ \
+ BT_INIT((bt), (shift)); \
+} while(0)
+#define BT_BLANK(bt, shift) do { \
+ (bt)->bt_addr = 0x06 << (shift); /* command reg */ \
+ (bt)->bt_ctrl = 0x70 << (shift); /* overlay plane */ \
+ (bt)->bt_addr = 0x04 << (shift); /* read mask */ \
+ (bt)->bt_ctrl = 0x00 << (shift); /* color planes */ \
+ /* Set color 0 to black -- note that this overwrites R of color 1. */\
+ (bt)->bt_addr = 0 << (shift); \
+ (bt)->bt_cmap = 0 << (shift); \
+ /* restore read mask */ \
+ BT_INIT((bt), (shift)); \
+} while(0)
+
+
+/*
+ * Sbus framebuffer control look like this (usually at offset 0x400000).
+ */
+struct fbcontrol {
+ struct bt_regs fbc_dac;
+ u_char fbc_ctrl;
+ u_char fbc_status;
+ u_char fbc_cursor_start;
+ u_char fbc_cursor_end;
+ u_char fbc_vcontrol[12]; /* 12 bytes of video timing goo */
+};
+/* fbc_ctrl bits: */
+#define FBC_IENAB 0x80 /* Interrupt enable */
+#define FBC_VENAB 0x40 /* Video enable */
+#define FBC_TIMING 0x20 /* Master timing enable */
+#define FBC_CURSOR 0x10 /* Cursor compare enable */
+#define FBC_XTALMSK 0x0c /* Xtal select (0,1,2,test) */
+#define FBC_DIVMSK 0x03 /* Divisor (1,2,3,4) */
+
+/* fbc_status bits: */
+#define FBS_INTR 0x80 /* Interrupt pending */
+#define FBS_MSENSE 0x70 /* Monitor sense mask */
+#define FBS_1024X768 0x10
+#define FBS_1152X900 0x30
+#define FBS_1280X1024 0x40
+#define FBS_1600X1280 0x50
+#define FBS_ID_MASK 0x0f /* ID mask */
+#define FBS_ID_COLOR 0x01
+#define FBS_ID_MONO 0x02
+#define FBS_ID_MONO_ECL 0x03 /* ? */
+
diff --git a/sys/arch/sparc/dev/bwtwo.c b/sys/arch/sparc/dev/bwtwo.c
index b024a82640a..78be5d0b885 100644
--- a/sys/arch/sparc/dev/bwtwo.c
+++ b/sys/arch/sparc/dev/bwtwo.c
@@ -1,35 +1,7 @@
-/* $NetBSD: bwtwo.c,v 1.15 1995/10/09 15:39:34 pk Exp $ */
+/* $NetBSD: bwtwo.c,v 1.26 1996/04/01 17:30:15 christos Exp $ */
/*
- * Copyright (c) 1995 Theo de Raadt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed under OpenBSD by
- * Theo de Raadt.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
+ * Copyright (c) 1996 Jason R. Thorpe. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -77,14 +49,19 @@
* black&white display (bwtwo) driver.
*
* Does not handle interrupts, even though they can occur.
+ *
+ * P4 and overlay plane support by Jason R. Thorpe <thorpej@NetBSD.ORG>.
+ * Overlay plane handling hints and ideas provided by Brad Spencer.
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/tty.h>
+#include <sys/conf.h>
#include <vm/vm.h>
@@ -92,25 +69,36 @@
#include <machine/autoconf.h>
#include <machine/pmap.h>
#include <machine/fbvar.h>
-#if defined(SUN4)
#include <machine/eeprom.h>
#include <machine/ctlreg.h>
+#include <machine/conf.h>
#include <sparc/sparc/asm.h>
-#endif
+#include <sparc/dev/btreg.h>
#include <sparc/dev/bwtworeg.h>
-#include <sparc/dev/pfourreg.h>
#include <sparc/dev/sbusvar.h>
-#include "pfour.h"
+#if defined(SUN4)
+#include <sparc/dev/pfourreg.h>
+#endif
/* per-display variables */
struct bwtwo_softc {
struct device sc_dev; /* base device */
struct sbusdev sc_sd; /* sbus device */
struct fbdevice sc_fb; /* frame buffer device */
- volatile struct bwtworeg *sc_reg;/* control registers */
- struct rom_reg sc_phys; /* display RAM (phys addr) */
- int sc_bustype;
+ volatile struct fbcontrol *sc_reg;/* control registers */
+ struct rom_reg sc_phys; /* phys address description */
+ int sc_bustype; /* type of bus we live on */
+ int sc_pixeloffset; /* offset to framebuffer */
+#if defined(SUN4)
+ /*
+ * Additional overlay plane goo.
+ */
+ int sc_ovtype; /* what kind of color fb? */
+#define BWO_NONE 0x00
+#define BWO_CGFOUR 0x01
+#define BWO_CGEIGHT 0x02
+#endif
};
/* autoconfiguration driver */
@@ -121,20 +109,24 @@ int bwtwoclose __P((dev_t, int, int, struct proc *));
int bwtwoioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
int bwtwommap __P((dev_t, int, int));
static void bwtwounblank __P((struct device *));
+static void bwtwo_set_video __P((struct bwtwo_softc *, int));
+static int bwtwo_get_video __P((struct bwtwo_softc *));
+
+struct cfattach bwtwo_ca = {
+ sizeof(struct bwtwo_softc), bwtwomatch, bwtwoattach
+};
-struct cfdriver bwtwocd = {
- NULL, "bwtwo", bwtwomatch, bwtwoattach,
- DV_DULL, sizeof(struct bwtwo_softc)
+struct cfdriver bwtwo_cd = {
+ NULL, "bwtwo", DV_DULL
};
+/* XXX we do not handle frame buffer interrupts (do not know how) */
+
/* frame buffer generic driver */
static struct fbdriver bwtwofbdriver = {
bwtwounblank, bwtwoopen, bwtwoclose, bwtwoioctl, bwtwommap
};
-static void bwtwoenable __P((struct bwtwo_softc *, int));
-static int bwtwostatus __P((struct bwtwo_softc *));
-
extern int fbnode;
extern struct tty *fbconstty;
@@ -150,18 +142,48 @@ bwtwomatch(parent, vcf, aux)
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
+ if (CPU_ISSUN4 && cf->cf_unit != 0)
+ return (0);
+
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
+
+ /*
+ * Mask out invalid flags from the user.
+ */
+ cf->cf_flags &= FB_USERMASK;
+
if (ca->ca_bustype == BUS_SBUS)
return(1);
-#if NPFOUR > 0
- if (ca->ca_bustype == BUS_PFOUR) {
- if (PFOUR_ID(ra->ra_pfour) == PFOUR_ID_BW)
- return (1);
+
+ /*
+ * Make sure there's hardware there.
+ */
+ if (probeget(ra->ra_vaddr, 4) == -1)
return (0);
+
+#if defined(SUN4)
+ if (CPU_ISSUN4 && (ca->ca_bustype == BUS_OBIO)) {
+ /*
+ * Check for a pfour framebuffer.
+ */
+ switch (fb_pfour_id(ra->ra_vaddr)) {
+ case PFOUR_ID_BW:
+ case PFOUR_ID_COLOR8P1: /* bwtwo in ... */
+ case PFOUR_ID_COLOR24: /* ...overlay plane */
+ cf->cf_flags |= FB_PFOUR;
+ /* FALLTHROUGH */
+
+ case PFOUR_NOTPFOUR:
+ return (1);
+
+ default:
+ return (0);
+ }
}
#endif
- return (probeget(ra->ra_vaddr, 4) != -1);
+
+ return (0);
}
/*
@@ -175,107 +197,180 @@ bwtwoattach(parent, self, args)
register struct bwtwo_softc *sc = (struct bwtwo_softc *)self;
register struct confargs *ca = args;
register int node = ca->ca_ra.ra_node, ramsize;
- int isconsole;
- char *nam;
+ struct fbdevice *fb = &sc->sc_fb;
+ int isconsole = 0;
+ int sbus = 1;
+ char *nam = NULL;
- sc->sc_fb.fb_driver = &bwtwofbdriver;
- sc->sc_fb.fb_device = &sc->sc_dev;
- sc->sc_fb.fb_type.fb_type = FBTYPE_SUN2BW;
+ fb->fb_driver = &bwtwofbdriver;
+ fb->fb_device = &sc->sc_dev;
+ fb->fb_type.fb_type = FBTYPE_SUN2BW;
+ fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags;
+
+ /*
+ * Map the control register.
+ */
+ if (fb->fb_flags & FB_PFOUR) {
+ fb->fb_pfour =
+ (volatile u_int32_t *)mapiodev(ca->ca_ra.ra_reg, 0,
+ sizeof(u_int32_t), ca->ca_bustype);
+ sc->sc_reg = NULL;
+ } else {
+ sc->sc_reg =
+ (volatile struct fbcontrol *)mapiodev(ca->ca_ra.ra_reg,
+ BWREG_REG, sizeof(struct fbcontrol), ca->ca_bustype);
+ fb->fb_pfour = NULL;
+ }
+
+ /* Set up default pixel offset. May be changed below. */
+ sc->sc_pixeloffset = BWREG_MEM;
- sc->sc_bustype = ca->ca_bustype;
switch (ca->ca_bustype) {
-#if defined(SUN4)
-#if NPFOUR > 0
- case BUS_PFOUR:
- node = 0;
- pfour_reset();
- pfour_videosize(ca->ca_ra.ra_pfour,
- &sc->sc_fb.fb_type.fb_width,
- &sc->sc_fb.fb_type.fb_height);
- sc->sc_fb.fb_linebytes = sc->sc_fb.fb_type.fb_width / 8;
- nam = "bwtwo";
- break;
-#endif
-#endif
case BUS_OBIO:
-#if defined(SUN4M)
- if (cputyp == CPU_SUN4M) { /* 4m has framebuffer on obio */
- nam = getpropstring(node, "model");
- break;
- }
-#endif
+ if (CPU_ISSUN4M) /* 4m has framebuffer on obio */
+ goto obp_name;
+
+ sbus = node = 0;
#if defined(SUN4)
- node = 0;
+ if (fb->fb_flags & FB_PFOUR) {
+ nam = "bwtwo/p4";
+ /*
+ * Notice if this is an overlay plane on a color
+ * framebuffer. Note that PFOUR_COLOR_OFF_OVERLAY
+ * is the same as PFOUR_BW_OFF, but we use the
+ * different names anyway.
+ */
+ switch (PFOUR_ID(*fb->fb_pfour)) {
+ case PFOUR_ID_COLOR8P1:
+ sc->sc_ovtype = BWO_CGFOUR;
+ sc->sc_pixeloffset = PFOUR_COLOR_OFF_OVERLAY;
+ break;
+
+ case PFOUR_ID_COLOR24:
+ sc->sc_ovtype = BWO_CGEIGHT;
+ sc->sc_pixeloffset = PFOUR_COLOR_OFF_OVERLAY;
+ break;
+
+ default:
+ sc->sc_ovtype = BWO_NONE;
+ sc->sc_pixeloffset = PFOUR_BW_OFF;
+ break;
+ }
+ } else
+#endif
+ nam = "bwtwo";
+ break;
+
+ case BUS_VME32:
+ case BUS_VME16:
+ sbus = node = 0;
nam = "bwtwo";
break;
-#endif
+
case BUS_SBUS:
+ obp_name:
#if defined(SUN4C) || defined(SUN4M)
nam = getpropstring(node, "model");
- break;
#endif
+ break;
}
+
sc->sc_phys = ca->ca_ra.ra_reg[0];
sc->sc_bustype = ca->ca_bustype;
- sc->sc_fb.fb_type.fb_depth = 1;
- fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth,
- 1152, 900, node, ca->ca_bustype);
+ fb->fb_type.fb_depth = 1;
+ fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype);
- ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes;
- sc->sc_fb.fb_type.fb_cmsize = 0;
- sc->sc_fb.fb_type.fb_size = ramsize;
+ ramsize = fb->fb_type.fb_height * fb->fb_linebytes;
+ fb->fb_type.fb_cmsize = 0;
+ fb->fb_type.fb_size = ramsize;
printf(": %s, %d x %d", nam,
- sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height);
+ fb->fb_type.fb_width, fb->fb_type.fb_height);
#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
struct eeprom *eep = (struct eeprom *)eeprom_va;
+ int constype = (fb->fb_flags & FB_PFOUR) ? EE_CONS_P4OPT :
+ EE_CONS_BW;
/*
* Assume this is the console if there's no eeprom info
* to be found.
*/
- if (eep == NULL || eep->ee_diag.eed_console == EED_CONS_BW)
+ if (eep == NULL || eep->eeConsole == constype)
isconsole = (fbconstty != NULL);
else
isconsole = 0;
}
#endif
-#if defined(SUN4C) || defined(SUN4M)
- if (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M)
+
+ if (CPU_ISSUN4COR4M)
isconsole = node == fbnode && fbconstty != NULL;
-#endif
+
/*
* When the ROM has mapped in a bwtwo display, the address
- * maps only the video RAM, so in any case we have to map the
+ * maps only the video RAM, hence we always map the control
* registers ourselves. We only need the video RAM if we are
* going to print characters via rconsole.
*/
- if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) {
+ if ((fb->fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) {
/* this probably cannot happen (on sun4c), but what the heck */
- sc->sc_fb.fb_pixels = mapiodev(ca->ca_ra.ra_reg, BWREG_MEM,
+ fb->fb_pixels =
+ mapiodev(ca->ca_ra.ra_reg, sc->sc_pixeloffset,
ramsize, ca->ca_bustype);
}
- sc->sc_reg = (volatile struct bwtworeg *)mapiodev(ca->ca_ra.ra_reg,
- BWREG_REG, sizeof(struct bwtworeg), ca->ca_bustype);
/* Insure video is enabled */
- bwtwoenable(sc, 1);
+ bwtwo_set_video(sc, 1);
if (isconsole) {
printf(" (console)\n");
#ifdef RASTERCONSOLE
- fbrcons_init(&sc->sc_fb);
+ fbrcons_init(fb);
#endif
} else
printf("\n");
+
#if defined(SUN4C) || defined(SUN4M)
- if (ca->ca_bustype == BUS_SBUS)
+ if (sbus)
sbus_establish(&sc->sc_sd, &sc->sc_dev);
#endif
- if ((node == fbnode && cputyp != CPU_SUN4) ||
- (isconsole && cputyp == CPU_SUN4))
- fb_attach(&sc->sc_fb);
+
+#if defined(SUN4)
+ if ((fb->fb_flags & FB_PFOUR) && (sc->sc_ovtype != BWO_NONE)) {
+ char *ovnam;
+
+ switch (sc->sc_ovtype) {
+ case BWO_CGFOUR:
+ ovnam = "cgfour";
+ break;
+
+ case BWO_CGEIGHT:
+ ovnam = "cgeight";
+ break;
+
+ default:
+ ovnam = "unknown";
+ break;
+ }
+ printf("%s: %s overlay plane\n", sc->sc_dev.dv_xname, ovnam);
+ }
+#endif
+
+ if (CPU_ISSUN4 || node == fbnode) {
+#if defined(SUN4)
+ /*
+ * If we're on an overlay plane of a color framebuffer,
+ * then we don't force the issue in fb_attach() because
+ * we'd like the color framebuffer to actually be the
+ * "console framebuffer". We're only around to speed
+ * up rconsole.
+ */
+ if ((fb->fb_flags & FB_PFOUR) && (sc->sc_ovtype != BWO_NONE ))
+ fb_attach(fb, 0);
+ else
+#endif
+ fb_attach(fb, isconsole);
+ }
}
int
@@ -286,8 +381,9 @@ bwtwoopen(dev, flags, mode, p)
{
int unit = minor(dev);
- if (unit >= bwtwocd.cd_ndevs || bwtwocd.cd_devs[unit] == NULL)
+ if (unit >= bwtwo_cd.cd_ndevs || bwtwo_cd.cd_devs[unit] == NULL)
return (ENXIO);
+
return (0);
}
@@ -309,7 +405,7 @@ bwtwoioctl(dev, cmd, data, flags, p)
int flags;
struct proc *p;
{
- struct bwtwo_softc *sc = bwtwocd.cd_devs[minor(dev)];
+ struct bwtwo_softc *sc = bwtwo_cd.cd_devs[minor(dev)];
switch (cmd) {
@@ -318,11 +414,11 @@ bwtwoioctl(dev, cmd, data, flags, p)
break;
case FBIOGVIDEO:
- bwtwostatus(sc);
+ *(int *)data = bwtwo_get_video(sc);
break;
case FBIOSVIDEO:
- bwtwoenable(sc, *(int *)data);
+ bwtwo_set_video(sc, (*(int *)data));
break;
default:
@@ -337,7 +433,7 @@ bwtwounblank(dev)
{
struct bwtwo_softc *sc = (struct bwtwo_softc *)dev;
- bwtwoenable(sc, 1);
+ bwtwo_set_video(sc, 1);
}
/*
@@ -349,7 +445,7 @@ bwtwommap(dev, off, prot)
dev_t dev;
int off, prot;
{
- register struct bwtwo_softc *sc = bwtwocd.cd_devs[minor(dev)];
+ register struct bwtwo_softc *sc = bwtwo_cd.cd_devs[minor(dev)];
if (off & PGOFSET)
panic("bwtwommap");
@@ -359,55 +455,59 @@ bwtwommap(dev, off, prot)
* I turned on PMAP_NC here to disable the cache as I was
* getting horribly broken behaviour with it on.
*/
- return (REG2PHYS(&sc->sc_phys, BWREG_MEM+off, sc->sc_bustype) | PMAP_NC);
+ return (REG2PHYS(&sc->sc_phys, sc->sc_pixeloffset + off,
+ sc->sc_bustype) | PMAP_NC);
}
-
-int
-bwtwostatus(sc)
+static int
+bwtwo_get_video(sc)
struct bwtwo_softc *sc;
{
-#ifdef SUN4
-#if NPFOUR > 0
- if (sc->sc_bustype == BUS_PFOUR)
- return pfourstatus();
-#endif
- if (sc->sc_bustype == BUS_OBIO)
- return (lduba(AC_SYSENABLE, ASI_CONTROL) & SYSEN_VIDEO);
-#endif
-#if defined(SUN4C) || defined(SUN4M)
- return (sc->sc_reg->bw_ctl & CTL_VE);
+
+#if defined(SUN4)
+ if (CPU_ISSUN4 && (sc->sc_bustype == BUS_OBIO)) {
+ if (sc->sc_fb.fb_flags & FB_PFOUR) {
+ /*
+ * This handles the overlay plane case, too.
+ */
+ return (fb_pfour_get_video(&sc->sc_fb));
+ } else
+ return ((lduba(AC_SYSENABLE,
+ ASI_CONTROL) & SYSEN_VIDEO) != 0);
+ }
#endif
+
+ return ((sc->sc_reg->fbc_ctrl & FBC_VENAB) != 0);
}
-void
-bwtwoenable(sc, on)
+static void
+bwtwo_set_video(sc, enable)
struct bwtwo_softc *sc;
- int on;
+ int enable;
{
-#if NPFOUR > 0
- if (sc->sc_bustype == BUS_PFOUR) {
- pfourenable(on);
+
+#if defined(SUN4)
+ if (CPU_ISSUN4 && (sc->sc_bustype == BUS_OBIO)) {
+ if (sc->sc_fb.fb_flags & FB_PFOUR) {
+ /*
+ * This handles the overlay plane case, too.
+ */
+ fb_pfour_set_video(&sc->sc_fb, enable);
return;
}
-#endif
- if (on) {
-#ifdef SUN4
- if (sc->sc_bustype == BUS_OBIO) {
+ if (enable)
stba(AC_SYSENABLE, ASI_CONTROL,
lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_VIDEO);
- return;
- }
-#endif
- sc->sc_reg->bw_ctl |= CTL_VE;
- } else {
-#ifdef SUN4
- if (sc->sc_bustype == BUS_OBIO) {
+ else
stba(AC_SYSENABLE, ASI_CONTROL,
lduba(AC_SYSENABLE, ASI_CONTROL) & ~SYSEN_VIDEO);
- return;
- }
-#endif
- sc->sc_reg->bw_ctl &= ~CTL_VE;
+
+ return;
}
+#endif
+
+ if (enable)
+ sc->sc_reg->fbc_ctrl |= FBC_VENAB;
+ else
+ sc->sc_reg->fbc_ctrl &= ~FBC_VENAB;
}
diff --git a/sys/arch/sparc/dev/bwtworeg.h b/sys/arch/sparc/dev/bwtworeg.h
index cae902991a8..236f4a44929 100644
--- a/sys/arch/sparc/dev/bwtworeg.h
+++ b/sys/arch/sparc/dev/bwtworeg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: bwtworeg.h,v 1.2 1994/11/20 20:51:58 deraadt Exp $ */
+/* $NetBSD: bwtworeg.h,v 1.3 1996/02/27 00:32:39 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -53,20 +53,9 @@
* the sparc addressing modes work well.
*/
struct bwtworeg {
- /*
- * The xxx0 range is all 0xff on my IPC but causes a screen glitch
- * on my SS1+, so it must do *some*thing... the xxx1 range is full
- * of values but I do not know what they are. bw_ctl changes for
- * a blanked screen.
- */
- char bw_xxx0[16];
- u_char bw_ctl; /* contains video enable */
- char bw_xxx1[15];
+ struct fbcontrol bw_fbc;
};
-/* bits in bw_ctl */
-#define CTL_VE 0x40 /* video enable */
-
/* offsets */
#define BWREG_ID 0
#define BWREG_REG 0x400000
@@ -76,7 +65,7 @@ struct bwtworeg {
struct bwtwo_all {
long ba_id; /* ID = 0xfe010104 on my IPC */
char ba_xxx0[0x400000-4];
- struct bwtworeg ba_reg; /* control registers */
+ struct fbcontrol ba_reg; /* control registers */
char ba_xxx1[0x400000-32];
char ba_ram[4096]; /* actually larger */
};
diff --git a/sys/arch/sparc/dev/cgeight.c b/sys/arch/sparc/dev/cgeight.c
index 546a6992797..aea11563608 100644
--- a/sys/arch/sparc/dev/cgeight.c
+++ b/sys/arch/sparc/dev/cgeight.c
@@ -1,6 +1,7 @@
-/* $NetBSD: cgeight.c,v 1.12 1994/11/23 07:02:07 deraadt Exp $ */
+/* $NetBSD: cgeight.c,v 1.7 1996/04/01 17:29:57 christos Exp $ */
/*
+ * Copyright (c) 1996 Jason R. Thorpe. All rights reserved.
* Copyright (c) 1995 Theo de Raadt
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -54,12 +55,14 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/tty.h>
+#include <sys/conf.h>
#include <vm/vm.h>
@@ -67,20 +70,20 @@
#include <machine/autoconf.h>
#include <machine/pmap.h>
#include <machine/fbvar.h>
+#include <machine/eeprom.h>
+#include <machine/conf.h>
#include <sparc/dev/btreg.h>
#include <sparc/dev/btvar.h>
-#include <sparc/dev/cgeightreg.h>
#include <sparc/dev/pfourreg.h>
/* per-display variables */
struct cgeight_softc {
struct device sc_dev; /* base device */
struct fbdevice sc_fb; /* frame buffer device */
- volatile struct bt_regs *sc_bt; /* Brooktree registers */
struct rom_reg sc_phys; /* display RAM (phys addr) */
+ volatile struct fbcontrol *sc_fbc; /* Brooktree registers */
int sc_bustype; /* type of bus we live on */
- int sc_blanked; /* true if blanked */
union bt_cmap sc_cmap; /* Brooktree color map */
};
@@ -91,13 +94,19 @@ int cgeightopen __P((dev_t, int, int, struct proc *));
int cgeightclose __P((dev_t, int, int, struct proc *));
int cgeightioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
int cgeightmmap __P((dev_t, int, int));
+#if defined(SUN4)
static void cgeightunblank __P((struct device *));
+#endif
+
+struct cfattach cgeight_ca = {
+ sizeof(struct cgeight_softc), cgeightmatch, cgeightattach
+};
-struct cfdriver cgeightcd = {
- NULL, "cgeight", cgeightmatch, cgeightattach,
- DV_DULL, sizeof(struct cgeight_softc)
+struct cfdriver cgeight_cd = {
+ NULL, "cgeight", DV_DULL
};
+#if defined(SUN4)
/* frame buffer generic driver */
static struct fbdriver cgeightfbdriver = {
cgeightunblank, cgeightopen, cgeightclose, cgeightioctl, cgeightmmap
@@ -107,6 +116,9 @@ extern int fbnode;
extern struct tty *fbconstty;
static void cgeightloadcmap __P((struct cgeight_softc *, int, int));
+static int cgeight_get_video __P((struct cgeight_softc *));
+static void cgeight_set_video __P((struct cgeight_softc *, int));
+#endif
/*
* Match a cgeight.
@@ -122,8 +134,40 @@ cgeightmatch(parent, vcf, aux)
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
- if (PFOUR_ID(ra->ra_pfour) == PFOUR_ID_COLOR24)
+
+ /*
+ * Mask out invalid flags from the user.
+ */
+ cf->cf_flags &= FB_USERMASK;
+
+ /*
+ * Only exists on a sun4.
+ */
+ if (!CPU_ISSUN4)
+ return (0);
+
+ /*
+ * Only exists on obio.
+ */
+ if (ca->ca_bustype != BUS_OBIO)
+ return (0);
+
+ /*
+ * Make sure there's hardware there.
+ */
+ if (probeget(ra->ra_vaddr, 4) == -1)
+ return (0);
+
+#if defined(SUN4)
+ /*
+ * Check the pfour register.
+ */
+ if (fb_pfour_id(ra->ra_vaddr) == PFOUR_ID_COLOR24) {
+ cf->cf_flags |= FB_PFOUR;
return (1);
+ }
+#endif
+
return (0);
}
@@ -135,99 +179,115 @@ cgeightattach(parent, self, args)
struct device *parent, *self;
void *args;
{
+#if defined(SUN4)
register struct cgeight_softc *sc = (struct cgeight_softc *)self;
register struct confargs *ca = args;
register int node = 0, ramsize, i;
register volatile struct bt_regs *bt;
- register struct cgeight_all *p;
+ struct fbdevice *fb = &sc->sc_fb;
int isconsole;
-#ifdef RASTERCONSOLE
- struct fbdevice fbd;
-#endif
- sc->sc_fb.fb_driver = &cgeightfbdriver;
- sc->sc_fb.fb_device = &sc->sc_dev;
- sc->sc_fb.fb_type.fb_type = FBTYPE_MEMCOLOR;
+ fb->fb_driver = &cgeightfbdriver;
+ fb->fb_device = &sc->sc_dev;
+ fb->fb_type.fb_type = FBTYPE_MEMCOLOR;
+ fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags;
+
+ /*
+ * Only pfour cgfours, thank you...
+ */
+ if ((ca->ca_bustype != BUS_OBIO) ||
+ ((fb->fb_flags & FB_PFOUR) == 0)) {
+ printf("%s: ignoring; not a pfour\n", sc->sc_dev.dv_xname);
+ return;
+ }
- pfour_reset();
- pfour_videosize(ca->ca_ra.ra_pfour, &sc->sc_fb.fb_type.fb_width,
- &sc->sc_fb.fb_type.fb_height);
+ /* Map the pfour register. */
+ fb->fb_pfour = (volatile u_int32_t *)mapiodev(ca->ca_ra.ra_reg, 0,
+ sizeof(u_int32_t), ca->ca_bustype);
- sc->sc_fb.fb_linebytes = sc->sc_fb.fb_type.fb_width * 4;
+ ramsize = PFOUR_COLOR_OFF_END - PFOUR_COLOR_OFF_OVERLAY;
+
+ fb->fb_type.fb_depth = 24;
+ fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype);
- ramsize = CG8REG_END - CG8REG_OVERLAY;
- sc->sc_fb.fb_type.fb_depth = 24;
sc->sc_fb.fb_type.fb_cmsize = 256;
sc->sc_fb.fb_type.fb_size = ramsize;
- printf(": %d x %d", sc->sc_fb.fb_type.fb_width,
- sc->sc_fb.fb_type.fb_height);
+ printf(": cgeight/p4, %d x %d", fb->fb_type.fb_width,
+ fb->fb_type.fb_height);
+
+ isconsole = 0;
+
+ if (cputyp == CPU_SUN4) {
+ struct eeprom *eep = (struct eeprom *)eeprom_va;
+
+ /*
+ * Assume this is the console if there's no eeprom info
+ * to be found.
+ */
+ if (eep == NULL || eep->eeConsole == EE_CONS_P4OPT)
+ isconsole = (fbconstty != NULL);
+ }
+
+#if 0
+ /*
+ * We don't do any of the console handling here. Instead,
+ * we let the bwtwo driver pick up the overlay plane and
+ * use it instead. Rconsole should have better performance
+ * with the 1-bit depth.
+ * -- Jason R. Thorpe <thorpej@NetBSD.ORG>
+ */
/*
- * When the ROM has mapped in a cgeight display, the address
+ * When the ROM has mapped in a cgfour display, the address
* maps only the video RAM, so in any case we have to map the
* registers ourselves. We only need the video RAM if we are
* going to print characters via rconsole.
- *
- * XXX: it is insane to map the full 0x800000 space, when
- * the mmap code down below doesn't want it that way.
- * Ridiculous!
*/
- isconsole = node == fbnode && fbconstty != NULL;
- if (ca->ca_ra.ra_vaddr == NULL) {
- /* this probably cannot happen, but what the heck */
- ca->ca_ra.ra_vaddr = mapiodev(ca->ca_ra.ra_reg, 0,
- ramsize, ca->ca_bustype);
+
+ if (isconsole) {
+ /* XXX this is kind of a waste */
+ fb->fb_pixels = mapiodev(ca->ca_ra.ra_reg,
+ PFOUR_COLOR_OFF_OVERLAY, ramsize, ca->ca_bustype);
}
- sc->sc_fb.fb_pixels = (char *)((int)ca->ca_ra.ra_vaddr +
- CG8REG_COLOUR - CG8REG_OVERLAY);
+#endif
+
+ /* Map the Brooktree. */
+ sc->sc_fbc = (volatile struct fbcontrol *)mapiodev(ca->ca_ra.ra_reg,
+ PFOUR_COLOR_OFF_CMAP, sizeof(struct fbcontrol), ca->ca_bustype);
-#define O(memb) ((u_int)(&((struct cgeight_all *)0)->memb))
- sc->sc_bt = bt = (volatile struct bt_regs *)mapiodev(ca->ca_ra.ra_reg,
- O(ba_btreg), sizeof(struct bt_regs), ca->ca_bustype);
sc->sc_phys = ca->ca_ra.ra_reg[0];
sc->sc_bustype = ca->ca_bustype;
+#if 0 /* XXX thorpej ??? */
/* tell the enable plane to look at the mono image */
memset(ca->ca_ra.ra_vaddr, 0xff,
sc->sc_fb.fb_type.fb_width * sc->sc_fb.fb_type.fb_height / 8);
-#if 0
- memset((caddr_t)((int)ca->ca_ra.ra_vaddr +
- CG8REG_ENABLE - CG8REG_OVERLAY), 0x00,
- sc->sc_fb.fb_type.fb_width * sc->sc_fb.fb_type.fb_height / 8);
#endif
/* grab initial (current) color map */
+ bt = &sc->sc_fbc->fbc_dac;
bt->bt_addr = 0;
for (i = 0; i < 256 * 3 / 4; i++)
sc->sc_cmap.cm_chip[i] = bt->bt_cmap;
- /* make sure we are not blanked (see cgeightunblank) */
- bt->bt_addr = 0x06; /* command reg */
- bt->bt_ctrl = 0x73; /* overlay plane */
- bt->bt_addr = 0x04; /* read mask */
- bt->bt_ctrl = 0xff; /* color planes */
+ BT_INIT(bt, 0);
+
+#if 0 /* see above */
if (isconsole) {
printf(" (console)\n");
-#ifdef RASTERCONSOLE
- /*
- * Like SunOS and the bootrom, we want to do full-screen
- * text on the overlay plane. But rcons_init() requires
- * our fbdevice pointer to remain the same; so we hack
- * the fbdevice, pass it in, and then restore it's
- * values. Ugly -- should change rcons_init()'s interface.
- */
- bcopy(&sc->sc_fb, &fbd, sizeof fbd);
- sc->sc_fb.fb_type.fb_depth = 1;
- sc->sc_fb.fb_linebytes = sc->sc_fb.fb_type.fb_width / 8;
- sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr;
- rcons_init(&fbd);
- bcopy(&fbd, &sc->sc_fb, sizeof fbd);
+#if defined(RASTERCONSOLE) && 0 /* XXX been told it doesn't work well. */
+ fbrcons_init(fb);
#endif
} else
+#endif /* 0 */
printf("\n");
- if ((node == fbnode && cputyp != CPU_SUN4) ||
- (isconsole && cputyp == CPU_SUN4))
- fb_attach(&sc->sc_fb);
+
+ /*
+ * Even though we're not using rconsole, we'd still like
+ * to notice if we're the console framebuffer.
+ */
+ fb_attach(&sc->sc_fb, isconsole);
+#endif
}
int
@@ -238,7 +298,7 @@ cgeightopen(dev, flags, mode, p)
{
int unit = minor(dev);
- if (unit >= cgeightcd.cd_ndevs || cgeightcd.cd_devs[unit] == NULL)
+ if (unit >= cgeight_cd.cd_ndevs || cgeight_cd.cd_devs[unit] == NULL)
return (ENXIO);
return (0);
}
@@ -261,7 +321,8 @@ cgeightioctl(dev, cmd, data, flags, p)
int flags;
struct proc *p;
{
- register struct cgeight_softc *sc = cgeightcd.cd_devs[minor(dev)];
+#if defined(SUN4)
+ register struct cgeight_softc *sc = cgeight_cd.cd_devs[minor(dev)];
register struct fbgattr *fba;
int error;
@@ -299,83 +360,21 @@ cgeightioctl(dev, cmd, data, flags, p)
break;
case FBIOGVIDEO:
- *(int *)data = sc->sc_blanked;
+ *(int *)data = cgeight_get_video(sc);
break;
case FBIOSVIDEO:
- if (*(int *)data)
- cgeightunblank(&sc->sc_dev);
- else if (!sc->sc_blanked) {
- register volatile struct bt_regs *bt;
-
- bt = sc->sc_bt;
- bt->bt_addr = 0x06; /* command reg */
- bt->bt_ctrl = 0x70; /* overlay plane */
- bt->bt_addr = 0x04; /* read mask */
- bt->bt_ctrl = 0x00; /* color planes */
- /*
- * Set color 0 to black -- note that this overwrites
- * R of color 1.
- */
- bt->bt_addr = 0;
- bt->bt_cmap = 0;
-
- sc->sc_blanked = 1;
- }
+ cgeight_set_video(sc, *(int *)data);
break;
default:
return (ENOTTY);
}
+#endif
return (0);
}
/*
- * Undo the effect of an FBIOSVIDEO that turns the video off.
- */
-static void
-cgeightunblank(dev)
- struct device *dev;
-{
- struct cgeight_softc *sc = (struct cgeight_softc *)dev;
- register volatile struct bt_regs *bt;
-
- if (sc->sc_blanked) {
- sc->sc_blanked = 0;
- bt = sc->sc_bt;
- /* restore color 0 (and R of color 1) */
- bt->bt_addr = 0;
- bt->bt_cmap = sc->sc_cmap.cm_chip[0];
-
- /* restore read mask */
- bt->bt_addr = 0x06; /* command reg */
- bt->bt_ctrl = 0x73; /* overlay plane */
- bt->bt_addr = 0x04; /* read mask */
- bt->bt_ctrl = 0xff; /* color planes */
- }
-}
-
-/*
- * Load a subset of the current (new) colormap into the Brooktree DAC.
- */
-static void
-cgeightloadcmap(sc, start, ncolors)
- register struct cgeight_softc *sc;
- register int start, ncolors;
-{
- register volatile struct bt_regs *bt;
- register u_int *ip;
- register int count;
-
- ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */
- count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
- bt = sc->sc_bt;
- bt->bt_addr = BT_D4M4(start);
- while (--count >= 0)
- bt->bt_cmap = *ip++;
-}
-
-/*
* Return the address that would map the given device at the given
* offset, allowing for the given protection, or return -1 for error.
*
@@ -389,14 +388,14 @@ cgeightmmap(dev, off, prot)
dev_t dev;
int off, prot;
{
- register struct cgeight_softc *sc = cgeightcd.cd_devs[minor(dev)];
+ register struct cgeight_softc *sc = cgeight_cd.cd_devs[minor(dev)];
int poff;
#define START_ENABLE (128*1024)
-#define START_COLOUR (128*1024 + 128*1024)
-#define COLOUR_SIZE (sc->sc_fb.fb_type.fb_width * \
- sc->sc_fb.fb_type.fb_height * 4)
-#define END_COLOUR (START_COLOUR + COLOUR_SIZE)
+#define START_COLOR ((128*1024) + (128*1024))
+#define COLOR_SIZE (sc->sc_fb.fb_type.fb_width * \
+ sc->sc_fb.fb_type.fb_height * 3)
+#define END_COLOR (START_COLOR + COLOR_SIZE)
#define START_SPECIAL 0x800000
#define PROMSIZE 0x40000
#define NOOVERLAY (0x04000000)
@@ -405,36 +404,108 @@ cgeightmmap(dev, off, prot)
panic("cgeightmap");
if ((u_int)off >= NOOVERLAY) {
- off = off - NOOVERLAY;
+ off =- NOOVERLAY;
/*
* X11 maps a huge chunk of the frame buffer; far more than
* there really is. We compensate by double-mapping the
* first page for as many other pages as it wants
*/
- while (off >= COLOUR_SIZE)
- off = 0;
- poff = off + (CG8REG_COLOUR - CG8REG_OVERLAY);
- } else if ((u_int)off < START_ENABLE) /* in overlay plane */
- poff = off;
- else if ((u_int)off < START_COLOUR) /* in enable plane */
- poff = off + (CG8REG_ENABLE - CG8REG_OVERLAY) - START_ENABLE;
- else if ((u_int)off < END_COLOUR) /* in colour plane */
- poff = off + (CG8REG_COLOUR - CG8REG_OVERLAY) - START_COLOUR;
- else if ((u_int)off < START_SPECIAL) /* hole */
+ while (off >= COLOR_SIZE)
+ off -= COLOR_SIZE; /* XXX thorpej ??? */
+
+ poff = off + PFOUR_COLOR_OFF_COLOR;
+ } else if ((u_int)off < START_ENABLE) {
+ /*
+ * in overlay plane
+ */
+ poff = PFOUR_COLOR_OFF_OVERLAY + off;
+ } else if ((u_int)off < START_COLOR) {
+ /*
+ * in enable plane
+ */
+ poff = (off - START_ENABLE) + PFOUR_COLOR_OFF_ENABLE;
+ } else if ((u_int)off < END_COLOR) {
+ /*
+ * in colour plane
+ */
+ poff = (off - START_COLOR) + PFOUR_COLOR_OFF_COLOR;
+ } else if ((u_int)off < START_SPECIAL) {
+ /*
+ * hole
+ */
+ poff = 0; /* XXX */
+ } else if ((u_int)off == START_SPECIAL) {
+ /*
+ * colour map (Brooktree)
+ */
+ poff = PFOUR_COLOR_OFF_CMAP;
+ } else if ((u_int)off == START_SPECIAL + NBPG) {
+ /*
+ * p4 register
+ */
poff = 0;
- else if ((u_int)off == START_SPECIAL) /* colour map */
- poff = CG8REG_CMAP;
- else if ((u_int)off == START_SPECIAL + NBPG) /* p4 register */
- poff = PFOUR_REG;
- else if ((u_int)off > START_SPECIAL + NBPG*2 &&
- (u_int) off < START_SPECIAL + NBPG*2 + PROMSIZE) /* rom */
- poff = CG8REG_P4REG + 0x8000 + off - START_SPECIAL + NBPG*2;
- else
+ } else if ((u_int)off > (START_SPECIAL + (NBPG * 2)) &&
+ (u_int) off < (START_SPECIAL + (NBPG * 2) + PROMSIZE)) {
+ /*
+ * rom
+ */
+ poff = 0x8000 + (off - (START_SPECIAL + (NBPG * 2)));
+ } else
return (-1);
/*
* I turned on PMAP_NC here to disable the cache as I was
* getting horribly broken behaviour with it on.
*/
- return (REG2PHYS(&sc->sc_phys, off, sc->sc_bustype) | PMAP_NC);
+ return (REG2PHYS(&sc->sc_phys, poff, sc->sc_bustype) | PMAP_NC);
+}
+
+#if defined(SUN4)
+/*
+ * Undo the effect of an FBIOSVIDEO that turns the video off.
+ */
+static void
+cgeightunblank(dev)
+ struct device *dev;
+{
+
+ cgeight_set_video((struct cgeight_softc *)dev, 1);
+}
+
+static int
+cgeight_get_video(sc)
+ struct cgeight_softc *sc;
+{
+
+ return (fb_pfour_get_video(&sc->sc_fb));
}
+
+static void
+cgeight_set_video(sc, enable)
+ struct cgeight_softc *sc;
+ int enable;
+{
+
+ fb_pfour_set_video(&sc->sc_fb, enable);
+}
+
+/*
+ * Load a subset of the current (new) colormap into the Brooktree DAC.
+ */
+static void
+cgeightloadcmap(sc, start, ncolors)
+ register struct cgeight_softc *sc;
+ register int start, ncolors;
+{
+ register volatile struct bt_regs *bt;
+ register u_int *ip;
+ register int count;
+
+ ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */
+ count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
+ bt = &sc->sc_fbc->fbc_dac;
+ bt->bt_addr = BT_D4M4(start);
+ while (--count >= 0)
+ bt->bt_cmap = *ip++;
+}
+#endif
diff --git a/sys/arch/sparc/dev/cgfour.c b/sys/arch/sparc/dev/cgfour.c
index ebd6b1fecd7..d5dde467a9c 100644
--- a/sys/arch/sparc/dev/cgfour.c
+++ b/sys/arch/sparc/dev/cgfour.c
@@ -1,6 +1,7 @@
-/* $NetBSD: cgfour.c,v 1.12 1994/11/23 07:02:07 deraadt Exp $ */
+/* $NetBSD: cgfour.c,v 1.7 1996/04/01 17:29:58 christos Exp $ */
/*
+ * Copyright (c) 1996 Jason R. Thorpe. All rights reserved.
* Copyright (c) 1995 Theo de Raadt. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -58,12 +59,14 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/tty.h>
+#include <sys/conf.h>
#include <vm/vm.h>
@@ -71,20 +74,20 @@
#include <machine/autoconf.h>
#include <machine/pmap.h>
#include <machine/fbvar.h>
+#include <machine/eeprom.h>
+#include <machine/conf.h>
#include <sparc/dev/btreg.h>
#include <sparc/dev/btvar.h>
-#include <sparc/dev/cgfourreg.h>
#include <sparc/dev/pfourreg.h>
/* per-display variables */
struct cgfour_softc {
struct device sc_dev; /* base device */
struct fbdevice sc_fb; /* frame buffer device */
- volatile struct bt_regs *sc_bt; /* Brooktree registers */
struct rom_reg sc_phys; /* display RAM (phys addr) */
+ volatile struct fbcontrol *sc_fbc; /* Brooktree registers */
int sc_bustype; /* type of bus we live on */
- int sc_blanked; /* true if blanked */
union bt_cmap sc_cmap; /* Brooktree color map */
};
@@ -95,13 +98,19 @@ int cgfouropen __P((dev_t, int, int, struct proc *));
int cgfourclose __P((dev_t, int, int, struct proc *));
int cgfourioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
int cgfourmmap __P((dev_t, int, int));
+#if defined(SUN4)
static void cgfourunblank __P((struct device *));
+#endif
+
+struct cfattach cgfour_ca = {
+ sizeof(struct cgfour_softc), cgfourmatch, cgfourattach
+};
-struct cfdriver cgfourcd = {
- NULL, "cgfour", cgfourmatch, cgfourattach,
- DV_DULL, sizeof(struct cgfour_softc)
+struct cfdriver cgfour_cd = {
+ NULL, "cgfour", DV_DULL
};
+#if defined(SUN4)
/* frame buffer generic driver */
static struct fbdriver cgfourfbdriver = {
cgfourunblank, cgfouropen, cgfourclose, cgfourioctl, cgfourmmap
@@ -111,6 +120,9 @@ extern int fbnode;
extern struct tty *fbconstty;
static void cgfourloadcmap __P((struct cgfour_softc *, int, int));
+static int cgfour_get_video __P((struct cgfour_softc *));
+static void cgfour_set_video __P((struct cgfour_softc *, int));
+#endif
/*
* Match a cgfour.
@@ -126,8 +138,40 @@ cgfourmatch(parent, vcf, aux)
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
- if (PFOUR_ID(ra->ra_pfour) == PFOUR_ID_COLOR8P1)
+
+ /*
+ * Mask out invalid flags from the user.
+ */
+ cf->cf_flags &= FB_USERMASK;
+
+ /*
+ * Only exists on a sun4.
+ */
+ if (!CPU_ISSUN4)
+ return (0);
+
+ /*
+ * Only exists on obio.
+ */
+ if (ca->ca_bustype != BUS_OBIO)
+ return (0);
+
+ /*
+ * Make sure there's hardware there.
+ */
+ if (probeget(ra->ra_vaddr, 4) == -1)
+ return (0);
+
+#if defined(SUN4)
+ /*
+ * Check the pfour register.
+ */
+ if (fb_pfour_id(ra->ra_vaddr) == PFOUR_ID_COLOR8P1) {
+ cf->cf_flags |= FB_PFOUR;
return (1);
+ }
+#endif
+
return (0);
}
@@ -139,74 +183,109 @@ cgfourattach(parent, self, args)
struct device *parent, *self;
void *args;
{
+#if defined(SUN4)
register struct cgfour_softc *sc = (struct cgfour_softc *)self;
register struct confargs *ca = args;
register int node = 0, ramsize, i;
register volatile struct bt_regs *bt;
+ struct fbdevice *fb = &sc->sc_fb;
int isconsole;
- sc->sc_fb.fb_driver = &cgfourfbdriver;
- sc->sc_fb.fb_device = &sc->sc_dev;
- sc->sc_fb.fb_type.fb_type = FBTYPE_SUN4COLOR;
+ fb->fb_driver = &cgfourfbdriver;
+ fb->fb_device = &sc->sc_dev;
+ fb->fb_type.fb_type = FBTYPE_SUN4COLOR;
+ fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags;
+
+ /*
+ * Only pfour cgfours, thank you...
+ */
+ if ((ca->ca_bustype != BUS_OBIO) ||
+ ((fb->fb_flags & FB_PFOUR) == 0)) {
+ printf("%s: ignoring; not a pfour\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ /* Map the pfour register. */
+ fb->fb_pfour = (volatile u_int32_t *)mapiodev(ca->ca_ra.ra_reg, 0,
+ sizeof(u_int32_t), ca->ca_bustype);
+
+ ramsize = PFOUR_COLOR_OFF_END - PFOUR_COLOR_OFF_OVERLAY;
+
+ fb->fb_type.fb_depth = 8;
+ fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype);
+
+ fb->fb_type.fb_cmsize = 256;
+ fb->fb_type.fb_size = ramsize;
+ printf(": cgfour/p4, %d x %d", fb->fb_type.fb_width,
+ fb->fb_type.fb_height);
+
+ isconsole = 0;
- pfour_reset();
- pfour_videosize(ca->ca_ra.ra_pfour, &sc->sc_fb.fb_type.fb_width,
- &sc->sc_fb.fb_type.fb_height);
+ if (CPU_ISSUN4) {
+ struct eeprom *eep = (struct eeprom *)eeprom_va;
- sc->sc_fb.fb_linebytes = sc->sc_fb.fb_type.fb_width;
+ /*
+ * Assume this is the console if there's no eeprom info
+ * to be found.
+ */
+ if (eep == NULL || eep->eeConsole == EE_CONS_P4OPT)
+ isconsole = (fbconstty != NULL);
+ }
- ramsize = CG4REG_END - CG4REG_OVERLAY;
- sc->sc_fb.fb_type.fb_depth = 8;
- sc->sc_fb.fb_type.fb_cmsize = 256;
- sc->sc_fb.fb_type.fb_size = ramsize;
- printf(": %d x %d", sc->sc_fb.fb_type.fb_width,
- sc->sc_fb.fb_type.fb_height);
+#if 0
+ /*
+ * We don't do any of the console handling here. Instead,
+ * we let the bwtwo driver pick up the overlay plane and
+ * use it instead. Rconsole should have better performance
+ * with the 1-bit depth.
+ * -- Jason R. Thorpe <thorpej@NetBSD.ORG>
+ */
/*
* When the ROM has mapped in a cgfour display, the address
* maps only the video RAM, so in any case we have to map the
* registers ourselves. We only need the video RAM if we are
* going to print characters via rconsole.
- *
- * XXX: it is insane to map the full 0x800000 space, when
- * the mmap code down below doesn't use it all. Ridiculous!
*/
- isconsole = node == fbnode && fbconstty != NULL;
- if (ca->ca_ra.ra_vaddr == NULL) {
- /* this probably cannot happen, but what the heck */
- ca->ca_ra.ra_vaddr = mapiodev(ca->ca_ra.ra_reg, 0,
- ramsize, ca->ca_bustype);
+
+ if (isconsole) {
+ /* XXX this is kind of a waste */
+ fb->fb_pixels = mapiodev(ca->ca_ra.ra_reg,
+ PFOUR_COLOR_OFF_OVERLAY, ramsize, ca->ca_bustype);
}
- sc->sc_fb.fb_pixels = (char *)((int)ca->ca_ra.ra_vaddr +
- CG4REG_COLOUR - CG4REG_OVERLAY);
+#endif
+
+ /* Map the Brooktree. */
+ sc->sc_fbc = (volatile struct fbcontrol *)mapiodev(ca->ca_ra.ra_reg,
+ PFOUR_COLOR_OFF_CMAP, sizeof(struct fbcontrol), ca->ca_bustype);
-#define O(memb) ((u_int)(&((struct cgfour_all *)0)->memb))
- sc->sc_bt = bt = (volatile struct bt_regs *)mapiodev(ca->ca_ra.ra_reg,
- O(ba_btreg), sizeof(struct bt_regs), ca->ca_bustype);
sc->sc_phys = ca->ca_ra.ra_reg[0];
sc->sc_bustype = ca->ca_bustype;
/* grab initial (current) color map */
+ bt = &sc->sc_fbc->fbc_dac;
bt->bt_addr = 0;
for (i = 0; i < 256 * 3 / 4; i++)
((char *)&sc->sc_cmap)[i] = bt->bt_cmap >> 24;
- /* make sure we are not blanked (see cgfourunblank) */
- bt->bt_addr = 0x06 << 24; /* command reg */
- bt->bt_ctrl = 0x73 << 24; /* overlay plane */
- bt->bt_addr = 0x04 << 24; /* read mask */
- bt->bt_ctrl = 0xff << 24; /* color planes */
+ BT_INIT(bt, 24);
+#if 0 /* See above. */
if (isconsole) {
printf(" (console)\n");
-#ifdef RASTERCONSOLE
- fbrcons_init(&sc->sc_fb);
+#if defined(RASTERCONSOLE) && 0 /* XXX been told it doesn't work well. */
+ fbrcons_init(fb);
#endif
} else
+#endif /* 0 */
printf("\n");
- if ((node == fbnode && cputyp != CPU_SUN4) ||
- (isconsole && cputyp == CPU_SUN4))
- fb_attach(&sc->sc_fb);
+
+ /*
+ * Even though we're not using rconsole, we'd still like
+ * to notice if we're the console framebuffer.
+ */
+ fb_attach(fb, isconsole);
+#endif
}
int
@@ -217,7 +296,7 @@ cgfouropen(dev, flags, mode, p)
{
int unit = minor(dev);
- if (unit >= cgfourcd.cd_ndevs || cgfourcd.cd_devs[unit] == NULL)
+ if (unit >= cgfour_cd.cd_ndevs || cgfour_cd.cd_devs[unit] == NULL)
return (ENXIO);
return (0);
}
@@ -240,7 +319,8 @@ cgfourioctl(dev, cmd, data, flags, p)
int flags;
struct proc *p;
{
- register struct cgfour_softc *sc = cgfourcd.cd_devs[minor(dev)];
+#if defined(SUN4)
+ register struct cgfour_softc *sc = cgfour_cd.cd_devs[minor(dev)];
register struct fbgattr *fba;
int error;
@@ -278,62 +358,109 @@ cgfourioctl(dev, cmd, data, flags, p)
break;
case FBIOGVIDEO:
- *(int *)data = sc->sc_blanked;
+ *(int *)data = cgfour_get_video(sc);
break;
case FBIOSVIDEO:
- if (*(int *)data)
- cgfourunblank(&sc->sc_dev);
- else if (!sc->sc_blanked) {
- register volatile struct bt_regs *bt;
-
- bt = sc->sc_bt;
- bt->bt_addr = 0x06 << 24; /* command reg */
- bt->bt_ctrl = 0x70 << 24; /* overlay plane */
- bt->bt_addr = 0x04 << 24; /* read mask */
- bt->bt_ctrl = 0x00 << 24; /* color planes */
- /*
- * Set color 0 to black -- note that this overwrites
- * R of color 1.
- */
- bt->bt_addr = 0 << 24;
- bt->bt_cmap = 0 << 24;
-
- sc->sc_blanked = 1;
- }
+ cgfour_set_video(sc, *(int *)data);
break;
default:
return (ENOTTY);
}
+#endif
return (0);
}
/*
+ * Return the address that would map the given device at the given
+ * offset, allowing for the given protection, or return -1 for error.
+ *
+ * the cg4 maps it's overlay plane for 128K, followed by the enable
+ * plane for 128K, followed by the colour plane (for as much colour
+ * as their is.)
+ *
+ * As well, mapping at an offset of 0x04000000 causes the cg4 to map
+ * only it's colour plane, at 0.
+ */
+int
+cgfourmmap(dev, off, prot)
+ dev_t dev;
+ int off, prot;
+{
+ register struct cgfour_softc *sc = cgfour_cd.cd_devs[minor(dev)];
+ int poff;
+
+#define START_ENABLE (128*1024)
+#define START_COLOR ((128*1024) + (128*1024))
+#define COLOR_SIZE (sc->sc_fb.fb_type.fb_width * \
+ sc->sc_fb.fb_type.fb_height)
+#define END_COLOR (START_COLOR + COLOR_SIZE)
+#define NOOVERLAY (0x04000000)
+
+ if (off & PGOFSET)
+ panic("cgfourmap");
+
+ if ((u_int)off >= NOOVERLAY) {
+ off =- NOOVERLAY;
+
+ /*
+ * X11 maps a huge chunk of the frame buffer; far more than
+ * there really is. We compensate by double-mapping the
+ * first page for as many other pages as it wants
+ */
+ while (off >= COLOR_SIZE)
+ off -= COLOR_SIZE; /* XXX thorpej ??? */
+
+ poff = off + PFOUR_COLOR_OFF_COLOR;
+ } else if ((u_int)off < START_ENABLE) {
+ /*
+ * in overlay plane
+ */
+ poff = PFOUR_COLOR_OFF_OVERLAY + off;
+ } else if ((u_int)off < START_COLOR) {
+ /*
+ * in enable plane
+ */
+ poff = (off - START_ENABLE) + PFOUR_COLOR_OFF_ENABLE;
+ } else if ((u_int)off < END_COLOR) {
+ /*
+ * in colour plane
+ */
+ poff = (off - START_COLOR) + PFOUR_COLOR_OFF_COLOR;
+ } else
+ return (-1);
+
+ return (REG2PHYS(&sc->sc_phys, poff, sc->sc_bustype) | PMAP_NC);
+}
+
+#if defined(SUN4)
+/*
* Undo the effect of an FBIOSVIDEO that turns the video off.
*/
static void
cgfourunblank(dev)
struct device *dev;
{
- struct cgfour_softc *sc = (struct cgfour_softc *)dev;
- register volatile struct bt_regs *bt;
- if (sc->sc_blanked) {
- sc->sc_blanked = 0;
- bt = sc->sc_bt;
- /* restore color 0 (and R of color 1) */
- bt->bt_addr = 0 << 24;
- bt->bt_cmap = sc->sc_cmap.cm_chip[0];
- bt->bt_cmap = sc->sc_cmap.cm_chip[0] << 8;
- bt->bt_cmap = sc->sc_cmap.cm_chip[0] << 16;
-
- /* restore read mask */
- bt->bt_addr = 0x06 << 24; /* command reg */
- bt->bt_ctrl = 0x73 << 24; /* overlay plane */
- bt->bt_addr = 0x04 << 24; /* read mask */
- bt->bt_ctrl = 0xff << 24; /* color planes */
- }
+ cgfour_set_video((struct cgfour_softc *)dev, 1);
+}
+
+static int
+cgfour_get_video(sc)
+ struct cgfour_softc *sc;
+{
+
+ return (fb_pfour_get_video(&sc->sc_fb));
+}
+
+static void
+cgfour_set_video(sc, enable)
+ struct cgfour_softc *sc;
+ int enable;
+{
+
+ fb_pfour_set_video(&sc->sc_fb, enable);
}
/*
@@ -350,7 +477,7 @@ cgfourloadcmap(sc, start, ncolors)
ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */
count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
- bt = sc->sc_bt;
+ bt = &sc->sc_fbc->fbc_dac;
bt->bt_addr = BT_D4M4(start) << 24;
while (--count >= 0) {
i = *ip++;
@@ -361,53 +488,4 @@ cgfourloadcmap(sc, start, ncolors)
bt->bt_cmap = i << 24;
}
}
-
-/*
- * Return the address that would map the given device at the given
- * offset, allowing for the given protection, or return -1 for error.
- *
- * the cg4 maps it's overlay plane for 128K, followed by the enable
- * plane for 128K, followed by the colour plane (for as much colour
- * as their is.)
- *
- * As well, mapping at an offset of 0x04000000 causes the cg4 to map
- * only it's colour plane, at 0.
- */
-int
-cgfourmmap(dev, off, prot)
- dev_t dev;
- int off, prot;
-{
- register struct cgfour_softc *sc = cgfourcd.cd_devs[minor(dev)];
- int poff;
-
-#define START_ENABLE (128*1024)
-#define START_COLOUR (128*1024 + 128*1024)
-#define COLOUR_SIZE (sc->sc_fb.fb_type.fb_width * sc->sc_fb.fb_type.fb_height)
-#define END_COLOUR (START_COLOUR + COLOUR_SIZE)
-#define NOOVERLAY (0x04000000)
-
- if (off & PGOFSET)
- panic("cgfourmap");
-
- if ((u_int)off >= NOOVERLAY) {
- off = off - NOOVERLAY;
-
- /*
- * X11 maps a huge chunk of the frame buffer; far more than
- * there really is. We compensate by double-mapping the
- * first page for as many other pages as it wants
- */
- while (off >= COLOUR_SIZE)
- off = 0;
- poff = off + (CG4REG_COLOUR - CG4REG_OVERLAY);
- } else if ((u_int)off < START_ENABLE) /* in overlay plane */
- poff = off;
- else if ((u_int)off < START_COLOUR) /* in enable plane */
- poff = off + (CG4REG_ENABLE - CG4REG_OVERLAY) - START_ENABLE;
- else if ((u_int)off < (CG4REG_END - CG4REG_OVERLAY)) /* in colour plane */
- poff = off + (CG4REG_COLOUR - CG4REG_OVERLAY) - START_COLOUR;
- else
- return (-1);
- return (REG2PHYS(&sc->sc_phys, off, sc->sc_bustype) | PMAP_NC);
-}
+#endif
diff --git a/sys/arch/sparc/dev/cgsix.c b/sys/arch/sparc/dev/cgsix.c
index 9dab9af06b0..259024c7da6 100644
--- a/sys/arch/sparc/dev/cgsix.c
+++ b/sys/arch/sparc/dev/cgsix.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cgsix.c,v 1.16 1995/10/08 01:39:16 pk Exp $ */
+/* $NetBSD: cgsix.c,v 1.25 1996/04/01 17:30:00 christos Exp $ */
/*
* Copyright (c) 1993
@@ -53,6 +53,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <machine/fbio.h>
@@ -60,6 +61,7 @@
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/tty.h>
+#include <sys/conf.h>
#ifdef DEBUG
#include <sys/proc.h>
@@ -71,12 +73,19 @@
#include <machine/autoconf.h>
#include <machine/pmap.h>
#include <machine/fbvar.h>
+#include <machine/cpu.h>
+#if defined(SUN4)
+#include <machine/eeprom.h>
+#endif
+#include <machine/conf.h>
#include <sparc/dev/btreg.h>
#include <sparc/dev/btvar.h>
#include <sparc/dev/cgsixreg.h>
#include <sparc/dev/sbusvar.h>
+#if defined(SUN4)
#include <sparc/dev/pfourreg.h>
+#endif
union cursor_cmap { /* colormap, like bt_cmap, but tiny */
u_char cm_map[2][3]; /* 2 R/G/B entries */
@@ -118,9 +127,12 @@ int cgsixioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
int cgsixmmap __P((dev_t, int, int));
static void cg6_unblank __P((struct device *));
-struct cfdriver cgsixcd = {
- NULL, "cgsix", cgsixmatch, cgsixattach,
- DV_DULL, sizeof(struct cgsix_softc)
+struct cfattach cgsix_ca = {
+ sizeof(struct cgsix_softc), cgsixmatch, cgsixattach
+};
+
+struct cfdriver cgsix_cd = {
+ NULL, "cgsix", DV_DULL
};
/* frame buffer generic driver */
@@ -155,19 +167,35 @@ cgsixmatch(parent, vcf, aux)
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
+
+ /*
+ * Mask out invalid flags from the user.
+ */
+ cf->cf_flags &= FB_USERMASK;
+
if (ca->ca_bustype == BUS_SBUS)
return (1);
-#ifdef SUN4
- if (ca->ca_bustype == BUS_PFOUR &&
- PFOUR_ID(ra->ra_pfour) == PFOUR_ID_FASTCOLOR)
- return (1);
- if (ca->ca_bustype == BUS_OBIO) {
- struct cg6_layout *p = (struct cg6_layout *)ra->ra_paddr;
- void *tmp = bus_tmp(&p->cg6_fhc_un.un_fhc, ca->ca_bustype);
- return (probeget(tmp, 4) != 0);
- }
+#if defined(SUN4)
+ if (CPU_ISSUN4 && (ca->ca_bustype == BUS_OBIO)) {
+ void *tmp;
+
+ /*
+ * Check for a pfour framebuffer. This is done somewhat
+ * differently on the cgsix than other pfour framebuffers.
+ */
+ bus_untmp();
+ tmp = bus_tmp(ra->ra_paddr + CGSIX_FHC_OFFSET, ca->ca_bustype);
+ if (probeget(tmp, 4) == -1)
+ return (0);
+
+ if (fb_pfour_id(tmp) == PFOUR_ID_FASTCOLOR) {
+ cf->cf_flags |= FB_PFOUR;
+ return (1);
+ }
+ }
#endif
+
return (0);
}
@@ -181,79 +209,105 @@ cgsixattach(parent, self, args)
{
register struct cgsix_softc *sc = (struct cgsix_softc *)self;
register struct confargs *ca = args;
- register int node = ca->ca_ra.ra_node, ramsize, i, isconsole;
+ register int node = 0, ramsize, i;
register volatile struct bt_regs *bt;
- register volatile struct cg6_layout *p;
- char *nam;
+ struct fbdevice *fb = &sc->sc_fb;
+ int isconsole = 0, sbus = 1;
+ char *nam = NULL;
extern struct tty *fbconstty;
- sc->sc_fb.fb_driver = &cg6_fbdriver;
- sc->sc_fb.fb_device = &sc->sc_dev;
- sc->sc_fb.fb_type.fb_type = FBTYPE_SUNFAST_COLOR;
+ fb->fb_driver = &cg6_fbdriver;
+ fb->fb_device = &sc->sc_dev;
+ fb->fb_type.fb_type = FBTYPE_SUNFAST_COLOR;
+ fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags;
+
+ /*
+ * Dunno what the PROM has mapped, though obviously it must have
+ * the video RAM mapped. Just map what we care about for ourselves
+ * (the FHC, THC, and Brooktree registers).
+ */
+#define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb))
+ sc->sc_physadr = ca->ca_ra.ra_reg[0];
+ sc->sc_bustype = ca->ca_bustype;
+ sc->sc_bt = bt = (volatile struct bt_regs *)
+ mapiodev(ca->ca_ra.ra_reg, O(cg6_bt_un.un_btregs),
+ sizeof *sc->sc_bt, ca->ca_bustype);
+ sc->sc_fhc = (volatile int *)
+ mapiodev(ca->ca_ra.ra_reg, O(cg6_fhc_un.un_fhc),
+ sizeof *sc->sc_fhc, ca->ca_bustype);
+ sc->sc_thc = (volatile struct cg6_thc *)
+ mapiodev(ca->ca_ra.ra_reg, O(cg6_thc_un.un_thc),
+ sizeof *sc->sc_thc, ca->ca_bustype);
+ sc->sc_tec = (volatile struct cg6_tec_xxx *)
+ mapiodev(ca->ca_ra.ra_reg, O(cg6_tec_un.un_tec),
+ sizeof *sc->sc_tec, ca->ca_bustype);
switch (ca->ca_bustype) {
-#if defined(SUN4)
- case BUS_PFOUR:
- node = 0;
-#if 0
- /*
- * XXX cg6 reset routine is not good enough to
- * rebuild state correctly!
- */
- pfour_reset();
-#endif
- /*
- * XXX pfour register is confused?
- */
- sc->sc_fb.fb_type.fb_width = 1152;
- sc->sc_fb.fb_type.fb_height = 900;
- nam = "cgsix";
- break;
- case BUS_VME32:
- node = 0;
- nam = "cgsix";
- break;
-#endif /* SUN4 */
case BUS_OBIO:
+ sbus = node = 0;
+ if (fb->fb_flags & FB_PFOUR)
+ nam = "cgsix/p4";
+ else
+ nam = "cgsix";
+
#if defined(SUN4M)
- if (cputyp == CPU_SUN4M) { /* 4m has framebuffer on obio */
+ if (CPU_ISSUN4M) { /* 4m has framebuffer on obio */
+ node = ca->ca_ra.ra_node;
nam = getpropstring(node, "model");
break;
}
#endif
break;
+
+ case BUS_VME32:
+ case BUS_VME16:
+ sbus = node = 0;
+ nam = "cgsix";
+ break;
+
case BUS_SBUS:
+ node = ca->ca_ra.ra_node;
nam = getpropstring(node, "model");
break;
+
+ case BUS_MAIN:
+ printf("cgsix on mainbus?\n");
+ return;
}
- sc->sc_fb.fb_type.fb_depth = 8;
- fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth,
- 1152, 900, node, ca->ca_bustype);
+ /* Don't have to map the pfour register on the cgsix. */
+ fb->fb_pfour = NULL;
- ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes;
- sc->sc_fb.fb_type.fb_cmsize = 256;
- sc->sc_fb.fb_type.fb_size = ramsize;
- printf(": %s, %d x %d", nam,
- sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height);
- isconsole = node == fbnode && fbconstty != NULL;
+ fb->fb_type.fb_depth = 8;
+ fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900,
+ node, ca->ca_bustype);
- /*
- * Dunno what the PROM has mapped, though obviously it must have
- * the video RAM mapped. Just map what we care about for ourselves
- * (the FHC, THC, and Brooktree registers).
- */
-#define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb))
- sc->sc_physadr = ca->ca_ra.ra_reg[0];
- sc->sc_bustype = ca->ca_bustype;
- sc->sc_bt = bt = (volatile struct bt_regs *)mapiodev(ca->ca_ra.ra_reg,
- O(cg6_bt_un.un_btregs), sizeof *sc->sc_bt, ca->ca_bustype);
- sc->sc_fhc = (volatile int *)mapiodev(ca->ca_ra.ra_reg,
- O(cg6_fhc_un.un_fhc), sizeof *sc->sc_fhc, ca->ca_bustype);
- sc->sc_thc = (volatile struct cg6_thc *)mapiodev(ca->ca_ra.ra_reg,
- O(cg6_thc_un.un_thc), sizeof *sc->sc_thc, ca->ca_bustype);
- sc->sc_tec = (volatile struct cg6_tec_xxx *)mapiodev(ca->ca_ra.ra_reg,
- O(cg6_tec_un.un_tec), sizeof *sc->sc_tec, ca->ca_bustype);
+ ramsize = fb->fb_type.fb_height * fb->fb_linebytes;
+ fb->fb_type.fb_cmsize = 256;
+ fb->fb_type.fb_size = ramsize;
+ printf(": %s, %d x %d", nam, fb->fb_type.fb_width,
+ fb->fb_type.fb_height);
+
+#if defined(SUN4)
+ if (CPU_ISSUN4) {
+ struct eeprom *eep = (struct eeprom *)eeprom_va;
+ int constype = (fb->fb_flags & FB_PFOUR) ? EE_CONS_P4OPT :
+ EE_CONS_COLOR;
+ /*
+ * Assume this is the console if there's no eeprom info
+ * to be found.
+ */
+ if (eep == NULL || eep->eeConsole == constype)
+ isconsole = (fbconstty != NULL);
+ else
+ isconsole = 0;
+ }
+#endif
+
+#if defined(SUN4C) || defined(SUN4M)
+ if (CPU_ISSUN4COR4M)
+ isconsole = node == fbnode && fbconstty != NULL;
+#endif
sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) &
(FHC_REV_MASK >> FHC_REV_SHIFT);
@@ -273,19 +327,19 @@ cgsixattach(parent, self, args)
if (isconsole) {
printf(" (console)\n");
#ifdef RASTERCONSOLE
- sc->sc_fb.fb_pixels = (caddr_t)mapiodev(ca->ca_ra.ra_reg,
- O(cg6_ram[0]), ramsize, ca->ca_bustype);
+ sc->sc_fb.fb_pixels = (caddr_t)
+ mapiodev(ca->ca_ra.ra_reg, O(cg6_ram[0]),
+ ramsize, ca->ca_bustype);
fbrcons_init(&sc->sc_fb);
#endif
} else
printf("\n");
#if defined(SUN4C) || defined(SUN4M)
- if (ca->ca_bustype == BUS_SBUS)
+ if (sbus)
sbus_establish(&sc->sc_sd, &sc->sc_dev);
-#endif /* SUN4C || SUN4M */
- if ((node == fbnode && cputyp != CPU_SUN4) ||
- (isconsole && cputyp == CPU_SUN4))
- fb_attach(&sc->sc_fb);
+#endif
+ if (CPU_ISSUN4 || (node == fbnode))
+ fb_attach(&sc->sc_fb, isconsole);
}
int
@@ -296,7 +350,7 @@ cgsixopen(dev, flags, mode, p)
{
int unit = minor(dev);
- if (unit >= cgsixcd.cd_ndevs || cgsixcd.cd_devs[unit] == NULL)
+ if (unit >= cgsix_cd.cd_ndevs || cgsix_cd.cd_devs[unit] == NULL)
return (ENXIO);
return (0);
}
@@ -307,7 +361,7 @@ cgsixclose(dev, flags, mode, p)
int flags, mode;
struct proc *p;
{
- struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)];
+ struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
cg6_reset(sc);
return (0);
@@ -321,9 +375,9 @@ cgsixioctl(dev, cmd, data, flags, p)
int flags;
struct proc *p;
{
- register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)];
+ register struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
u_int count;
- int i, v, error;
+ int v, error;
union cursor_cmap tcm;
switch (cmd) {
@@ -480,7 +534,7 @@ cgsixioctl(dev, cmd, data, flags, p)
default:
#ifdef DEBUG
- log(LOG_NOTICE, "cgsixioctl(%x) (%s[%d])\n", cmd,
+ log(LOG_NOTICE, "cgsixioctl(%lx) (%s[%d])\n", cmd,
p->p_comm, p->p_pid);
#endif
return (ENOTTY);
@@ -663,7 +717,7 @@ cgsixmmap(dev, off, prot)
dev_t dev;
int off, prot;
{
- register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)];
+ register struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
register struct mmo *mo;
register u_int u, sz;
#define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb))
@@ -698,7 +752,7 @@ cgsixmmap(dev, off, prot)
sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size;
if (u < sz)
return (REG2PHYS(&sc->sc_physadr, u + mo->mo_physoff,
- sc->sc_bustype) | PMAP_NC);
+ sc->sc_bustype) | PMAP_NC);
}
#ifdef DEBUG
{
diff --git a/sys/arch/sparc/dev/cgsixreg.h b/sys/arch/sparc/dev/cgsixreg.h
index 15a7d603f9e..d9b90977c85 100644
--- a/sys/arch/sparc/dev/cgsixreg.h
+++ b/sys/arch/sparc/dev/cgsixreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: cgsixreg.h,v 1.3 1994/11/20 20:52:00 deraadt Exp $ */
+/* $NetBSD: cgsixreg.h,v 1.4 1996/02/27 22:09:31 thorpej Exp $ */
/*
* Copyright (c) 1993
@@ -71,6 +71,9 @@
* we have only seen rev 1 & 2.
*/
+/* offsets */
+#define CGSIX_FHC_OFFSET 0x300000
+
/* bits in FHC register */
#define FHC_FBID_MASK 0xff000000 /* bits 24..31 are frame buffer ID */
#define FHC_FBID_SHIFT 24
diff --git a/sys/arch/sparc/dev/cgthree.c b/sys/arch/sparc/dev/cgthree.c
index 06c62b15e91..1599048c61d 100644
--- a/sys/arch/sparc/dev/cgthree.c
+++ b/sys/arch/sparc/dev/cgthree.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cgthree.c,v 1.16 1995/10/08 01:39:18 pk Exp $ */
+/* $NetBSD: cgthree.c,v 1.27 1996/04/01 17:30:03 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -53,12 +53,14 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/tty.h>
+#include <sys/conf.h>
#include <vm/vm.h>
@@ -66,6 +68,8 @@
#include <machine/autoconf.h>
#include <machine/pmap.h>
#include <machine/fbvar.h>
+#include <machine/cpu.h>
+#include <machine/conf.h>
#include <sparc/dev/btreg.h>
#include <sparc/dev/btvar.h>
@@ -77,10 +81,9 @@ struct cgthree_softc {
struct device sc_dev; /* base device */
struct sbusdev sc_sd; /* sbus device */
struct fbdevice sc_fb; /* frame buffer device */
- volatile struct bt_regs *sc_bt; /* Brooktree registers */
- struct rom_reg sc_phys; /* display RAM (phys addr) */
+ struct rom_reg sc_phys; /* phys address description */
+ volatile struct fbcontrol *sc_fbc; /* Brooktree registers */
int sc_bustype; /* type of bus we live on */
- int sc_blanked; /* true if blanked */
union bt_cmap sc_cmap; /* Brooktree color map */
};
@@ -93,9 +96,12 @@ int cgthreeioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
int cgthreemmap __P((dev_t, int, int));
static void cgthreeunblank(struct device *);
-struct cfdriver cgthreecd = {
- NULL, "cgthree", cgthreematch, cgthreeattach,
- DV_DULL, sizeof(struct cgthree_softc)
+struct cfattach cgthree_ca = {
+ sizeof(struct cgthree_softc), cgthreematch, cgthreeattach
+};
+
+struct cfdriver cgthree_cd = {
+ NULL, "cgthree", DV_DULL
};
/* frame buffer generic driver */
@@ -107,6 +113,8 @@ extern int fbnode;
extern struct tty *fbconstty;
static void cgthreeloadcmap __P((struct cgthree_softc *, int, int));
+static void cgthree_set_video __P((struct cgthree_softc *, int));
+static int cgthree_get_video __P((struct cgthree_softc *));
/*
* Match a cgthree.
@@ -120,6 +128,11 @@ cgthreematch(parent, vcf, aux)
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
+ /*
+ * Mask out invalid flags from the user.
+ */
+ cf->cf_flags &= FB_USERMASK;
+
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
if (ca->ca_bustype == BUS_SBUS)
@@ -138,32 +151,36 @@ cgthreeattach(parent, self, args)
{
register struct cgthree_softc *sc = (struct cgthree_softc *)self;
register struct confargs *ca = args;
- register int node = ca->ca_ra.ra_node, ramsize, i;
+ register int node = 0, ramsize, i;
register volatile struct bt_regs *bt;
- register struct cgthree_all *p;
int isconsole;
- char *nam;
+ int sbus = 1;
+ char *nam = NULL;
sc->sc_fb.fb_driver = &cgthreefbdriver;
sc->sc_fb.fb_device = &sc->sc_dev;
+ sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags;
/*
* The defaults below match my screen, but are not guaranteed
* to be correct as defaults go...
*/
sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR;
switch (ca->ca_bustype) {
-#if defined(SUN4M)
case BUS_OBIO:
- if (cputyp == CPU_SUN4M) /* 4m has framebuffer on obio */
+ if (CPU_ISSUN4M) { /* 4m has framebuffer on obio */
+ sbus = 0;
+ node = ca->ca_ra.ra_node;
nam = getpropstring(node, "model");
- break;
-#endif
-
+ break;
+ }
case BUS_VME32:
- node = 0;
+ case BUS_VME16:
+ sbus = node = 0;
nam = "cgthree";
break;
+
case BUS_SBUS:
+ node = ca->ca_ra.ra_node;
nam = getpropstring(node, "model");
break;
}
@@ -173,7 +190,7 @@ cgthreeattach(parent, self, args)
1152, 900, node, ca->ca_bustype);
ramsize = roundup(sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes,
- NBPG);
+ NBPG);
sc->sc_fb.fb_type.fb_cmsize = 256;
sc->sc_fb.fb_type.fb_size = ramsize;
printf(": %s, %d x %d", nam,
@@ -186,27 +203,27 @@ cgthreeattach(parent, self, args)
* going to print characters via rconsole.
*/
isconsole = node == fbnode && fbconstty != NULL;
- p = (struct cgthree_all *)ca->ca_ra.ra_paddr;
if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) {
/* this probably cannot happen, but what the heck */
sc->sc_fb.fb_pixels = mapiodev(ca->ca_ra.ra_reg, CG3REG_MEM,
- ramsize, ca->ca_bustype);
+ ramsize, ca->ca_bustype);
}
- sc->sc_bt = bt = (volatile struct bt_regs *)mapiodev(ca->ca_ra.ra_reg,
- CG3REG_REG, sizeof(struct bt_regs), ca->ca_bustype);
+ sc->sc_fbc = (volatile struct fbcontrol *)
+ mapiodev(ca->ca_ra.ra_reg, CG3REG_REG,
+ sizeof(struct fbcontrol), ca->ca_bustype);
sc->sc_phys = ca->ca_ra.ra_reg[0];
sc->sc_bustype = ca->ca_bustype;
/* grab initial (current) color map */
+ bt = &sc->sc_fbc->fbc_dac;
bt->bt_addr = 0;
for (i = 0; i < 256 * 3 / 4; i++)
sc->sc_cmap.cm_chip[i] = bt->bt_cmap;
- /* make sure we are not blanked (see cgthreeunblank) */
- bt->bt_addr = 0x06; /* command reg */
- bt->bt_ctrl = 0x73; /* overlay plane */
- bt->bt_addr = 0x04; /* read mask */
- bt->bt_ctrl = 0xff; /* color planes */
+
+ /* make sure we are not blanked */
+ cgthree_set_video(sc, 1);
+ BT_INIT(bt, 0);
if (isconsole) {
printf(" (console)\n");
@@ -215,12 +232,10 @@ cgthreeattach(parent, self, args)
#endif
} else
printf("\n");
-#if defined(SUN4C) || defined(SUN4M)
- if (ca->ca_bustype == BUS_SBUS)
+ if (sbus)
sbus_establish(&sc->sc_sd, &sc->sc_dev);
-#endif /* SUN4C || SUN4M */
if (node == fbnode)
- fb_attach(&sc->sc_fb);
+ fb_attach(&sc->sc_fb, isconsole);
}
int
@@ -231,7 +246,7 @@ cgthreeopen(dev, flags, mode, p)
{
int unit = minor(dev);
- if (unit >= cgthreecd.cd_ndevs || cgthreecd.cd_devs[unit] == NULL)
+ if (unit >= cgthree_cd.cd_ndevs || cgthree_cd.cd_devs[unit] == NULL)
return (ENXIO);
return (0);
}
@@ -254,7 +269,7 @@ cgthreeioctl(dev, cmd, data, flags, p)
int flags;
struct proc *p;
{
- register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)];
+ register struct cgthree_softc *sc = cgthree_cd.cd_devs[minor(dev)];
register struct fbgattr *fba;
int error;
@@ -292,29 +307,11 @@ cgthreeioctl(dev, cmd, data, flags, p)
break;
case FBIOGVIDEO:
- *(int *)data = sc->sc_blanked;
+ *(int *)data = cgthree_get_video(sc);
break;
case FBIOSVIDEO:
- if (*(int *)data)
- cgthreeunblank(&sc->sc_dev);
- else if (!sc->sc_blanked) {
- register volatile struct bt_regs *bt;
-
- bt = sc->sc_bt;
- bt->bt_addr = 0x06; /* command reg */
- bt->bt_ctrl = 0x70; /* overlay plane */
- bt->bt_addr = 0x04; /* read mask */
- bt->bt_ctrl = 0x00; /* color planes */
- /*
- * Set color 0 to black -- note that this overwrites
- * R of color 1.
- */
- bt->bt_addr = 0;
- bt->bt_cmap = 0;
-
- sc->sc_blanked = 1;
- }
+ cgthree_set_video(sc, *(int *)data);
break;
default:
@@ -330,22 +327,28 @@ static void
cgthreeunblank(dev)
struct device *dev;
{
- struct cgthree_softc *sc = (struct cgthree_softc *)dev;
- register volatile struct bt_regs *bt;
- if (sc->sc_blanked) {
- sc->sc_blanked = 0;
- bt = sc->sc_bt;
- /* restore color 0 (and R of color 1) */
- bt->bt_addr = 0;
- bt->bt_cmap = sc->sc_cmap.cm_chip[0];
-
- /* restore read mask */
- bt->bt_addr = 0x06; /* command reg */
- bt->bt_ctrl = 0x73; /* overlay plane */
- bt->bt_addr = 0x04; /* read mask */
- bt->bt_ctrl = 0xff; /* color planes */
- }
+ cgthree_set_video((struct cgthree_softc *)dev, 1);
+}
+
+static void
+cgthree_set_video(sc, enable)
+ struct cgthree_softc *sc;
+ int enable;
+{
+
+ if (enable)
+ sc->sc_fbc->fbc_ctrl |= FBC_VENAB;
+ else
+ sc->sc_fbc->fbc_ctrl &= ~FBC_VENAB;
+}
+
+static int
+cgthree_get_video(sc)
+ struct cgthree_softc *sc;
+{
+
+ return ((sc->sc_fbc->fbc_ctrl & FBC_VENAB) != 0);
}
/*
@@ -362,7 +365,7 @@ cgthreeloadcmap(sc, start, ncolors)
ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */
count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
- bt = sc->sc_bt;
+ bt = &sc->sc_fbc->fbc_dac;
bt->bt_addr = BT_D4M4(start);
while (--count >= 0)
bt->bt_cmap = *ip++;
@@ -378,7 +381,7 @@ cgthreeloadcmap(sc, start, ncolors)
* map the whole thing, so we repeatedly map the first 256K to the
* first page of the color screen. If someone tries to use the overlay
* and enable regions, they will get a surprise....
- *
+ *
* As well, mapping at an offset of 0x04000000 causes the cg3 to be
* mapped in flat mode without the cg4 emulation.
*/
@@ -387,7 +390,7 @@ cgthreemmap(dev, off, prot)
dev_t dev;
int off, prot;
{
- register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)];
+ register struct cgthree_softc *sc = cgthree_cd.cd_devs[minor(dev)];
#define START (128*1024 + 128*1024)
#define NOOVERLAY (0x04000000)
diff --git a/sys/arch/sparc/dev/cgthreereg.h b/sys/arch/sparc/dev/cgthreereg.h
index 0b8356e4126..073cc52e66c 100644
--- a/sys/arch/sparc/dev/cgthreereg.h
+++ b/sys/arch/sparc/dev/cgthreereg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: cgthreereg.h,v 1.4 1994/11/20 20:52:03 deraadt Exp $ */
+/* $NetBSD: cgthreereg.h,v 1.5 1996/02/27 00:14:17 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -58,7 +58,7 @@
struct cgthree_all {
long ba_id; /* ID = 0xfe010104 on my IPC */
char ba_xxx0[0x400000-4];
- struct bt_regs ba_btreg; /* Brooktree registers */
- char ba_xxx1[0x400000-sizeof(struct bt_regs)];
+ struct fbcontrol ba_fbc; /* Brooktree regs (+ misc control) */
+ char ba_xxx1[0x400000-sizeof(struct fbcontrol)];
char ba_ram[4096]; /* actually larger */
};
diff --git a/sys/arch/sparc/dev/cgtwo.c b/sys/arch/sparc/dev/cgtwo.c
index 17be2ccbc12..243c7cde111 100644
--- a/sys/arch/sparc/dev/cgtwo.c
+++ b/sys/arch/sparc/dev/cgtwo.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cgtwo.c,v 1.5 1995/10/08 01:39:15 pk Exp $ */
+/* $NetBSD: cgtwo.c,v 1.16 1996/05/18 12:19:14 mrg Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -53,12 +53,14 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/tty.h>
+#include <sys/conf.h>
#include <vm/vm.h>
@@ -66,10 +68,13 @@
#include <machine/autoconf.h>
#include <machine/pmap.h>
#include <machine/fbvar.h>
+#if defined(SUN4)
#include <machine/eeprom.h>
-
+#endif
+#include <machine/conf.h>
#include <machine/cgtworeg.h>
+
/* per-display variables */
struct cgtwo_softc {
struct device sc_dev; /* base device */
@@ -91,10 +96,15 @@ int cgtwoclose __P((dev_t, int, int, struct proc *));
int cgtwoioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
int cgtwommap __P((dev_t, int, int));
static void cgtwounblank __P((struct device *));
+int cgtwogetcmap __P((struct cgtwo_softc *, struct fbcmap *));
+int cgtwoputcmap __P((struct cgtwo_softc *, struct fbcmap *));
-struct cfdriver cgtwocd = {
- NULL, "cgtwo", cgtwomatch, cgtwoattach,
- DV_DULL, sizeof(struct cgtwo_softc)
+struct cfattach cgtwo_ca = {
+ sizeof(struct cgtwo_softc), cgtwomatch, cgtwoattach
+};
+
+struct cfdriver cgtwo_cd = {
+ NULL, "cgtwo", DV_DULL
};
/* frame buffer generic driver */
@@ -105,8 +115,6 @@ static struct fbdriver cgtwofbdriver = {
extern int fbnode;
extern struct tty *fbconstty;
-static void cgtwoloadcmap __P((struct cgtwo_softc *, int, int));
-
/*
* Match a cgtwo.
*/
@@ -118,18 +126,32 @@ cgtwomatch(parent, vcf, aux)
struct cfdata *cf = vcf;
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
- int probe;
+#if defined(SUN4)
caddr_t tmp;
+#endif
+
+ /*
+ * Mask out invalid flags from the user.
+ */
+ cf->cf_flags &= FB_USERMASK;
+
+ if (ca->ca_bustype != BUS_VME16)
+ return (0);
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
+#if defined(SUN4)
+ if (!CPU_ISSUN4 || cf->cf_unit != 0)
+ return (0);
+
/* XXX - Must do our own mapping at CG2_CTLREG_OFF */
bus_untmp();
tmp = (caddr_t)bus_tmp(ra->ra_paddr + CG2_CTLREG_OFF, ca->ca_bustype);
if (probeget(tmp, 2) != -1)
return 1;
- return (0);
+#endif
+ return 0;
}
/*
@@ -142,15 +164,25 @@ cgtwoattach(parent, self, args)
{
register struct cgtwo_softc *sc = (struct cgtwo_softc *)self;
register struct confargs *ca = args;
- register int node = 0, i;
- register struct cgtwo_all *p;
- struct eeprom *eep = (struct eeprom *)eeprom_va;
- int isconsole;
- char *nam;
+ register int node = 0;
+ int isconsole = 0;
+ char *nam = NULL;
sc->sc_fb.fb_driver = &cgtwofbdriver;
sc->sc_fb.fb_device = &sc->sc_dev;
sc->sc_fb.fb_type.fb_type = FBTYPE_SUN2COLOR;
+ sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags;
+
+ switch (ca->ca_bustype) {
+ case BUS_VME16:
+ node = 0;
+ nam = "cgtwo";
+ break;
+
+ default:
+ panic("cgtwoattach: impossible bustype");
+ /* NOTREACHED */
+ }
sc->sc_fb.fb_type.fb_depth = 8;
fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth,
@@ -158,8 +190,8 @@ cgtwoattach(parent, self, args)
sc->sc_fb.fb_type.fb_cmsize = 256;
sc->sc_fb.fb_type.fb_size = roundup(CG2_MAPPED_SIZE, NBPG);
- printf(": cgtwo, %d x %d", sc->sc_fb.fb_type.fb_width,
- sc->sc_fb.fb_type.fb_height);
+ printf(": %s, %d x %d", nam,
+ sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height);
/*
* When the ROM has mapped in a cgtwo display, the address
@@ -167,30 +199,41 @@ cgtwoattach(parent, self, args)
* registers ourselves. We only need the video RAM if we are
* going to print characters via rconsole.
*/
- if (eep == NULL || eep->ee_diag.eed_console == EED_CONS_COLOR)
- isconsole = (fbconstty != NULL);
- else
- isconsole = 0;
-
+#if defined(SUN4)
+ if (CPU_ISSUN4) {
+ struct eeprom *eep = (struct eeprom *)eeprom_va;
+ /*
+ * Assume this is the console if there's no eeprom info
+ * to be found.
+ */
+ if (eep == NULL || eep->eeConsole == EE_CONS_COLOR)
+ isconsole = (fbconstty != NULL);
+ else
+ isconsole = 0;
+ }
+#endif
sc->sc_phys = ca->ca_ra.ra_reg[0];
sc->sc_bustype = ca->ca_bustype;
if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) {
/* this probably cannot happen, but what the heck */
sc->sc_fb.fb_pixels = mapiodev(ca->ca_ra.ra_reg, CG2_PIXMAP_OFF,
- CG2_PIXMAP_SIZE, ca->ca_bustype);
+ CG2_PIXMAP_SIZE,
+ PMAP_VME32/*ca->ca_bustype*/);
}
#ifndef offsetof
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
#endif
- sc->sc_reg = (volatile struct cg2statusreg *)mapiodev(ca->ca_ra.ra_reg,
- CG2_ROPMEM_OFF + offsetof(struct cg2fb, status.reg),
- sizeof(struct cg2statusreg), ca->ca_bustype);
+ sc->sc_reg = (volatile struct cg2statusreg *)
+ mapiodev(ca->ca_ra.ra_reg,
+ CG2_ROPMEM_OFF + offsetof(struct cg2fb, status.reg),
+ sizeof(struct cg2statusreg), ca->ca_bustype);
- sc->sc_cmap = (volatile u_short *)mapiodev(ca->ca_ra.ra_reg,
- CG2_ROPMEM_OFF + offsetof(struct cg2fb, redmap[0]),
- 3 * CG2_CMSIZE, ca->ca_bustype);
+ sc->sc_cmap = (volatile u_short *)
+ mapiodev(ca->ca_ra.ra_reg,
+ CG2_ROPMEM_OFF + offsetof(struct cg2fb, redmap[0]),
+ 3 * CG2_CMSIZE, ca->ca_bustype);
if (isconsole) {
printf(" (console)\n");
@@ -199,8 +242,9 @@ cgtwoattach(parent, self, args)
#endif
} else
printf("\n");
- if (isconsole)
- fb_attach(&sc->sc_fb);
+
+ if (node == fbnode || CPU_ISSUN4)
+ fb_attach(&sc->sc_fb, isconsole);
}
int
@@ -211,7 +255,7 @@ cgtwoopen(dev, flags, mode, p)
{
int unit = minor(dev);
- if (unit >= cgtwocd.cd_ndevs || cgtwocd.cd_devs[unit] == NULL)
+ if (unit >= cgtwo_cd.cd_ndevs || cgtwo_cd.cd_devs[unit] == NULL)
return (ENXIO);
return (0);
}
@@ -234,9 +278,8 @@ cgtwoioctl(dev, cmd, data, flags, p)
int flags;
struct proc *p;
{
- register struct cgtwo_softc *sc = cgtwocd.cd_devs[minor(dev)];
+ register struct cgtwo_softc *sc = cgtwo_cd.cd_devs[minor(dev)];
register struct fbgattr *fba;
- int error;
switch (cmd) {
@@ -257,10 +300,10 @@ cgtwoioctl(dev, cmd, data, flags, p)
break;
case FBIOGETCMAP:
- return cgtwogetcmap(sc, data);
+ return cgtwogetcmap(sc, (struct fbcmap *) data);
case FBIOPUTCMAP:
- return cgtwoputcmap(sc, data);
+ return cgtwoputcmap(sc, (struct fbcmap *) data);
case FBIOGVIDEO:
*(int *)data = sc->sc_reg->video_enab;
@@ -284,7 +327,6 @@ cgtwounblank(dev)
struct device *dev;
{
struct cgtwo_softc *sc = (struct cgtwo_softc *)dev;
-
sc->sc_reg->video_enab = 1;
}
@@ -381,7 +423,7 @@ cgtwommap(dev, off, prot)
dev_t dev;
int off, prot;
{
- register struct cgtwo_softc *sc = cgtwocd.cd_devs[minor(dev)];
+ register struct cgtwo_softc *sc = cgtwo_cd.cd_devs[minor(dev)];
if (off & PGOFSET)
panic("cgtwommap");
@@ -389,5 +431,5 @@ cgtwommap(dev, off, prot)
if ((unsigned)off >= sc->sc_fb.fb_type.fb_size)
return (-1);
- return (REG2PHYS(&sc->sc_phys, off, PMAP_VME32) | PMAP_NC);
+ return (REG2PHYS(&sc->sc_phys, off, PMAP_VME32/*sc->sc_bustype*/) | PMAP_NC);
}
diff --git a/sys/arch/sparc/dev/cons.c b/sys/arch/sparc/dev/cons.c
index d4e096bf88d..08df311233b 100644
--- a/sys/arch/sparc/dev/cons.c
+++ b/sys/arch/sparc/dev/cons.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cons.c,v 1.15 1995/07/13 12:02:19 pk Exp $ */
+/* $NetBSD: cons.c,v 1.23.4.1 1996/06/02 09:07:53 mrg Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -49,7 +49,6 @@
*/
#include <sys/param.h>
-#include <sys/types.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
@@ -57,11 +56,18 @@
#include <sys/file.h>
#include <sys/conf.h>
+#include <dev/cons.h>
+
#include <machine/bsd_openprom.h>
+#include <machine/eeprom.h>
#include <machine/psl.h>
-#ifdef SUN4
+#include <machine/cpu.h>
+#include <machine/kbd.h>
+#if defined(SUN4)
#include <machine/oldmon.h>
#endif
+#include <machine/autoconf.h>
+#include <machine/conf.h>
#include "zs.h"
@@ -71,25 +77,25 @@ int rom_console_input; /* when set, hardclock calls cnrom() */
int cons_ocount; /* output byte count */
-extern struct promvec *promvec;
-
/*
* The output driver may munge the minor number in cons.t_dev.
*/
struct tty cons; /* rom console tty device */
-static void (*fcnstop) __P((struct tty *, int));
+static int (*fcnstop) __P((struct tty *, int));
static void cnstart __P((struct tty *));
-void cnstop __P((struct tty *, int));
+int cnstop __P((struct tty *, int));
static void cnfbstart __P((struct tty *));
-static void cnfbstop __P((struct tty *, int));
+static int cnfbstop __P((struct tty *, int));
static void cnfbdma __P((void *));
+static struct tty *xxcntty __P((dev_t));
extern char char_type[];
-/*XXX*/static struct tty *
-cntty()
+/*XXX*/
+static struct tty *
+xxcntty(dev_t dev)
{
return &cons;
}
@@ -99,16 +105,121 @@ consinit()
{
register struct tty *tp = &cons;
register int in, out;
- void zsconsole();
-/*XXX*/ cdevsw[0].d_tty = cntty;
+/*XXX*/ cdevsw[0].d_tty = xxcntty;
tp->t_dev = makedev(0, 0); /* /dev/console */
tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
tp->t_param = (int (*)(struct tty *, struct termios *))nullop;
- in = *promvec->pv_stdin;
- out = *promvec->pv_stdout;
- switch (in) {
+ if (promvec->pv_romvec_vers > 2) {
+ /* We need to probe the PROM device tree */
+ register int node,fd;
+ char buffer[128];
+ register struct nodeops *no;
+ register struct v2devops *op;
+ register char *cp;
+ extern int fbnode;
+
+ in = out = -1;
+ no = promvec->pv_nodeops;
+ op = &promvec->pv_v2devops;
+
+ node = findroot();
+ if (no->no_proplen(node, "stdin-path") >= sizeof(buffer)) {
+ printf("consinit: increase buffer size and recompile\n");
+ goto setup_output;
+ }
+ /* XXX: fix above */
+
+ no->no_getprop(node, "stdin-path",buffer);
+
+ /*
+ * Open an "instance" of this device.
+ * You'd think it would be appropriate to call v2_close()
+ * on the handle when we're done with it. But that seems
+ * to cause the device to shut down somehow; for the moment,
+ * we simply leave it open...
+ */
+ if ((fd = op->v2_open(buffer)) == 0 ||
+ (node = op->v2_fd_phandle(fd)) == 0) {
+ printf("consinit: bogus stdin path %s.\n",buffer);
+ goto setup_output;
+ }
+ if (no->no_proplen(node,"keyboard") >= 0) {
+ in = PROMDEV_KBD;
+ goto setup_output;
+ }
+ if (strcmp(getpropstring(node,"device_type"),"serial") != 0) {
+ /* not a serial, not keyboard. what is it?!? */
+ in = -1;
+ goto setup_output;
+ }
+ /*
+ * At this point we assume the device path is in the form
+ * ....device@x,y:a for ttya and ...device@x,y:b for ttyb.
+ * If it isn't, we defer to the ROM
+ */
+ cp = buffer;
+ while (*cp)
+ cp++;
+ cp -= 2;
+#ifdef DEBUG
+ if (cp < buffer)
+ panic("consinit: bad stdin path %s",buffer);
+#endif
+ /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */
+ if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z')
+ in = PROMDEV_TTYA + (cp[1] - 'a');
+ /* else use rom */
+setup_output:
+ node = findroot();
+ if (no->no_proplen(node, "stdout-path") >= sizeof(buffer)) {
+ printf("consinit: increase buffer size and recompile\n");
+ goto setup_console;
+ }
+ /* XXX: fix above */
+
+ no->no_getprop(node, "stdout-path", buffer);
+
+ if ((fd = op->v2_open(buffer)) == 0 ||
+ (node = op->v2_fd_phandle(fd)) == 0) {
+ printf("consinit: bogus stdout path %s.\n",buffer);
+ goto setup_output;
+ }
+ if (strcmp(getpropstring(node,"device_type"),"display") == 0) {
+ /* frame buffer output */
+ out = PROMDEV_SCREEN;
+ fbnode = node;
+ } else if (strcmp(getpropstring(node,"device_type"), "serial")
+ != 0) {
+ /* not screen, not serial. Whatzit? */
+ out = -1;
+ } else { /* serial console. which? */
+ /*
+ * At this point we assume the device path is in the
+ * form:
+ * ....device@x,y:a for ttya, etc.
+ * If it isn't, we defer to the ROM
+ */
+ cp = buffer;
+ while (*cp)
+ cp++;
+ cp -= 2;
+#ifdef DEBUG
+ if (cp < buffer)
+ panic("consinit: bad stdout path %s",buffer);
+#endif
+ /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */
+ if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z')
+ out = PROMDEV_TTYA + (cp[1] - 'a');
+ else out = -1;
+ }
+ } else {
+ in = *promvec->pv_stdin;
+ out = *promvec->pv_stdout;
+ }
+setup_console:
+ switch (in) {
#if NZS > 0
case PROMDEV_TTYA:
zsconsole(tp, 0, 0, NULL);
@@ -152,12 +263,13 @@ consinit()
default:
printf("unknown console output sink %d; using rom\n", out);
tp->t_oproc = cnstart;
- fcnstop = (void (*)(struct tty *, int))nullop;
+ fcnstop = (int (*)(struct tty *, int))nullop;
break;
}
}
/* ARGSUSED */
+int
cnopen(dev, flag, mode, p)
dev_t dev;
int flag, mode;
@@ -165,12 +277,42 @@ cnopen(dev, flag, mode, p)
{
register struct tty *tp = &cons;
static int firstopen = 1;
+ static int rows = 0, cols = 0;
- if(firstopen) {
+ if (firstopen) {
clalloc(&tp->t_rawq, 1024, 1);
clalloc(&tp->t_canq, 1024, 1);
/* output queue doesn't need quoting */
clalloc(&tp->t_outq, 1024, 0);
+ tty_attach(tp);
+ /*
+ * get the console struct winsize.
+ */
+ if (CPU_ISSUN4COR4M) {
+ int i;
+ char *prop;
+
+ if ((prop = getpropstring(optionsnode, "screen-#rows"))) {
+ i = 0;
+ while (*prop != '\0')
+ i = i * 10 + *prop++ - '0';
+ rows = (unsigned short)i;
+ }
+ if ((prop = getpropstring(optionsnode, "screen-#columns"))) {
+ i = 0;
+ while (*prop != '\0')
+ i = i * 10 + *prop++ - '0';
+ cols = (unsigned short)i;
+ }
+ }
+ if (CPU_ISSUN4) {
+ struct eeprom *ep = (struct eeprom *)eeprom_va;
+
+ if (ep) {
+ rows = (u_short)ep->eeTtyRows;
+ cols = (u_short)ep->eeTtyCols;
+ }
+ }
firstopen = 0;
}
@@ -186,12 +328,15 @@ cnopen(dev, flag, mode, p)
tp->t_state = TS_ISOPEN | TS_CARR_ON;
(void)(*tp->t_param)(tp, &tp->t_termios);
ttsetwater(tp);
+ tp->t_winsize.ws_row = rows;
+ tp->t_winsize.ws_col = cols;
} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
return (EBUSY);
return ((*linesw[tp->t_line].l_open)(dev, tp));
}
/* ARGSUSED */
+int
cnclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
@@ -205,6 +350,7 @@ cnclose(dev, flag, mode, p)
}
/* ARGSUSED */
+int
cnread(dev, uio, flag)
dev_t dev;
struct uio *uio;
@@ -216,19 +362,21 @@ cnread(dev, uio, flag)
}
/* ARGSUSED */
+int
cnwrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
register struct tty *tp;
-
+
if ((tp = constty) == NULL ||
(tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN))
tp = &cons;
return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
}
+int
cnioctl(dev, cmd, data, flag, p)
dev_t dev;
u_long cmd;
@@ -258,6 +406,7 @@ cnioctl(dev, cmd, data, flag, p)
return (ENOTTY);
}
+int
cnselect(dev, which, p)
dev_t dev;
int which;
@@ -281,9 +430,9 @@ cnstart(tp)
register int c, s;
register union {
void (*v1)__P((int));
- void (*v3)__P((int, u_char *, int));
+ int (*v3)__P((int, void *, int));
} putc;
- register int fd, v;
+ register int fd = 0, v;
s = spltty();
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
@@ -291,7 +440,7 @@ cnstart(tp)
return;
}
if ((v = promvec->pv_romvec_vers) > 2) {
- putc.v3 = (void (*))promvec->pv_v2devops.v2_write;
+ putc.v3 = promvec->pv_v2devops.v2_write;
fd = *promvec->pv_v2bootargs.v2_fd1;
} else
putc.v1 = promvec->pv_putchar;
@@ -304,7 +453,7 @@ cnstart(tp)
*/
(void) splhigh();
if (v > 2) {
- u_char c0 = c & 0177;
+ unsigned char c0 = c & 0177;
(*putc.v3)(fd, &c0, 1);
} else
(*putc.v1)(c & 0177);
@@ -318,12 +467,13 @@ cnstart(tp)
splx(s);
}
-void
+int
cnstop(tp, flag)
register struct tty *tp;
int flag;
{
- (*fcnstop)(tp, flag);
+ (void)(*fcnstop)(tp, flag);
+ return 0;
}
/*
@@ -367,7 +517,7 @@ cnfbstart(tp)
/*
* Stop frame buffer output: just assert TS_FLUSH if necessary.
*/
-static void
+static int
cnfbstop(tp, flag)
register struct tty *tp;
int flag;
@@ -377,6 +527,7 @@ cnfbstop(tp, flag)
if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY)
tp->t_state |= TS_FLUSH;
splx(s);
+ return 0;
}
/*
@@ -387,7 +538,7 @@ cnfbdma(tpaddr)
void *tpaddr;
{
register struct tty *tp = tpaddr;
- register char *p, *q;
+ register unsigned char *p, *q;
register int n, c, s;
s = spltty(); /* paranoid */
@@ -406,7 +557,7 @@ cnfbdma(tpaddr)
(*promvec->pv_v2devops.v2_write)
(*promvec->pv_v2bootargs.v2_fd1, p, n);
} else
- (*promvec->pv_putstr)(p, n);
+ (*promvec->pv_putstr)((char *)p, n);
ndflush(&tp->t_outq, n);
}
if (tp->t_line)
@@ -423,6 +574,7 @@ cnfbdma(tpaddr)
volatile int cn_rxc = -1; /* XXX receive `silo' */
/* called from hardclock, which is above spltty, so no tty calls! */
+int
cnrom()
{
register int c;
@@ -442,6 +594,7 @@ cnrom()
}
/* pseudo console software interrupt scheduled when cnrom() returns 1 */
+void
cnrint()
{
register struct tty *tp;
@@ -466,6 +619,7 @@ cnrint()
(*linesw[tp->t_line].l_rint)(c, tp);
}
+int
cngetc()
{
register int s, c;
@@ -473,30 +627,30 @@ cngetc()
if (promvec->pv_romvec_vers > 2) {
register int n = 0;
unsigned char c0;
+ s = splhigh();
while (n <= 0) {
- s = splhigh();
n = (*promvec->pv_v2devops.v2_read)
(*promvec->pv_v2bootargs.v2_fd0, &c0, 1);
- splx(s);
}
+ splx(s);
c = c0;
} else {
-#ifdef SUN4
+#if defined(SUN4)
/* SUN4 PROM: must turn off echo to avoid double char echo */
extern struct om_vector *oldpvec;
- int saveecho;
+ int saveecho = 0;
#endif
s = splhigh();
-#ifdef SUN4
- if (cputyp == CPU_SUN4) {
+#if defined(SUN4)
+ if (CPU_ISSUN4) {
saveecho = *(oldpvec->echo);
*(oldpvec->echo) = 0;
}
#endif
c = (*promvec->pv_getchar)();
-#ifdef SUN4
- if (cputyp == CPU_SUN4)
+#if defined(SUN4)
+ if (CPU_ISSUN4)
*(oldpvec->echo) = saveecho;
#endif
splx(s);
@@ -506,6 +660,7 @@ cngetc()
return (c);
}
+void
cnputc(c)
register int c;
{
@@ -523,6 +678,7 @@ cnputc(c)
splx(s);
}
+void
cnpollc(on)
int on;
{
diff --git a/sys/arch/sparc/dev/dma.c b/sys/arch/sparc/dev/dma.c
index 54be0c4fdf8..ee40392c0fe 100644
--- a/sys/arch/sparc/dev/dma.c
+++ b/sys/arch/sparc/dev/dma.c
@@ -1,35 +1,7 @@
-/* $NetBSD: dma.c,v 1.8 1995/02/01 12:37:21 pk Exp $ */
+/* $NetBSD: dma.c,v 1.28.2.2 1996/07/02 23:46:29 jtc Exp $ */
/*
- * Copyright (c) 1995 Theo de Raadt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed under OpenBSD by
- * Theo de Raadt.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
+ * Copyright (c) 1994 Paul Kranenburg. All rights reserved.
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,46 +49,63 @@
#include <scsi/scsiconf.h>
#include <sparc/dev/sbusvar.h>
-#include <sparc/dev/sbusreg.h>
#include <sparc/dev/dmareg.h>
#include <sparc/dev/dmavar.h>
#include <sparc/dev/espreg.h>
#include <sparc/dev/espvar.h>
-#include <sparc/sparc/cache.h>
-
-/*#define DMA_TEST*/
-
-extern int sbus_print __P((void *, char *));
-
+int dmaprint __P((void *, char *));
void dmaattach __P((struct device *, struct device *, void *));
int dmamatch __P((struct device *, void *, void *));
+void dma_reset __P((struct dma_softc *));
+void dma_enintr __P((struct dma_softc *));
+int dma_isintr __P((struct dma_softc *));
+int espdmaintr __P((struct dma_softc *));
+int ledmaintr __P((struct dma_softc *));
+int dma_setup __P((struct dma_softc *, caddr_t *, size_t *,
+ int, size_t *));
+void dma_go __P((struct dma_softc *));
+
+struct cfattach dma_ca = {
+ sizeof(struct dma_softc), dmamatch, dmaattach
+};
-struct cfdriver dmacd = {
- NULL, "dma", dmamatch, dmaattach,
- DV_DULL, sizeof(struct dma_softc)
+struct cfdriver dma_cd = {
+ NULL, "dma", DV_DULL
};
-struct cfdriver ledmacd = {
- NULL, "ledma", dmamatch, dmaattach,
- DV_DULL, sizeof(struct dma_softc)
+struct cfattach ledma_ca = {
+ sizeof(struct dma_softc), matchbyname, dmaattach
};
-struct cfdriver espdmacd = {
- NULL, "espdma", dmamatch, dmaattach,
- DV_DULL, sizeof(struct dma_softc)
+struct cfdriver ledma_cd = {
+ NULL, "ledma", DV_DULL
};
int
+dmaprint(aux, name)
+ void *aux;
+ char *name;
+{
+ register struct confargs *ca = aux;
+
+ if (name)
+ printf("[%s at %s]", ca->ca_ra.ra_name, name);
+ printf(" slot 0x%x offset 0x%x", ca->ca_slot, ca->ca_offset);
+ return (UNCONF);
+}
+
+int
dmamatch(parent, vcf, aux)
- struct device *parent;
- void *vcf, *aux;
+ struct device *parent;
+ void *vcf, *aux;
{
- struct cfdata *cf = vcf;
+ struct cfdata *cf = vcf;
register struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
- if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
+ if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
+ strcmp("espdma", ra->ra_name))
return (0);
if (ca->ca_bustype == BUS_SBUS)
return (1);
@@ -129,353 +118,408 @@ dmamatch(parent, vcf, aux)
*/
void
dmaattach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
+ struct device *parent, *self;
+ void *aux;
{
register struct confargs *ca = aux;
- struct confargs oca;
- struct dma_softc *sc = (void *)self;
- int node, base, slot;
- char *name;
-
- /* XXX modifying ra_vaddr is bad! */
- if (ca->ca_ra.ra_vaddr == NULL)
- ca->ca_ra.ra_vaddr = mapiodev(ca->ca_ra.ra_reg, 0,
- ca->ca_ra.ra_len, ca->ca_bustype);
- if ((u_long)ca->ca_ra.ra_paddr & PGOFSET)
- (u_long)ca->ca_ra.ra_vaddr |= ((u_long)ca->ca_ra.ra_paddr & PGOFSET);
+ struct dma_softc *sc = (void *)self;
+#if defined(SUN4C) || defined(SUN4M)
+ int node;
+ struct confargs oca;
+ char *name;
+#endif
+
+ if (ca->ca_ra.ra_vaddr == NULL || ca->ca_ra.ra_nvaddrs == 0)
+ ca->ca_ra.ra_vaddr =
+ mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len,
+ ca->ca_bustype);
+
sc->sc_regs = (struct dma_regs *) ca->ca_ra.ra_vaddr;
/*
- * What happens here is that if the esp driver has not been
- * configured, then this returns a NULL pointer. Then when the
- * esp actually gets configured, it does the opposing test, and
- * if the sc->sc_dma field in it's softc is NULL, then tries to
- * find the matching dma driver.
+ * If we're a ledma, check to see what cable type is currently
+ * active and set the appropriate bit in the ledma csr so that
+ * it gets used. If we didn't netboot, the PROM won't have the
+ * "cable-selection" property; default to TP and then the user
+ * can change it via a "link0" option to ifconfig.
+ */
+ if (strcmp(ca->ca_ra.ra_name, "ledma") == 0) {
+ char *cabletype = getpropstring(ca->ca_ra.ra_node,
+ "cable-selection");
+ if (strcmp(cabletype, "tpe") == 0) {
+ sc->sc_regs->csr |= DE_AUI_TP;
+ } else if (strcmp(cabletype, "aui") == 0) {
+ sc->sc_regs->csr &= ~DE_AUI_TP;
+ } else {
+ /* assume TP if nothing there */
+ sc->sc_regs->csr |= DE_AUI_TP;
+ }
+ delay(20000); /* manual says we need 20ms delay */
+ }
+
+ /*
+ * Get transfer burst size from PROM and plug it into the controller
+ * registers. This is needed on the Sun4m; do others need it too?
+ * XXX
*/
- sc->sc_esp = ((struct esp_softc *)
- getdevunit("esp", sc->sc_dev.dv_unit));
- if (sc->sc_esp)
- sc->sc_esp->sc_dma = sc;
+ if (CPU_ISSUN4M) {
+ sc->sc_burst = getpropint(ca->ca_ra.ra_node,"burst-sizes", -1);
+ if (sc->sc_burst == -1) {
+ /* check parent SBus for burst sizes */
+ if (((struct sbus_softc *)parent)->sc_burst == 0)
+ sc->sc_burst = SBUS_BURST_32 - 1; /* 1->16 */
+ else
+ sc->sc_burst =
+ ((struct sbus_softc *)parent)->sc_burst;
+ }
+ sc->sc_regs->csr &= ~D_BURST_SIZE; /* must clear first */
+ if (sc->sc_burst & SBUS_BURST_32) {
+ sc->sc_regs->csr |= D_BURST_32;
+ } else if (sc->sc_burst & SBUS_BURST_16) {
+ sc->sc_regs->csr |= D_BURST_16;
+ } else if (strcmp(ca->ca_ra.ra_name,"espdma") == 0) {
+ /* only espdma supports non-burst */
+ sc->sc_regs->csr |= D_BURST_0;
+#ifdef DIAGNOSTIC
+ } else {
+ printf(" <unknown burst size 0x%x>", sc->sc_burst);
+#endif
+ }
+ }
printf(": rev ");
sc->sc_rev = sc->sc_regs->csr & D_DEV_ID;
switch (sc->sc_rev) {
- case DMAREV_4300:
- printf("4/300\n");
+ case DMAREV_0:
+ printf("0");
break;
case DMAREV_1:
- printf("1\n");
- break;
- case DMAREV_ESC1:
- printf("ESC1\n");
+ printf("1");
break;
case DMAREV_PLUS:
- printf("1+\n");
+ printf("1+");
break;
case DMAREV_2:
- printf("2\n");
+ printf("2");
break;
default:
- printf("unknown\n");
+ printf("unknown");
+ }
+ printf("\n");
+
+ /* indirect functions */
+ if (sc->sc_dev.dv_cfdata->cf_attach == &dma_ca) {
+ sc->intr = espdmaintr;
+ } else {
+ sc->intr = ledmaintr;
}
+ sc->enintr = dma_enintr;
+ sc->isintr = dma_isintr;
+ sc->reset = dma_reset;
+ sc->setup = dma_setup;
+ sc->go = dma_go;
+
+ sc->sc_node = ca->ca_ra.ra_node;
+ if (CPU_ISSUN4)
+ goto espsearch;
#if defined(SUN4C) || defined(SUN4M)
- if (ca->ca_bustype == BUS_SBUS) {
- sc->sc_node = ca->ca_ra.ra_node;
+ if (ca->ca_bustype == BUS_SBUS)
sbus_establish(&sc->sc_sd, &sc->sc_dev);
+ /* Propagate bootpath */
+ if (ca->ca_ra.ra_bp != NULL &&
+ (strcmp(ca->ca_ra.ra_bp->name, "espdma") == 0 ||
+ strcmp(ca->ca_ra.ra_bp->name, "dma") == 0 ||
+ strcmp(ca->ca_ra.ra_bp->name, "ledma") == 0))
+ oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1;
+ else
+ oca.ca_ra.ra_bp = NULL;
+
+ /* search through children */
+ node = firstchild(sc->sc_node);
+ if (node != 0) do {
+ name = getpropstring(node, "name");
+ if (!romprop(&oca.ca_ra, name, node))
+ continue;
+
+ sbus_translate(parent, &oca);
+ oca.ca_bustype = BUS_SBUS;
+ (void) config_found(&sc->sc_dev, (void *)&oca, dmaprint);
+ } while ((node = nextsibling(node)) != 0); else
+#endif /* SUN4C || SUN4M */
+
+ if (strcmp(ca->ca_ra.ra_name, "dma") == 0) {
+espsearch:
/*
- * If the device is in an SBUS slave slot, report
- * it (but we don't care, because the corresponding
- * ESP will also realize the same thing.)
+ * find the ESP by poking around the esp device structures
+ *
+ * What happens here is that if the esp driver has not been
+ * configured, then this returns a NULL pointer. Then when the
+ * esp actually gets configured, it does the opposing test, and
+ * if the sc->sc_dma field in it's softc is NULL, then tries to
+ * find the matching dma driver.
+ *
*/
- (void) sbus_slavecheck(self, ca);
+ sc->sc_esp = (struct esp_softc *)
+ getdevunit("esp", sc->sc_dev.dv_unit);
/*
- * if our name is not "dma", we may have subdevices
- * below us in the device tree (like an esp)
- * XXX: TDR: should we do this even if it is "dma"?
+ * and a back pointer to us, for DMA
*/
- if (strcmp(ca->ca_ra.ra_name, "dma") == 0)
- return;
-
- /* search through children */
- for (node = firstchild(sc->sc_node); node;
- node = nextsibling(node)) {
- name = getpropstring(node, "name");
- if (!romprop(&oca.ca_ra, name, node))
- continue;
-
- /*
- * advance bootpath if it currently points to us
- * XXX There appears to be strangeness in the unit
- * number on at least one espdma system (SS5 says
- * espdma5, but nothing is available to compare
- * against that digit 5...
- */
- if (ca->ca_ra.ra_bp &&
- !strcmp(ca->ca_ra.ra_bp->name, ca->ca_ra.ra_name) &&
- ca->ca_ra.ra_bp->val[1] == (int)ca->ca_ra.ra_paddr)
- oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1;
- else
- oca.ca_ra.ra_bp = NULL;
-
- base = (int)oca.ca_ra.ra_paddr;
- if (SBUS_ABS(base)) {
- oca.ca_slot = SBUS_ABS_TO_SLOT(base);
- oca.ca_offset = SBUS_ABS_TO_OFFSET(base);
- } else {
- oca.ca_slot = slot = ca->ca_ra.ra_iospace;
- oca.ca_offset = base;
- oca.ca_ra.ra_paddr = (void *)SBUS_ADDR(slot, base);
- }
- oca.ca_bustype = BUS_SBUS;
- (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print);
- }
-
+ if (sc->sc_esp)
+ sc->sc_esp->sc_dma = sc;
}
-#endif /* SUN4C || SUN4M */
}
void
-dmareset(sc)
- struct dma_softc *sc;
+dma_reset(sc)
+ struct dma_softc *sc;
{
- DMAWAIT_PEND(sc);
+ DMAWAIT(sc);
+ DMA_DRAIN(sc); /* Drain (DMA rev 1) */
+ DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */
+ DMAWAIT1(sc); /* let things drain */
DMACSR(sc) |= D_RESET; /* reset DMA */
DELAY(200); /* what should this be ? */
+ DMAWAIT1(sc);
DMACSR(sc) &= ~D_RESET; /* de-assert reset line */
+ DMACSR(sc) |= D_INT_EN; /* enable interrupts */
+ if (sc->sc_rev > DMAREV_1)
+ DMACSR(sc) |= D_FASTER;
+ sc->sc_active = 0; /* and of course we aren't */
+}
- switch (sc->sc_rev) {
- case DMAREV_1:
- case DMAREV_4300:
- case DMAREV_ESC1:
- break;
- case DMAREV_PLUS:
- case DMAREV_2:
- if (sc->sc_esp->sc_rev >= ESP100A)
- DMACSR(sc) |= D_FASTER;
- break;
- }
- sc->sc_active = 0; /* and of course we aren't */
+void
+dma_enintr(sc)
+ struct dma_softc *sc;
+{
+ sc->sc_regs->csr |= D_INT_EN;
}
int
-dmapending(sc)
+dma_isintr(sc)
struct dma_softc *sc;
{
return (sc->sc_regs->csr & (D_INT_PEND|D_ERR_PEND));
}
-/* bytes between loc and the end of this 16M region of memory */
-#define DMAMAX(loc) (0x01000000 - ((loc) & 0x00ffffff))
+#define DMAMAX(a) (0x01000000 - ((a) & 0x00ffffff))
-#define ESPMAX ((sc->sc_esp->sc_rev > ESP100A) ? \
- (16 * 1024 * 1024) : (64 * 1024))
/*
- * Start a dma transfer or keep it going.
- * We do the loading of the transfer counter.
- * XXX: what about write-back caches?
+ * setup a dma transfer
*/
-void
-dmastart(sc, addr, len, datain, poll)
- struct dma_softc *sc;
- void *addr;
- size_t *len;
- int datain, poll;
+int
+dma_setup(sc, addr, len, datain, dmasize)
+ struct dma_softc *sc;
+ caddr_t *addr;
+ size_t *len;
+ int datain;
+ size_t *dmasize; /* IN-OUT */
{
- struct espregs *espr = sc->sc_esp->sc_regs;
- int size;
+ u_long csr;
- if (sc->sc_active)
- panic("dma: dmastart() called while active\n");
+ /* clear errors and D_TC flag */
+ DMAWAIT(sc);
+ DMA_DRAIN(sc); /* ? */
+ DMAWAIT1(sc);
+ DMACSR(sc) |= D_INVALIDATE;
+ DMAWAIT1(sc);
+#if 0
+ DMACSR(sc) &= ~D_INT_EN;
+#endif
sc->sc_dmaaddr = addr;
sc->sc_dmalen = len;
- sc->sc_dmapolling = poll;
- sc->sc_dmadev2mem = datain;
+
+ ESP_DMA(("%s: start %d@%p,%d\n", sc->sc_dev.dv_xname,
+ *sc->sc_dmalen, *sc->sc_dmaaddr, datain ? 1 : 0));
/*
* the rules say we cannot transfer more than the limit
* of this DMA chip (64k for old and 16Mb for new),
* and we cannot cross a 16Mb boundary.
*/
- size = min(*sc->sc_dmalen, ESPMAX);
- size = min(size, DMAMAX((size_t) *sc->sc_dmaaddr));
- sc->sc_segsize = size;
-
-#ifdef DMA_TEST
- printf("%s: start %d@0x%08x [%s scsi] [chunk=%d] %d\n",
- sc->sc_dev.dv_xname,
- *sc->sc_dmalen, *sc->sc_dmaaddr,
- datain ? "read from" : "write to",
- sc->sc_segsize, poll);
-#endif
+ *dmasize = sc->sc_dmasize =
+ min(*dmasize, DMAMAX((size_t) *sc->sc_dmaaddr));
- espr->espr_tcl = size;
- espr->espr_tcm = size >> 8;
- if (sc->sc_esp->sc_rev > ESP100A)
- espr->espr_tch = size >> 16;
- espr->espr_cmd = ESPCMD_DMA|ESPCMD_NOP; /* load the count in */
+ ESP_DMA(("dma_setup: dmasize = %d\n", sc->sc_dmasize));
- DMADDR(sc) = *sc->sc_dmaaddr;
- DMACSR(sc) = (DMACSR(sc) & ~(D_WRITE|D_INT_EN)) | D_EN_DMA |
- (datain ? D_WRITE : 0) | (poll ? 0 : D_INT_EN);
+ /* Program the DMA address */
+ if (CPU_ISSUN4M && sc->sc_dmasize) {
+ /*
+ * Use dvma mapin routines to map the buffer into DVMA space.
+ */
+ sc->sc_dvmaaddr = *sc->sc_dmaaddr;
+ sc->sc_dvmakaddr = kdvma_mapin(sc->sc_dvmaaddr,
+ sc->sc_dmasize, 0);
+ if (sc->sc_dvmakaddr == NULL)
+ panic("dma: cannot allocate DVMA address");
+ DMADDR(sc) = sc->sc_dvmakaddr;
+ } else
+ DMADDR(sc) = *sc->sc_dmaaddr;
+
+ /* Setup DMA control register */
+ csr = DMACSR(sc);
+ if (datain)
+ csr |= D_WRITE;
+ else
+ csr &= ~D_WRITE;
+ csr |= D_INT_EN;
+ DMACSR(sc) = csr;
+
+ return 0;
+}
- /* and kick the SCSI */
- espr->espr_cmd = ESPCMD_DMA|ESPCMD_TRANS;
+void
+dma_go(sc)
+ struct dma_softc *sc;
+{
+ /* Start DMA */
+ DMACSR(sc) |= D_EN_DMA;
sc->sc_active = 1;
}
/*
* Pseudo (chained) interrupt from the esp driver to kick the
- * current running DMA transfer. espintr() cleans up errors.
+ * current running DMA transfer. I am replying on espintr() to
+ * pickup and clean errors for now
*
- * return 1 if a dma operation is being continued (for when all
- * the data could not be transferred in one dma operation).
+ * return 1 if it was a DMA continue.
*/
int
-dmaintr(sc, restart)
- struct dma_softc *sc;
- int restart;
+espdmaintr(sc)
+ struct dma_softc *sc;
{
- struct espregs *espr = sc->sc_esp->sc_regs;
- int trans = 0, resid;
+ int trans, resid;
+ u_long csr;
+ csr = DMACSR(sc);
-#ifdef DMA_TEST
- printf("%s: intr\n", sc->sc_dev.dv_xname);
-#endif
+ ESP_DMA(("%s: intr: addr %p, csr %b\n", sc->sc_dev.dv_xname,
+ DMADDR(sc), csr, DMACSRBITS));
- if (DMACSR(sc) & D_ERR_PEND) {
- printf("%s: error", sc->sc_dev.dv_xname);
- if (sc->sc_rev == DMAREV_4300)
- DMAWAIT_PEND(sc);
+ if (csr & D_ERR_PEND) {
+ DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */
DMACSR(sc) |= D_INVALIDATE;
- return (0);
+ printf("%s: error: csr=%b\n", sc->sc_dev.dv_xname,
+ csr, DMACSRBITS);
+ return 0;
}
+ /* This is an "assertion" :) */
if (sc->sc_active == 0)
panic("dmaintr: DMA wasn't active");
- /* DMA has stopped, but flush it first */
- dmadrain(sc);
- if (DMACSR(sc) & D_DRAINING)
- printf("drain failed %d left\n", DMACSR(sc) & D_DRAINING);
+ /* clear errors and D_TC flag */
+ DMAWAIT(sc);
+ DMA_DRAIN(sc); /* ? */
+ DMAWAIT1(sc);
+ DMACSR(sc) |= D_INVALIDATE;
+ DMAWAIT1(sc);
+
+ /* DMA has stopped */
DMACSR(sc) &= ~D_EN_DMA;
sc->sc_active = 0;
- /*
- * XXX: The subtracting of resid and throwing away up to 31
- * bytes cannot be the best/right way to do this. There's got
- * to be a better way, such as letting the DMA take control
- * again and putting it into memory, or pulling it out and
- * putting it in memory by ourselves.
- * XXX in the meantime, just do this job silently
- */
+ if (sc->sc_dmasize == 0) {
+ /* A "Transfer Pad" operation completed */
+ ESP_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
+ ESP_READ_REG(sc->sc_esp, ESP_TCL) |
+ (ESP_READ_REG(sc->sc_esp, ESP_TCM) << 8),
+ ESP_READ_REG(sc->sc_esp, ESP_TCL),
+ ESP_READ_REG(sc->sc_esp, ESP_TCM)));
+ return 0;
+ }
+
resid = 0;
- if (!sc->sc_dmadev2mem &&
- (resid = (espr->espr_fflag & ESPFIFO_FF)) != 0) {
-#if 0
- printf("empty FIFO of %d ", resid);
-#endif
- espr->espr_cmd = ESPCMD_FLUSH;
- DELAY(1);
+ /*
+ * If a transfer onto the SCSI bus gets interrupted by the device
+ * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
+ * as residual since the ESP counter registers get decremented as
+ * bytes are clocked into the FIFO.
+ */
+ if (!(csr & D_WRITE) &&
+ (resid = (ESP_READ_REG(sc->sc_esp, ESP_FFLAG) & ESPFIFO_FF)) != 0) {
+ ESP_DMA(("dmaintr: empty esp FIFO of %d ", resid));
+ ESPCMD(sc->sc_esp, ESPCMD_FLUSH);
+ }
+
+ if ((sc->sc_esp->sc_espstat & ESPSTAT_TC) == 0) {
+ /*
+ * `Terminal count' is off, so read the residue
+ * out of the ESP counter registers.
+ */
+ resid += ( ESP_READ_REG(sc->sc_esp, ESP_TCL) |
+ (ESP_READ_REG(sc->sc_esp, ESP_TCM) << 8) |
+ ((sc->sc_esp->sc_cfg2 & ESPCFG2_FE)
+ ? (ESP_READ_REG(sc->sc_esp, ESP_TCH) << 16)
+ : 0));
+
+ if (resid == 0 && sc->sc_dmasize == 65536 &&
+ (sc->sc_esp->sc_cfg2 & ESPCFG2_FE) == 0)
+ /* A transfer of 64K is encoded as `TCL=TCM=0' */
+ resid = 65536;
}
- resid += espr->espr_tcl | (espr->espr_tcm << 8) |
- (sc->sc_esp->sc_rev > ESP100A ? (espr->espr_tch << 16) : 0);
- trans = sc->sc_segsize - resid;
+
+ trans = sc->sc_dmasize - resid;
if (trans < 0) { /* transferred < 0 ? */
printf("%s: xfer (%d) > req (%d)\n",
- sc->sc_dev.dv_xname, trans, sc->sc_segsize);
- trans = sc->sc_segsize;
+ sc->sc_dev.dv_xname, trans, sc->sc_dmasize);
+ trans = sc->sc_dmasize;
}
-#ifdef DMA_TEST
- printf("dmaintr: resid=%d, trans=%d\n", resid, trans);
-#endif
+ ESP_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
+ ESP_READ_REG(sc->sc_esp, ESP_TCL),
+ ESP_READ_REG(sc->sc_esp, ESP_TCM),
+ (sc->sc_esp->sc_cfg2 & ESPCFG2_FE)
+ ? ESP_READ_REG(sc->sc_esp, ESP_TCH) : 0,
+ trans, resid));
- if (sc->sc_dmadev2mem && vactype != VAC_NONE)
+ if (csr & D_WRITE)
cache_flush(*sc->sc_dmaaddr, trans);
- sc->sc_segsize -= trans;
+ if (CPU_ISSUN4M && sc->sc_dvmakaddr)
+ dvma_mapout((vm_offset_t)sc->sc_dvmakaddr,
+ (vm_offset_t)sc->sc_dvmaaddr, sc->sc_dmasize);
+
*sc->sc_dmalen -= trans;
*sc->sc_dmaaddr += trans;
-#ifdef DMA_TEST
- printf("%s: %d/%d bytes left\n", sc->sc_dev.dv_xname,
- *sc->sc_dmalen, sc->sc_segsize);
-#endif
-
- /* completely finished with the DMA transaction */
- if (sc->sc_segsize == 0 && *sc->sc_dmalen == 0)
- return (0);
+#if 0 /* this is not normal operation just yet */
+ if (*sc->sc_dmalen == 0 ||
+ sc->sc_esp->sc_phase != sc->sc_esp->sc_prevphase)
+ return 0;
- if (restart == 0)
- return (1);
/* and again */
- dmastart(sc, sc->sc_dmaaddr, sc->sc_dmalen, sc->sc_dmadev2mem,
- sc->sc_dmapolling);
- return (1);
-}
-
-/*
- * We have to ask rev 1 and 4/300 dma controllers to drain their fifo.
- * Apparently the other chips have drained by the time we get an
- * interrupt, but we check anyways.
- */
-void
-dmadrain(sc)
- struct dma_softc *sc;
-{
- switch (sc->sc_rev) {
- case DMAREV_1:
- case DMAREV_4300:
- case DMAREV_PLUS:
- case DMAREV_2:
- if (DMACSR(sc) & D_DRAINING)
- DMAWAIT_DRAIN(sc);
- break;
- case DMAREV_ESC1:
- DMAWAIT_PEND(sc)
- DMAWAIT_DRAIN(sc); /* XXX: needed? */
- break;
- }
- DMACSR(sc) |= D_INVALIDATE;
+ dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, DMACSR(sc) & D_WRITE);
+ return 1;
+#endif
+ return 0;
}
/*
- * XXX
- * During autoconfig we are in polled mode and we execute some commands.
- * eventually we execute the last polled command. esp interrupts go through
- * the dma chip's D_INT_EN gate. thus, because we have our data, we're happy
- * and return. the esp chip has not, however, become unbusy. as soon as we
- * execute our first non-polled command, we find the esp state machine is
- * non-idle. it has not finished getting off the scsi bus, because it didn't
- * get interrupts (and the polled code has long since gone it's merry way.)
- *
- * therefore, whenever we finish with a polled mode command, we enable
- * interrupts so that we can get our data. it is probably safe to do so,
- * since the scsi transfer has happened without error. the interrupts that
- * will happen have no bearing on the higher level scsi subsystem, since it
- * just functions to let the esp chip "clean up" it's state.
+ * Pseudo (chained) interrupt from the le driver to handle DMA
+ * errors.
+ *
+ * XXX: untested
*/
-void
-dmaenintr(sc)
- struct dma_softc *sc;
-{
- DMACSR(sc) |= D_INT_EN;
-}
-
int
-dmadisintr(sc)
+ledmaintr(sc)
struct dma_softc *sc;
{
- int x = DMACSR(sc) & D_INT_EN;
+ u_long csr;
- DMACSR(sc) &= ~D_INT_EN;
- return x;
+ csr = DMACSR(sc);
+
+ if (csr & D_ERR_PEND) {
+ printf("Lance DMA error, see your doctor!\n");
+ DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */
+ DMACSR(sc) |= D_INVALIDATE;
+ printf("%s: error: csr=%b\n", sc->sc_dev.dv_xname,
+ (u_int)csr, DMACSRBITS);
+ }
+ return 1;
}
diff --git a/sys/arch/sparc/dev/dmareg.h b/sys/arch/sparc/dev/dmareg.h
index d19c5c2960e..3998581845a 100644
--- a/sys/arch/sparc/dev/dmareg.h
+++ b/sys/arch/sparc/dev/dmareg.h
@@ -1,9 +1,7 @@
-/* $NetBSD: dmareg.h,v 1.5 1994/11/20 20:52:06 deraadt Exp $ */
+/* $NetBSD: dmareg.h,v 1.8 1996/04/22 02:34:58 abrown Exp $ */
/*
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
- * Copyright (c) 1995 Theo de Raadt. All rights reserved.
- *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -14,8 +12,7 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by Peter Galbavy and
- * Theo de Raadt.
+ * This product includes software developed by Peter Galbavy.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -31,51 +28,64 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define DMACSRBITS "\020\01INT\02ERR\03DR1\04DR2\05IEN\011WRITE\016ENCNT\017TC\032DMAON"
+
struct dma_regs {
- volatile u_long csr; /* DMA CSR */
-#define D_INT_PEND 0x00000001 /* interrupt pending */
-#define D_ERR_PEND 0x00000002 /* error pending */
-#define D_DRAINING 0x0000000c /* fifo draining */
-#define D_INT_EN 0x00000010 /* interrupt enable */
-#define D_INVALIDATE 0x00000020 /* invalidate fifo */
-#define D_SLAVE_ERR 0x00000040 /* slave access size error */
-#define D_DRAIN 0x00000040 /* drain fifo if DMAREV_1 */
-#define D_RESET 0x00000080 /* reset scsi */
-#define D_WRITE 0x00000100 /* 1 = dev -> mem */
-#define D_EN_DMA 0x00000200 /* enable DMA requests */
-#define D_R_PEND 0x00000400 /* no reset/flush allowed! */
-#define D_BYTEADDR 0x00001800 /* next byte to be accessed by esp */
-#define D_EN_CNT 0x00002000 /* enable byte counter */
-#define D_TC 0x00004000 /* terminal count */
-#define D_ILLAC 0x00008000 /* enable lance ethernet */
-#define D_DSBL_CSR_DRN 0x00010000 /* disable fifo drain on csr */
-#define D_DSBL_SCSI_DRN 0x00020000 /* disable fifo drain on reg */
-#define D_BURST_SIZE 0x000c0000 /* sbus read/write burst size */
-#define D_DIAG 0x00100000 /* disable fifo drain on addr */
-#define D_TWO_CYCLE 0x00200000 /* 2 clocks per transfer */
-#define D_FASTER 0x00400000 /* 3 clocks per transfer */
-#define D_TCI_DIS 0x00800000 /* disable intr on D_TC */
-#define D_EN_NEXT 0x01000000 /* enable auto next address */
-#define D_DMA_ON 0x02000000 /* enable dma from scsi */
-#define D_A_LOADED 0x04000000 /* address loaded */
-#define D_NA_LOADED 0x08000000 /* next address loaded */
-#define D_DEV_ID 0xf0000000 /* device ID */
-#define DMAREV_4300 0x00000000 /* Sunray DMA */
-#define DMAREV_ESC1 0x40000000 /* ESC gate array */
-#define DMAREV_1 0x80000000 /* 'DMA' */
-#define DMAREV_PLUS 0x90000000 /* 'DMA+' */
-#define DMAREV_2 0xa0000000 /* 'DMA2' */
+ volatile u_long csr; /* DMA CSR */
+#define D_INT_PEND 0x00000001 /* interrupt pending */
+#define D_ERR_PEND 0x00000002 /* error pending */
+#define D_DRAINING 0x0000000c /* fifo draining */
+#define D_INT_EN 0x00000010 /* interrupt enable */
+#define D_INVALIDATE 0x00000020 /* invalidate fifo */
+#define D_SLAVE_ERR 0x00000040 /* slave access size error */
+#define D_DRAIN 0x00000040 /* drain fifo if DMAREV_1 */
+#define D_RESET 0x00000080 /* reset scsi */
+#define D_WRITE 0x00000100 /* 1 = dev -> mem */
+#define D_EN_DMA 0x00000200 /* enable DMA requests */
+#define D_R_PEND 0x00000400 /* something only on ver < 2 */
+#define D_EN_CNT 0x00002000 /* enable byte counter */
+#define D_TC 0x00004000 /* terminal count */
+#define D_DSBL_CSR_DRN 0x00010000 /* disable fifo drain on csr */
+#define D_DSBL_SCSI_DRN 0x00020000 /* disable fifo drain on reg */
+#define D_BURST_SIZE 0x000c0000 /* sbus read/write burst size */
+#define D_BURST_0 0x00080000 /* no bursts (SCSI-only) */
+#define D_BURST_16 0x00040000 /* 16-byte bursts */
+#define D_BURST_32 0x00000000 /* 32-byte bursts */
+#define D_DIAG 0x00100000 /* disable fifo drain on addr */
+#define D_TWO_CYCLE 0x00200000 /* 2 clocks per transfer */
+#define D_FASTER 0x00400000 /* 3 clocks per transfer */
+#define DE_AUI_TP 0x00400000 /* 1 for TP, 0 for AUI */
+#define D_TCI_DIS 0x00800000 /* disable intr on D_TC */
+#define D_EN_NEXT 0x01000000 /* enable auto next address */
+#define D_DMA_ON 0x02000000 /* enable dma from scsi */
+#define D_A_LOADED 0x04000000 /* address loaded */
+#define D_NA_LOADED 0x08000000 /* next address loaded */
+#define D_DEV_ID 0xf0000000 /* device ID */
+#define DMAREV_0 0x00000000 /* Sunray DMA */
+#define DMAREV_1 0x80000000 /* 'DMA' */
+#define DMAREV_PLUS 0x90000000 /* 'DMA+' */
+#define DMAREV_2 0xa0000000 /* 'DMA2' */
- volatile caddr_t addr;
-#define DMA_D_ADDR 0x01 /* DMA ADDR */
+ volatile caddr_t addr;
+#define DMA_D_ADDR 0x01 /* DMA ADDR (in u_longs) */
- /*
- * some versions of dma controller lack the following
- * two registers -- do not use them!
- */
+ volatile u_long bcnt; /* DMA COUNT (in u_longs) */
+#define D_BCNT_MASK 0x00ffffff /* only 24 bits */
- volatile u_long bcnt; /* DMA COUNT */
-#define D_BCNT_MASK 0x00ffffff /* only 24 bits */
+ volatile u_long test; /* DMA TEST (in u_longs) */
+#define en_testcsr addr /* enet registers overlap */
+#define en_cachev bcnt
+#define en_bar test
- volatile u_long test; /* DMA TEST (in u_longs) */
};
+
+/*
+ * PROM-reported DMA burst sizes for the SBus
+ */
+#define SBUS_BURST_1 0x1
+#define SBUS_BURST_2 0x2
+#define SBUS_BURST_4 0x4
+#define SBUS_BURST_8 0x8
+#define SBUS_BURST_16 0x10
+#define SBUS_BURST_32 0x20
+#define SBUS_BURST_64 0x40
diff --git a/sys/arch/sparc/dev/dmavar.h b/sys/arch/sparc/dev/dmavar.h
index c5ebb58357c..6bc42333a98 100644
--- a/sys/arch/sparc/dev/dmavar.h
+++ b/sys/arch/sparc/dev/dmavar.h
@@ -1,10 +1,7 @@
-/* $NetBSD: dmavar.h,v 1.4 1994/11/27 00:08:34 deraadt Exp $ */
+/* $NetBSD: dmavar.h,v 1.8 1996/04/22 02:35:00 abrown Exp $ */
/*
- * Copyright (c) 1994 Peter Galbavy
- * Copyright (c) 1995 Theo de Raadt
- * All rights reserved.
- *
+ * Copyright (c) 1994 Peter Galbavy. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -15,8 +12,7 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by Peter Galbavy and
- * Theo de Raadt.
+ * This product includes software developed by Peter Galbavy.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -33,49 +29,62 @@
*/
struct dma_softc {
- struct device sc_dev; /* us as a device */
- struct sbusdev sc_sd; /* sbus device */
- struct esp_softc *sc_esp; /* my scsi */
- struct dma_regs *sc_regs; /* the registers */
+ struct device sc_dev; /* us as a device */
+ struct sbusdev sc_sd; /* sbus device */
+ struct esp_softc *sc_esp; /* my scsi */
+ struct le_softc *sc_le; /* my ethernet */
+ struct dma_regs *sc_regs; /* the registers */
int sc_active; /* DMA active ? */
int sc_rev; /* revision */
int sc_node; /* PROM node ID */
-
- size_t sc_segsize; /* current operation */
- void **sc_dmaaddr;
+ int sc_burst; /* DVMA burst size in effect */
+ caddr_t sc_dvmakaddr; /* DVMA cookies */
+ caddr_t sc_dvmaaddr; /* */
+ size_t sc_dmasize;
+ caddr_t *sc_dmaaddr;
size_t *sc_dmalen;
- char sc_dmapolling; /* ... is polled */
- char sc_dmadev2mem; /* transfer direction */
+ void (*reset)(struct dma_softc *); /* reset routine */
+ void (*enintr)(struct dma_softc *); /* enable interrupts */
+ int (*isintr)(struct dma_softc *); /* interrupt ? */
+ int (*intr)(struct dma_softc *); /* interrupt ! */
+ int (*setup)(struct dma_softc *, caddr_t *, size_t *, int, size_t *);
+ void (*go)(struct dma_softc *);
};
-void dmareset __P((struct dma_softc *sc));
-void dmastart __P((struct dma_softc *sc, void *addr,
- size_t *len, int datain, int poll));
-int dmaintr __P((struct dma_softc *sc, int restart));
-int dmapending __P((struct dma_softc *sc));
-void dmadrain __P((struct dma_softc *sc));
-void dmaenintr __P((struct dma_softc *sc));
-int dmadisintr __P((struct dma_softc *sc));
-
#define DMACSR(sc) (sc->sc_regs->csr)
#define DMADDR(sc) (sc->sc_regs->addr)
-#define DMABCNT(sc) (sc->sc_regs->bcnt)
-#define TIME_WAIT(cond, msg, sc) { \
- int count = 500000; \
- while (--count > 0 && (cond)) \
- DELAY(1); \
- if (count == 0) { \
- printf("CSR = %x\n", (sc)->sc_regs->csr); \
- panic(msg); \
- } \
-}
+/*
+ * We are not allowed to touch the DMA "flush" and "drain" bits
+ * while it is still thinking about a request (DMA_RP).
+ */
+
+/*
+ * TIME WAIT (to debug hanging machine problem)
+ */
+
+#define TIME_WAIT(COND, MSG, SC) { int count = 500000; \
+ while (--count > 0 && (COND)) DELAY(1); \
+ if (count == 0) { \
+ printf("CSR = %lx\n",\
+ SC->sc_regs->csr);\
+ panic(MSG); } \
+ }
+
+#define DMAWAIT(sc) TIME_WAIT((sc->sc_regs->csr & D_R_PEND), "DMAWAIT", sc)
+#define DMAWAIT1(sc) TIME_WAIT((sc->sc_regs->csr & D_DRAINING), "DMAWAIT1", sc)
+#define DMAREADY(sc) TIME_WAIT((!(sc->sc_regs->csr & D_DMA_ON)), "DMAREADY", sc)
-#define DMAWAIT_PEND(sc) \
- TIME_WAIT((DMACSR(sc) & D_R_PEND), \
- "DMAWAIT_PEND", sc)
+#define DMA_DRAIN(sc) if (sc->sc_rev < DMAREV_2) { \
+ DMACSR(sc) |= D_DRAIN; \
+ DMAWAIT1(sc); \
+ }
-/* keep punching the chip until it's flushed */
-#define DMAWAIT_DRAIN(sc) \
- TIME_WAIT((DMACSR(sc) |= D_DRAIN, DMACSR(sc) & D_DRAINING), \
- "DMAWAIT_DRAIN", sc)
+/* DMA engine functions */
+#define DMA_ENINTR(r) (((r)->enintr)(r))
+#define DMA_ISINTR(r) (((r)->isintr)(r))
+#define DMA_RESET(r) (((r)->reset)(r))
+#define DMA_INTR(r) (((r)->intr)(r))
+#define DMA_ISACTIVE(r) ((r)->sc_active)
+#define DMA_SETUP(a, b, c, d, e) (((a)->setup)(a, b, c, d, e))
+#define DMA_GO(r) (((r)->go)(r))
diff --git a/sys/arch/sparc/dev/esp.c b/sys/arch/sparc/dev/esp.c
index 7941b614917..840ca8100d0 100644
--- a/sys/arch/sparc/dev/esp.c
+++ b/sys/arch/sparc/dev/esp.c
@@ -1,6 +1,10 @@
+/* $NetBSD: esp.c,v 1.47.2.1 1996/06/12 20:46:52 pk Exp $ */
+
/*
- * Copyright (c) 1995 Theo de Raadt
- *
+ * Copyright (c) 1994 Peter Galbavy
+ * Copyright (c) 1995 Paul Kranenburg
+ * All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -11,33 +15,29 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed under OpenBSD by
- * Theo de Raadt.
+ * This product includes software developed by Peter Galbavy
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Based IN PART on aic6360 by Jarle Greipsland, an older esp driver
- * by Peter Galbavy, and work by Charles Hannum on a few other drivers.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
/*
- * todo:
- * fix & enable sync
- * confirm parity and bus failures do not lock up driver
+ * Based on aic6360 by Jarle Greipsland
+ *
+ * Acknowledgements: Many of the algorithms used in this driver are
+ * inspired by the work of Julian Elischer (julian@tfs.com) and
+ * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million!
*/
#include <sys/types.h>
@@ -59,62 +59,68 @@
#include <machine/cpu.h>
#include <machine/autoconf.h>
#include <sparc/dev/sbusvar.h>
-#include <sparc/dev/dmavar.h>
#include <sparc/dev/dmareg.h>
+#include <sparc/dev/dmavar.h>
#include <sparc/dev/espreg.h>
#include <sparc/dev/espvar.h>
-int esp_debug = ESP_SHOWPHASE|ESP_SHOWMISC|ESP_SHOWTRAC|ESP_SHOWCMDS; /**/
-
-#if 1
-#define ESPD(x)
-#else
-#define ESPD(x) printf x
-#endif
+int esp_debug = 0; /*ESP_SHOWPHASE|ESP_SHOWMISC|ESP_SHOWTRAC|ESP_SHOWCMDS;*/
+
+/*static*/ void espattach __P((struct device *, struct device *, void *));
+/*static*/ int espmatch __P((struct device *, void *, void *));
+/*static*/ int espprint __P((void *, char *));
+/*static*/ u_int esp_adapter_info __P((struct esp_softc *));
+/*static*/ void espreadregs __P((struct esp_softc *));
+/*static*/ void espselect __P((struct esp_softc *,
+ u_char, u_char, u_char *, u_char));
+/*static*/ void esp_scsi_reset __P((struct esp_softc *));
+/*static*/ void esp_reset __P((struct esp_softc *));
+/*static*/ void esp_init __P((struct esp_softc *, int));
+/*static*/ int esp_scsi_cmd __P((struct scsi_xfer *));
+/*static*/ int esp_poll __P((struct esp_softc *, struct ecb *));
+/*static*/ void esp_sched __P((struct esp_softc *));
+/*static*/ void esp_done __P((struct ecb *));
+/*static*/ void esp_msgin __P((struct esp_softc *));
+/*static*/ void esp_msgout __P((struct esp_softc *));
+/*static*/ int espintr __P((struct esp_softc *));
+/*static*/ void esp_timeout __P((void *arg));
+/*static*/ void esp_abort __P((struct esp_softc *, struct ecb *));
+int esp_stp2cpb __P((struct esp_softc *, int));
+int esp_cpb2stp __P((struct esp_softc *, int));
+
+/* Linkup to the rest of the kernel */
+struct cfattach esp_ca = {
+ sizeof(struct esp_softc), espmatch, espattach
+};
-void espattach __P((struct device *, struct device *, void *));
-int espmatch __P((struct device *, void *, void *));
-int espprint __P((void *, char *));
-void espreadregs __P((struct esp_softc *));
-int espgetbyte __P((struct esp_softc *, int));
-void espselect __P((struct esp_softc *));
-void esp_reset __P((struct esp_softc *));
-void esp_init __P((struct esp_softc *, int));
-int esp_scsi_cmd __P((struct scsi_xfer *));
-int esp_poll __P((struct esp_softc *, struct ecb *));
-int espphase __P((struct esp_softc *));
-void esp_sched __P((struct esp_softc *));
-void esp_done __P((struct ecb *));
-void esp_msgin __P((struct esp_softc *));
-void esp_makemsg __P((struct esp_softc *));
-void esp_msgout __P((struct esp_softc *));
-int espintr __P((struct esp_softc *));
-void esp_timeout __P((void *arg));
-
-struct cfdriver espcd = {
- NULL, "esp", espmatch, espattach, DV_DULL, sizeof(struct esp_softc)
+struct cfdriver esp_cd = {
+ NULL, "esp", DV_DULL
};
struct scsi_adapter esp_switch = {
- esp_scsi_cmd, minphys, NULL, NULL
+ esp_scsi_cmd,
+ minphys, /* no max at this level; handled by DMA code */
+ NULL,
+ NULL,
};
struct scsi_device esp_dev = {
- NULL, NULL, NULL, NULL
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
};
-/*
- * Does anyone actually use this, and what for ?
- */
int
espprint(aux, name)
void *aux;
char *name;
{
- return (UNCONF);
+ if (name != NULL)
+ printf("%s: scsibus ", name);
+ return UNCONF;
}
-
int
espmatch(parent, vcf, aux)
struct device *parent;
@@ -132,7 +138,6 @@ espmatch(parent, vcf, aux)
return (probeget(ra->ra_vaddr, 1) != -1);
}
-
/*
* Attach this instance, and then all the sub-devices
*/
@@ -143,9 +148,8 @@ espattach(parent, self, aux)
{
register struct confargs *ca = aux;
struct esp_softc *sc = (void *)self;
- struct espregs *espr;
struct bootpath *bp;
- int freq;
+ int dmachild = strncmp(parent->dv_xname, "dma", 3) == 0;
/*
* Make sure things are sane. I don't know if this is ever
@@ -164,13 +168,11 @@ espattach(parent, self, aux)
* address space.
*/
if (ca->ca_ra.ra_vaddr)
- sc->sc_regs = (struct espregs *) ca->ca_ra.ra_vaddr;
+ sc->sc_reg = (volatile u_char *) ca->ca_ra.ra_vaddr;
else {
- sc->sc_regs = (struct espregs *)
- mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len,
- ca->ca_bustype);
+ sc->sc_reg = (volatile u_char *)
+ mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len, ca->ca_bustype);
}
- espr = sc->sc_regs;
/* Other settings */
sc->sc_node = ca->ca_ra.ra_node;
@@ -185,92 +187,138 @@ espattach(parent, self, aux)
sc->sc_freq = ((struct sbus_softc *)
sc->sc_dev.dv_parent)->sc_clockfreq;
- freq = sc->sc_freq / 1000000; /* gimme Mhz */
-
- /*
- * This is the value used to start sync negotiations. For a
- * 25Mhz clock, this gives us 40, or 160nS, or 6.25Mb/s. It
- * is constant for each adapter. In turn, notice that the ESP
- * register "SYNCTP" is = (250 / the negotiated period).
- */
- sc->sc_minsync = 1000 / freq;
-
- /* 0 is actually 8, even though the register only has 3 bits */
- sc->sc_ccf = FREQTOCCF(freq) & 0x07;
+ /* gimme Mhz */
+ sc->sc_freq /= 1000000;
- /* The value must not be 1 -- make it 2 */
- if (sc->sc_ccf == 1)
- sc->sc_ccf = 2;
+ if (dmachild) {
+ sc->sc_dma = (struct dma_softc *)parent;
+ sc->sc_dma->sc_esp = sc;
+ } else {
+ /*
+ * find the DMA by poking around the dma device structures
+ *
+ * What happens here is that if the dma driver has not been
+ * configured, then this returns a NULL pointer. Then when the
+ * dma actually gets configured, it does the opposing test, and
+ * if the sc->sc_esp field in it's softc is NULL, then tries to
+ * find the matching esp driver.
+ *
+ */
+ sc->sc_dma = (struct dma_softc *)
+ getdevunit("dma", sc->sc_dev.dv_unit);
- /*
- * The recommended timeout is 250ms (1/4 seconds). This
- * register is loaded with a value calculated as follows:
- *
- * (timout period) x (CLK frequency)
- * reg = -------------------------------------
- * 8192 x (Clock Conversion Factor)
- *
- * We have the CCF from above. For a 25MHz clock this gives
- * a constant of 153 (we round up).
- */
- sc->sc_timeout = (sc->sc_freq / 4 / 8192 / sc->sc_ccf) + 1;
+ /*
+ * and a back pointer to us, for DMA
+ */
+ if (sc->sc_dma)
+ sc->sc_dma->sc_esp = sc;
+ else
+ panic("espattach: no dma found");
+ }
/*
- * find the corresponding DMA controller.
+ * It is necessary to try to load the 2nd config register here,
+ * to find out what rev the esp chip is, else the esp_reset
+ * will not set up the defaults correctly.
*/
- sc->sc_dma = ((struct dma_softc *)getdevunit("dma",
- sc->sc_dev.dv_unit));
- if (sc->sc_dma)
- sc->sc_dma->sc_esp = sc;
-
sc->sc_cfg1 = sc->sc_id | ESPCFG1_PARENB;
- sc->sc_cfg2 = 0;
- sc->sc_cfg3 = 0;
+ sc->sc_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_RPE;
+ sc->sc_cfg3 = ESPCFG3_CDB;
+ ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2);
- /*
- * The ESP100 only has a cfg1 register. The ESP100A has it, but
- * lacks the cfg3 register. Thus, we can tell which chip we have.
- * XXX: what about the FAS100A?
- */
- espr->espr_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_RPE;
- if ((espr->espr_cfg2 & ~ESPCFG2_RSVD) != (ESPCFG2_SCSI2 | ESPCFG2_RPE)) {
+ if ((ESP_READ_REG(sc, ESP_CFG2) & ~ESPCFG2_RSVD) != (ESPCFG2_SCSI2 | ESPCFG2_RPE)) {
printf(": ESP100");
sc->sc_rev = ESP100;
} else {
- espr->espr_cfg2 = 0;
- espr->espr_cfg3 = 0;
- espr->espr_cfg3 = ESPCFG3_CDB | ESPCFG3_FCLK;
- if (espr->espr_cfg3 != (ESPCFG3_CDB | ESPCFG3_FCLK)) {
+ sc->sc_cfg2 = ESPCFG2_SCSI2;
+ ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2);
+ sc->sc_cfg3 = 0;
+ ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3);
+ sc->sc_cfg3 = (ESPCFG3_CDB | ESPCFG3_FCLK);
+ ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3);
+ if (ESP_READ_REG(sc, ESP_CFG3) != (ESPCFG3_CDB | ESPCFG3_FCLK)) {
printf(": ESP100A");
- /* XXX sc->sc_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_FE; */
sc->sc_rev = ESP100A;
} else {
- espr->espr_cfg3 = 0;
+ /* ESPCFG2_FE enables > 64K transfers */
+ sc->sc_cfg2 |= ESPCFG2_FE;
+ sc->sc_cfg3 = 0;
+ ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3);
printf(": ESP200");
sc->sc_rev = ESP200;
}
}
+ /*
+ * This is the value used to start sync negotiations
+ * Note that the ESP register "SYNCTP" is programmed
+ * in "clocks per byte", and has a minimum value of 4.
+ * The SCSI period used in negotiation is one-fourth
+ * of the time (in nanoseconds) needed to transfer one byte.
+ * Since the chip's clock is given in MHz, we have the following
+ * formula: 4 * period = (1000 / freq) * 4
+ */
+ sc->sc_minsync = 1000 / sc->sc_freq;
+
+ /*
+ * Alas, we must now modify the value a bit, because it's
+ * only valid when can switch on FASTCLK and FASTSCSI bits
+ * in config register 3...
+ */
+ switch (sc->sc_rev) {
+ case ESP100:
+ sc->sc_maxxfer = 64 * 1024;
+ sc->sc_minsync = 0; /* No synch on old chip? */
+ break;
+ case ESP100A:
+ sc->sc_maxxfer = 64 * 1024;
+ sc->sc_minsync = esp_cpb2stp(sc, 5); /* Min clocks/byte is 5 */
+ break;
+ case ESP200:
+ sc->sc_maxxfer = 16 * 1024 * 1024;
+ /* XXX - do actually set FAST* bits */
+ }
+
+ sc->sc_ccf = FREQTOCCF(sc->sc_freq);
+
+ /* The value *must not* be == 1. Make it 2 */
+ if (sc->sc_ccf == 1)
+ sc->sc_ccf = 2;
+
+ /*
+ * The recommended timeout is 250ms. This register is loaded
+ * with a value calculated as follows, from the docs:
+ *
+ * (timout period) x (CLK frequency)
+ * reg = -------------------------------------
+ * 8192 x (Clock Conversion Factor)
+ *
+ * Since CCF has a linear relation to CLK, this generally computes
+ * to the constant of 153.
+ */
+ sc->sc_timeout = ((250 * 1000) * sc->sc_freq) / (8192 * sc->sc_ccf);
+
+ /* CCF register only has 3 bits; 0 is actually 8 */
+ sc->sc_ccf &= 7;
+
+ /* Reset state & bus */
sc->sc_state = 0;
esp_init(sc, 1);
- printf(" %dMhz, target %d\n", freq, sc->sc_id);
+ printf(" %dMhz, target %d\n", sc->sc_freq, sc->sc_id);
+ /* add me to the sbus structures */
+ sc->sc_sd.sd_reset = (void *) esp_reset;
#if defined(SUN4C) || defined(SUN4M)
if (ca->ca_bustype == BUS_SBUS) {
- /* add to the sbus structures */
- sc->sc_sd.sd_reset = (void *) esp_reset;
- sbus_establish(&sc->sc_sd, &sc->sc_dev);
-
- /*
- * If the device is in an SBUS slave slot, bail now.
- */
- if (sbus_slavecheck(self, ca))
- return;
+ if (dmachild)
+ sbus_establish(&sc->sc_sd, sc->sc_dev.dv_parent);
+ else
+ sbus_establish(&sc->sc_sd, &sc->sc_dev);
}
#endif /* SUN4C || SUN4M */
- /* and the interupts */
+ /* and the interuppts */
sc->sc_ih.ih_fun = (void *) espintr;
sc->sc_ih.ih_arg = sc;
intr_establish(sc->sc_pri, &sc->sc_ih);
@@ -286,23 +334,20 @@ espattach(parent, self, aux)
sc->sc_link.openings = 2;
/*
- * If the boot path is "esp", and the numbers point to
- * this controller, then advance the bootpath a step.
- * XXX boot /sbus/esp/sd@3,0 passes in esp@0,0 -- which
- * is almost always wrong, but match in that case anyways.
+ * If the boot path is "esp" at the moment and it's me, then
+ * walk our pointer to the sub-device, ready for the config
+ * below.
*/
bp = ca->ca_ra.ra_bp;
switch (ca->ca_bustype) {
case BUS_SBUS:
if (bp != NULL && strcmp(bp->name, "esp") == 0 &&
- ((bp->val[0]==ca->ca_slot &&
- (bp->val[1]==ca->ca_offset || bp->val[1]==0)) ||
- (bp->val[0]==-1 && bp->val[1]==sc->sc_dev.dv_unit)))
+ SAME_ESP(sc, bp, ca))
bootpath_store(1, bp + 1);
break;
default:
if (bp != NULL && strcmp(bp->name, "esp") == 0 &&
- bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit)
+ bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit)
bootpath_store(1, bp + 1);
break;
}
@@ -315,266 +360,317 @@ espattach(parent, self, aux)
bootpath_store(1, NULL);
}
-
/*
- * Warning: This inserts two commands into the ESP command fifo. Because
- * there are only 2 entries in that fifo, you may need to put a DELAY(1)
- * after calling this, if you are going to issue another command soon.
+ * This is the generic esp reset function. It does not reset the SCSI bus,
+ * only this controllers, but kills any on-going commands, and also stops
+ * and resets the DMA.
+ *
+ * After reset, registers are loaded with the defaults from the attach
+ * routine above.
*/
void
-espflush(sc)
+esp_reset(sc)
struct esp_softc *sc;
{
- struct espregs *espr = sc->sc_regs;
- if (espr->espr_fflag & ESPFIFO_FF) {
- espr->espr_cmd = ESPCMD_FLUSH;
- espr->espr_cmd = ESPCMD_NOP;
+ /* reset DMA first */
+ DMA_RESET(sc->sc_dma);
+
+ /* reset SCSI chip */
+ ESPCMD(sc, ESPCMD_RSTCHIP);
+ ESPCMD(sc, ESPCMD_NOP);
+ DELAY(500);
+
+ /* do these backwards, and fall through */
+ switch (sc->sc_rev) {
+ case ESP200:
+ ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3);
+ case ESP100A:
+ ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2);
+ case ESP100:
+ ESP_WRITE_REG(sc, ESP_CFG1, sc->sc_cfg1);
+ ESP_WRITE_REG(sc, ESP_CCF, sc->sc_ccf);
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, 0);
+ ESP_WRITE_REG(sc, ESP_TIMEOUT, sc->sc_timeout);
+ break;
+ default:
+ printf("%s: unknown revision code, assuming ESP100\n",
+ sc->sc_dev.dv_xname);
+ ESP_WRITE_REG(sc, ESP_CFG1, sc->sc_cfg1);
+ ESP_WRITE_REG(sc, ESP_CCF, sc->sc_ccf);
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, 0);
+ ESP_WRITE_REG(sc, ESP_TIMEOUT, sc->sc_timeout);
}
}
/*
- * returns -1 if no byte is available because fifo is empty.
+ * Reset the SCSI bus, but not the chip
*/
-int
-espgetbyte(sc, dotrans)
+void
+esp_scsi_reset(sc)
struct esp_softc *sc;
- int dotrans;
{
- struct espregs *espr = sc->sc_regs;
+ /* stop DMA first, as the chip will return to Bus Free phase */
+ DMACSR(sc->sc_dma) &= ~D_EN_DMA;
- if (espr->espr_fflag & ESPFIFO_FF)
- return espr->espr_fifo;
- return -1;
+ printf("esp: resetting SCSI bus\n");
+ ESPCMD(sc, ESPCMD_RSTSCSI);
}
/*
- * Send a command to a target, as well as any required messages.
- * There are three cases. The first two cases are fairly simple..
- * 1) command alone
- * load command into fifo, and use ESPCMD_SELNATN
- * 2) MSG_IDENTIFY + command
- * load message and command into fifo, and use ESPCMD_SELATN
- * 3) a bunch of messages + command
- * load first message byte into fifo. Use ESPCMD_SELATNS. When the
- * next interrupt occurs, load the remainer of the message into
- * the fifo and use ESPCMD_TRANS. When the device is ready to
- * receive the command, it will switch into COMMAND_PHASE, and
- * at that point we will feed it the command.
+ * Initialize esp state machine
*/
void
-espselect(sc)
+esp_init(sc, doreset)
struct esp_softc *sc;
+ int doreset;
{
- struct espregs *espr = sc->sc_regs;
- register struct ecb *ecb = sc->sc_nexus;
- register struct scsi_link *sc_link = ecb->xs->sc_link;
- struct esp_tinfo *ti = &sc->sc_tinfo[sc_link->target];
- u_char *cmd = (u_char *)&ecb->cmd;
- int loadcmd = 1;
- int outcmd, i;
-
- espr->espr_selid = sc_link->target;
- espr->espr_syncoff = ti->offset;
- espr->espr_synctp = ti->synctp;
-
- sc->sc_state = ESPS_SELECTING;
-
- if (ecb->xs->flags & SCSI_RESET)
- sc->sc_msgpriq = SEND_DEV_RESET;
- else if (ti->flags & DO_NEGOTIATE)
- sc->sc_msgpriq = SEND_SDTR;
- else
- sc->sc_msgpriq = SEND_IDENTIFY;
-
- if (sc->sc_msgpriq) {
- esp_makemsg(sc);
+ struct ecb *ecb;
+ int r;
- ESPD(("OM["));
- for (i = 0; i < sc->sc_omlen; i++)
- ESPD(("%02x%c", sc->sc_omp[i],
- (i == sc->sc_omlen-1) ? ']' : ' '));
- ESPD((" "));
+ ESP_TRACE(("[ESP_INIT(%d)] ", doreset));
- espr->espr_fifo = sc->sc_omp[0]; /* 1st msg byte only */
- if (sc->sc_omlen == 1) {
- outcmd = ESPCMD_SELATN;
- } else {
- outcmd = ESPCMD_SELATNS;
- /* and this will will load the rest of the msg bytes */
- sc->sc_state = ESPS_SELECTSTOP;
- loadcmd = 0;
+ if (sc->sc_state == 0) { /* First time through */
+ TAILQ_INIT(&sc->ready_list);
+ TAILQ_INIT(&sc->nexus_list);
+ TAILQ_INIT(&sc->free_list);
+ sc->sc_nexus = NULL;
+ ecb = sc->sc_ecb;
+ bzero(ecb, sizeof(sc->sc_ecb));
+ for (r = 0; r < sizeof(sc->sc_ecb) / sizeof(*ecb); r++) {
+ TAILQ_INSERT_TAIL(&sc->free_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QFREE);
+ ecb++;
+ }
+ bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
+ } else {
+ sc->sc_flags |= ESP_ABORTING;
+ sc->sc_state = ESP_IDLE;
+ ecb = sc->sc_nexus;
+ if (ecb != NULL) {
+ ecb->xs->error = XS_TIMEOUT;
+ esp_done(ecb);
+ sc->sc_nexus = NULL;
+ }
+ while ((ecb = sc->nexus_list.tqh_first) != NULL) {
+ ecb->xs->error = XS_TIMEOUT;
+ esp_done(ecb);
}
- } else
- outcmd = ESPCMD_SELNATN;
+ }
- ESPD(("P%d/%02x/%d ", (ecb->xs->flags & SCSI_POLL) ? 1 : 0, outcmd, loadcmd));
+ /*
+ * reset the chip to a known state
+ */
+ esp_reset(sc);
- if (loadcmd) {
- ESPD(("CMD["));
- for (i = 0; i < ecb->clen; i++)
- ESPD(("%02x%c", cmd[i],
- (i == ecb->clen-1) ? ']' : ' '));
- ESPD((" "));
+ sc->sc_phase = sc->sc_prevphase = INVALID_PHASE;
+ for (r = 0; r < 8; r++) {
+ struct esp_tinfo *tp = &sc->sc_tinfo[r];
+/* XXX - config flags per target: low bits: no reselect; high bits: no synch */
+ int fl = sc->sc_dev.dv_cfdata->cf_flags;
+
+ tp->flags = ((sc->sc_minsync && !(fl & (1<<(r+8))))
+ ? T_NEGOTIATE : 0) |
+ ((fl & (1<<r)) ? T_RSELECTOFF : 0) |
+ T_NEED_TO_RESET;
+ tp->period = sc->sc_minsync;
+ tp->offset = 0;
+ }
+ sc->sc_flags &= ~ESP_ABORTING;
- /* load the command into the FIFO */
- for (i = 0; i < ecb->clen; i++)
- espr->espr_fifo = cmd[i];
+ if (doreset) {
+ sc->sc_state = ESP_SBR;
+ ESPCMD(sc, ESPCMD_RSTSCSI);
+ return;
}
- espr->espr_cmd = outcmd;
- if (!(ecb->xs->flags & SCSI_POLL))
- sc->sc_flags |= ESPF_MAYDISCON;
+ sc->sc_state = ESP_IDLE;
+ esp_sched(sc);
+ return;
}
-
/*
- * Reset the ESP and DMA chips. Stops any transactions dead in the water;
- * does not cause an interrupt.
+ * Read the ESP registers, and save their contents for later use.
+ * ESP_STAT, ESP_STEP & ESP_INTR are mostly zeroed out when reading
+ * ESP_INTR - so make sure it is the last read.
+ *
+ * I think that (from reading the docs) most bits in these registers
+ * only make sense when he DMA CSR has an interrupt showing. Call only
+ * if an interrupt is pending.
*/
-void
-esp_reset(sc)
+void
+espreadregs(sc)
struct esp_softc *sc;
{
- struct espregs *espr = sc->sc_regs;
- dmareset(sc->sc_dma); /* reset DMA first */
+ sc->sc_espstat = ESP_READ_REG(sc, ESP_STAT);
+ /* Only the stepo bits are of interest */
+ sc->sc_espstep = ESP_READ_REG(sc, ESP_STEP) & ESPSTEP_MASK;
+ sc->sc_espintr = ESP_READ_REG(sc, ESP_INTR);
- espr->espr_cmd = ESPCMD_RSTCHIP;
- DELAY(5);
- espr->espr_cmd = ESPCMD_NOP;
- DELAY(5);
+ /*
+ * Determine the SCSI bus phase, return either a real SCSI bus phase
+ * or some pseudo phase we use to detect certain exceptions.
+ */
- /* do these backwards, and fall through */
- switch (sc->sc_rev) {
- case ESP200:
- espr->espr_cfg3 = sc->sc_cfg3;
- case ESP100A:
- espr->espr_cfg2 = sc->sc_cfg2;
- case ESP100:
- espr->espr_cfg1 = sc->sc_cfg1;
- espr->espr_ccf = sc->sc_ccf;
- espr->espr_syncoff = 0;
- espr->espr_timeout = sc->sc_timeout;
- break;
- }
+ sc->sc_phase = (sc->sc_espintr & ESPINTR_DIS)
+ ? /* Disconnected */ BUSFREE_PHASE
+ : sc->sc_espstat & ESPSTAT_PHASE;
+
+ ESP_MISC(("regs[intr=%02x,stat=%02x,step=%02x] ",
+ sc->sc_espintr, sc->sc_espstat, sc->sc_espstep));
}
/*
- * Initialize esp state machine
+ * Convert Synchronous Transfer Period to chip register Clock Per Byte value.
+ */
+int
+esp_stp2cpb(sc, period)
+ struct esp_softc *sc;
+ int period;
+{
+ int v;
+ v = (sc->sc_freq * period) / 250;
+ if (esp_cpb2stp(sc, v) < period)
+ /* Correct round-down error */
+ v++;
+ return v;
+}
+
+/*
+ * Convert chip register Clock Per Byte value to Synchronous Transfer Period.
+ */
+int
+esp_cpb2stp(sc, cpb)
+ struct esp_softc *sc;
+ int cpb;
+{
+ return ((250 * cpb) / sc->sc_freq);
+}
+
+/*
+ * Send a command to a target, set the driver state to ESP_SELECTING
+ * and let the caller take care of the rest.
+ *
+ * Keeping this as a function allows me to say that this may be done
+ * by DMA instead of programmed I/O soon.
*/
void
-esp_init(sc, doreset)
+espselect(sc, target, lun, cmd, clen)
struct esp_softc *sc;
- int doreset;
+ u_char target, lun;
+ u_char *cmd;
+ u_char clen;
{
- struct espregs *espr = sc->sc_regs;
- struct ecb *ecb;
+ struct esp_tinfo *ti = &sc->sc_tinfo[target];
int i;
-
- /*
- * reset the chip to a known state
- */
- esp_reset(sc);
- if (doreset) {
- espr->espr_cmd = ESPCMD_RSTSCSI;
- DELAY(500);
- /* cheat: we don't want the state machine to reset again.. */
- esp_reset(sc);
- }
+ ESP_TRACE(("[espselect(t%d,l%d,cmd:%x)] ", target, lun, *(u_char *)cmd));
- if (sc->sc_state == 0) { /* First time through */
- TAILQ_INIT(&sc->ready_list);
- TAILQ_INIT(&sc->nexus_list);
- TAILQ_INIT(&sc->free_list);
- sc->sc_nexus = 0;
- ecb = sc->sc_ecb;
- bzero(ecb, sizeof(sc->sc_ecb));
- for (i = 0; i < sizeof(sc->sc_ecb) / sizeof(*ecb); i++) {
- TAILQ_INSERT_TAIL(&sc->free_list, ecb, chain);
- ecb++;
- }
- bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
+ /* new state ESP_SELECTING */
+ sc->sc_state = ESP_SELECTING;
+
+ ESPCMD(sc, ESPCMD_FLUSH);
+
+ /*
+ * The docs say the target register is never reset, and I
+ * can't think of a better place to set it
+ */
+ ESP_WRITE_REG(sc, ESP_SELID, target);
+ if (ti->flags & T_SYNCMODE) {
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, ti->offset);
+ ESP_WRITE_REG(sc, ESP_SYNCTP, esp_stp2cpb(sc, ti->period));
} else {
- sc->sc_state = ESPS_IDLE;
- if (sc->sc_nexus != NULL) {
- sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
- untimeout(esp_timeout, sc->sc_nexus);
- esp_done(sc->sc_nexus);
- }
- sc->sc_nexus = NULL;
- while (ecb = sc->nexus_list.tqh_first) {
- ecb->xs->error = XS_DRIVER_STUFFUP;
- untimeout(esp_timeout, ecb);
- esp_done(ecb);
- }
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, 0);
+ ESP_WRITE_REG(sc, ESP_SYNCTP, 0);
}
-
- for (i = 0; i < 8; i++) {
- struct esp_tinfo *ti = &sc->sc_tinfo[i];
-
- ti->flags = DO_NEGOTIATE;
- ti->period = sc->sc_minsync;
- ti->synctp = 250 / ti->period;
- ti->offset = ESP_SYNC_REQOFF;
+
+ /*
+ * Who am I. This is where we tell the target that we are
+ * happy for it to disconnect etc.
+ */
+ ESP_WRITE_REG(sc, ESP_FIFO,
+ MSG_IDENTIFY(lun, (ti->flags & T_RSELECTOFF)?0:1));
+
+ if (ti->flags & T_NEGOTIATE) {
+ /* Arbitrate, select and stop after IDENTIFY message */
+ ESPCMD(sc, ESPCMD_SELATNS);
+ return;
}
- sc->sc_state = ESPS_IDLE;
+
+ /* Now the command into the FIFO */
+ for (i = 0; i < clen; i++)
+ ESP_WRITE_REG(sc, ESP_FIFO, *cmd++);
+
+ /* And get the targets attention */
+ ESPCMD(sc, ESPCMD_SELATN);
+
}
/*
- * Start a SCSI-command: This function is called by the higher level
- * SCSI-driver to queue/run SCSI-commands.
+ * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS
+ */
+
+/*
+ * Start a SCSI-command
+ * This function is called by the higher level SCSI-driver to queue/run
+ * SCSI-commands.
*/
-int
+int
esp_scsi_cmd(xs)
struct scsi_xfer *xs;
{
struct scsi_link *sc_link = xs->sc_link;
struct esp_softc *sc = sc_link->adapter_softc;
- struct ecb *ecb;
- int s;
-
- /*ESPD(("NS%08x/%08x/%d ", xs, xs->data, xs->datalen));*/
+ struct ecb *ecb;
+ int s, flags;
+
+ ESP_TRACE(("[esp_scsi_cmd] "));
+ ESP_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen,
+ sc_link->target));
- /* XXX: set lun */
- xs->cmd->bytes[0] |= (sc_link->lun << SCSI_CMD_LUN_SHIFT);
+ flags = xs->flags;
/* Get a esp command block */
s = splbio();
ecb = sc->free_list.tqh_first;
if (ecb) {
TAILQ_REMOVE(&sc->free_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QNONE);
}
splx(s);
-
+
if (ecb == NULL) {
- xs->error = XS_DRIVER_STUFFUP;
+ ESP_MISC(("TRY_AGAIN_LATER"));
return TRY_AGAIN_LATER;
}
/* Initialize ecb */
- ecb->flags = ECB_ACTIVE;
ecb->xs = xs;
bcopy(xs->cmd, &ecb->cmd, xs->cmdlen);
ecb->clen = xs->cmdlen;
ecb->daddr = xs->data;
ecb->dleft = xs->datalen;
ecb->stat = 0;
-
+
s = splbio();
TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain);
- if ((xs->flags & SCSI_POLL) == 0)
- timeout(esp_timeout, ecb, (xs->timeout * hz) / 1000);
+ ECB_SETQ(ecb, ECB_QREADY);
+ timeout(esp_timeout, ecb, (xs->timeout*hz)/1000);
- if (sc->sc_state == ESPS_IDLE)
+ if (sc->sc_state == ESP_IDLE)
esp_sched(sc);
+
splx(s);
- /* Not allowed to use interrupts, use polling instead */
- if (xs->flags & SCSI_POLL)
+ if (flags & SCSI_POLL) {
+ /* Not allowed to use interrupts, use polling instead */
return esp_poll(sc, ecb);
+ }
+
+ ESP_MISC(("SUCCESSFULLY_QUEUED"));
return SUCCESSFULLY_QUEUED;
+
}
/*
@@ -586,57 +682,45 @@ esp_poll(sc, ecb)
struct ecb *ecb;
{
struct scsi_xfer *xs = ecb->xs;
- int count = xs->timeout * 1000;
+ int count = xs->timeout * 100;
- ESP_TRACE(("esp_poll\n"));
+ ESP_TRACE(("[esp_poll] "));
while (count) {
- if (dmapending(sc->sc_dma)) {
- /*
- * We decrement the interrupt event counter to
- * repair it... because this isn't a real interrupt.
- */
- if (espintr(sc))
- --sc->sc_intrcnt.ev_count;
- continue;
+ if (DMA_ISINTR(sc->sc_dma)) {
+ espintr(sc);
}
+#if alternatively
+ if (ESP_READ_REG(sc, ESP_STAT) & ESPSTAT_INT)
+ espintr(sc);
+#endif
if (xs->flags & ITSDONE)
break;
- DELAY(1);
+ DELAY(10);
+ if (sc->sc_state == ESP_IDLE) {
+ ESP_TRACE(("[esp_poll: rescheduling] "));
+ esp_sched(sc);
+ }
count--;
}
if (count == 0) {
- ecb->xs->error = XS_TIMEOUT;
- sc_print_addr(ecb->xs->sc_link);
- printf("timed out\n");
- esp_reset(sc);
+ ESP_MISC(("esp_poll: timeout"));
+ esp_timeout((caddr_t)ecb);
}
- dmaenintr(sc->sc_dma);
+
return COMPLETE;
}
/*
- * Notice that we do not read the live register on an ESP100. On the
- * ESP100A and above the FE (Feature Enable) bit in config 2 latches
- * the phase in the register so it is safe to read.
+ * LOW LEVEL SCSI UTILITIES
*/
-int
-espphase(sc)
- struct esp_softc *sc;
-{
-
- if (sc->sc_rev > ESP100)
- return (sc->sc_regs->espr_stat & ESPSTAT_PHASE);
- return (sc->sc_espstat & ESPSTAT_PHASE);
-}
-
/*
* Schedule a scsi operation. This has now been pulled out of the interrupt
* handler so that we may call it from esp_scsi_cmd and esp_done. This may
* save us an unecessary interrupt just to get things going. Should only be
- * called when state == ESPS_IDLE and at bio pl.
+ * called when state == ESP_IDLE and at bio pl.
*/
void
esp_sched(sc)
@@ -645,29 +729,40 @@ esp_sched(sc)
struct scsi_link *sc_link;
struct ecb *ecb;
int t;
-
- ESP_TRACE(("esp_sched\n"));
+
+ ESP_TRACE(("[esp_sched] "));
+ if (sc->sc_state != ESP_IDLE)
+ panic("esp_sched: not IDLE (state=%d)", sc->sc_state);
+
+ if (sc->sc_flags & ESP_ABORTING)
+ return;
/*
* Find first ecb in ready queue that is for a target/lunit
* combinations that is not busy.
*/
for (ecb = sc->ready_list.tqh_first; ecb; ecb = ecb->chain.tqe_next) {
- caddr_t cmd = (caddr_t) &ecb->cmd;
sc_link = ecb->xs->sc_link;
t = sc_link->target;
if (!(sc->sc_tinfo[t].lubusy & (1 << sc_link->lun))) {
- struct esp_tinfo *ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+ struct esp_tinfo *ti = &sc->sc_tinfo[t];
+ if ((ecb->flags & ECB_QBITS) != ECB_QREADY)
+ panic("esp: busy entry on ready list");
TAILQ_REMOVE(&sc->ready_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QNONE);
sc->sc_nexus = ecb;
sc->sc_flags = 0;
- sc_link = ecb->xs->sc_link;
- espselect(sc);
- ti = &sc->sc_tinfo[sc_link->target];
+ sc->sc_prevphase = INVALID_PHASE;
sc->sc_dp = ecb->daddr;
sc->sc_dleft = ecb->dleft;
ti->lubusy |= (1<<sc_link->lun);
+/*XXX*/if (sc->sc_msgpriq) {
+ printf("esp: message queue not empty: %x!\n", sc->sc_msgpriq);
+}
+/*XXX*/sc->sc_msgpriq = sc->sc_msgout = 0;
+ espselect(sc, t, sc_link->lun,
+ (u_char *)&ecb->cmd, ecb->clen);
break;
} else
ESP_MISC(("%d:%d busy\n", t, sc_link->lun));
@@ -684,24 +779,27 @@ esp_done(ecb)
struct scsi_xfer *xs = ecb->xs;
struct scsi_link *sc_link = xs->sc_link;
struct esp_softc *sc = sc_link->adapter_softc;
+ struct esp_tinfo *ti = &sc->sc_tinfo[sc_link->target];
- ESP_TRACE(("esp_done "));
+ ESP_TRACE(("[esp_done(error:%x)] ", xs->error));
+
+ untimeout(esp_timeout, ecb);
/*
- * Now, if we've come here with no error code, i.e. we've kept the
+ * Now, if we've come here with no error code, i.e. we've kept the
* initial XS_NOERROR, and the status code signals that we should
- * check sense, we'll need to set up a request sense cmd block and
- * push the command back into the ready queue *before* any other
+ * check sense, we'll need to set up a request sense cmd block and
+ * push the command back into the ready queue *before* any other
* commands for this target/lunit, else we lose the sense info.
* We don't support chk sense conditions for the request sense cmd.
*/
if (xs->error == XS_NOERROR) {
- if (ecb->flags & ECB_CHKSENSE)
+ if ((ecb->flags & ECB_ABORTED) != 0) {
+ xs->error = XS_TIMEOUT;
+ } else if ((ecb->flags & ECB_CHKSENSE) != 0) {
xs->error = XS_SENSE;
- else if ((ecb->stat & ST_MASK) == SCSI_CHECK) {
+ } else if ((ecb->stat & ST_MASK) == SCSI_CHECK) {
struct scsi_sense *ss = (void *)&ecb->cmd;
-
- ESPD(("RS "));
ESP_MISC(("requesting sense "));
/* First, save the return values */
xs->resid = ecb->dleft;
@@ -709,35 +807,43 @@ esp_done(ecb)
/* Next, setup a request sense command block */
bzero(ss, sizeof(*ss));
ss->opcode = REQUEST_SENSE;
- ss->byte2 = sc_link->lun << SCSI_CMD_LUN_SHIFT;
+ /*ss->byte2 = sc_link->lun << 5;*/
ss->length = sizeof(struct scsi_sense_data);
ecb->clen = sizeof(*ss);
ecb->daddr = (char *)&xs->sense;
ecb->dleft = sizeof(struct scsi_sense_data);
- ecb->flags = ECB_ACTIVE|ECB_CHKSENSE;
+ ecb->flags |= ECB_CHKSENSE;
+/*XXX - must take off queue here */
+ if (ecb != sc->sc_nexus) {
+ panic("%s: esp_sched: floating ecb %p",
+ sc->sc_dev.dv_xname, ecb);
+ }
TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
- sc->sc_tinfo[sc_link->target].lubusy &=
- ~(1<<sc_link->lun);
- sc->sc_tinfo[sc_link->target].senses++;
- /* found it */
- if (sc->sc_nexus != ecb)
- TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
- sc->sc_state = ESPS_IDLE;
- esp_sched(sc);
+ ECB_SETQ(ecb, ECB_QREADY);
+ ti->lubusy &= ~(1<<sc_link->lun);
+ ti->senses++;
+ timeout(esp_timeout, ecb, (xs->timeout*hz)/1000);
+ if (sc->sc_nexus == ecb) {
+ sc->sc_nexus = NULL;
+ sc->sc_state = ESP_IDLE;
+ esp_sched(sc);
+ }
return;
- } else
+ } else {
xs->resid = ecb->dleft;
+ }
}
xs->flags |= ITSDONE;
-#if ESP_DEBUG > 1
+#ifdef ESP_DEBUG
if (esp_debug & ESP_SHOWMISC) {
- printf("err=0x%02x ", xs->error);
- if (xs->error == XS_SENSE)
- printf("sense=%02x\n", xs->sense.error_code);
+ printf("err=0x%02x ",xs->error);
+ if (xs->error == XS_SENSE) {
+ printf("sense=%2x; ", xs->sense.error_code);
+ }
}
- if ((xs->resid || xs->error > XS_SENSE) && (esp_debug & ESP_SHOWMISC)) {
+ if ((xs->resid || xs->error > XS_SENSE) && esp_debug & ESP_SHOWMISC) {
if (xs->resid)
printf("esp_done: resid=%d\n", xs->resid);
if (xs->error)
@@ -746,45 +852,41 @@ esp_done(ecb)
#endif
/*
- * Remove the ECB from whatever queue it's on. We have to do a bit of
- * a hack to figure out which queue it's on. Note that it is *not*
- * necessary to cdr down the ready queue, but we must cdr down the
- * nexus queue and see if it's there, so we can mark the unit as no
- * longer busy. This code is sickening, but it works.
+ * Remove the ECB from whatever queue it's on.
*/
- if (ecb == sc->sc_nexus) {
- sc->sc_tinfo[sc_link->target].lubusy &= ~(1<<sc_link->lun);
+ switch (ecb->flags & ECB_QBITS) {
+ case ECB_QNONE:
+ if (ecb != sc->sc_nexus) {
+ panic("%s: floating ecb", sc->sc_dev.dv_xname);
+ }
sc->sc_nexus = NULL;
- sc->sc_state = ESPS_IDLE;
+ sc->sc_state = ESP_IDLE;
+ ti->lubusy &= ~(1<<sc_link->lun);
esp_sched(sc);
- } else if (sc->ready_list.tqh_last == &ecb->chain.tqe_next) {
+ break;
+ case ECB_QREADY:
TAILQ_REMOVE(&sc->ready_list, ecb, chain);
- } else {
- register struct ecb *ecb2;
-
- for (ecb2 = sc->nexus_list.tqh_first; ecb2;
- ecb2 = ecb2->chain.tqe_next)
- if (ecb2 == ecb)
- break;
- if (ecb2) {
- TAILQ_REMOVE(&sc->nexus_list, ecb, chain);
- sc->sc_tinfo[sc_link->target].lubusy &=
- ~(1<<sc_link->lun);
- } else if (ecb->chain.tqe_next) {
- TAILQ_REMOVE(&sc->ready_list, ecb, chain);
- } else {
- printf("%s: can't find matching ecb\n",
- sc->sc_dev.dv_xname);
- Debugger();
- }
+ break;
+ case ECB_QNEXUS:
+ TAILQ_REMOVE(&sc->nexus_list, ecb, chain);
+ ti->lubusy &= ~(1<<sc_link->lun);
+ break;
+ case ECB_QFREE:
+ panic("%s: dequeue: busy ecb on free list",
+ sc->sc_dev.dv_xname);
+ break;
+ default:
+ panic("%s: dequeue: unknown queue %d",
+ sc->sc_dev.dv_xname, ecb->flags & ECB_QBITS);
}
- /* Put it on the free list. */
- ecb->flags = ECB_FREE;
+
+ /* Put it on the free list, and clear flags. */
TAILQ_INSERT_HEAD(&sc->free_list, ecb, chain);
+ ecb->flags = ECB_QFREE;
- sc->sc_tinfo[sc_link->target].cmds++;
- ESPD(("DONE%d ", xs->resid));
+ ti->cmds++;
scsi_done(xs);
+ return;
}
/*
@@ -797,13 +899,13 @@ esp_done(ecb)
* else there will be an illegal command interrupt.
*/
#define esp_sched_msgout(m) \
- do { \
- sc->sc_regs->espr_cmd = ESPCMD_SETATN; \
- sc->sc_msgpriq |= (m); \
- ESPD(("Mq%02x ", sc->sc_msgpriq)); \
+ do { \
+ ESP_MISC(("esp_sched_msgout %d ", m)); \
+ ESPCMD(sc, ESPCMD_SETATN); \
+ sc->sc_msgpriq |= (m); \
} while (0)
-#define IS1BYTEMSG(m) (((m) != 1 && ((unsigned)(m)) < 0x20) || (m) & 0x80)
+#define IS1BYTEMSG(m) (((m) != 1 && (m) < 0x20) || (m) & 0x80)
#define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
#define ISEXTMSG(m) ((m) == 1)
@@ -817,22 +919,16 @@ void
esp_msgin(sc)
register struct esp_softc *sc;
{
- struct espregs *espr = sc->sc_regs;
- struct ecb *ecb;
- int extlen;
- int x, i;
-
- ESP_TRACE(("esp_msgin "));
-
- /* is something wrong ? */
- if (sc->sc_phase != MESSAGE_IN_PHASE) {
- printf("%s: not MESSAGE_IN_PHASE\n", sc->sc_dev.dv_xname);
+ register int v;
+
+ ESP_TRACE(("[esp_msgin(curmsglen:%d)] ", sc->sc_imlen));
+
+ if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) == 0) {
+ printf("%s: msgin: no msg byte available\n",
+ sc->sc_dev.dv_xname);
return;
}
- ESPD(("MSGIN:%d ", espr->espr_fflag & ESPFIFO_FF));
-
-#ifdef fixme
/*
* Prepare for a new message. A message should (according
* to the SCSI standard) be transmitted in one single
@@ -840,187 +936,125 @@ esp_msgin(sc)
* then this is a new message.
*/
if (sc->sc_prevphase != MESSAGE_IN_PHASE) {
- sc->sc_flags &= ~ESPF_DROP_MSGI;
- if (sc->sc_imlen > 0) {
- printf("%s: message type %02x",
- sc->sc_dev.dv_xname, sc->sc_imess[0]);
- if (!IS1BYTEMSG(sc->sc_imess[0]))
- printf(" %02x", sc->sc_imess[1]);
- printf(" was dropped\n");
- }
+ sc->sc_flags &= ~ESP_DROP_MSGI;
sc->sc_imlen = 0;
}
-#endif
- /*
- * Which target is reselecting us? (The ID bit really)
- * On a reselection, there should be the reselecting target's
- * id and an identify message in the fifo.
- */
- if (sc->sc_state == ESPS_RESELECTED && sc->sc_imlen == 0) {
- x = espgetbyte(sc, 0);
- if (x == -1) {
- printf("%s: msgin reselection found fifo empty\n",
- sc->sc_dev.dv_xname);
- return;
- }
- ESPD(("ID=%02x ", x));
- sc->sc_selid = (u_char)x & ~(1<<sc->sc_id);
- ESP_MISC(("selid=0x%02x ", sc->sc_selid));
- }
+ v = ESP_READ_REG(sc, ESP_FIFO);
+ ESP_MISC(("<msgbyte:0x%02x>", v));
- /*
- * If parity errors just dump everything on the floor
- */
- if (sc->sc_espstat & ESPSTAT_PE) {
- printf("%s: SCSI bus parity error\n",
- sc->sc_dev.dv_xname);
- esp_sched_msgout(SEND_PARITY_ERROR);
- DELAY(1);
- sc->sc_flags |= ESPF_DROP_MSGI;
+#if 0
+ if (sc->sc_state == ESP_RESELECTED && sc->sc_imlen == 0) {
+ /*
+ * Which target is reselecting us? (The ID bit really)
+ */
+ sc->sc_selid = v;
+ sc->sc_selid &= ~(1<<sc->sc_id);
+ ESP_MISC(("selid=0x%2x ", sc->sc_selid));
+ return;
}
+#endif
+
+ sc->sc_imess[sc->sc_imlen] = v;
/*
* If we're going to reject the message, don't bother storing
* the incoming bytes. But still, we need to ACK them.
- * XXX: the above comment might be true -- this is not being
- * done though!
*/
- if ((sc->sc_flags & ESPF_DROP_MSGI) == 0) {
- x = espgetbyte(sc, 1);
- if (x == -1) {
- printf("%s: msgin fifo empty at %d\n",
- sc->sc_dev.dv_xname, sc->sc_imlen);
- if (sc->sc_espintr & ESPINTR_BS) {
- espr->espr_cmd = ESPCMD_TRANS;
- ESPD(("MSI:y "));
- } else
- ESPD(("MSI:n "));
- return;
- }
- ESPD(("{%02x} ", (u_char)x));
- sc->sc_imess[sc->sc_imlen] = (u_char)x;
- if (sc->sc_imlen >= ESP_MSGLEN_MAX) {
- esp_sched_msgout(SEND_REJECT);
- DELAY(1);
- sc->sc_flags |= ESPF_DROP_MSGI;
- } else {
- sc->sc_imlen++;
- /*
- * This testing is suboptimal, but most
- * messages will be of the one byte variety, so
- * it should not effect performance
- * significantly.
- */
- if (sc->sc_imlen == 1 && IS1BYTEMSG(sc->sc_imess[0]))
- goto gotit;
- if (sc->sc_imlen == 2 && IS2BYTEMSG(sc->sc_imess[0]))
- goto gotit;
- if (sc->sc_imlen >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
- sc->sc_imlen == sc->sc_imess[1] + 2)
- goto gotit;
- }
- }
- goto done;
-gotit:
- ESPD(("MP["));
- for (i=0; i<sc->sc_imlen; i++)
- ESPD(("%02x%c", sc->sc_imess[i],
- (i==sc->sc_imlen-1) ? ']' : ' '));
- ESPD((" "));
+ if ((sc->sc_flags & ESP_DROP_MSGI)) {
+ ESPCMD(sc, ESPCMD_SETATN);
+ ESPCMD(sc, ESPCMD_MSGOK);
+ printf("<dropping msg byte %x>",
+ sc->sc_imess[sc->sc_imlen]);
+ return;
+ }
- sc->sc_imlen = 0; /* message is fully received */
+ if (sc->sc_imlen >= ESP_MAX_MSG_LEN) {
+ esp_sched_msgout(SEND_REJECT);
+ sc->sc_flags |= ESP_DROP_MSGI;
+ } else {
+ sc->sc_imlen++;
+ /*
+ * This testing is suboptimal, but most
+ * messages will be of the one byte variety, so
+ * it should not effect performance
+ * significantly.
+ */
+ if (sc->sc_imlen == 1 && IS1BYTEMSG(sc->sc_imess[0]))
+ goto gotit;
+ if (sc->sc_imlen == 2 && IS2BYTEMSG(sc->sc_imess[0]))
+ goto gotit;
+ if (sc->sc_imlen >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
+ sc->sc_imlen == sc->sc_imess[1] + 2)
+ goto gotit;
+ }
+ /* Ack what we have so far */
+ ESPCMD(sc, ESPCMD_MSGOK);
+ return;
- ESP_MISC(("gotmsg "));
+gotit:
+ ESP_MSGS(("gotmsg(%x)", sc->sc_imess[0]));
/*
* Now we should have a complete message (1 byte, 2 byte
* and moderately long extended messages). We only handle
* extended messages which total length is shorter than
- * ESP_MSGLEN_MAX. Longer messages will be amputated.
+ * ESP_MAX_MSG_LEN. Longer messages will be amputated.
*/
- if (sc->sc_state == ESPS_NEXUS ||
- sc->sc_state == ESPS_DOINGMSGIN ||
- sc->sc_state == ESPS_DOINGSTATUS) {
- struct esp_tinfo *ti;
-
- ecb = sc->sc_nexus;
- ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
-
- sc->sc_state = ESPS_NEXUS; /* where we go after this */
+ if (sc->sc_state == ESP_HASNEXUS) {
+ struct ecb *ecb = sc->sc_nexus;
+ struct esp_tinfo *ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
switch (sc->sc_imess[0]) {
case MSG_CMDCOMPLETE:
- ESP_MISC(("cmdcomplete "));
- if (!ecb) {
- esp_sched_msgout(SEND_ABORT);
- DELAY(1);
- printf("%s: CMDCOMPLETE but no command?\n",
- sc->sc_dev.dv_xname);
- break;
- }
+ ESP_MSGS(("cmdcomplete "));
if (sc->sc_dleft < 0) {
- sc_print_addr(ecb->xs->sc_link);
- printf("%d extra bytes\n", -sc->sc_dleft);
- ecb->dleft = 0;
+ struct scsi_link *sc_link = ecb->xs->sc_link;
+ printf("esp: %d extra bytes from %d:%d\n",
+ -sc->sc_dleft,
+ sc_link->target, sc_link->lun);
+ sc->sc_dleft = 0;
}
ecb->xs->resid = ecb->dleft = sc->sc_dleft;
- ecb->flags |= ECB_DONE;
+ sc->sc_flags |= ESP_BUSFREE_OK;
break;
+
case MSG_MESSAGE_REJECT:
- if (esp_debug & ESP_SHOWMISC)
- printf("%s targ %d: our msg rejected by target\n",
- sc->sc_dev.dv_xname,
- ecb->xs->sc_link->target);
- if (sc->sc_flags & ESPF_SYNCHNEGO) {
- /*
- * Device doesn't even know what sync is
- * (right?)
- */
- ti->offset = 0;
- ti->period = sc->sc_minsync;
- ti->synctp = 250 / ti->period;
- sc->sc_flags &= ~ESPF_SYNCHNEGO;
- ti->flags &= ~DO_NEGOTIATE;
+ if (esp_debug & ESP_SHOWMSGS)
+ printf("%s: our msg rejected by target\n",
+ sc->sc_dev.dv_xname);
+#if 1 /* XXX - must remember last message */
+sc_print_addr(ecb->xs->sc_link); printf("MSG_MESSAGE_REJECT>>");
+#endif
+ if (sc->sc_flags & ESP_SYNCHNEGO) {
+ ti->period = ti->offset = 0;
+ sc->sc_flags &= ~ESP_SYNCHNEGO;
+ ti->flags &= ~T_NEGOTIATE;
}
/* Not all targets understand INITIATOR_DETECTED_ERR */
- if (sc->sc_msgout == SEND_INIT_DET_ERR) {
+ if (sc->sc_msgout == SEND_INIT_DET_ERR)
esp_sched_msgout(SEND_ABORT);
- DELAY(1);
- }
break;
case MSG_NOOP:
+ ESP_MSGS(("noop "));
break;
case MSG_DISCONNECT:
- if (!ecb) {
- esp_sched_msgout(SEND_ABORT);
- DELAY(1);
- printf("%s: nothing to DISCONNECT\n",
- sc->sc_dev.dv_xname);
- break;
- }
+ ESP_MSGS(("disconnect "));
ti->dconns++;
- TAILQ_INSERT_HEAD(&sc->nexus_list, ecb, chain);
- ecb = sc->sc_nexus = NULL;
- sc->sc_state = ESPS_EXPECTDISC;
- sc->sc_flags |= ESPF_MAYDISCON;
- break;
- case MSG_SAVEDATAPOINTER:
- if (!ecb) {
- esp_sched_msgout(SEND_ABORT);
- DELAY(1);
- printf("%s: no DATAPOINTERs to save\n",
- sc->sc_dev.dv_xname);
+ sc->sc_flags |= ESP_DISCON;
+ sc->sc_flags |= ESP_BUSFREE_OK;
+ if ((ecb->xs->sc_link->quirks & SDEV_AUTOSAVE) == 0)
break;
- }
- ESPD(("DL%d/%d ", sc->sc_dleft, ecb->dleft));
+ /*FALLTHROUGH*/
+ case MSG_SAVEDATAPOINTER:
+ ESP_MSGS(("save datapointer "));
ecb->dleft = sc->sc_dleft;
ecb->daddr = sc->sc_dp;
break;
case MSG_RESTOREPOINTERS:
+ ESP_MSGS(("restore datapointer "));
if (!ecb) {
esp_sched_msgout(SEND_ABORT);
- DELAY(1);
printf("%s: no DATAPOINTERs to restore\n",
sc->sc_dev.dv_xname);
break;
@@ -1028,43 +1062,95 @@ gotit:
sc->sc_dp = ecb->daddr;
sc->sc_dleft = ecb->dleft;
break;
+ case MSG_PARITY_ERROR:
+ printf("%s:target%d: MSG_PARITY_ERROR\n",
+ sc->sc_dev.dv_xname,
+ ecb->xs->sc_link->target);
+ break;
case MSG_EXTENDED:
+ ESP_MSGS(("extended(%x) ", sc->sc_imess[2]));
switch (sc->sc_imess[2]) {
case MSG_EXT_SDTR:
+ ESP_MSGS(("SDTR period %d, offset %d ",
+ sc->sc_imess[3], sc->sc_imess[4]));
ti->period = sc->sc_imess[3];
ti->offset = sc->sc_imess[4];
- sc->sc_flags &= ~ESPF_SYNCHNEGO;
- ti->flags &= ~DO_NEGOTIATE;
- if (ti->offset == 0 ||
- ti->offset > ESP_SYNC_MAXOFF ||
- ti->period < sc->sc_minsync) {
+ if (sc->sc_minsync == 0) {
+ /* We won't do synch */
ti->offset = 0;
- ti->period = sc->sc_minsync;
- ti->synctp = 250 / ti->period;
- break;
+ esp_sched_msgout(SEND_SDTR);
+ } else if (ti->offset == 0) {
+ printf("%s:%d: async\n", "esp",
+ ecb->xs->sc_link->target);
+ ti->offset = 0;
+ sc->sc_flags &= ~ESP_SYNCHNEGO;
+ } else if (ti->period > 124) {
+ printf("%s:%d: async\n", "esp",
+ ecb->xs->sc_link->target);
+ ti->offset = 0;
+ esp_sched_msgout(SEND_SDTR);
+ } else {
+ int r = 250/ti->period;
+ int s = (100*250)/ti->period - 100*r;
+ int p;
+ p = esp_stp2cpb(sc, ti->period);
+ ti->period = esp_cpb2stp(sc, p);
+#ifdef ESP_DEBUG
+ sc_print_addr(ecb->xs->sc_link);
+#endif
+ if ((sc->sc_flags&ESP_SYNCHNEGO) == 0) {
+ /* Target initiated negotiation */
+ if (ti->flags & T_SYNCMODE) {
+ ti->flags &= ~T_SYNCMODE;
+#ifdef ESP_DEBUG
+ printf("renegotiated ");
+#endif
+ }
+ ESP_WRITE_REG(sc, ESP_SYNCOFF,
+ 0);
+ ESP_WRITE_REG(sc, ESP_SYNCTP,
+ 0);
+ /* Clamp to our maxima */
+ if (ti->period < sc->sc_minsync)
+ ti->period = sc->sc_minsync;
+ if (ti->offset > 15)
+ ti->offset = 15;
+ esp_sched_msgout(SEND_SDTR);
+ } else {
+ /* we are sync */
+ sc->sc_flags &= ~ESP_SYNCHNEGO;
+ ESP_WRITE_REG(sc, ESP_SYNCOFF,
+ ti->offset);
+ ESP_WRITE_REG(sc, ESP_SYNCTP,
+ p);
+ ti->flags |= T_SYNCMODE;
+ }
+#ifdef ESP_DEBUG
+ printf("max sync rate %d.%02dMb/s\n",
+ r, s);
+#endif
}
- printf("%s targ %d: sync, offset %d, period %dnsec\n",
- sc->sc_dev.dv_xname, ecb->xs->sc_link->target,
- ti->offset, ti->period * 4);
- ti->synctp = 250 / ti->period;
+ ti->flags &= ~T_NEGOTIATE;
break;
- default:
- /* Extended messages we don't handle */
- esp_sched_msgout(SEND_REJECT);
- DELAY(1);
+ default: /* Extended messages we don't handle */
+ ESPCMD(sc, ESPCMD_SETATN);
break;
}
break;
default:
- /* thanks for that ident... XXX: we should check it? */
+ ESP_MSGS(("ident "));
+ /* thanks for that ident... */
if (!MSG_ISIDENTIFY(sc->sc_imess[0])) {
- esp_sched_msgout(SEND_REJECT);
- DELAY(1);
+ ESP_MISC(("unknown "));
+printf("%s: unimplemented message: %d\n", sc->sc_dev.dv_xname, sc->sc_imess[0]);
+ ESPCMD(sc, ESPCMD_SETATN);
}
break;
}
- } else if (sc->sc_state == ESPS_RESELECTED) {
- struct scsi_link *sc_link;
+ } else if (sc->sc_state == ESP_RESELECTED) {
+ struct scsi_link *sc_link = NULL;
+ struct ecb *ecb;
+ struct esp_tinfo *ti;
u_char lunit;
if (MSG_ISIDENTIFY(sc->sc_imess[0])) { /* Identify? */
@@ -1073,115 +1159,65 @@ gotit:
* Search wait queue for disconnected cmd
* The list should be short, so I haven't bothered with
* any more sophisticated structures than a simple
- * singly linked list.
+ * singly linked list.
*/
lunit = sc->sc_imess[0] & 0x07;
for (ecb = sc->nexus_list.tqh_first; ecb;
- ecb = ecb->chain.tqe_next) {
+ ecb = ecb->chain.tqe_next) {
sc_link = ecb->xs->sc_link;
if (sc_link->lun == lunit &&
sc->sc_selid == (1<<sc_link->target)) {
TAILQ_REMOVE(&sc->nexus_list, ecb,
chain);
+ ECB_SETQ(ecb, ECB_QNONE);
break;
}
}
- if (!ecb) {
- /* Invalid reselection! */
+ if (!ecb) { /* Invalid reselection! */
esp_sched_msgout(SEND_ABORT);
- DELAY(1);
printf("esp: invalid reselect (idbit=0x%2x)\n",
sc->sc_selid);
- } else {
+ } else { /* Reestablish nexus */
/*
- * Reestablish nexus:
* Setup driver data structures and
* do an implicit RESTORE POINTERS
*/
+ ti = &sc->sc_tinfo[sc_link->target];
sc->sc_nexus = ecb;
sc->sc_dp = ecb->daddr;
sc->sc_dleft = ecb->dleft;
- sc->sc_tinfo[sc_link->target].lubusy |=
- (1<<sc_link->lun);
- espr->espr_syncoff =
- sc->sc_tinfo[sc_link->target].offset;
- espr->espr_synctp = 250 /
- sc->sc_tinfo[sc_link->target].period;
+ sc->sc_tinfo[sc_link->target].lubusy
+ |= (1<<sc_link->lun);
+ if (ti->flags & T_SYNCMODE) {
+ ESP_WRITE_REG(sc, ESP_SYNCOFF,
+ ti->offset);
+ ESP_WRITE_REG(sc, ESP_SYNCTP,
+ esp_stp2cpb(sc, ti->period));
+ } else {
+ ESP_WRITE_REG(sc, ESP_SYNCOFF, 0);
+ ESP_WRITE_REG(sc, ESP_SYNCTP, 0);
+ }
ESP_MISC(("... found ecb"));
- sc->sc_state = ESPS_NEXUS;
+ sc->sc_state = ESP_HASNEXUS;
}
} else {
printf("%s: bogus reselect (no IDENTIFY) %0x2x\n",
sc->sc_dev.dv_xname, sc->sc_selid);
esp_sched_msgout(SEND_DEV_RESET);
- DELAY(1);
}
} else { /* Neither ESP_HASNEXUS nor ESP_RESELECTED! */
printf("%s: unexpected message in; will send DEV_RESET\n",
sc->sc_dev.dv_xname);
esp_sched_msgout(SEND_DEV_RESET);
- DELAY(1);
}
-done:
- espr->espr_cmd = ESPCMD_MSGOK;
- espr->espr_cmd = ESPCMD_NOP;
-}
-
-void
-esp_makemsg(sc)
- register struct esp_softc *sc;
-{
- struct esp_tinfo *ti;
- struct ecb *ecb = sc->sc_nexus;
- int i;
+ /* Ack last message byte */
+ ESPCMD(sc, ESPCMD_MSGOK);
- sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
- ESPD(("MQ%02x/%02x ", sc->sc_msgpriq, sc->sc_msgout));
-
- sc->sc_omlen = 1; /* "Default" message len */
- switch (sc->sc_msgout) {
- case SEND_SDTR: /* implies an IDENTIFY message */
- sc->sc_flags |= ESPF_SYNCHNEGO;
- ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
- sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun,
- !(ecb->xs->flags & SCSI_POLL));
- sc->sc_omess[1] = MSG_EXTENDED;
- sc->sc_omess[2] = 3;
- sc->sc_omess[3] = MSG_EXT_SDTR;
- sc->sc_omess[4] = ti->period;
- sc->sc_omess[5] = ti->offset;
- sc->sc_omlen = 6;
- /* Fallthrough! */
- case SEND_IDENTIFY:
- sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun,
- !(ecb->xs->flags & SCSI_POLL));
- break;
- case SEND_DEV_RESET:
- sc->sc_omess[0] = MSG_BUS_DEV_RESET;
- if (sc->sc_nexus)
- sc->sc_nexus->flags |= ECB_DONE;
- break;
- case SEND_PARITY_ERROR:
- sc->sc_omess[0] = MSG_PARITY_ERROR;
- break;
- case SEND_ABORT:
- sc->sc_omess[0] = MSG_ABORT;
- if (sc->sc_nexus)
- sc->sc_nexus->flags |= ECB_DONE;
- break;
- case SEND_INIT_DET_ERR:
- sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
- break;
- case SEND_REJECT:
- sc->sc_omess[0] = MSG_MESSAGE_REJECT;
- break;
- default:
- sc->sc_omess[0] = MSG_NOOP;
- break;
- }
- sc->sc_omp = sc->sc_omess;
+ /* Done, reset message pointer. */
+ sc->sc_flags &= ~ESP_DROP_MSGI;
+ sc->sc_imlen = 0;
}
@@ -1192,650 +1228,746 @@ void
esp_msgout(sc)
register struct esp_softc *sc;
{
- struct espregs *espr = sc->sc_regs;
struct esp_tinfo *ti;
struct ecb *ecb;
- int i;
-
- /* Pick up highest priority message */
- sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
- esp_makemsg(sc);
-
- for (i = 0; i < sc->sc_omlen; i++)
- espr->espr_fifo = sc->sc_omp[i];
- espr->espr_cmd = ESPCMD_TRANS;
-}
-
+ size_t size;
-void
-esp_timeout(arg)
- void *arg;
-{
- struct ecb *ecb = (struct ecb *)arg;
- struct esp_softc *sc;
+ ESP_TRACE(("[esp_msgout(priq:%x, prevphase:%x)]", sc->sc_msgpriq, sc->sc_prevphase));
- sc = ecb->xs->sc_link->adapter_softc;
- sc_print_addr(ecb->xs->sc_link);
- printf("timed out at %d %d\n", sc->sc_state, sc->sc_phase);
+ if (sc->sc_prevphase != MESSAGE_OUT_PHASE) {
+ /* Pick up highest priority message */
+ sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
+ sc->sc_omlen = 1; /* "Default" message len */
+ switch (sc->sc_msgout) {
+ case SEND_SDTR:
+ ecb = sc->sc_nexus;
+ ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+ sc->sc_omess[0] = MSG_EXTENDED;
+ sc->sc_omess[1] = 3;
+ sc->sc_omess[2] = MSG_EXT_SDTR;
+ sc->sc_omess[3] = ti->period;
+ sc->sc_omess[4] = ti->offset;
+ sc->sc_omlen = 5;
+ break;
+ case SEND_IDENTIFY:
+ if (sc->sc_state != ESP_HASNEXUS) {
+ printf("esp at line %d: no nexus", __LINE__);
+ }
+ ecb = sc->sc_nexus;
+ sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun,0);
+ break;
+ case SEND_DEV_RESET:
+ sc->sc_omess[0] = MSG_BUS_DEV_RESET;
+ sc->sc_flags |= ESP_BUSFREE_OK;
+ ecb = sc->sc_nexus;
+ ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+ ti->flags &= ~T_SYNCMODE;
+ ti->flags |= T_NEGOTIATE;
+ break;
+ case SEND_PARITY_ERROR:
+ sc->sc_omess[0] = MSG_PARITY_ERROR;
+ break;
+ case SEND_ABORT:
+ sc->sc_omess[0] = MSG_ABORT;
+ sc->sc_flags |= ESP_BUSFREE_OK;
+ break;
+ case SEND_INIT_DET_ERR:
+ sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
+ break;
+ case SEND_REJECT:
+ sc->sc_omess[0] = MSG_MESSAGE_REJECT;
+ break;
+ default:
+ sc->sc_omess[0] = MSG_NOOP;
+ break;
+ }
+ sc->sc_omp = sc->sc_omess;
+ }
- ecb->xs->error = XS_TIMEOUT;
- esp_reset(sc);
- esp_done(ecb);
- printf("new ecb %08x\n", sc->sc_nexus);
+#if 1
+ /* (re)send the message */
+ size = min(sc->sc_omlen, sc->sc_maxxfer);
+ DMA_SETUP(sc->sc_dma, &sc->sc_omp, &sc->sc_omlen, 0, &size);
+ /* Program the SCSI counter */
+ ESP_WRITE_REG(sc, ESP_TCL, size);
+ ESP_WRITE_REG(sc, ESP_TCM, size >> 8);
+ if (sc->sc_cfg2 & ESPCFG2_FE) {
+ ESP_WRITE_REG(sc, ESP_TCH, size >> 16);
+ }
+ /* load the count in */
+ ESPCMD(sc, ESPCMD_NOP|ESPCMD_DMA);
+ ESPCMD(sc, (size==0?ESPCMD_TRPAD:ESPCMD_TRANS)|ESPCMD_DMA);
+ DMA_GO(sc->sc_dma);
+#else
+ { int i;
+ ESPCMD(sc, ESPCMD_FLUSH);
+ for (i = 0; i < sc->sc_omlen; i++)
+ ESP_WRITE_REG(sc, FIFO, sc->sc_omess[i]);
+ ESPCMD(sc, ESPCMD_TRANS);
+#if test_stuck_on_msgout
+printf("<<XXXmsgoutdoneXXX>>");
+#endif
+ }
+#endif
}
/*
- * Read the ESP registers, and save their contents for later use.
- * ESP_STAT, ESP_STEP & ESP_INTR are mostly zeroed out when reading
- * ESP_INTR - so make sure it is the last read.
+ * This is the most critical part of the driver, and has to know
+ * how to deal with *all* error conditions and phases from the SCSI
+ * bus. If there are no errors and the DMA was active, then call the
+ * DMA pseudo-interrupt handler. If this returns 1, then that was it
+ * and we can return from here without further processing.
*
- * XXX: TDR: this logic seems unsound
- * I think that (from reading the docs) most bits in these registers
- * only make sense when the DMA CSR has an interrupt showing. So I have
- * coded this to not do anything if there is no interrupt or error
- * pending.
+ * Most of this needs verifying.
*/
-void
-espreadregs(sc)
- struct esp_softc *sc;
-{
- struct espregs *espr = sc->sc_regs;
-
- /* they mean nothing if the is no pending interrupt ??? */
- if (!(dmapending(sc->sc_dma)))
- return;
-
- /* Only the stepo bits are of interest */
- sc->sc_espstep = espr->espr_step & ESPSTEP_MASK;
- sc->sc_espstat = espr->espr_stat;
- sc->sc_espintr = espr->espr_intr;
-
- ESP_MISC(("regs[intr=%02x,stat=%02x,step=%02x] ", sc->sc_espintr,
- sc->sc_espstat, sc->sc_espstep));
-}
-
-/*
- * Whatever we do, we must generate an interrupt if we expect to go
- * to the next state.
- * Note: this increments the events even if called from esp_poll()
- */
-int
+int
espintr(sc)
register struct esp_softc *sc;
{
- struct espregs *espr = sc->sc_regs;
- register struct ecb *ecb = sc->sc_nexus;
+ register struct ecb *ecb;
register struct scsi_link *sc_link;
- u_char *cmd;
struct esp_tinfo *ti;
- int dmaintrwas, i;
+ int loop;
+ size_t size;
- /*
- * Revision 1 DMA's must have their interrupts disabled,
- * otherwise we can get bus timeouts while reading ESP
- * registers.
- */
- if (sc->sc_dma->sc_rev == DMAREV_1)
- dmaintrwas = dmadisintr(sc->sc_dma);
-
- espreadregs(sc);
+ ESP_TRACE(("[espintr]"));
/*
- * If either of these two things is true, we caused an interrupt.
- * If we didn't, let's get out of here.
+ * I have made some (maybe seriously flawed) assumptions here,
+ * but basic testing (uncomment the printf() below), show that
+ * certainly something happens when this loop is here.
+ *
+ * The idea is that many of the SCSI operations take very little
+ * time, and going away and getting interrupted is too high an
+ * overhead to pay. For example, selecting, sending a message
+ * and command and then doing some work can be done in one "pass".
+ *
+ * The DELAY is not variable because I do not understand that the
+ * DELAY loop should be fixed-time regardless of CPU speed, but
+ * I am *assuming* that the faster SCSI processors get things done
+ * quicker (sending a command byte etc), and so there is no
+ * need to be too slow.
+ *
+ * This is a heuristic. It is 2 when at 20Mhz, 2 at 25Mhz and 1
+ * at 40Mhz. This needs testing.
*/
- if ((sc->sc_espintr | dmapending(sc->sc_dma)) == 0) {
- if (sc->sc_dma->sc_rev == DMAREV_1 && dmaintrwas)
- dmaenintr(sc->sc_dma);
- return (0);
- }
+ for (loop = 0; 1;loop++, DELAY(50/sc->sc_freq)) {
+ /* a feeling of deja-vu */
+ if (!DMA_ISINTR(sc->sc_dma))
+ return (loop != 0);
+#if 0
+ if (loop)
+ printf("*");
+#endif
- sc->sc_phase = espphase(sc);
+ /* and what do the registers say... */
+ espreadregs(sc);
- ESPD(("I%02x/%02x/%02x ", sc->sc_espintr, sc->sc_state, sc->sc_phase));
+ sc->sc_intrcnt.ev_count++;
- if (sc->sc_espintr & ESPINTR_SBR) {
- espflush(sc);
- printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
- esp_init(sc, 0); /* Restart everything */
/*
- * No interrupt expected, since there are now no
- * ecb's in progress.
+ * At the moment, only a SCSI Bus Reset or Illegal
+ * Command are classed as errors. A disconnect is a
+ * valid condition, and we let the code check is the
+ * "ESP_BUSFREE_OK" flag was set before declaring it
+ * and error.
+ *
+ * Also, the status register tells us about "Gross
+ * Errors" and "Parity errors". Only the Gross Error
+ * is really bad, and the parity errors are dealt
+ * with later
+ *
+ * TODO
+ * If there are too many parity error, go to slow
+ * cable mode ?
*/
- goto done;
- }
- if (sc->sc_espintr & ESPINTR_ILL) {
- printf("%s: illegal command %02x\n",
- sc->sc_dev.dv_xname, espr->espr_cmd);
- if (sc->sc_state == ESPS_NEXUS) {
- ecb->xs->error = XS_DRIVER_STUFFUP;
- untimeout(esp_timeout, ecb);
- esp_done(ecb);
+ /* SCSI Reset */
+ if (sc->sc_espintr & ESPINTR_SBR) {
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+ if (sc->sc_state != ESP_SBR) {
+ printf("%s: SCSI bus reset\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 0); /* Restart everything */
+ return 1;
+ }
+#if 0
+ /*XXX*/ printf("<expected bus reset: "
+ "[intr %x, stat %x, step %d]>\n",
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+#endif
+ if (sc->sc_nexus)
+ panic("%s: nexus in reset state",
+ sc->sc_dev.dv_xname);
+ sc->sc_state = ESP_IDLE;
+ esp_sched(sc);
+ return 1;
}
- esp_reset(sc);
- esp_sched(sc); /* start next command */
- goto done;
- }
- if (sc->sc_espstat & ESPSTAT_GE) {
- /* no target ? */
- espflush(sc);
- printf("%s: gross error\n", sc->sc_dev.dv_xname);
- if (sc->sc_state == ESPS_NEXUS) {
- ecb->xs->error = XS_DRIVER_STUFFUP;
- untimeout(esp_timeout, ecb);
- esp_done(ecb);
- }
- esp_reset(sc);
- esp_sched(sc);
- /* started next command, which will interrupt us */
- goto done;
- }
+ ecb = sc->sc_nexus;
- /*
- * The `bad interrupts' have already been checked.
- */
-states:
- switch (sc->sc_state) {
- case ESPS_IDLE:
- ESPD(("I "));
+#define ESPINTR_ERR (ESPINTR_SBR|ESPINTR_ILL)
+ if (sc->sc_espintr & ESPINTR_ERR ||
+ sc->sc_espstat & ESPSTAT_GE) {
- sc->sc_nexus = NULL;
+ if (sc->sc_espstat & ESPSTAT_GE) {
+ /* no target ? */
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+ if (sc->sc_state == ESP_HASNEXUS ||
+ sc->sc_state == ESP_SELECTING) {
+ ecb->xs->error = XS_DRIVER_STUFFUP;
+ esp_done(ecb);
+ }
+ return 1;
+ }
- if (sc->sc_espintr & ESPINTR_RESEL) {
- sc->sc_state = ESPS_RESELECTED;
- goto states;
+ if (sc->sc_espintr & ESPINTR_ILL) {
+ /* illegal command, out of sync ? */
+ printf("%s: illegal command: 0x%x (state %d, phase %x, prevphase %x)\n",
+ sc->sc_dev.dv_xname, sc->sc_lastcmd,
+ sc->sc_state, sc->sc_phase,
+ sc->sc_prevphase);
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
+ esp_init(sc, 0); /* Restart everything */
+ return 1;
+ }
}
- esp_sched(sc);
/*
- * We will get an interrupt if esp_sched() queues
- * anything to the scsi bus.
+ * Call if DMA is active.
+ *
+ * If DMA_INTR returns true, then maybe go 'round the loop
+ * again in case there is no more DMA queued, but a phase
+ * change is expected.
*/
- goto done;
- case ESPS_SELECTING:
+ if (DMA_ISACTIVE(sc->sc_dma)) {
+ DMA_INTR(sc->sc_dma);
+ /* If DMA active here, then go back to work... */
+ if (DMA_ISACTIVE(sc->sc_dma))
+ return 1;
+
+ if (sc->sc_dleft == 0 &&
+ (sc->sc_espstat & ESPSTAT_TC) == 0)
+ printf("%s: !TC [intr %x, stat %x, step %d]"
+ " prevphase %x, resid %x\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr,
+ sc->sc_espstat,
+ sc->sc_espstep,
+ sc->sc_prevphase,
+ ecb?ecb->dleft:-1);
+ }
+
+#if 0 /* Unreliable on some ESP revisions? */
+ if ((sc->sc_espstat & ESPSTAT_INT) == 0) {
+ printf("%s: spurious interrupt\n", sc->sc_dev.dv_xname);
+ return 1;
+ }
+#endif
+
/*
- * For a simple select, we sent either
- * ESPCMD_SELATN or ESPCMD_SELNATN
+ * check for less serious errors
*/
- ESPD(("S "));
-
- if (sc->sc_espintr & ESPINTR_DIS) {
- sc->sc_state = ESPS_NEXUS; /* will cleanup */
- goto states;
+ if (sc->sc_espstat & ESPSTAT_PE) {
+ printf("%s: SCSI bus parity error\n",
+ sc->sc_dev.dv_xname);
+ if (sc->sc_prevphase == MESSAGE_IN_PHASE)
+ esp_sched_msgout(SEND_PARITY_ERROR);
+ else
+ esp_sched_msgout(SEND_INIT_DET_ERR);
}
- if (sc->sc_espintr & ESPINTR_RESEL) {
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ ESP_MISC(("<DISC [intr %x, stat %x, step %d]>",
+ sc->sc_espintr,sc->sc_espstat,sc->sc_espstep));
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ }
/*
- * If we were trying to select a target,
- * push our command back into the ready list.
+ * This command must (apparently) be issued within
+ * 250mS of a disconnect. So here you are...
*/
- if (sc->sc_state == ESPS_SELECTING) {
- TAILQ_INSERT_HEAD(&sc->ready_list,
- sc->sc_nexus, chain);
- ecb = sc->sc_nexus = NULL;
- }
- sc->sc_state = ESPS_RESELECTED;
- goto states;
- }
-
- if (sc->sc_espintr == (ESPINTR_FC|ESPINTR_BS)) {
- ESPD(("STEP%d ", sc->sc_espstep));
- if (sc->sc_espstep == 0) {
- /* ATN: cannot happen */
- /* NATN: target did not assert message phase */
- sc->sc_state = ESPS_IDLE;
- goto states;
- } else if (sc->sc_espstep == 2) {
- /* BOTH: target did not assert command phase */
- sc->sc_state = ESPS_IDLE;
- goto states;
- } else if (sc->sc_espstep == 3) {
- /* BOTH: changed phase during cmd transfer */
- ESPD(("FF%d ", espr->espr_fflag & ESPFIFO_FF));
- if (espr->espr_fflag & ESPFIFO_FF) {
- sc->sc_state = ESPS_IDLE;
- goto states;
+ ESPCMD(sc, ESPCMD_ENSEL);
+ if (sc->sc_state != ESP_IDLE) {
+ if ((sc->sc_flags & ESP_SYNCHNEGO)) {
+#ifdef ESP_DEBUG
+ if (ecb)
+ sc_print_addr(ecb->xs->sc_link);
+ printf("sync nego not completed!\n");
+#endif
+ sc->sc_flags &= ~ESP_SYNCHNEGO;
+ sc->sc_tinfo[ecb->xs->sc_link->target].offset = 0;
+ sc->sc_tinfo[ecb->xs->sc_link->target].flags &= ~T_NEGOTIATE;
+ }
+ /*XXX*/sc->sc_msgpriq = sc->sc_msgout = 0;
+
+ /* it may be OK to disconnect */
+ if (!(sc->sc_flags & ESP_BUSFREE_OK)) {
+ if (sc->sc_state == ESP_HASNEXUS) {
+ sc_print_addr(ecb->xs->sc_link);
+ printf("disconnect without"
+ "warning\n");
+ }
+ ecb->xs->error = XS_TIMEOUT;
+ } else if (sc->sc_flags & ESP_DISCON) {
+ TAILQ_INSERT_HEAD(&sc->nexus_list, ecb, chain);
+ ECB_SETQ(ecb, ECB_QNEXUS);
+ sc->sc_nexus = NULL;
+ sc->sc_flags &= ~ESP_DISCON;
+ sc->sc_state = ESP_IDLE;
+#if ESP_DEBUG
+if ((esp_debug & 0x10000) && ecb->dleft == 0) {
+ printf("%s: silly disconnect (ecb %p [stat %x])\n",
+ sc->sc_dev.dv_xname, ecb, ecb->stat);
+}
+#endif
+ esp_sched(sc);
+ return 1;
}
- }
- espr->espr_cmd = ESPCMD_NOP; /* unlatch fifo counter */
- if (sc->sc_phase != DATA_IN_PHASE &&
- sc->sc_tinfo[ecb->xs->sc_link->target].offset == 0) {
- DELAY(1);
- espflush(sc);
+ esp_done(ecb);
+ return 1;
}
+ printf("%s: DISCONNECT in IDLE state!\n",
+ sc->sc_dev.dv_xname);
+ }
- ecb = sc->sc_nexus;
- if (!ecb)
- panic("esp: not nexus at sc->sc_nexus");
- sc_link = ecb->xs->sc_link;
- ti = &sc->sc_tinfo[sc_link->target];
- sc->sc_flags = 0;
-
- /* Clearly we succeeded at sending the message */
+ /* did a message go out OK ? This must be broken */
+ if (sc->sc_prevphase == MESSAGE_OUT_PHASE &&
+ sc->sc_phase != MESSAGE_OUT_PHASE) {
+ /* we have sent it */
+ if (sc->sc_msgout == SEND_SDTR &&
+ (sc->sc_flags & ESP_SYNCHNEGO) == 0) {
+ /* We've just accepted new sync parameters */
+ sc->sc_tinfo[ecb->xs->sc_link->target].flags |=
+ T_SYNCMODE;
+if (ecb) sc_print_addr(ecb->xs->sc_link);else printf("NO nexus: ");
+printf("target put in SYNC mode\n");
+ }
sc->sc_msgpriq &= ~sc->sc_msgout;
sc->sc_msgout = 0;
- if (sc->sc_msgpriq)
- espr->espr_cmd = ESPCMD_SETATN;
-
- sc->sc_dp = ecb->daddr; /* implicit RESTOREDATAPOINTERS */
- sc->sc_dleft = ecb->dleft;
- ti->lubusy |= (1<<sc_link->lun);
-
- sc->sc_state = ESPS_NEXUS;
}
- break; /* handle the phase */
- case ESPS_SELECTSTOP:
- /*
- * We wanted to select with multiple message bytes.
- * As a result, we needed to use SELATNS. One
- * message byte has been sent at this point. We need
- * to send the other bytes, then the target will either
- * switch to command phase to fetch the command or
- * send us a message.
- */
- ESPD(("SS%d ", sc->sc_espstep));
- if (sc->sc_espintr & ESPINTR_DIS) {
- sc->sc_state = ESPS_NEXUS;
- goto states;
- }
+ switch (sc->sc_state) {
+
+ case ESP_SBR:
+ printf("%s: waiting for SCSI Bus Reset to happen\n",
+ sc->sc_dev.dv_xname);
+ return 1;
- if (sc->sc_espintr & ESPINTR_RESEL) {
+ case ESP_RESELECTED:
/*
- * If we were trying to select a target,
- * push our command back into the ready list.
+ * we must be continuing a message ?
*/
- if (sc->sc_state == ESPS_SELECTING) {
- TAILQ_INSERT_HEAD(&sc->ready_list,
- sc->sc_nexus, chain);
- ecb = sc->sc_nexus = NULL;
+ if (sc->sc_phase != MESSAGE_IN_PHASE) {
+ printf("%s: target didn't identify\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ return 1;
}
- sc->sc_state = ESPS_RESELECTED;
- goto states;
- }
+printf("<<RESELECT CONT'd>>");
+#if XXXX
+ esp_msgin(sc);
+ if (sc->sc_state != ESP_HASNEXUS) {
+ /* IDENTIFY fail?! */
+ printf("%s: identify failed\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ return 1;
+ }
+#endif
+ break;
- if (sc->sc_espintr & (ESPINTR_BS|ESPINTR_FC)) {
- int i;
+ case ESP_IDLE:
+if (sc->sc_flags & ESP_ICCS) printf("[[esp: BUMMER]]");
+ case ESP_SELECTING:
- /*
- * Shove the remainder of the message bytes
- * into the fifo. After we send them, command
- * phase will request the command...
- */
- espflush(sc);
- for (i = 1; i < sc->sc_omlen; i++)
- espr->espr_fifo = sc->sc_omp[i];
- espr->espr_cmd = ESPCMD_TRANS;
- sc->sc_state = ESPS_MULTMSGEND;
- goto done;
- }
- goto done;
- case ESPS_MULTMSGEND:
- ESPD(("MME "));
- if (sc->sc_espintr & ESPINTR_DIS) {
- sc->sc_state = ESPS_NEXUS;
- goto states;
- }
+ if (sc->sc_espintr & ESPINTR_RESEL) {
+ /*
+ * If we're trying to select a
+ * target ourselves, push our command
+ * back into the ready list.
+ */
+ if (sc->sc_state == ESP_SELECTING) {
+ ESP_MISC(("backoff selector "));
+ sc_link = sc->sc_nexus->xs->sc_link;
+ ti = &sc->sc_tinfo[sc_link->target];
+ TAILQ_INSERT_HEAD(&sc->ready_list,
+ sc->sc_nexus, chain);
+ ECB_SETQ(sc->sc_nexus, ECB_QREADY);
+ ti->lubusy &= ~(1<<sc_link->lun);
+ ecb = sc->sc_nexus = NULL;
+ }
+ sc->sc_state = ESP_RESELECTED;
+ if (sc->sc_phase != MESSAGE_IN_PHASE) {
+ /*
+ * Things are seriously fucked up.
+ * Pull the brakes, i.e. reset
+ */
+ printf("%s: target didn't identify\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ return 1;
+ }
+ if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) != 2) {
+ printf("%s: RESELECT: %d bytes in FIFO!\n",
+ sc->sc_dev.dv_xname,
+ ESP_READ_REG(sc, ESP_FFLAG) &
+ ESPFIFO_FF);
+ esp_init(sc, 1);
+ return 1;
+ }
+ sc->sc_selid = ESP_READ_REG(sc, ESP_FIFO);
+ sc->sc_selid &= ~(1<<sc->sc_id);
+ ESP_MISC(("selid=0x%2x ", sc->sc_selid));
+ esp_msgin(sc); /* Handle identify message */
+ if (sc->sc_state != ESP_HASNEXUS) {
+ /* IDENTIFY fail?! */
+ printf("%s: identify failed\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ return 1;
+ }
+ continue; /* ie. next phase expected soon */
+ }
- sc->sc_msgpriq &= ~sc->sc_msgout;
- sc->sc_msgout = 0;
+#define ESPINTR_DONE (ESPINTR_FC|ESPINTR_BS)
+ if ((sc->sc_espintr & ESPINTR_DONE) == ESPINTR_DONE) {
+ ecb = sc->sc_nexus;
+ if (!ecb)
+ panic("esp: not nexus at sc->sc_nexus");
- ESPD(("F%d ", espr->espr_fflag & ESPFIFO_FF));
- if (espr->espr_fflag & ESPFIFO_FF) {
- espflush(sc);
- DELAY(1);
- }
+ sc_link = ecb->xs->sc_link;
+ ti = &sc->sc_tinfo[sc_link->target];
+
+ switch (sc->sc_espstep) {
+ case 0:
+ printf("%s: select timeout/no disconnect\n",
+ sc->sc_dev.dv_xname);
+ esp_abort(sc, ecb);
+ return 1;
+ case 1:
+ if ((ti->flags & T_NEGOTIATE) == 0) {
+ printf("%s: step 1 & !NEG\n",
+ sc->sc_dev.dv_xname);
+ esp_abort(sc, ecb);
+ return 1;
+ }
+ if (sc->sc_phase != MESSAGE_OUT_PHASE) {
+ printf("%s: !MSGOUT\n",
+ sc->sc_dev.dv_xname);
+ esp_abort(sc, ecb);
+ return 1;
+ }
+ /* Start negotiating */
+ ti->period = sc->sc_minsync;
+ ti->offset = 15;
+ sc->sc_msgpriq = SEND_SDTR;
+ sc->sc_flags |= ESP_SYNCHNEGO;
+ break;
+ case 3:
+ /*
+ * Grr, this is supposed to mean
+ * "target left command phase
+ * prematurely". It seems to happen
+ * regularly when sync mode is on.
+ * Look at FIFO to see if command
+ * went out.
+ * (Timing problems?)
+ */
+ if ((ESP_READ_REG(sc, ESP_FFLAG)&ESPFIFO_FF) == 0) {
+ /* Hope for the best.. */
+ break;
+ }
+ printf("(%s:%d:%d): selection failed;"
+ " %d left in FIFO "
+ "[intr %x, stat %x, step %d]\n",
+ sc->sc_dev.dv_xname,
+ sc_link->target,
+ sc_link->lun,
+ ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ ESPCMD(sc, ESPCMD_FLUSH);
+ sc->sc_flags |= ESP_ABORTING;
+ esp_sched_msgout(SEND_ABORT);
+ return 1;
+ case 2:
+ /* Select stuck at Command Phase */
+ ESPCMD(sc, ESPCMD_FLUSH);
+ case 4:
+ /* So far, everything went fine */
+ sc->sc_msgpriq = 0;
+ break;
+ }
+#if 0
+/* Why set msgpriq? (and not raise ATN) */
+ if (ecb->xs->flags & SCSI_RESET)
+ sc->sc_msgpriq = SEND_DEV_RESET;
+ else if (ti->flags & T_NEGOTIATE)
+ sc->sc_msgpriq =
+ SEND_IDENTIFY | SEND_SDTR;
+ else
+ sc->sc_msgpriq = SEND_IDENTIFY;
+#endif
+ sc->sc_state = ESP_HASNEXUS;
+ /*???sc->sc_flags = 0; */
+ sc->sc_prevphase = INVALID_PHASE; /* ?? */
+ sc->sc_dp = ecb->daddr;
+ sc->sc_dleft = ecb->dleft;
+ ti->lubusy |= (1<<sc_link->lun);
+ break;
+ } else {
+ printf("%s: unexpected status after select"
+ ": [intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ ESPCMD(sc, ESPCMD_FLUSH);
+ DELAY(1);
+ esp_abort(sc, ecb);
+ }
+ if (sc->sc_state == ESP_IDLE) {
+ printf("%s: stray interrupt\n", sc->sc_dev.dv_xname);
+ return 0;
+ }
+ break;
- /*
- * If there are more messages, re-assert
- * ATN so that we will enter MSGOUT phase
- * again. Also, pause till that interrupt is
- * done to see if the phase changes.
- */
- if (sc->sc_msgpriq)
- espr->espr_cmd = ESPCMD_SETATN;
- sc->sc_state = ESPS_NEXUS;
- goto states;
- case ESPS_RESELECTED:
- ESPD(("RS "));
-
- if (sc->sc_phase != MESSAGE_IN_PHASE) {
- printf("%s: target didn't identify\n",
- sc->sc_dev.dv_xname);
- esp_init(sc, 1);
- goto done;
- }
- esp_msgin(sc);
- if (sc->sc_state != ESPS_NEXUS) {
- /* IDENTIFY failed?! */
- printf("%s: identify failed\n", sc->sc_dev.dv_xname);
- esp_init(sc, 1);
- goto done;
- }
+ case ESP_HASNEXUS:
+ if (sc->sc_flags & ESP_ICCS) {
+ unsigned char msg;
- /*
- * We will get an interrupt because of the ESPCMD_MSGOK
- * interrupt inside esp_msgin()
- */
- goto done;
- case ESPS_DOINGDMA:
- /*
- * Call if DMA is still active. If dmaintr() has finished,
- * delay a while to let things settle, and then re-read the
- * phase.
- *
- * XXX: should check ESPINTR_DIS
- */
- if (sc->sc_espstat & ESPSTAT_PE) {
- printf("%s: SCSI bus parity error\n",
- sc->sc_dev.dv_xname);
- esp_sched_msgout(SEND_INIT_DET_ERR);
- /* XXX: anything else to do? */
- }
+ sc->sc_flags &= ~ESP_ICCS;
- if (sc->sc_espintr & ESPINTR_BS) {
- /*
- * ESP says we have changed phase, or have
- * finished transferring all the bytes. It
- * doesn't matter which case, either way we
- * will let the phase determine what happens
- * next.
- */
- ESPD(("DOINGDMA:BS:%02x/%02x ", sc->sc_espstat,
- espr->espr_tcl));
- if (sc->sc_dma->sc_active) {
- dmaintr(sc->sc_dma, 0);
- if (sc->sc_dma->sc_active)
- goto done;
- }
- } else {
- ESPD(("DOINGDMA:cont "));
- if (sc->sc_dma->sc_active) {
- dmaintr(sc->sc_dma, 1);
- if (sc->sc_dma->sc_active)
- goto done;
+ if (!(sc->sc_espintr & ESPINTR_DONE)) {
+ printf("%s: ICCS: "
+ ": [intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ }
+ if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) != 2) {
+ printf("%s: ICCS: expected 2, got %d "
+ ": [intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ ESPCMD(sc, ESPCMD_FLUSH);
+ esp_abort(sc, ecb);
+ return 1;
+ }
+ ecb->stat = ESP_READ_REG(sc, ESP_FIFO);
+ msg = ESP_READ_REG(sc, ESP_FIFO);
+ ESP_PHASE(("<stat:(%x,%x)>", ecb->stat, msg));
+ if (msg == MSG_CMDCOMPLETE) {
+ sc->sc_flags |= ESP_BUSFREE_OK;
+ ecb->xs->resid = ecb->dleft = sc->sc_dleft;
+ } else
+ printf("%s: STATUS_PHASE: msg %d\n",
+ sc->sc_dev.dv_xname, msg);
+ ESPCMD(sc, ESPCMD_MSGOK);
+ continue; /* ie. wait for disconnect */
}
+ break;
+ default:
+ panic("%s: invalid state: %d",
+ sc->sc_dev.dv_xname,
+ sc->sc_state);
}
- /* finished a DMA transaction */
- sc->sc_flags = 0;
-
- ecb->daddr = sc->sc_dp; /* implicit SAVEDATAPOINTERS */
- ecb->dleft = sc->sc_dleft;
-
/*
- * ESP100 strangeness -- need to fetch a new phase --
- * why?
+ * Driver is now in state ESP_HASNEXUS, i.e. we
+ * have a current command working the SCSI bus.
*/
- if (sc->sc_rev==ESP100 &&
- sc->sc_tinfo[ecb->xs->sc_link->target].offset) {
- sc->sc_espstat = espr->espr_stat & ESPSTAT_PHASE;
- sc->sc_phase = espphase(sc);
- /* XXX should check if sync under/overran */
- }
- sc->sc_state = ESPS_NEXUS;
- break; /* handle the phase */
- case ESPS_DOINGMSGOUT:
- ESPD(("DMO "));
- if (sc->sc_espintr & ESPINTR_DIS) {
- sc->sc_state = ESPS_NEXUS; /* will cleanup */
- goto states;
+ if (sc->sc_state != ESP_HASNEXUS || ecb == NULL) {
+ panic("esp no nexus");
}
- if (sc->sc_espintr & ESPINTR_BS) {
- sc->sc_msgpriq &= ~sc->sc_msgout;
- sc->sc_msgout = 0;
+ switch (sc->sc_phase) {
+ case MESSAGE_OUT_PHASE:
+ ESP_PHASE(("MESSAGE_OUT_PHASE "));
+ esp_msgout(sc);
+ sc->sc_prevphase = MESSAGE_OUT_PHASE;
+ break;
+ case MESSAGE_IN_PHASE:
+ ESP_PHASE(("MESSAGE_IN_PHASE "));
+ if (sc->sc_espintr & ESPINTR_BS) {
+ ESPCMD(sc, ESPCMD_FLUSH);
+ sc->sc_flags |= ESP_WAITI;
+ ESPCMD(sc, ESPCMD_TRANS);
+ } else if (sc->sc_espintr & ESPINTR_FC) {
+ if ((sc->sc_flags & ESP_WAITI) == 0) {
+ printf("%s: MSGIN: unexpected FC bit: "
+ "[intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ }
+ sc->sc_flags &= ~ESP_WAITI;
+ esp_msgin(sc);
+ } else {
+ printf("%s: MSGIN: weird bits: "
+ "[intr %x, stat %x, step %x]\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_espintr, sc->sc_espstat,
+ sc->sc_espstep);
+ }
+ sc->sc_prevphase = MESSAGE_IN_PHASE;
+ break;
+ case COMMAND_PHASE: {
+ /* well, this means send the command again */
+ u_char *cmd = (u_char *)&ecb->cmd;
+ int i;
- ESPD(("F%d ", espr->espr_fflag & ESPFIFO_FF));
- if (espr->espr_fflag & ESPFIFO_FF) {
- espflush(sc);
+ ESP_PHASE(("COMMAND_PHASE 0x%02x (%d) ",
+ ecb->cmd.opcode, ecb->clen));
+ if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) {
+ ESPCMD(sc, ESPCMD_FLUSH);
DELAY(1);
}
-
- /*
- * If there are more messages, re-assert
- * ATN so that we will enter MSGOUT phase
- * again. Also, pause till that interrupt is
- * done to see if the phase changes.
- */
- if (sc->sc_msgpriq)
- espr->espr_cmd = ESPCMD_SETATN;
+ /* Now the command into the FIFO */
+ for (i = 0; i < ecb->clen; i++)
+ ESP_WRITE_REG(sc, ESP_FIFO, *cmd++);
+ ESPCMD(sc, ESPCMD_TRANS);
+ sc->sc_prevphase = COMMAND_PHASE;
+ }
break;
- }
-
-#if 0
- if (sc->sc_espintr & ESPINTR_FC) {
- /*
- * XXX: the book claims that an ESPINTR_BS is
- * generated, not ESPINTR_FC. Check if that is
- * true.
- */
- }
-#endif
- break; /* handle the phase */
- case ESPS_DOINGMSGIN:
- /*
- * We receive two interrupts per message byte here: one for
- * the MSGOK command in esp_msgin(), and one for the TRANS
- * command below.
- */
- ESPD(("DMI "));
-
- if (sc->sc_espintr & ESPINTR_DIS) {
- sc->sc_state = ESPS_NEXUS; /* will cleanup */
- goto states;
- }
-
- if (sc->sc_espstat & ESPSTAT_PE) {
- printf("%s: SCSI bus parity error\n",
- sc->sc_dev.dv_xname);
- esp_sched_msgout(SEND_PARITY_ERROR);
- espflush(sc);
- sc->sc_state = ESPS_NEXUS;
- /* XXX: are we missing some fifo handling? */
- goto done; /* will be interrupted for MSGOUT */
- }
+ case DATA_OUT_PHASE:
+ ESP_PHASE(("DATA_OUT_PHASE [%d] ", sc->sc_dleft));
+ ESPCMD(sc, ESPCMD_FLUSH);
+ size = min(sc->sc_dleft, sc->sc_maxxfer);
+ DMA_SETUP(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft,
+ 0, &size);
+ sc->sc_prevphase = DATA_OUT_PHASE;
+ goto setup_xfer;
+ case DATA_IN_PHASE:
+ ESP_PHASE(("DATA_IN_PHASE "));
+ if (sc->sc_rev == ESP100)
+ ESPCMD(sc, ESPCMD_FLUSH);
+ size = min(sc->sc_dleft, sc->sc_maxxfer);
+ DMA_SETUP(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft,
+ 1, &size);
+ sc->sc_prevphase = DATA_IN_PHASE;
+ setup_xfer:
+ /* Program the SCSI counter */
+ ESP_WRITE_REG(sc, ESP_TCL, size);
+ ESP_WRITE_REG(sc, ESP_TCM, size >> 8);
+ if (sc->sc_cfg2 & ESPCFG2_FE) {
+ ESP_WRITE_REG(sc, ESP_TCH, size >> 16);
+ }
+ /* load the count in */
+ ESPCMD(sc, ESPCMD_NOP|ESPCMD_DMA);
- /*
- * The two interrupts we receive per byte will alternate
- * between entering the following two if() statements.
- * XXX: just incase, are these two if()'s in the correct
- * order?
- */
- if (sc->sc_espintr & ESPINTR_BS) {
/*
- * interrupted by ESPCMD_MSGOK in esp_msgin()
+ * Note that if `size' is 0, we've already transceived
+ * all the bytes we want but we're still in DATA PHASE.
+ * Apparently, the device needs padding. Also, a
+ * transfer size of 0 means "maximum" to the chip
+ * DMA logic.
*/
- if (sc->sc_phase == MESSAGE_IN_PHASE)
- espr->espr_cmd = ESPCMD_TRANS;
- else {
- ESPD(("PC "));
- /*
- * XXX: The phase has been changed on us.
- * This should lead us to discard the
- * current (incomplete) message, perhaps
- * assert an error(?), and go handle whatever
- * new phase we are now in.
- */
- break;
+ ESPCMD(sc,
+ (size==0?ESPCMD_TRPAD:ESPCMD_TRANS)|ESPCMD_DMA);
+ DMA_GO(sc->sc_dma);
+ return 1;
+ case STATUS_PHASE:
+ ESP_PHASE(("STATUS_PHASE "));
+ sc->sc_flags |= ESP_ICCS;
+ ESPCMD(sc, ESPCMD_ICCS);
+ sc->sc_prevphase = STATUS_PHASE;
+ break;
+ case INVALID_PHASE:
+ break;
+ case BUSFREE_PHASE:
+ if (sc->sc_flags & ESP_BUSFREE_OK) {
+ /*It's fun the 1st time.. */
+ sc->sc_flags &= ~ESP_BUSFREE_OK;
}
- goto done;
- }
- if (sc->sc_espintr & ESPINTR_FC) {
- /*
- * interrupted by ESPCMD_TRANS a few lines above.
- */
- esp_msgin(sc);
- goto done;
+ break;
+ default:
+ panic("esp: bogus bus phase\n");
}
- goto done;
- case ESPS_DOINGSTATUS:
- if (sc->sc_espintr & ESPINTR_DIS) {
- sc->sc_state = ESPS_NEXUS; /* will cleanup */
- goto states;
+ }
+ panic("esp: should not get here..");
+}
+
+void
+esp_abort(sc, ecb)
+ struct esp_softc *sc;
+ struct ecb *ecb;
+{
+ if (ecb == sc->sc_nexus) {
+ if (sc->sc_state == ESP_HASNEXUS) {
+ sc->sc_flags |= ESP_ABORTING;
+ esp_sched_msgout(SEND_ABORT);
}
+ } else {
+ if (sc->sc_state == ESP_IDLE)
+ esp_sched(sc);
+ }
+}
- if (sc->sc_espintr & (ESPINTR_FC|ESPINTR_BS)) {
- i = espgetbyte(sc, 0);
- if (i == -1) {
- printf("%s: ESPS_DOINGSTATUS fifo empty\n",
- sc->sc_dev.dv_xname);
- /* XXX: how do we cleanup from this error? */
- goto done;
- }
- if (sc->sc_espstat & ESPSTAT_PE) {
- printf("%s: SCSI bus parity error\n",
- sc->sc_dev.dv_xname);
- /*
- * Can't tell what the real status should
- * be, so force a later check.
- */
- i = SCSI_CHECK;
- }
- ecb->stat = (u_char)i;
- ESPD(("status=%02x ", (u_char)i));
+void
+esp_timeout(arg)
+ void *arg;
+{
+ int s = splbio();
+ struct ecb *ecb = (struct ecb *)arg;
+ struct esp_softc *sc;
+ struct scsi_xfer *xs = ecb->xs;
- if (sc->sc_espintr & ESPINTR_FC) {
- /*
- * XXX assumes a single byte message --
- * and what about parity errors and other
- * possible botches inside esp_msgin?
- */
- esp_msgin(sc);
- sc->sc_state = ESPS_NEXUS;
- } else
- sc->sc_state = ESPS_DOINGMSGIN;
- goto done;
- }
- goto done;
- case ESPS_EXPECTDISC:
- /*
- * We were told to expect a disconnection interrupt.
- * When we get it, we can go back to other work.
- */
- ESPD(("ED "));
- if (sc->sc_espintr & ESPINTR_DIS) {
- espflush(sc);
- DELAY(1);
- espr->espr_cmd = ESPCMD_ENSEL; /* within 250ms of disconnect */
- sc->sc_state = ESPS_IDLE;
- }
- goto states;
- case ESPS_NEXUS:
- ESPD(("NX "));
+ sc = xs->sc_link->adapter_softc;
+ sc_print_addr(xs->sc_link);
+again:
+ printf("%s: timed out [ecb %p (flags 0x%x, dleft %x, stat %x)], "
+ "<state %d, nexus %p, phase(c %x, p %x), resid %x, msg(q %x,o %x) %s>",
+ sc->sc_dev.dv_xname,
+ ecb, ecb->flags, ecb->dleft, ecb->stat,
+ sc->sc_state, sc->sc_nexus, sc->sc_phase, sc->sc_prevphase,
+ sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout,
+ DMA_ISACTIVE(sc->sc_dma) ? "DMA active" : "");
+#if ESP_DEBUG > 0
+ printf("TRACE: %s.", ecb->trace);
+#endif
- if (sc->sc_espintr & ESPINTR_DIS) {
- espflush(sc);
- DELAY(1);
- espr->espr_cmd = ESPCMD_ENSEL; /* within 250ms of disconnect */
- sc->sc_msgpriq = sc->sc_msgout = 0;
-
- ESPD(("DD:"));
- if (ecb->flags & ECB_DONE) {
- ESPD(("D "));
- /* successfully finished a transaction */
- untimeout(esp_timeout, ecb);
- esp_done(ecb);
- } else if (sc->sc_flags & ESPF_MAYDISCON) {
- ESPD(("M "));
- /* legal discon/recon is happening */
- TAILQ_INSERT_HEAD(&sc->nexus_list,
- ecb, chain);
- sc->sc_nexus = NULL;
- sc->sc_state = ESPS_IDLE;
- sc->sc_flags &= ~ESPF_MAYDISCON;
- goto states;
- } else {
- ESPD(("U "));
- /* unexpected disconnection! fail. */
- ecb->xs->error = XS_TIMEOUT;
- untimeout(esp_timeout, ecb);
- esp_done(ecb);
+ if (ecb->flags & ECB_ABORTED) {
+ /* abort timed out */
+ printf(" AGAIN\n");
+ esp_init(sc, 1);
+ } else {
+ /* abort the operation that has timed out */
+ printf("\n");
+ xs->error = XS_TIMEOUT;
+ ecb->flags |= ECB_ABORTED;
+ esp_abort(sc, ecb);
+ /* 2 secs for the abort */
+ if ((xs->flags & SCSI_POLL) == 0)
+ timeout(esp_timeout, ecb, 2 * hz);
+ else {
+ int count = 200000;
+ while (count) {
+ if (DMA_ISINTR(sc->sc_dma)) {
+ espintr(sc);
+ }
+ if (xs->flags & ITSDONE)
+ break;
+ DELAY(10);
+ --count;
}
- goto done;
+ if (count == 0)
+ goto again;
}
- break; /* handle the phase */
- default:
- printf("%s: unknown state %d\n",
- sc->sc_dev.dv_xname, sc->sc_state);
- panic("cannot continue");
}
-
- ecb = sc->sc_nexus;
-
- switch (sc->sc_phase) {
- case MESSAGE_OUT_PHASE:
- /*
- * ATN was asserted, and the bus changed into MSGOUT phase.
- * Send a message.
- */
- esp_msgout(sc); /* cause intr */
- sc->sc_state = ESPS_DOINGMSGOUT;
- break;
- case COMMAND_PHASE:
- /*
- * Apparently we need to repeat the previous command.
- */
- espflush(sc);
- DELAY(1);
- cmd = (u_char *)&ecb->cmd;
-
- ESPD(("CMD["));
- for (i = 0; i < ecb->clen; i++)
- ESPD(("%02x%c", cmd[i],
- (i == ecb->clen-1) ? ']' : ' '));
- ESPD((" "));
-
- /* Now the command into the FIFO */
- for (i = 0; i < ecb->clen; i++)
- espr->espr_fifo = cmd[i];
-
- espr->espr_cmd = ESPCMD_TRANS; /* cause intr */
- sc->sc_state = ESPS_NEXUS;
- break;
- case DATA_OUT_PHASE:
- /*
- * We can feed the device the data now.
- */
- espflush(sc);
- DELAY(1);
- dmastart(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 0,
- ecb->xs->flags & SCSI_POLL); /* cause intr */
- sc->sc_state = ESPS_DOINGDMA;
- break;
- case DATA_IN_PHASE:
- /*
- * The device is ready to give us the data.
- */
- dmadrain(sc->sc_dma);
- dmastart(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 1,
- ecb->xs->flags & SCSI_POLL); /* cause intr */
- sc->sc_state = ESPS_DOINGDMA;
- break;
- case MESSAGE_IN_PHASE:
- espflush(sc);
- DELAY(1);
- espr->espr_cmd = ESPCMD_TRANS; /* cause intr */
- sc->sc_state = ESPS_DOINGMSGIN;
- break;
- case STATUS_PHASE:
- espflush(sc);
- DELAY(1);
- espr->espr_cmd = ESPCMD_ICCS; /* cause intr */
- sc->sc_state = ESPS_DOINGSTATUS;
- break;
- default:
- printf("%s: bogus bus phase %d\n",
- sc->sc_dev.dv_xname);
- break;
- }
-
-done:
- if (sc->sc_dma->sc_rev == DMAREV_1 && dmaintrwas)
- dmaenintr(sc->sc_dma);
- sc->sc_intrcnt.ev_count++;
- return (1);
+ splx(s);
}
diff --git a/sys/arch/sparc/dev/espreg.h b/sys/arch/sparc/dev/espreg.h
index 31db483c1bc..e08eebcad7c 100644
--- a/sys/arch/sparc/dev/espreg.h
+++ b/sys/arch/sparc/dev/espreg.h
@@ -1,9 +1,7 @@
-/* $NetBSD: espreg.h,v 1.5 1995/01/07 05:17:15 mycroft Exp $ */
+/* $NetBSD: espreg.h,v 1.7 1995/12/18 23:58:39 pk Exp $ */
/*
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
- * Copyright (c) 1995 Theo de Raadt. All rights reserved.
- *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -14,8 +12,7 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by Peter Galbavy and
- * Theo de Raadt
+ * This product includes software developed by Peter Galbavy.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -35,137 +32,117 @@
* Register addresses, relative to some base address
*/
-struct espregs {
- volatile u_char espr_tcl;
- volatile u_char x01;
- volatile u_char x02;
- volatile u_char x03;
- volatile u_char espr_tcm;
- volatile u_char x05;
- volatile u_char x06;
- volatile u_char x07;
- volatile u_char espr_fifo;
- volatile u_char x09;
- volatile u_char x0a;
- volatile u_char x0b;
- volatile u_char espr_cmd;
- volatile u_char x0d;
- volatile u_char x0e;
- volatile u_char x0f;
- volatile u_char espr_stat;
-#define espr_selid espr_stat
- volatile u_char x11;
- volatile u_char x12;
- volatile u_char x13;
- volatile u_char espr_intr;
-#define espr_timeout espr_intr
- volatile u_char x15;
- volatile u_char x16;
- volatile u_char x17;
- volatile u_char espr_step;
-#define espr_synctp espr_step
- volatile u_char x19;
- volatile u_char x1a;
- volatile u_char x1b;
- volatile u_char espr_fflag;
-#define espr_syncoff espr_fflag
- volatile u_char x1d;
- volatile u_char x1e;
- volatile u_char x1f;
- volatile u_char espr_cfg1;
- volatile u_char x21;
- volatile u_char x22;
- volatile u_char x23;
- volatile u_char espr_ccf;
- volatile u_char x25;
- volatile u_char x26;
- volatile u_char x27;
- volatile u_char espr_test;
- volatile u_char x29;
- volatile u_char x2a;
- volatile u_char x2b;
- volatile u_char espr_cfg2;
- volatile u_char x2d;
- volatile u_char x2e;
- volatile u_char x2f;
- volatile u_char espr_cfg3; /* ESP200 only */
- volatile u_char x31;
- volatile u_char x32;
- volatile u_char x33;
- volatile u_char espr_tch; /* ESP200 only */
-};
-
-#define ESPCMD_DMA 0x80 /* DMA Bit */
-#define ESPCMD_NOP 0x00 /* No Operation */
-#define ESPCMD_FLUSH 0x01 /* Flush FIFO */
-#define ESPCMD_RSTCHIP 0x02 /* Reset Chip */
-#define ESPCMD_RSTSCSI 0x03 /* Reset SCSI Bus */
-#define ESPCMD_RESEL 0x40 /* Reselect Sequence */
-#define ESPCMD_SELNATN 0x41 /* Select without ATN */
-#define ESPCMD_SELATN 0x42 /* Select with ATN */
-#define ESPCMD_SELATNS 0x43 /* Select with ATN & Stop */
-#define ESPCMD_ENSEL 0x44 /* Enable (Re)Selection */
-#define ESPCMD_DISSEL 0x45 /* Disable (Re)Selection */
-#define ESPCMD_SELATN3 0x46 /* Select with ATN3 */
-#define ESPCMD_RESEL3 0x47 /* Reselect3 Sequence */
-#define ESPCMD_SNDMSG 0x20 /* Send Message */
-#define ESPCMD_SNDSTAT 0x21 /* Send Status */
-#define ESPCMD_SNDDATA 0x22 /* Send Data */
-#define ESPCMD_DISCSEQ 0x23 /* Disconnect Sequence */
-#define ESPCMD_TERMSEQ 0x24 /* Terminate Sequence */
-#define ESPCMD_TCCS 0x25 /* Target Command Comp Seq */
-#define ESPCMD_DISC 0x27 /* Disconnect */
-#define ESPCMD_RECMSG 0x28 /* Receive Message */
-#define ESPCMD_RECCMD 0x29 /* Receive Command */
-#define ESPCMD_RECDATA 0x2a /* Receive Data */
-#define ESPCMD_RECCSEQ 0x2b /* Receive Command Sequence*/
-#define ESPCMD_ABORT 0x04 /* Target Abort DMA */
-#define ESPCMD_TRANS 0x10 /* Transfer Information */
-#define ESPCMD_ICCS 0x11 /* Initiator Cmd Comp Seq */
-#define ESPCMD_MSGOK 0x12 /* Message Accepted */
-#define ESPCMD_TRPAD 0x18 /* Transfer Pad */
-#define ESPCMD_SETATN 0x1a /* Set ATN */
-#define ESPCMD_RSTATN 0x1b /* Reset ATN */
-
-#define ESPSTAT_INT 0x80 /* Interrupt */
-#define ESPSTAT_GE 0x40 /* Gross Error */
-#define ESPSTAT_PE 0x20 /* Parity Error */
-#define ESPSTAT_TC 0x10 /* Terminal Count */
-#define ESPSTAT_VGC 0x08 /* Valid Group Code */
-#define ESPSTAT_PHASE 0x07 /* Phase bits */
-
-#define ESPINTR_SBR 0x80 /* SCSI Bus Reset */
-#define ESPINTR_ILL 0x40 /* Illegal Command */
-#define ESPINTR_DIS 0x20 /* Disconnect */
-#define ESPINTR_BS 0x10 /* Bus Service */
-#define ESPINTR_FC 0x08 /* Function Complete */
-#define ESPINTR_RESEL 0x04 /* Reselected */
-#define ESPINTR_SELATN 0x02 /* Select with ATN */
-#define ESPINTR_SEL 0x01 /* Selected */
-
-#define ESPSTEP_MASK 0x07 /* the last 3 bits */
-#define ESPSTEP_DONE 0x04 /* command went out */
-
-#define ESPFIFO_SS 0xe0 /* Sequence Step (Dup) */
-#define ESPFIFO_FF 0x1f /* Bytes in FIFO */
-
-#define ESPCFG1_SLOW 0x80 /* Slow Cable Mode */
-#define ESPCFG1_SRR 0x40 /* SCSI Reset Rep Int Dis */
-#define ESPCFG1_PTEST 0x20 /* Parity Test Mod */
-#define ESPCFG1_PARENB 0x10 /* Enable Parity Check */
-#define ESPCFG1_CTEST 0x08 /* Enable Chip Test */
-#define ESPCFG1_BUSID 0x07 /* Bus ID */
-
-#define ESPCFG2_RSVD 0xe0 /* reserved */
-#define ESPCFG2_FE 0x40 /* Features Enable */
-#define ESPCFG2_DREQ 0x10 /* DREQ High Impedance */
-#define ESPCFG2_SCSI2 0x08 /* SCSI-2 Enable */
-#define ESPCFG2_BPA 0x04 /* Target Bad Parity Abort */
-#define ESPCFG2_RPE 0x02 /* Register Parity Error */
-#define ESPCFG2_DPE 0x01 /* DMA Parity Error */
-
-#define ESPCFG3_IDM 0x10 /* ID Message Res Check */
-#define ESPCFG3_QTE 0x08 /* Queue Tag Enable */
-#define ESPCFG3_CDB 0x04 /* CDB 10-bytes OK */
-#define ESPCFG3_FSCSI 0x02 /* Fast SCSI */
-#define ESPCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */
+#define ESP_TCL 0x00 /* RW - Transfer Count Low */
+#define ESP_TCM 0x01 /* RW - Transfer Count Mid */
+#define ESP_TCH 0x0e /* RW - Transfer Count High */
+ /* NOT on 53C90 */
+
+#define ESP_FIFO 0x02 /* RW - FIFO data */
+
+#define ESP_CMD 0x03 /* RW - Command (2 deep) */
+#define ESPCMD_DMA 0x80 /* DMA Bit */
+#define ESPCMD_NOP 0x00 /* No Operation */
+#define ESPCMD_FLUSH 0x01 /* Flush FIFO */
+#define ESPCMD_RSTCHIP 0x02 /* Reset Chip */
+#define ESPCMD_RSTSCSI 0x03 /* Reset SCSI Bus */
+#define ESPCMD_RESEL 0x40 /* Reselect Sequence */
+#define ESPCMD_SELNATN 0x41 /* Select without ATN */
+#define ESPCMD_SELATN 0x42 /* Select with ATN */
+#define ESPCMD_SELATNS 0x43 /* Select with ATN & Stop */
+#define ESPCMD_ENSEL 0x44 /* Enable (Re)Selection */
+#define ESPCMD_DISSEL 0x45 /* Disable (Re)Selection */
+#define ESPCMD_SELATN3 0x46 /* Select with ATN3 */
+#define ESPCMD_RESEL3 0x47 /* Reselect3 Sequence */
+#define ESPCMD_SNDMSG 0x20 /* Send Message */
+#define ESPCMD_SNDSTAT 0x21 /* Send Status */
+#define ESPCMD_SNDDATA 0x22 /* Send Data */
+#define ESPCMD_DISCSEQ 0x23 /* Disconnect Sequence */
+#define ESPCMD_TERMSEQ 0x24 /* Terminate Sequence */
+#define ESPCMD_TCCS 0x25 /* Target Command Comp Seq */
+#define ESPCMD_DISC 0x27 /* Disconnect */
+#define ESPCMD_RECMSG 0x28 /* Receive Message */
+#define ESPCMD_RECCMD 0x29 /* Receive Command */
+#define ESPCMD_RECDATA 0x2a /* Receive Data */
+#define ESPCMD_RECCSEQ 0x2b /* Receive Command Sequence*/
+#define ESPCMD_ABORT 0x04 /* Target Abort DMA */
+#define ESPCMD_TRANS 0x10 /* Transfer Information */
+#define ESPCMD_ICCS 0x11 /* Initiator Cmd Comp Seq */
+#define ESPCMD_MSGOK 0x12 /* Message Accepted */
+#define ESPCMD_TRPAD 0x18 /* Transfer Pad */
+#define ESPCMD_SETATN 0x1a /* Set ATN */
+#define ESPCMD_RSTATN 0x1b /* Reset ATN */
+
+#define ESP_STAT 0x04 /* RO - Status */
+#define ESPSTAT_INT 0x80 /* Interrupt */
+#define ESPSTAT_GE 0x40 /* Gross Error */
+#define ESPSTAT_PE 0x20 /* Parity Error */
+#define ESPSTAT_TC 0x10 /* Terminal Count */
+#define ESPSTAT_VGC 0x08 /* Valid Group Code */
+#define ESPSTAT_PHASE 0x07 /* Phase bits */
+
+#define ESP_SELID 0x04 /* WO - Select/Reselect Bus ID */
+
+#define ESP_INTR 0x05 /* RO - Interrupt */
+#define ESPINTR_SBR 0x80 /* SCSI Bus Reset */
+#define ESPINTR_ILL 0x40 /* Illegal Command */
+#define ESPINTR_DIS 0x20 /* Disconnect */
+#define ESPINTR_BS 0x10 /* Bus Service */
+#define ESPINTR_FC 0x08 /* Function Complete */
+#define ESPINTR_RESEL 0x04 /* Reselected */
+#define ESPINTR_SELATN 0x02 /* Select with ATN */
+#define ESPINTR_SEL 0x01 /* Selected */
+
+#define ESP_TIMEOUT 0x05 /* WO - Select/Reselect Timeout */
+
+#define ESP_STEP 0x06 /* RO - Sequence Step */
+#define ESPSTEP_MASK 0x07 /* the last 3 bits */
+#define ESPSTEP_DONE 0x04 /* command went out */
+
+#define ESP_SYNCTP 0x06 /* WO - Synch Transfer Period */
+ /* Default 5 (53C9X) */
+
+#define ESP_FFLAG 0x07 /* RO - FIFO Flags */
+#define ESPFIFO_SS 0xe0 /* Sequence Step (Dup) */
+#define ESPFIFO_FF 0x1f /* Bytes in FIFO */
+
+#define ESP_SYNCOFF 0x07 /* WO - Synch Offset */
+ /* 0 = ASYNC */
+ /* 1 - 15 = SYNC bytes */
+
+#define ESP_CFG1 0x08 /* RW - Configuration #1 */
+#define ESPCFG1_SLOW 0x80 /* Slow Cable Mode */
+#define ESPCFG1_SRR 0x40 /* SCSI Reset Rep Int Dis */
+#define ESPCFG1_PTEST 0x20 /* Parity Test Mod */
+#define ESPCFG1_PARENB 0x10 /* Enable Parity Check */
+#define ESPCFG1_CTEST 0x08 /* Enable Chip Test */
+#define ESPCFG1_BUSID 0x07 /* Bus ID */
+
+#define ESP_CCF 0x09 /* WO - Clock Conversion Factor */
+ /* 0 = 35.01 - 40Mhz */
+ /* NEVER SET TO 1 */
+ /* 2 = 10Mhz */
+ /* 3 = 10.01 - 15Mhz */
+ /* 4 = 15.01 - 20Mhz */
+ /* 5 = 20.01 - 25Mhz */
+ /* 6 = 25.01 - 30Mhz */
+ /* 7 = 30.01 - 35Mhz */
+
+#define ESP_TEST 0x0a /* WO - Test (Chip Test Only) */
+
+#define ESP_CFG2 0x0b /* RW - Configuration #2 */
+#define ESPCFG2_RSVD 0xa0 /* reserved */
+#define ESPCFG2_FE 0x40 /* Features Enable */
+#define ESPCFG2_DREQ 0x10 /* DREQ High Impedance */
+#define ESPCFG2_SCSI2 0x08 /* SCSI-2 Enable */
+#define ESPCFG2_BPA 0x04 /* Target Bad Parity Abort */
+#define ESPCFG2_RPE 0x02 /* Register Parity Error */
+#define ESPCFG2_DPE 0x01 /* DMA Parity Error */
+
+/* Config #3 only on 53C9X */
+#define ESP_CFG3 0x0c /* RW - Configuration #3 */
+#define ESPCFG3_RSVD 0xe0 /* reserved */
+#define ESPCFG3_IDM 0x10 /* ID Message Res Check */
+#define ESPCFG3_QTE 0x08 /* Queue Tag Enable */
+#define ESPCFG3_CDB 0x04 /* CDB 10-bytes OK */
+#define ESPCFG3_FSCSI 0x02 /* Fast SCSI */
+#define ESPCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */
diff --git a/sys/arch/sparc/dev/espvar.h b/sys/arch/sparc/dev/espvar.h
index c8592af5b29..8b0b414a08a 100644
--- a/sys/arch/sparc/dev/espvar.h
+++ b/sys/arch/sparc/dev/espvar.h
@@ -1,37 +1,7 @@
-/* $NetBSD: espvar.h,v 1.3 1994/11/20 20:52:12 deraadt Exp $ */
+/* $NetBSD: espvar.h,v 1.13 1996/05/16 20:31:30 pk Exp $ */
/*
- * Copyright (c) 1995 Theo de Raadt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed under OpenBSD by
- * Theo de Raadt.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
- *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -58,82 +28,103 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* esp chip revisions */
-#define ESP100 0
-#define ESP100A 1
-#define ESP200 2
-
-/* Grabbed from Julians SCSI aha-drivers */
-#ifdef DDB
-int Debugger();
-#else DDB
-#define Debugger() panic("should call debugger here (esp.c)")
-#endif DDB
-
-#define ESP_MSGLEN_MAX 8 /* maximum msglen we handle */
-#define ESP_SYNC_REQOFF 0 /* offset we request */
-#define ESP_SYNC_MAXOFF 15 /* maximum supportable sync offset */
-#if ESP_SYNC_REQOFF > ESP_SYNC_MAXOFF
-#warning requested sync offset is higher than maximum possible sync offset.
-#endif
+#define ESP_DEBUG 0
#define FREQTOCCF(freq) (((freq + 4) / 5))
-/*
- * ECB. Holds additional information for each SCSI command
- * Comments: We need a separate scsi command block because we may need
- * to overwrite it with a request sense command. Basically, we refrain
- * from fiddling with the scsi_xfer struct (except do the expected
- * updating of return values). We'll generally update:
- * xs->{flags,resid,error,sense,status} and occasionally xs->retries.
+/* esp revisions */
+#define ESP100 0x01
+#define ESP100A 0x02
+#define ESP200 0x03
+
+#if 0
+typedef caddr_t physaddr;
+
+struct esp_dma_seg {
+ physaddr addr;
+ long len;
+};
+#endif
+
+/*
+ * ECB. Holds additional information for each SCSI command Comments: We
+ * need a separate scsi command block because we may need to overwrite it
+ * with a request sense command. Basicly, we refrain from fiddling with
+ * the scsi_xfer struct (except do the expected updating of return values).
+ * We'll generally update: xs->{flags,resid,error,sense,status} and
+ * occasionally xs->retries.
*/
struct ecb {
TAILQ_ENTRY(ecb) chain;
- struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
- int flags; /* Status */
-#define ECB_FREE 0x00
-#define ECB_ACTIVE 0x01
-#define ECB_DONE 0x04
+ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+ int flags; /* Status */
+#define ECB_QNONE 0
+#define ECB_QFREE 1
+#define ECB_QREADY 2
+#define ECB_QNEXUS 3
+#define ECB_QBITS 0x07
#define ECB_CHKSENSE 0x08
- struct scsi_generic cmd; /* SCSI command block */
- int clen;
- caddr_t daddr; /* Saved data pointer */
- int dleft; /* Residue */
- int stat; /* SCSI status byte */
+#define ECB_ABORTED 0x10
+#define ECB_SETQ(e, q) do (e)->flags = ((e)->flags&~ECB_QBITS)|(q); while(0)
+ struct scsi_generic cmd; /* SCSI command block */
+ int clen;
+ char *daddr; /* Saved data pointer */
+ int dleft; /* Residue */
+ u_char stat; /* SCSI status byte */
+#if ESP_DEBUG > 0
+ char trace[1000];
+#endif
};
+#if ESP_DEBUG > 0
+#define ECB_TRACE(ecb, msg, a, b) do { \
+ const char *f = "[" msg "]"; \
+ int n = strlen((ecb)->trace); \
+ if (n < (sizeof((ecb)->trace)-100)) \
+ sprintf((ecb)->trace + n, f, a, b); \
+} while(0)
+#else
+#define ECB_TRACE(ecb, msg, a, b)
+#endif
-/*
- * Some info about each (possible) target on the SCSI bus. This should
- * probably have been a "per target+lunit" structure, but we'll leave it at
+/*
+ * Some info about each (possible) target on the SCSI bus. This should
+ * probably have been a "per target+lunit" structure, but we'll leave it at
* this for now. Is there a way to reliably hook it up to sc->fordriver??
*/
struct esp_tinfo {
- int cmds; /* #commands processed */
- int dconns; /* #disconnects */
- int touts; /* #timeouts */
- int perrs; /* #parity errors */
- int senses; /* #request sense commands sent */
- u_char lubusy; /* What luns are busy? */
- u_char flags;
-#define DO_NEGOTIATE 0x01 /* (re)negotiate synchronous options */
-#define TARGET_BUSY 0x02 /* target is busy, i.e. cmd in progress */
- u_char period; /* sync period */
- u_char synctp; /* sync period translated for SYNCTP */
- u_char offset; /* sync offset */
-};
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int touts; /* #timeouts */
+ int perrs; /* #parity errors */
+ int senses; /* #request sense commands sent */
+ ushort lubusy; /* What local units/subr. are busy? */
+ u_char flags;
+#define T_NEED_TO_RESET 0x01 /* Should send a BUS_DEV_RESET */
+#define T_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */
+#define T_BUSY 0x04 /* Target is busy, i.e. cmd in progress */
+#define T_SYNCMODE 0x08 /* sync mode has been negotiated */
+#define T_SYNCHOFF 0x10 /* .. */
+#define T_RSELECTOFF 0x20 /* .. */
+ u_char period; /* Period suggestion */
+ u_char offset; /* Offset suggestion */
+} tinfo_t;
/* Register a linenumber (for debugging) */
#define LOGLINE(p)
-#define ESP_SHOWECBS 0x01
-#define ESP_SHOWINTS 0x02
-#define ESP_SHOWCMDS 0x04
-#define ESP_SHOWMISC 0x08
-#define ESP_SHOWTRAC 0x10
-#define ESP_SHOWSTART 0x20
-#define ESP_SHOWPHASE 0x40
+#define ESP_SHOWECBS 0x01
+#define ESP_SHOWINTS 0x02
+#define ESP_SHOWCMDS 0x04
+#define ESP_SHOWMISC 0x08
+#define ESP_SHOWTRAC 0x10
+#define ESP_SHOWSTART 0x20
+#define ESP_SHOWPHASE 0x40
+#define ESP_SHOWDMA 0x80
+#define ESP_SHOWCCMDS 0x100
+#define ESP_SHOWMSGS 0x200
-#if ESP_DEBUG
+#ifdef ESP_DEBUG
+extern int esp_debug;
#define ESP_ECBS(str) do {if (esp_debug & ESP_SHOWECBS) printf str;} while (0)
#define ESP_MISC(str) do {if (esp_debug & ESP_SHOWMISC) printf str;} while (0)
#define ESP_INTS(str) do {if (esp_debug & ESP_SHOWINTS) printf str;} while (0)
@@ -141,6 +132,8 @@ struct esp_tinfo {
#define ESP_CMDS(str) do {if (esp_debug & ESP_SHOWCMDS) printf str;} while (0)
#define ESP_START(str) do {if (esp_debug & ESP_SHOWSTART) printf str;}while (0)
#define ESP_PHASE(str) do {if (esp_debug & ESP_SHOWPHASE) printf str;}while (0)
+#define ESP_DMA(str) do {if (esp_debug & ESP_SHOWDMA) printf str;}while (0)
+#define ESP_MSGS(str) do {if (esp_debug & ESP_SHOWMSGS) printf str;}while (0)
#else
#define ESP_ECBS(str)
#define ESP_MISC(str)
@@ -149,85 +142,104 @@ struct esp_tinfo {
#define ESP_CMDS(str)
#define ESP_START(str)
#define ESP_PHASE(str)
+#define ESP_DMA(str)
#endif
+#define ESP_MAX_MSG_LEN 8
+
struct esp_softc {
- struct device sc_dev;
- struct sbusdev sc_sd; /* sbus device */
- struct intrhand sc_ih; /* intr handler */
- struct evcnt sc_intrcnt; /* intr count */
- struct scsi_link sc_link; /* scsi lint struct */
- struct espregs *sc_regs; /* the registers */
- struct dma_softc *sc_dma; /* corresponding DMA ctrlr */
+ struct device sc_dev; /* us as a device */
+ struct sbusdev sc_sd; /* sbus device */
+ struct intrhand sc_ih; /* intr handler */
+ struct evcnt sc_intrcnt; /* intr count */
+ struct scsi_link sc_link; /* scsi lint struct */
+ volatile u_char *sc_reg; /* the registers */
+ struct dma_softc *sc_dma; /* pointer to my dma */
/* register defaults */
- u_char sc_cfg1; /* config 1 */
- u_char sc_cfg2; /* config 2, only ESP100A/200 */
- u_char sc_cfg3; /* config 3, only ESP200 */
- u_char sc_ccf; /* clock conversion */
+ u_char sc_cfg1; /* Config 1 */
+ u_char sc_cfg2; /* Config 2, not ESP100 */
+ u_char sc_cfg3; /* Config 3, only ESP200 */
+ u_char sc_ccf; /* Clock Conversion */
u_char sc_timeout;
- u_char sc_espintr; /* copies of registers */
+ /* register copies, see espreadregs() */
+ u_char sc_espintr;
u_char sc_espstat;
u_char sc_espstep;
u_char sc_espfflags;
- struct bootpath *sc_bp; /* current boot path component */
-
/* Lists of command blocks */
- TAILQ_HEAD(ecb_list, ecb) free_list, ready_list, nexus_list;
+ TAILQ_HEAD(ecb_list, ecb) free_list,
+ ready_list,
+ nexus_list;
- struct ecb *sc_nexus; /* current command */
- struct ecb sc_ecb[8]; /* one per target */
- struct esp_tinfo sc_tinfo[8];
+ struct ecb *sc_nexus; /* current command */
+ struct ecb sc_ecb[8]; /* one per target */
+ struct esp_tinfo sc_tinfo[8];
- /* data about the current nexus (updated for every cmd switch) */
- caddr_t sc_dp; /* current data pointer */
- size_t sc_dleft; /* data left to transfer */
+ /* Data about the current nexus (updated for every cmd switch) */
+ caddr_t sc_dp; /* Current data pointer */
+ ssize_t sc_dleft; /* Data left to transfer */
- /* adapter state */
- int sc_phase; /* bus phase (based on sc_espstat) */
- u_char sc_state; /* state applicable to the adapter */
+ /* Adapter state */
+ int sc_phase; /* Copy of what bus phase we are in */
+ int sc_prevphase; /* Copy of what bus phase we were in */
+ u_char sc_state; /* State applicable to the adapter */
u_char sc_flags;
u_char sc_selid;
+ u_char sc_lastcmd;
- /* message stuff */
- u_char sc_msgpriq; /* messages to send (see SEND_* below) */
- u_char sc_msgout; /* message that is on it's way out */
- u_char sc_omess[ESP_MSGLEN_MAX];
- u_char *sc_omp; /* message pointer (for multibyte messages) */
+ /* Message stuff */
+ u_char sc_msgpriq; /* One or more messages to send (encoded) */
+ u_char sc_msgout; /* What message is on its way out? */
+ u_char sc_omess[ESP_MAX_MSG_LEN];
+ caddr_t sc_omp; /* Message pointer (for multibyte messages) */
size_t sc_omlen;
- u_char sc_imess[ESP_MSGLEN_MAX + 1];
- u_char *sc_imp; /* message pointer (for multibyte messages) */
+ u_char sc_imess[ESP_MAX_MSG_LEN + 1];
+ caddr_t sc_imp; /* Message pointer (for multibyte messages) */
size_t sc_imlen;
/* hardware/openprom stuff */
- int sc_node; /* PROM node ID */
- int sc_freq; /* Freq in HZ */
- int sc_pri; /* SBUS priority */
- int sc_id; /* our scsi id */
- int sc_rev; /* esp revision */
- int sc_minsync; /* minimum sync period / 4 */
+ int sc_node; /* PROM node ID */
+ int sc_freq; /* Freq in HZ */
+ int sc_pri; /* SBUS priority */
+ int sc_id; /* our scsi id */
+ int sc_rev; /* esp revision */
+ int sc_minsync; /* minimum sync period / 4 */
+ int sc_maxxfer; /* maximum transfer size */
};
+/*
+ * Macros to read and write the chip's registers.
+ */
+#define ESP_READ_REG(sc, reg) \
+ ((sc)->sc_reg[(reg) * 4])
+#define ESP_WRITE_REG(sc, reg, val) \
+ do { \
+ u_char v = (val); \
+ (sc)->sc_reg[(reg) * 4] = v; \
+ } while (0)
+
/* values for sc_state */
-#define ESPS_IDLE 0x01 /* waiting for something to do */
-#define ESPS_EXPECTDISC 0x02 /* a disconnect is going to happen */
-#define ESPS_SELECTING 0x03 /* SCSI command is arbiting */
-#define ESPS_RESELECTED 0x04 /* has been reselected */
-#define ESPS_NEXUS 0x05 /* actively using the SCSI bus */
-#define ESPS_DOINGDMA 0x06 /* doing a DMA transaction */
-#define ESPS_DOINGMSGOUT 0x07 /* message-out in progress */
-#define ESPS_DOINGMSGIN 0x08 /* message-in in progress */
-#define ESPS_DOINGSTATUS 0x09 /* status-in in progress */
-#define ESPS_SELECTSTOP 0x0a /* sent first byte of message.. */
-#define ESPS_MULTMSGEND 0x0b /* done sending multibyte msg */
+#define ESP_IDLE 0x01 /* waiting for something to do */
+#define ESP_TMP_UNAVAIL 0x02 /* Don't accept SCSI commands */
+#define ESP_SELECTING 0x03 /* SCSI command is arbiting */
+#define ESP_RESELECTED 0x04 /* Has been reselected */
+#define ESP_HASNEXUS 0x05 /* Actively using the SCSI bus */
+#define ESP_CLEANING 0x06
+#define ESP_SBR 0x07 /* Expect a SCSI RST because we commanded it */
/* values for sc_flags */
-#define ESPF_DROP_MSGI 0x01 /* Discard all msgs (parity err detected) */
-#define ESPF_MAYDISCON 0x02 /* disconnection allowed */
-#define ESPF_DONE 0x04 /* finished transaction */
-#define ESPF_SYNCHNEGO 0x08 /* Synch negotiation in progress. */
+#define ESP_DROP_MSGI 0x01 /* Discard all msgs (parity err detected) */
+#define ESP_DOINGDMA 0x02 /* The FIFO data path is active! */
+#define ESP_BUSFREE_OK 0x04 /* Bus free phase is OK. */
+#define ESP_SYNCHNEGO 0x08 /* Synch negotiation in progress. */
+/*#define ESP_BLOCKED 0x10 * Don't schedule new scsi bus operations */
+#define ESP_DISCON 0x10 /* Target sent DISCONNECT msg */
+#define ESP_ABORTING 0x20 /* Bailing out */
+#define ESP_ICCS 0x40 /* Expect status phase results */
+#define ESP_WAITI 0x80 /* Waiting for non-DMA data to arrive */
/* values for sc_msgout */
#define SEND_DEV_RESET 0x01
@@ -238,14 +250,25 @@ struct esp_softc {
#define SEND_IDENTIFY 0x20
#define SEND_SDTR 0x40
-#define ST_MASK 0x3e /* bits 0, 6, and 7 are reserved */
+/* SCSI Status codes */
+#define ST_GOOD 0x00
+#define ST_CHKCOND 0x02
+#define ST_CONDMET 0x04
+#define ST_BUSY 0x08
+#define ST_INTERMED 0x10
+#define ST_INTERMED_CONDMET 0x14
+#define ST_RESERVATION_CONFLICT 0x18
+#define ST_CMD_TERM 0x22
+#define ST_QUEUE_FULL 0x28
-/* physical phase bits */
+#define ST_MASK 0x3e /* bit 0,6,7 is reserved */
+
+/* phase bits */
#define IOI 0x01
#define CDI 0x02
#define MSGI 0x04
-/* values for sc_phase (where information transfer happens) */
+/* Information transfer phases */
#define DATA_OUT_PHASE (0)
#define DATA_IN_PHASE (IOI)
#define COMMAND_PHASE (CDI)
@@ -255,5 +278,23 @@ struct esp_softc {
#define PHASE_MASK (MSGI|CDI|IOI)
-#define TARGETNAME(ecb) \
- ((struct device *)(ecb)->xs->sc_link->adapter_softc)->dv_xname
+/* Some pseudo phases for getphase()*/
+#define BUSFREE_PHASE 0x100 /* Re/Selection no longer valid */
+#define INVALID_PHASE 0x101 /* Re/Selection valid, but no REQ yet */
+#define PSEUDO_PHASE 0x100 /* "pseudo" bit */
+
+#ifdef ESP_DEBUG
+#define ESPCMD(sc, cmd) do { \
+ if (esp_debug & ESP_SHOWCCMDS) \
+ printf("<cmd:0x%x>", (unsigned)cmd); \
+ sc->sc_lastcmd = cmd; \
+ ESP_WRITE_REG(sc, ESP_CMD, cmd); \
+} while (0)
+#else
+#define ESPCMD(sc, cmd) ESP_WRITE_REG(sc, ESP_CMD, cmd)
+#endif
+
+#define SAME_ESP(sc, bp, ca) \
+ ((bp->val[0] == ca->ca_slot && bp->val[1] == ca->ca_offset) || \
+ (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit))
+
diff --git a/sys/arch/sparc/dev/fb.c b/sys/arch/sparc/dev/fb.c
index ade9db9dbe6..836bc7dbdad 100644
--- a/sys/arch/sparc/dev/fb.c
+++ b/sys/arch/sparc/dev/fb.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fb.c,v 1.11 1995/10/08 01:39:19 pk Exp $ */
+/* $NetBSD: fb.c,v 1.18 1996/04/01 17:29:54 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -50,19 +50,24 @@
*/
#include <sys/param.h>
-#include <sys/conf.h>
+#include <sys/systm.h>
#include <sys/device.h>
#include <sys/proc.h>
+#include <sys/conf.h>
#include <machine/autoconf.h>
#include <machine/fbio.h>
+#include <machine/kbd.h>
#include <machine/fbvar.h>
+#include <machine/conf.h>
#if defined(SUN4)
#include <machine/eeprom.h>
+#include <sparc/dev/pfourreg.h>
#endif
static struct fbdevice *devfb;
+
void
fb_unblank()
{
@@ -72,13 +77,71 @@ fb_unblank()
}
void
-fb_attach(fb)
+fb_attach(fb, isconsole)
struct fbdevice *fb;
+ int isconsole;
{
+ static int no_replace, seen_force;
+
+ /*
+ * We've already had a framebuffer forced into /dev/fb. Don't
+ * allow any more, even if this is the console.
+ */
+ if (seen_force) {
+ if (devfb) { /* sanity */
+ printf("%s: /dev/fb already full\n",
+ fb->fb_device->dv_xname);
+ return;
+ } else
+ seen_force = 0;
+ }
+
+ /*
+ * Check to see if we're being forced into /dev/fb.
+ */
+ if (fb->fb_flags & FB_FORCE) {
+ if (devfb)
+ printf("%s: forcefully replacing %s\n",
+ fb->fb_device->dv_xname,
+ devfb->fb_device->dv_xname);
+ devfb = fb;
+ seen_force = no_replace = 1;
+ goto attached;
+ }
+
+ /*
+ * Check to see if we're the console. If we are, then replace
+ * any currently existing framebuffer.
+ */
+ if (isconsole) {
+ if (devfb)
+ printf("%s: replacing %s\n", fb->fb_device->dv_xname,
+ devfb->fb_device->dv_xname);
+ devfb = fb;
+ no_replace = 1;
+ goto attached;
+ }
+
+ /*
+ * For the final case, we check to see if we can replace an
+ * existing framebuffer, if not, say so and return.
+ */
+ if (no_replace) {
+ if (devfb) { /* sanity */
+ printf("%s: /dev/fb already full\n",
+ fb->fb_device->dv_xname);
+ return;
+ } else
+ no_replace = 0;
+ }
if (devfb)
- printf("warning: multiple /dev/fb declarers\n");
+ printf("%s: replacing %s\n", fb->fb_device->dv_xname,
+ devfb->fb_device->dv_xname);
devfb = fb;
+
+ attached:
+ printf("%s: attached to /dev/fb\n", devfb->fb_device->dv_xname);
}
int
@@ -138,25 +201,18 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype)
* to be correct as defaults go...
*/
switch (bustype) {
- case BUS_PFOUR:
- fb->fb_type.fb_width = def_width;
- fb->fb_type.fb_height = def_height;
- fb->fb_linebytes = (fb->fb_type.fb_width * depth) / 8;
- break;
case BUS_VME16:
case BUS_VME32:
case BUS_OBIO:
-#if defined(SUN4M)
- if (cputyp == CPU_SUN4M) { /* 4m has framebuffer on obio */
- fb->fb_type.fb_width = getpropint(node, "width",
- def_width);
+ if (CPU_ISSUN4M) { /* 4m has framebuffer on obio */
+ fb->fb_type.fb_width = getpropint(node, "width",
+ def_width);
fb->fb_type.fb_height = getpropint(node, "height",
- def_height);
+ def_height);
fb->fb_linebytes = getpropint(node, "linebytes",
(fb->fb_type.fb_width * depth) / 8);
break;
}
-#endif
/* Set up some defaults. */
fb->fb_type.fb_width = def_width;
fb->fb_type.fb_height = def_height;
@@ -165,39 +221,104 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype)
* This is not particularly useful on Sun 4 VME framebuffers.
* The EEPROM only contains info about the built-in.
*/
- if (cputyp == CPU_SUN4 && (bustype == BUS_VME16 ||
+ if (CPU_ISSUN4 && (bustype == BUS_VME16 ||
bustype == BUS_VME32))
goto donesize;
#if defined(SUN4)
- if (cputyp==CPU_SUN4) {
+ if (CPU_ISSUN4) {
struct eeprom *eep = (struct eeprom *)eeprom_va;
- if (eep != NULL) {
- switch (eep->ee_diag.eed_scrsize) {
- case EED_SCR_1152X900:
+
+ if (fb->fb_flags & FB_PFOUR) {
+ volatile u_int32_t pfour;
+
+ /*
+ * Some pfour framebuffers, e.g. the
+ * cgsix, don't encode resolution the
+ * same, so the driver handles that.
+ * The driver can let us know that it
+ * needs to do this by not mapping in
+ * the pfour register by the time this
+ * routine is called.
+ */
+ if (fb->fb_pfour == NULL)
+ goto donesize;
+
+ pfour = *fb->fb_pfour;
+
+ /*
+ * Use the pfour register to determine
+ * the size. Note that the cgsix and
+ * cgeight don't use this size encoding.
+ * In this case, we have to settle
+ * for the defaults we were provided
+ * with.
+ */
+ if ((PFOUR_ID(pfour) == PFOUR_ID_COLOR24) ||
+ (PFOUR_ID(pfour) == PFOUR_ID_FASTCOLOR))
+ goto donesize;
+
+ switch (PFOUR_SIZE(pfour)) {
+ case PFOUR_SIZE_1152X900:
fb->fb_type.fb_width = 1152;
fb->fb_type.fb_height = 900;
break;
- case EED_SCR_1024X1024:
+
+ case PFOUR_SIZE_1024X1024:
fb->fb_type.fb_width = 1024;
fb->fb_type.fb_height = 1024;
break;
- case EED_SCR_1600X1280:
+
+ case PFOUR_SIZE_1280X1024:
+ fb->fb_type.fb_width = 1280;
+ fb->fb_type.fb_height = 1024;
+ break;
+
+ case PFOUR_SIZE_1600X1280:
fb->fb_type.fb_width = 1600;
fb->fb_type.fb_height = 1280;
break;
- case EED_SCR_1440X1440:
+
+ case PFOUR_SIZE_1440X1440:
fb->fb_type.fb_width = 1440;
fb->fb_type.fb_height = 1440;
break;
- case EED_SCR_640X480:
+
+ case PFOUR_SIZE_640X480:
fb->fb_type.fb_width = 640;
fb->fb_type.fb_height = 480;
break;
- case EED_SCR_1280X1024:
- fb->fb_type.fb_width = 1280;
+
+ default:
+ /*
+ * XXX: Do nothing, I guess.
+ * Should we print a warning about
+ * an unknown value? --thorpej
+ */
+ break;
+ }
+ } else if (eep != NULL) {
+ switch (eep->eeScreenSize) {
+ case EE_SCR_1152X900:
+ fb->fb_type.fb_width = 1152;
+ fb->fb_type.fb_height = 900;
+ break;
+
+ case EE_SCR_1024X1024:
+ fb->fb_type.fb_width = 1024;
fb->fb_type.fb_height = 1024;
break;
+
+ case EE_SCR_1600X1280:
+ fb->fb_type.fb_width = 1600;
+ fb->fb_type.fb_height = 1280;
+ break;
+
+ case EE_SCR_1440X1440:
+ fb->fb_type.fb_width = 1440;
+ fb->fb_type.fb_height = 1440;
+ break;
+
default:
/*
* XXX: Do nothing, I guess.
@@ -210,20 +331,22 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype)
}
#endif /* SUN4 */
#if defined(SUN4M)
- if (cputyp==CPU_SUN4M) {
+ if (CPU_ISSUN4M) {
/* XXX: need code to find 4/600 vme screen size */
}
#endif /* SUN4M */
-donesize:
+ donesize:
fb->fb_linebytes = (fb->fb_type.fb_width * depth) / 8;
break;
+
case BUS_SBUS:
- fb->fb_type.fb_width = getpropint(node, "width", 1152);
- fb->fb_type.fb_height = getpropint(node, "height", 900);
+ fb->fb_type.fb_width = getpropint(node, "width", def_width);
+ fb->fb_type.fb_height = getpropint(node, "height", def_height);
fb->fb_linebytes = getpropint(node, "linebytes",
(fb->fb_type.fb_width * depth) / 8);
break;
+
default:
panic("fb_setsize: inappropriate bustype");
/* NOTREACHED */
@@ -233,7 +356,8 @@ donesize:
#ifdef RASTERCONSOLE
#include <machine/kbd.h>
-extern int (*v_putc) __P((int));
+static int a2int __P((char *, int));
+static void fb_bell __P((int));
static int
a2int(cp, deflt)
@@ -278,40 +402,103 @@ fbrcons_init(fb)
#if defined(RASTERCONS_FULLSCREEN) || defined(RASTERCONS_SMALLFONT)
rc->rc_maxcol = rc->rc_width / rc->rc_font->width;
- rc->rc_maxrow = rc->rc_height / rc->rc_font->height;
+ rc->rc_maxrow = rc->rc_height / rc->rc_font->height;
#else
#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
struct eeprom *eep = (struct eeprom *)eeprom_va;
if (eep == NULL) {
rc->rc_maxcol = 80;
rc->rc_maxrow = 34;
} else {
- rc->rc_maxcol = eep->ee_diag.eed_colsize;
- rc->rc_maxrow = eep->ee_diag.eed_rowsize;
+ rc->rc_maxcol = eep->eeTtyCols;
+ rc->rc_maxrow = eep->eeTtyRows;
}
}
#endif /* SUN4 */
-#if defined(SUN4C) || defined(SUN4M)
- if (cputyp != CPU_SUN4) {
- rc->rc_maxcol = a2int(getpropstring(optionsnode,
- "screen-#columns"), 80);
- rc->rc_maxrow = a2int(getpropstring(optionsnode,
- "screen-#rows"), 34);
+
+ if (!CPU_ISSUN4) {
+ rc->rc_maxcol =
+ a2int(getpropstring(optionsnode, "screen-#columns"), 80);
+ rc->rc_maxrow =
+ a2int(getpropstring(optionsnode, "screen-#rows"), 34);
}
-#endif /* SUN4C || SUN4M */
#endif /* RASTERCONS_FULLSCREEN || RASTERCONS_SMALLFONT */
#if !(defined(RASTERCONS_FULLSCREEN) || defined(RASTERCONS_SMALLFONT))
/* Determine addresses of prom emulator row and column */
- if (cputyp == CPU_SUN4 || romgetcursoraddr(&rc->rc_row, &rc->rc_col))
+ if (CPU_ISSUN4 ||
+ romgetcursoraddr(&rc->rc_row, &rc->rc_col))
#endif
rc->rc_row = rc->rc_col = NULL;
rc->rc_bell = fb_bell;
rcons_init(rc);
/* Hook up virtual console */
- v_putc = (int (*) __P((int)))rcons_cnputc;
+ v_putc = rcons_cnputc;
}
#endif
+
+#if defined(SUN4)
+/*
+ * Support routines for pfour framebuffers.
+ */
+
+/*
+ * Probe for a pfour framebuffer. Return values:
+ *
+ * PFOUR_NOTPFOUR framebuffer is not a pfour
+ * framebuffer
+ *
+ * otherwise returns pfour ID
+ */
+int
+fb_pfour_id(va)
+ void *va;
+{
+ volatile u_int32_t val, save, *pfour = va;
+
+ /* Read the pfour register. */
+ save = *pfour;
+
+ /*
+ * Try to modify the type code. If it changes, put the
+ * original value back, and notify the caller that it's
+ * not a pfour framebuffer.
+ */
+ val = save & ~PFOUR_REG_RESET;
+ *pfour = (val ^ PFOUR_FBTYPE_MASK);
+ if ((*pfour ^ val) & PFOUR_FBTYPE_MASK) {
+ *pfour = save;
+ return (PFOUR_NOTPFOUR);
+ }
+
+ return (PFOUR_ID(val));
+}
+
+/*
+ * Return the status of the video enable.
+ */
+int
+fb_pfour_get_video(fb)
+ struct fbdevice *fb;
+{
+
+ return ((*fb->fb_pfour & PFOUR_REG_VIDEO) != 0);
+}
+
+/*
+ * Enable or disable the framebuffer.
+ */
+void
+fb_pfour_set_video(fb, enable)
+ struct fbdevice *fb;
+ int enable;
+{
+ volatile u_int32_t pfour;
+
+ pfour = *fb->fb_pfour & ~(PFOUR_REG_INTCLR|PFOUR_REG_VIDEO);
+ *fb->fb_pfour = pfour | (enable ? PFOUR_REG_VIDEO : 0);
+}
+#endif /* SUN4 */
diff --git a/sys/arch/sparc/dev/fd.c b/sys/arch/sparc/dev/fd.c
index fa729ce26ea..d4dee591b72 100644
--- a/sys/arch/sparc/dev/fd.c
+++ b/sys/arch/sparc/dev/fd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fd.c,v 1.13 1995/10/09 22:33:07 pk Exp $ */
+/* $NetBSD: fd.c,v 1.33.4.1 1996/06/12 20:52:25 pk Exp $ */
/*-
* Copyright (c) 1993, 1994, 1995 Charles Hannum.
@@ -43,7 +43,6 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/conf.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/device.h>
@@ -52,12 +51,17 @@
#include <sys/disk.h>
#include <sys/buf.h>
#include <sys/uio.h>
-#include <sys/mtio.h>
+#include <sys/stat.h>
#include <sys/syslog.h>
#include <sys/queue.h>
+#include <sys/conf.h>
+
+#include <dev/cons.h>
#include <machine/cpu.h>
#include <machine/autoconf.h>
+#include <machine/conf.h>
+
#include <sparc/sparc/auxreg.h>
#include <sparc/dev/fdreg.h>
#include <sparc/dev/fdvar.h>
@@ -128,10 +132,16 @@ extern struct fdcio *fdciop;
int fdcmatch __P((struct device *, void *, void *));
void fdcattach __P((struct device *, struct device *, void *));
-struct cfdriver fdccd = {
- NULL, "fdc", fdcmatch, fdcattach, DV_DULL, sizeof(struct fdc_softc)
+struct cfattach fdc_ca = {
+ sizeof(struct fdc_softc), fdcmatch, fdcattach
};
+struct cfdriver fdc_cd = {
+ NULL, "fdc", DV_DULL
+};
+
+__inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
+
/*
* Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
* we tell them apart.
@@ -184,6 +194,8 @@ struct fd_softc {
#define FD_MOTOR_WAIT 0x04 /* motor coming up */
int sc_cylin; /* where we think the head is */
+ void *sc_sdhook; /* shutdownhook cookie */
+
TAILQ_ENTRY(fd_softc) sc_drivechain;
int sc_ops; /* I/O ops since last switch */
struct buf sc_q; /* head of buf chain */
@@ -193,14 +205,19 @@ struct fd_softc {
int fdmatch __P((struct device *, void *, void *));
void fdattach __P((struct device *, struct device *, void *));
-struct cfdriver fdcd = {
- NULL, "fd", fdmatch, fdattach, DV_DISK, sizeof(struct fd_softc)
+struct cfattach fd_ca = {
+ sizeof(struct fd_softc), fdmatch, fdattach
};
-void fdgetdisklabel __P((struct fd_softc *));
+struct cfdriver fd_cd = {
+ NULL, "fd", DV_DISK
+};
+
+void fdgetdisklabel __P((dev_t));
int fd_get_parms __P((struct fd_softc *));
void fdstrategy __P((struct buf *));
void fdstart __P((struct fd_softc *));
+int fdprint __P((void *, char *));
struct dkdriver fddkdriver = { fdstrategy };
@@ -223,6 +240,9 @@ void fdchwintr __P((void));
int fdcswintr __P((struct fdc_softc *));
void fdcretry __P((struct fdc_softc *fdc));
void fdfinish __P((struct fd_softc *fd, struct buf *bp));
+void fd_do_eject __P((void));
+void fd_mountroot_hook __P((struct device *));
+static void fdconf __P((struct fdc_softc *));
#if PIL_FDSOFT == 4
#define IE_FDSOFT IE_L4
@@ -230,29 +250,44 @@ void fdfinish __P((struct fd_softc *fd, struct buf *bp));
#error 4
#endif
-#define OBP_FDNAME (cputyp == CPU_SUN4M ? "SUNW,fdtwo" : "fd")
+#define OBP_FDNAME (CPU_ISSUN4M ? "SUNW,fdtwo" : "fd")
int
fdcmatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
- struct cfdata *cf = match;
register struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
+ /*
+ * Floppy doesn't exist on sun4.
+ */
+ if (CPU_ISSUN4)
+ return (0);
+
+ /*
+ * Floppy controller is on mainbus on sun4c.
+ */
+ if ((CPU_ISSUN4C) && (ca->ca_bustype != BUS_MAIN))
+ return (0);
+
+ /*
+ * Floppy controller is on obio on sun4m.
+ */
+ if ((CPU_ISSUN4M) && (ca->ca_bustype != BUS_OBIO))
+ return (0);
+
/* Sun PROMs call the controller an "fd" or "SUNW,fdtwo" */
if (strcmp(OBP_FDNAME, ra->ra_name))
return (0);
- if (ca->ca_bustype == BUS_MAIN) {
- if (ca->ca_ra.ra_vaddr &&
- probeget(ca->ca_ra.ra_vaddr, 1) == -1) {
- return (0);
- }
- return (1);
+
+ if (ca->ca_ra.ra_vaddr &&
+ probeget(ca->ca_ra.ra_vaddr, 1) == -1) {
+ return (0);
}
- return (0);
+ return (1);
}
/*
@@ -260,7 +295,7 @@ fdcmatch(parent, match, aux)
*/
struct fdc_attach_args {
int fa_drive;
- int fa_bootdev;
+ struct bootpath *fa_bootpath;
struct fd_type *fa_deftype;
};
@@ -315,7 +350,8 @@ fdcattach(parent, self, aux)
register struct confargs *ca = aux;
struct fdc_softc *fdc = (void *)self;
struct fdc_attach_args fa;
- int n, pri;
+ struct bootpath *bp;
+ int pri;
char code;
if (ca->ca_ra.ra_vaddr)
@@ -398,13 +434,36 @@ fdcattach(parent, self, aux)
* Controller and drives are represented by one and the same
* Openprom node, so we can as well check for the floppy boots here.
*/
- if (ca->ca_ra.ra_bp &&
- strcmp(ca->ca_ra.ra_bp->name, OBP_FDNAME) == 0 &&
- ca->ca_ra.ra_bp->val[0] == 0 &&
- ca->ca_ra.ra_bp->val[1] == 0)
- fa.fa_bootdev = 1;
- else
- fa.fa_bootdev = 0;
+ fa.fa_bootpath = 0;
+ if ((bp = ca->ca_ra.ra_bp) && strcmp(bp->name, OBP_FDNAME) == 0) {
+ /*
+ * WOAH THERE! It looks like we can get the bootpath
+ * in several different formats!! The faked
+ * bootpath (and some v2?) looks like /fd@0,0
+ * but the real bootpath on some v2 OpenPROM
+ * systems looks like /fd0. In the case of
+ * a floppy controller on obio (such as on the sun4m),
+ * we use "slot, offset" to determine if this is the
+ * right one. --thorpej
+ */
+ switch (ca->ca_bustype) {
+ case BUS_MAIN:
+ if (((bp->val[0] == 0) && /* /fd@0,0 */
+ (bp->val[1] == 0)) ||
+ ((bp->val[0] == -1) && /* /fd0 */
+ (bp->val[1] == 0)))
+ fa.fa_bootpath = bp;
+ break;
+
+ case BUS_OBIO:
+ /* /obio0/SUNW,fdtwo@0,700000 */
+ if ((bp->val[0] == ca->ca_slot) &&
+ (bp->val[1] == ca->ca_offset))
+ fa.fa_bootpath = bp;
+ break;
+ }
+
+ }
/* physical limit: four drives per controller. */
for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
@@ -422,10 +481,9 @@ fdmatch(parent, match, aux)
void *match, *aux;
{
struct fdc_softc *fdc = (void *)parent;
- struct cfdata *cf = match;
struct fdc_attach_args *fa = aux;
int drive = fa->fa_drive;
- int n;
+ int n, ok;
if (drive > 0)
/* XXX - for now, punt > 1 drives */
@@ -439,13 +497,12 @@ fdmatch(parent, match, aux)
} else {
auxregbisc(AUXIO_FDS, 0);
}
-
fdc->sc_nstat = 0;
out_fdc(fdc, NE7CMD_RECAL);
out_fdc(fdc, drive);
/* wait for recalibrate */
- for (n = 0; n < 100000; n++) {
- delay(10);
+ for (n = 0; n < 10000; n++) {
+ delay(1000);
if ((*fdc->sc_reg_msr & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) {
/* wait a bit longer till device *really* is ready */
delay(100000);
@@ -471,15 +528,17 @@ fdmatch(parent, match, aux)
printf("\n");
}
#endif
- if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
- return 0;
+ ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0;
+
/* turn off motor */
- if (fdc->sc_flags & FDC_82077)
+ if (fdc->sc_flags & FDC_82077) {
+ /* select drive and turn on motor */
*fdc->sc_reg_dor = FDO_FRST;
- else
+ } else {
auxregbisc(0, AUXIO_FDS);
+ }
- return 1;
+ return ok;
}
/*
@@ -499,7 +558,7 @@ fdattach(parent, self, aux)
/* XXX Allow `flags' to override device type? */
if (type)
- printf(": %s, %d cyl, %d head, %d sec\n", type->name,
+ printf(": %s %d cyl, %d head, %d sec\n", type->name,
type->tracks, type->heads, type->sectrac);
else
printf(": density unknown\n");
@@ -519,14 +578,23 @@ fdattach(parent, self, aux)
/*
* We're told if we're the boot device in fdcattach().
*/
- if (fa->fa_bootdev)
- bootdv = &fd->sc_dv;
+ if (fa->fa_bootpath)
+ fa->fa_bootpath->dev = &fd->sc_dv;
+
+ /*
+ * Establish a mountroot_hook anyway in case we booted
+ * with RB_ASKNAME and get selected as the boot device.
+ */
+ mountroot_hook_establish(fd_mountroot_hook, &fd->sc_dv);
+
+ /* Make sure the drive motor gets turned off at shutdown time. */
+ fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
/* XXX Need to do some more fiddling with sc_dk. */
dk_establish(&fd->sc_dk, &fd->sc_dv);
}
-inline struct fd_type *
+__inline struct fd_type *
fd_dev_to_type(fd, dev)
struct fd_softc *fd;
dev_t dev;
@@ -548,8 +616,8 @@ fdstrategy(bp)
int s;
/* Valid unit, controller, and request? */
- if (unit >= fdcd.cd_ndevs ||
- (fd = fdcd.cd_devs[unit]) == 0 ||
+ if (unit >= fd_cd.cd_ndevs ||
+ (fd = fd_cd.cd_devs[unit]) == 0 ||
bp->b_blkno < 0 ||
(bp->b_bcount % FDC_BSIZE) != 0) {
bp->b_error = EINVAL;
@@ -582,7 +650,7 @@ fdstrategy(bp)
#ifdef FD_DEBUG
if (fdc_debug > 1)
- printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d\n",
+ printf("fdstrategy: b_blkno %d b_bcount %ld blkno %d cylin %ld\n",
bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin);
#endif
@@ -685,7 +753,7 @@ fd_set_motor(fdc)
if (fdc->sc_flags & FDC_82077) {
status = FDO_FRST | FDO_FDMAEN;
- if (fd = fdc->sc_drives.tqh_first)
+ if ((fd = fdc->sc_drives.tqh_first) != NULL)
status |= fd->sc_drive;
for (n = 0; n < 4; n++)
@@ -774,18 +842,19 @@ out_fdc(fdc, x)
}
int
-Fdopen(dev, flags)
+fdopen(dev, flags, fmt, p)
dev_t dev;
- int flags;
+ int flags, fmt;
+ struct proc *p;
{
- int unit;
+ int unit, pmask;
struct fd_softc *fd;
struct fd_type *type;
unit = FDUNIT(dev);
- if (unit >= fdcd.cd_ndevs)
+ if (unit >= fd_cd.cd_ndevs)
return ENXIO;
- fd = fdcd.cd_devs[unit];
+ fd = fd_cd.cd_devs[unit];
if (fd == 0)
return ENXIO;
type = fd_dev_to_type(fd, dev);
@@ -800,33 +869,70 @@ Fdopen(dev, flags)
fd->sc_cylin = -1;
fd->sc_flags |= FD_OPEN;
+ /*
+ * Only update the disklabel if we're not open anywhere else.
+ */
+ if (fd->sc_dk.dk_openmask == 0)
+ fdgetdisklabel(dev);
+
+ pmask = (1 << DISKPART(dev));
+
+ switch (fmt) {
+ case S_IFCHR:
+ fd->sc_dk.dk_copenmask |= pmask;
+ break;
+
+ case S_IFBLK:
+ fd->sc_dk.dk_bopenmask |= pmask;
+ break;
+ }
+ fd->sc_dk.dk_openmask =
+ fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
+
return 0;
}
int
-fdclose(dev, flags)
+fdclose(dev, flags, fmt, p)
dev_t dev;
- int flags;
+ int flags, fmt;
+ struct proc *p;
{
- struct fd_softc *fd = fdcd.cd_devs[FDUNIT(dev)];
+ struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
+ int pmask = (1 << DISKPART(dev));
fd->sc_flags &= ~FD_OPEN;
+
+ switch (fmt) {
+ case S_IFCHR:
+ fd->sc_dk.dk_copenmask &= ~pmask;
+ break;
+
+ case S_IFBLK:
+ fd->sc_dk.dk_bopenmask &= ~pmask;
+ break;
+ }
+ fd->sc_dk.dk_openmask =
+ fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
+
return 0;
}
int
-fdread(dev, uio)
+fdread(dev, uio, flag)
dev_t dev;
struct uio *uio;
+ int flag;
{
return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
}
int
-fdwrite(dev, uio)
+fdwrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
+ int flag;
{
return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
@@ -855,7 +961,6 @@ fdcstatus(dv, n, s)
char *s;
{
struct fdc_softc *fdc = (void *)dv->dv_parent;
-
#if 0
/*
* A 82072 seems to return <invalid command> on
@@ -949,7 +1054,7 @@ fdchwintr(fdc)
fdcresult(fdc);
fdc->sc_istate = ISTATE_IDLE;
ienab_bis(IE_FDSOFT);
- goto done;
+ return 1;
case ISTATE_IDLE:
case ISTATE_SPURIOUS:
auxregbisc(0, AUXIO_FDS); /* Does this help? */
@@ -957,12 +1062,12 @@ fdchwintr(fdc)
fdc->sc_istate = ISTATE_SPURIOUS;
printf("fdc: stray hard interrupt... ");
ienab_bis(IE_FDSOFT);
- goto done;
+ return 1;
case ISTATE_DMA:
break;
default:
printf("fdc: goofed ...\n");
- goto done;
+ return 1;
}
read = bp->b_flags & B_READ;
@@ -1005,9 +1110,7 @@ fdchwintr(fdc)
break;
}
}
-done:
- sc->sc_intrcnt.ev_count++;
- return (1);
+ return 1;
}
#endif
@@ -1023,7 +1126,7 @@ fdcswintr(fdc)
struct fd_softc *fd;
struct buf *bp;
- int read, head, trac, sec, i, s, nblks;
+ int read, head, sec, nblks;
struct fd_type *type;
@@ -1246,11 +1349,12 @@ loop:
printf("fdc: %d -> threshold\n", thr);
#endif
fdconf(fdc);
- fdc->sc_state = DOIO;
fdc->sc_overruns = 0;
}
- if (++fdc->sc_overruns < 3)
+ if (++fdc->sc_overruns < 3) {
+ fdc->sc_state = DOIO;
goto loop;
+ }
}
fdcretry(fdc);
goto loop;
@@ -1367,7 +1471,7 @@ fdcretry(fdc)
case 0:
/* try again */
fdc->sc_state =
- (fdc->sc_flags & FDC_EIS) ? DOIO : SEEKCOMPLETE;
+ (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK;
break;
case 1: case 2: case 3:
@@ -1383,6 +1487,7 @@ fdcretry(fdc)
default:
diskerr(bp, "fd", "hard error", LOG_PRINTF,
fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
+
printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
fdc->sc_status[0], NE7_ST0BITS,
fdc->sc_status[1], NE7_ST1BITS,
@@ -1406,7 +1511,11 @@ fdsize(dev)
}
int
-fddump()
+fddump(dev, blkno, va, size)
+ dev_t dev;
+ daddr_t blkno;
+ caddr_t va;
+ size_t size;
{
/* Not implemented. */
@@ -1414,29 +1523,18 @@ fddump()
}
int
-fdioctl(dev, cmd, addr, flag)
+fdioctl(dev, cmd, addr, flag, p)
dev_t dev;
u_long cmd;
caddr_t addr;
int flag;
+ struct proc *p;
{
- struct fd_softc *fd = fdcd.cd_devs[FDUNIT(dev)];
- struct disklabel buffer;
+ struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
int error;
switch (cmd) {
case DIOCGDINFO:
- bzero(fd->sc_dk.dk_label, sizeof(struct disklabel));
-
- fd->sc_dk.dk_label->d_secpercyl = fd->sc_type->seccyl;
- fd->sc_dk.dk_label->d_type = DTYPE_FLOPPY;
- fd->sc_dk.dk_label->d_secsize = FDC_BSIZE;
-
- if (readdisklabel(dev, fdstrategy,
- fd->sc_dk.dk_label,
- fd->sc_dk.dk_cpulabel) != NULL)
- return EINVAL;
-
*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
return 0;
@@ -1461,16 +1559,16 @@ fdioctl(dev, cmd, addr, flag)
fd->sc_dk.dk_cpulabel);
return error;
- case MTIOCTOP:
- if (((struct mtop *)addr)->mt_op != MTOFFL)
- return EIO;
-#ifdef COMPAT_SUNOS
- case SUNOS_FDIOCEJECT:
-#endif
- auxregbisc(AUXIO_FDS, AUXIO_FEJ);
- delay(10);
- auxregbisc(AUXIO_FEJ, AUXIO_FDS);
+ case DIOCLOCK:
+ /*
+ * Nothing to do here, really.
+ */
+ return 0;
+
+ case DIOCEJECT:
+ fd_do_eject();
return 0;
+
#ifdef DEBUG
case _IO('f', 100):
{
@@ -1492,7 +1590,7 @@ fdioctl(dev, cmd, addr, flag)
~CFG_THRHLD_MASK;
((struct fdc_softc *)fd->sc_dv.dv_parent)->sc_cfg |=
(*(int *)addr & CFG_THRHLD_MASK);
- fdconf(fd->sc_dv.dv_parent);
+ fdconf((struct fdc_softc *) fd->sc_dv.dv_parent);
return 0;
case _IO('f', 102):
{
@@ -1516,3 +1614,92 @@ fdioctl(dev, cmd, addr, flag)
panic("fdioctl: impossible");
#endif
}
+
+void
+fdgetdisklabel(dev)
+ dev_t dev;
+{
+ int unit = FDUNIT(dev), i;
+ struct fd_softc *fd = fd_cd.cd_devs[unit];
+ struct disklabel *lp = fd->sc_dk.dk_label;
+ struct cpu_disklabel *clp = fd->sc_dk.dk_cpulabel;
+
+ bzero(lp, sizeof(struct disklabel));
+ bzero(lp, sizeof(struct cpu_disklabel));
+
+ lp->d_type = DTYPE_FLOPPY;
+ lp->d_secsize = FDC_BSIZE;
+ lp->d_secpercyl = fd->sc_type->seccyl;
+ lp->d_nsectors = fd->sc_type->sectrac;
+ lp->d_ncylinders = fd->sc_type->tracks;
+ lp->d_ntracks = fd->sc_type->heads; /* Go figure... */
+ lp->d_rpm = 3600; /* XXX like it matters... */
+
+ strncpy(lp->d_typename, "floppy", sizeof(lp->d_typename));
+ strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
+ lp->d_interleave = 1;
+
+ lp->d_partitions[RAW_PART].p_offset = 0;
+ lp->d_partitions[RAW_PART].p_size = lp->d_secpercyl * lp->d_ncylinders;
+ lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
+ lp->d_npartitions = RAW_PART + 1;
+
+ lp->d_magic = DISKMAGIC;
+ lp->d_magic2 = DISKMAGIC;
+ lp->d_checksum = dkcksum(lp);
+
+ /*
+ * Call the generic disklabel extraction routine. If there's
+ * not a label there, fake it.
+ */
+ if (readdisklabel(dev, fdstrategy, lp, clp) != NULL) {
+ strncpy(lp->d_packname, "default label",
+ sizeof(lp->d_packname));
+ /*
+ * Reset the partition info; it might have gotten
+ * trashed in readdisklabel().
+ *
+ * XXX Why do we have to do this? readdisklabel()
+ * should be safe...
+ */
+ for (i = 0; i < MAXPARTITIONS; ++i) {
+ lp->d_partitions[i].p_offset = 0;
+ if (i == RAW_PART) {
+ lp->d_partitions[i].p_size =
+ lp->d_secpercyl * lp->d_ncylinders;
+ lp->d_partitions[i].p_fstype = FS_BSDFFS;
+ } else {
+ lp->d_partitions[i].p_size = 0;
+ lp->d_partitions[i].p_fstype = FS_UNUSED;
+ }
+ }
+ lp->d_npartitions = RAW_PART + 1;
+ }
+}
+
+void
+fd_do_eject()
+{
+
+ auxregbisc(AUXIO_FDS, AUXIO_FEJ);
+ delay(10);
+ auxregbisc(AUXIO_FEJ, AUXIO_FDS);
+}
+
+/* ARGSUSED */
+void
+fd_mountroot_hook(dev)
+ struct device *dev;
+{
+ int c;
+
+ fd_do_eject();
+ printf("Insert filesystem floppy and press return.");
+ for (;;) {
+ c = cngetc();
+ if ((c == '\r') || (c == '\n')) {
+ printf("\n");
+ return;
+ }
+ }
+}
diff --git a/sys/arch/sparc/dev/fdreg.h b/sys/arch/sparc/dev/fdreg.h
index a522eb2d3c2..4166d58b0ba 100644
--- a/sys/arch/sparc/dev/fdreg.h
+++ b/sys/arch/sparc/dev/fdreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: fdreg.h,v 1.4 1995/06/28 04:31:19 cgd Exp $ */
+/* $NetBSD: fdreg.h,v 1.5 1996/02/01 22:32:27 mycroft Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@@ -42,7 +42,7 @@
/* uses NEC765 controller */
#include <dev/ic/nec765reg.h>
-#ifndef LOCORE
+#ifndef _LOCORE
struct fdreg_77 {
u_int8_t fd_statusA;
u_int8_t fd_statusB;
diff --git a/sys/arch/sparc/dev/fdvar.h b/sys/arch/sparc/dev/fdvar.h
index f74d37ce41d..9a74ebcf162 100644
--- a/sys/arch/sparc/dev/fdvar.h
+++ b/sys/arch/sparc/dev/fdvar.h
@@ -1,5 +1,5 @@
/*
- * $NetBSD: fdvar.h,v 1.3 1995/04/07 19:46:15 pk Exp $
+ * $NetBSD: fdvar.h,v 1.4 1996/02/01 22:32:29 mycroft Exp $
*
* Copyright (c) 1995 Paul Kranenburg
* All rights reserved.
@@ -36,7 +36,7 @@
#define FDC_NSTATUS 10
-#if !defined(LOCORE)
+#ifndef _LOCORE
struct fdcio {
/*
* 82072 (sun4c) and 82077 (sun4m) controllers have different
@@ -62,9 +62,9 @@ struct fdcio {
/*
* Statictics.
*/
- struct evcnt fdcio_intrcnt;
+ struct evcnt fdcio_intrcnt;
};
-#endif /* LOCORE */
+#endif /* _LOCORE */
/* istate values */
#define ISTATE_IDLE 0 /* No HW interrupt expected */
@@ -72,5 +72,5 @@ struct fdcio {
#define ISTATE_SENSEI 2 /* Do SENSEI on next HW interrupt */
#define ISTATE_DMA 3 /* Pseudo-DMA in progress */
-#define SUNOS_FDIOCEJECT _IO('f', 24)
+#define FDIOCEJECT _IO('f', 24)
diff --git a/sys/arch/sparc/dev/if_ie.c b/sys/arch/sparc/dev/if_ie.c
index 20aa5204d26..3bd3defb91a 100644
--- a/sys/arch/sparc/dev/if_ie.c
+++ b/sys/arch/sparc/dev/if_ie.c
@@ -1,4 +1,4 @@
-/* $NetBSD: if_ie.c,v 1.15 1995/04/11 09:18:09 pk Exp $ */
+/* $NetBSD: if_ie.c,v 1.24 1996/05/07 01:28:28 thorpej Exp $ */
/*-
* Copyright (c) 1993, 1994, 1995 Charles Hannum.
@@ -57,7 +57,7 @@
*
* Majorly cleaned up and 3C507 code merged by Charles Hannum.
*
- * Converted to SUN ie driver by Charles D. Cranor,
+ * Converted to SUN ie driver by Charles D. Cranor,
* October 1994, January 1995.
* This sun version based on i386 version 1.30.
*/
@@ -129,6 +129,11 @@ Mode of operation:
#include <netinet/if_ether.h>
#endif
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
#include <vm/vm.h>
/*
@@ -221,7 +226,6 @@ const char *ie_hardware_names[] = {
struct ie_softc {
struct device sc_dev; /* device structure */
struct intrhand sc_ih; /* interrupt info */
- struct evcnt sc_intrcnt; /* # of interrupts, per ie */
caddr_t sc_iobase; /* KVA of base of 24 bit addr space */
caddr_t sc_maddr; /* KVA of base of chip's RAM (16bit addr sp.)*/
@@ -230,15 +234,18 @@ struct ie_softc {
struct arpcom sc_arpcom;/* system arpcom structure */
- void (*reset_586)(); /* card dependent reset function */
- void (*chan_attn)(); /* card dependent attn function */
- void (*run_586)(); /* card depenent "go on-line" function */
+ void (*reset_586) __P((struct ie_softc *));
+ /* card dependent reset function */
+ void (*chan_attn) __P((struct ie_softc *));
+ /* card dependent attn function */
+ void (*run_586) __P((struct ie_softc *));
+ /* card depenent "go on-line" function */
void (*memcopy) __P((const void *, void *, u_int));
/* card dependent memory copy function */
void (*memzero) __P((void *, u_int));
/* card dependent memory zero function */
-
+
enum ie_hardware hard_type; /* card type */
int want_mcsetup; /* mcsetup flag */
@@ -253,10 +260,10 @@ struct ie_softc {
volatile struct ie_sys_ctl_block *scb;
/*
- * pointer and size of a block of KVA where the buffers
+ * pointer and size of a block of KVA where the buffers
* are to be allocated from
*/
-
+
caddr_t buf_area;
int buf_area_sz;
@@ -294,7 +301,7 @@ static void ie_vmereset __P((struct ie_softc *));
static void ie_vmeattend __P((struct ie_softc *));
static void ie_vmerun __P((struct ie_softc *));
-void iewatchdog __P((/* short */));
+void iewatchdog __P((struct ifnet *));
int ieintr __P((void *));
int ieinit __P((struct ie_softc *));
int ieioctl __P((struct ifnet *, u_long, caddr_t));
@@ -302,6 +309,7 @@ void iestart __P((struct ifnet *));
void iereset __P((struct ie_softc *));
static void ie_readframe __P((struct ie_softc *, int));
static void ie_drop_packet_buffer __P((struct ie_softc *));
+int ie_setupram __P((struct ie_softc *));
static int command_and_wait __P((struct ie_softc *, int,
void volatile *, int));
/*static*/ void ierint __P((struct ie_softc *));
@@ -311,6 +319,20 @@ static int ieget __P((struct ie_softc *, struct mbuf **,
static void setup_bufs __P((struct ie_softc *));
static int mc_setup __P((struct ie_softc *, void *));
static void mc_reset __P((struct ie_softc *));
+static __inline int ether_equal __P((u_char *, u_char *));
+static __inline void ie_ack __P((struct ie_softc *, u_int));
+static __inline void ie_setup_config __P((volatile struct ie_config_cmd *,
+ int, int));
+static __inline int check_eh __P((struct ie_softc *, struct ether_header *,
+ int *));
+static __inline int ie_buflen __P((struct ie_softc *, int));
+static __inline int ie_packet_len __P((struct ie_softc *));
+static __inline void iexmit __P((struct ie_softc *));
+static __inline caddr_t Align __P((caddr_t));
+
+static void chan_attn_timeout __P((void *));
+static void run_tdr __P((struct ie_softc *, struct ie_tdr_cmd *));
+static void iestop __P((struct ie_softc *));
#ifdef IEDEBUG
void print_rbd __P((volatile struct ie_recv_buf_desc *));
@@ -319,11 +341,15 @@ int in_ierint = 0;
int in_ietint = 0;
#endif
-int iematch();
-void ieattach();
+int iematch __P((struct device *, void *, void *));
+void ieattach __P((struct device *, struct device *, void *));
-struct cfdriver iecd = {
- NULL, "ie", iematch, ieattach, DV_IFNET, sizeof(struct ie_softc)
+struct cfattach ie_ca = {
+ sizeof(struct ie_softc), iematch, ieattach
+};
+
+struct cfdriver ie_cd = {
+ NULL, "ie", DV_IFNET
};
/*
@@ -344,7 +370,7 @@ struct cfdriver iecd = {
* Here are a few useful functions. We could have done these as macros, but
* since we have the inline facility, it makes sense to use that instead.
*/
-static inline void
+static __inline void
ie_setup_config(cmd, promiscuous, manchester)
volatile struct ie_config_cmd *cmd;
int promiscuous, manchester;
@@ -364,7 +390,7 @@ ie_setup_config(cmd, promiscuous, manchester)
cmd->ie_junk = 0xff;
}
-static inline void
+static __inline void
ie_ack(sc, mask)
struct ie_softc *sc;
u_int mask;
@@ -375,12 +401,13 @@ ie_ack(sc, mask)
}
-int
-iematch(parent, cf, aux)
+int
+iematch(parent, vcf, aux)
struct device *parent;
- struct cfdata *cf;
+ void *vcf;
void *aux;
{
+ struct cfdata *cf = vcf;
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
@@ -389,7 +416,7 @@ iematch(parent, cf, aux)
if (ca->ca_bustype == BUS_SBUS)
return (0);
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
/*
* XXX need better probe here so we can figure out what we've got
*/
@@ -408,7 +435,7 @@ iematch(parent, cf, aux)
/*
* MULTIBUS/VME support
*/
-void
+void
ie_vmereset(sc)
struct ie_softc *sc;
{
@@ -418,7 +445,7 @@ ie_vmereset(sc)
iev->status = 0;
}
-void
+void
ie_vmeattend(sc)
struct ie_softc *sc;
{
@@ -428,7 +455,7 @@ ie_vmeattend(sc)
iev->status &= ~IEVME_ATTEN; /* down. */
}
-void
+void
ie_vmerun(sc)
struct ie_softc *sc;
{
@@ -473,7 +500,8 @@ ie_obrun(sc)
*/
void
ieattach(parent, self, aux)
- struct device *parent, *self;
+ struct device *parent;
+ struct device *self;
void *aux;
{
struct ie_softc *sc = (void *) self;
@@ -511,13 +539,13 @@ ieattach(parent, self, aux)
* XXX
*/
- ie_map = vm_map_create(pmap_kernel(), (vm_offset_t)IEOB_ADBASE,
+ ie_map = vm_map_create(pmap_kernel(), (vm_offset_t)IEOB_ADBASE,
(vm_offset_t)IEOB_ADBASE + sc->sc_msize, 1);
if (ie_map == NULL) panic("ie_map");
sc->sc_maddr = (caddr_t) kmem_alloc(ie_map, sc->sc_msize);
if (sc->sc_maddr == NULL) panic("ie kmem_alloc");
kvm_uncache(sc->sc_maddr, sc->sc_msize >> PGSHIFT);
- if (((u_long)sc->sc_maddr & ~(NBPG-1)) != (u_long)sc->sc_maddr)
+ if (((u_long)sc->sc_maddr & ~(NBPG-1)) != (u_long)sc->sc_maddr)
panic("unaligned dvmamalloc breaks");
sc->sc_iobase = (caddr_t)IEOB_ADBASE; /* 24 bit base addr */
(sc->memzero)(sc->sc_maddr, sc->sc_msize);
@@ -539,7 +567,7 @@ ieattach(parent, self, aux)
pa = pmap_extract(pmap_kernel(), (vm_offset_t)sc->sc_maddr);
if (pa == 0) panic("ie pmap_extract");
pmap_enter(pmap_kernel(), trunc_page(IEOB_ADBASE+IE_SCP_ADDR),
- (vm_offset_t)pa | PMAP_NC,
+ (vm_offset_t)pa | PMAP_NC /*| PMAP_IOC*/,
VM_PROT_READ | VM_PROT_WRITE, 1);
sc->scp = (volatile struct ie_sys_conf_ptr *)
@@ -574,8 +602,8 @@ ieattach(parent, self, aux)
/* 4 more */
rampaddr = rampaddr | ((iev->status & IEVME_HADDR) << 16);
rampaddr -= (u_long)ca->ca_ra.ra_paddr;
- sc->sc_maddr = mapiodev(ca->ca_ra.ra_reg, rampaddr, sc->sc_msize,
- ca->ca_bustype);
+ sc->sc_maddr = mapiodev(ca->ca_ra.ra_reg, rampaddr,
+ sc->sc_msize, ca->ca_bustype);
sc->sc_iobase = sc->sc_maddr;
iev->pectrl = iev->pectrl | IEVME_PARACK; /* clear to start */
@@ -623,8 +651,8 @@ ieattach(parent, self, aux)
/* XXX should reclaim resources? */
return;
}
- ifp->if_unit = sc->sc_dev.dv_unit;
- ifp->if_name = iecd.cd_name;
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
ifp->if_start = iestart;
ifp->if_ioctl = ieioctl;
ifp->if_watchdog = iewatchdog;
@@ -651,6 +679,7 @@ ieattach(parent, self, aux)
intr_establish(pri, &sc->sc_ih);
break;
case BUS_VME16:
+ case BUS_VME32:
sc->sc_ih.ih_fun = ieintr;
sc->sc_ih.ih_arg = sc;
vmeintr_establish(ca->ca_ra.ra_intr[0].int_vec, pri,
@@ -659,12 +688,10 @@ ieattach(parent, self, aux)
#endif /* SUN4 */
}
- evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
-
bp = ca->ca_ra.ra_bp;
if (bp != NULL && strcmp(bp->name, "ie") == 0 &&
sc->sc_dev.dv_unit == bp->val[1])
- bootdv = &sc->sc_dev;
+ bp->dev = &sc->sc_dev;
}
@@ -674,10 +701,10 @@ ieattach(parent, self, aux)
* an interrupt after a transmit has been started on it.
*/
void
-iewatchdog(unit)
- short unit;
+iewatchdog(ifp)
+ struct ifnet *ifp;
{
- struct ie_softc *sc = iecd.cd_devs[unit];
+ struct ie_softc *sc = ifp->if_softc;
log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
++sc->sc_arpcom.ac_if.if_oerrors;
@@ -701,12 +728,12 @@ void *v;
* check for parity error
*/
if (sc->hard_type == IE_VME) {
- volatile struct ievme *iev = (volatile struct ievme *)sc->sc_reg;
-
+ volatile struct ievme *iev = (volatile struct ievme *)sc->sc_reg
+;
if (iev->status & IEVME_PERR) {
printf("%s: parity error (ctrl %x @ %02x%04x)\n",
- iev->pectrl, iev->pectrl & IEVME_HADDR,
- iev->peaddr);
+ sc->sc_dev.dv_xname, iev->pectrl,
+ iev->pectrl & IEVME_HADDR, iev->peaddr);
iev->pectrl = iev->pectrl | IEVME_PARACK;
}
}
@@ -754,7 +781,6 @@ loop:
if ((status = sc->scb->ie_status) & IE_ST_WHENCE)
goto loop;
- sc->sc_intrcnt.ev_count++;
return 1;
}
@@ -777,9 +803,9 @@ ierint(sc)
sc->sc_arpcom.ac_if.if_ipackets++;
if (!--timesthru) {
sc->sc_arpcom.ac_if.if_ierrors +=
- SWAP(scb->ie_err_crc) +
+ SWAP(scb->ie_err_crc) +
SWAP(scb->ie_err_align) +
- SWAP(scb->ie_err_resource) +
+ SWAP(scb->ie_err_resource) +
SWAP(scb->ie_err_overrun);
scb->ie_err_crc = scb->ie_err_align =
scb->ie_err_resource = scb->ie_err_overrun =
@@ -792,7 +818,7 @@ ierint(sc)
(scb->ie_status & IE_RU_READY) == 0) {
sc->rframes[0]->ie_fd_buf_desc =
MK_16(sc->sc_maddr, sc->rbuffs[0]);
- scb->ie_recv_list =
+ scb->ie_recv_list =
MK_16(sc->sc_maddr, sc->rframes[0]);
command_and_wait(sc, IE_RU_START, 0, 0);
}
@@ -823,7 +849,7 @@ ietint(sc)
if (status & IE_STAT_OK) {
sc->sc_arpcom.ac_if.if_opackets++;
- sc->sc_arpcom.ac_if.if_collisions +=
+ sc->sc_arpcom.ac_if.if_collisions +=
SWAP(status & IE_XS_MAXCOLL);
} else if (status & IE_STAT_ABORT) {
printf("%s: send aborted\n", sc->sc_dev.dv_xname);
@@ -865,7 +891,7 @@ ietint(sc)
* Compare two Ether/802 addresses for equality, inlined and unrolled for
* speed. I'd love to have an inline assembler version of this...
*/
-static inline int
+static __inline int
ether_equal(one, two)
u_char *one, *two;
{
@@ -888,7 +914,7 @@ ether_equal(one, two)
* only client which will fiddle with IFF_PROMISC is BPF. This is
* probably a good assumption, but we do not make it here. (Yet.)
*/
-static inline int
+static __inline int
check_eh(sc, eh, to_bpf)
struct ie_softc *sc;
struct ether_header *eh;
@@ -991,7 +1017,7 @@ check_eh(sc, eh, to_bpf)
* IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds
* the size of the buffer, then we are screwed anyway.
*/
-static inline int
+static __inline int
ie_buflen(sc, head)
struct ie_softc *sc;
int head;
@@ -1001,7 +1027,7 @@ ie_buflen(sc, head)
& (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1)));
}
-static inline int
+static __inline int
ie_packet_len(sc)
struct ie_softc *sc;
{
@@ -1034,7 +1060,7 @@ ie_packet_len(sc)
* command to the chip to be executed. On the way, if we have a BPF listener
* also give him a copy.
*/
-inline static void
+static __inline void
iexmit(sc)
struct ie_softc *sc;
{
@@ -1063,7 +1089,7 @@ iexmit(sc)
sc->xmit_cmds[sc->xctail]->ie_xmit_desc =
MK_16(sc->sc_maddr, sc->xmit_buffs[sc->xctail]);
- sc->scb->ie_command_list =
+ sc->scb->ie_command_list =
MK_16(sc->sc_maddr, sc->xmit_cmds[sc->xctail]);
command_and_wait(sc, IE_CU_START, 0, 0);
@@ -1079,7 +1105,7 @@ iexmit(sc)
* length of the data available. This enables us to allocate mbuf
* clusters in many situations where before we would have had a long
* chain of partially-full mbufs. This should help to speed up the
- * operation considerably. (Provided that it works, of course.)
+ * operation considerably. (Provided that it works, of course.)
*/
static inline int
ieget(sc, mp, ehp, to_bpf)
@@ -1385,7 +1411,7 @@ void
iestart(ifp)
struct ifnet *ifp;
{
- struct ie_softc *sc = iecd.cd_devs[ifp->if_unit];
+ struct ie_softc *sc = ifp->if_softc;
struct mbuf *m0, *m;
u_char *buffer;
u_short len;
@@ -1408,7 +1434,7 @@ iestart(ifp)
len = 0;
buffer = sc->xmit_cbuffs[sc->xchead];
- for (m0 = m; m && (len +m->m_len) < IE_TBUF_SIZE;
+ for (m0 = m; m && (len +m->m_len) < IE_TBUF_SIZE;
m = m->m_next) {
bcopy(mtod(m, caddr_t), buffer, m->m_len);
buffer += m->m_len;
@@ -1435,7 +1461,7 @@ iestart(ifp)
/*
* set up IE's ram space
*/
-int
+int
ie_setupram(sc)
struct ie_softc *sc;
{
@@ -1517,7 +1543,7 @@ iereset(sc)
*/
static void
chan_attn_timeout(rock)
- caddr_t rock;
+ void *rock;
{
*(int *)rock = 1;
@@ -1528,9 +1554,9 @@ chan_attn_timeout(rock)
* or be accepted, depending on the command. If the command pointer
* is null, then pretend that the command is not an action command.
* If the command pointer is not null, and the command is an action
- * command, wait for
- * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
- * to become true.
+ * command, wait for
+ * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
+ * to become true.
*/
static int
command_and_wait(sc, cmd, pcmd, mask)
@@ -1638,7 +1664,7 @@ run_tdr(sc, cmd)
#define ALLOC(p, n) _ALLOC(p, ALIGN(n)) /* XXX convert to this? */
#endif
-static inline caddr_t
+static __inline caddr_t
Align(ptr)
caddr_t ptr;
{
@@ -1661,13 +1687,11 @@ Align(ptr)
* note: this function was written to be easy to understand, rather than
* highly efficient (it isn't in the critical path).
*/
-static void
+static void
setup_bufs(sc)
struct ie_softc *sc;
{
caddr_t ptr = sc->buf_area; /* memory pool */
- volatile struct ie_recv_frame_desc *rfd = (void *) ptr;
- volatile struct ie_recv_buf_desc *rbd;
int n, r;
/*
@@ -1677,14 +1701,15 @@ setup_bufs(sc)
(sc->memzero)(ptr, sc->buf_area_sz);
ptr = Align(ptr); /* set alignment and stick with it */
- n = (int)Align(sizeof(struct ie_xmit_cmd)) +
- (int)Align(sizeof(struct ie_xmit_buf)) + IE_TBUF_SIZE;
+ n = (int)Align((caddr_t) sizeof(struct ie_xmit_cmd)) +
+ (int)Align((caddr_t) sizeof(struct ie_xmit_buf)) + IE_TBUF_SIZE;
n *= NTXBUF; /* n = total size of xmit area */
n = sc->buf_area_sz - n;/* n = free space for recv stuff */
- r = (int)Align(sizeof(struct ie_recv_frame_desc)) +
- (((int)Align(sizeof(struct ie_recv_buf_desc)) + IE_RBUF_SIZE) * B_PER_F);
+ r = (int)Align((caddr_t) sizeof(struct ie_recv_frame_desc)) +
+ (((int)Align((caddr_t) sizeof(struct ie_recv_buf_desc)) +
+ IE_RBUF_SIZE) * B_PER_F);
/* r = size of one R frame */
@@ -1804,7 +1829,7 @@ mc_setup(sc, ptr)
(sc->memcopy)((caddr_t)sc->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
sc->mcast_count * sizeof *sc->mcast_addrs);
- cmd->ie_mcast_bytes =
+ cmd->ie_mcast_bytes =
SWAP(sc->mcast_count * ETHER_ADDR_LEN); /* grrr... */
sc->scb->ie_command_list = MK_16(sc->sc_maddr, cmd);
@@ -1831,7 +1856,6 @@ ieinit(sc)
{
volatile struct ie_sys_ctl_block *scb = sc->scb;
void *ptr;
- int n;
ptr = sc->buf_area;
@@ -1867,7 +1891,7 @@ ieinit(sc)
cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
cmd->com.ie_cmd_link = SWAP(0xffff);
- (sc->memcopy)(sc->sc_arpcom.ac_enaddr,
+ (sc->memcopy)(sc->sc_arpcom.ac_enaddr,
(caddr_t)&cmd->ie_address, sizeof cmd->ie_address);
if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
@@ -1920,18 +1944,13 @@ ieioctl(ifp, cmd, data)
u_long cmd;
caddr_t data;
{
- struct ie_softc *sc = iecd.cd_devs[ifp->if_unit];
+ struct ie_softc *sc = ifp->if_softc;
struct ifaddr *ifa = (struct ifaddr *)data;
struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
s = splnet();
- if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
- splx(s);
- return error;
- }
-
switch(cmd) {
case SIOCSIFADDR:
@@ -1944,6 +1963,24 @@ ieioctl(ifp, cmd, data)
arp_ifinit(&sc->sc_arpcom, ifa);
break;
#endif
+#ifdef NS
+ /* XXX - This code is probably wrong. */
+ case AF_NS:
+ {
+ struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
+ else
+ bcopy(ina->x_host.c_host,
+ sc->sc_arpcom.ac_enaddr,
+ sizeof(sc->sc_arpcom.ac_enaddr));
+ /* Set new address. */
+ ieinit(sc);
+ break;
+ }
+#endif /* NS */
default:
ieinit(sc);
break;
diff --git a/sys/arch/sparc/dev/if_le.c b/sys/arch/sparc/dev/if_le.c
index 055e2a31a5c..4db240f0f62 100644
--- a/sys/arch/sparc/dev/if_le.c
+++ b/sys/arch/sparc/dev/if_le.c
@@ -1,6 +1,8 @@
-/* $NetBSD: if_le.c,v 1.24 1995/12/11 12:43:28 pk Exp $ */
+/* $NetBSD: if_le.c,v 1.35.4.1 1996/07/17 01:46:00 jtc Exp $ */
/*-
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -18,6 +20,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
@@ -62,46 +66,92 @@
#include <sparc/dev/sbusvar.h>
#include <sparc/dev/dmareg.h>
#include <sparc/dev/dmavar.h>
-#include <sparc/dev/if_lereg.h>
-#include <sparc/dev/if_levar.h>
+
#include <dev/ic/am7990reg.h>
-#define LE_NEED_BUF_CONTIG
#include <dev/ic/am7990var.h>
-#define LE_SOFTC(unit) lecd.cd_devs[unit]
-#define LE_DELAY(x) DELAY(x)
+#include <sparc/dev/if_lereg.h>
+#include <sparc/dev/if_levar.h>
int lematch __P((struct device *, void *, void *));
void leattach __P((struct device *, struct device *, void *));
-int leintr __P((void *));
-struct cfdriver lecd = {
- NULL, "le", lematch, leattach, DV_IFNET, sizeof(struct le_softc)
+#if defined(SUN4M) /* XXX */
+int myleintr __P((void *));
+int ledmaintr __P((struct dma_softc *));
+
+int
+myleintr(arg)
+ void *arg;
+{
+ register struct le_softc *lesc = arg;
+
+ if (lesc->sc_dma->sc_regs->csr & D_ERR_PEND)
+ return ledmaintr(lesc->sc_dma);
+
+ /*
+ * XXX There is a bug somewhere in the interrupt code that causes stray
+ * ethernet interrupts under high network load. This bug has been
+ * impossible to locate, so until it is found, we just ignore stray
+ * interrupts, as they do not in fact correspond to dropped packets.
+ */
+
+ /* return */ am7990_intr(arg);
+ return 1;
+}
+#endif
+
+struct cfattach le_ca = {
+ sizeof(struct le_softc), lematch, leattach
};
-integrate void
+hide void lewrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t));
+hide u_int16_t lerdcsr __P((struct am7990_softc *, u_int16_t));
+hide void lehwinit __P((struct am7990_softc *));
+
+hide void
lewrcsr(sc, port, val)
- struct le_softc *sc;
+ struct am7990_softc *sc;
u_int16_t port, val;
{
- register struct lereg1 *ler1 = sc->sc_r1;
+ register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
ler1->ler1_rap = port;
ler1->ler1_rdp = val;
}
-integrate u_int16_t
+hide u_int16_t
lerdcsr(sc, port)
- struct le_softc *sc;
+ struct am7990_softc *sc;
u_int16_t port;
{
- register struct lereg1 *ler1 = sc->sc_r1;
+ register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
u_int16_t val;
ler1->ler1_rap = port;
val = ler1->ler1_rdp;
return (val);
-}
+}
+
+hide void
+lehwinit(sc)
+ struct am7990_softc *sc;
+{
+#if defined(SUN4M)
+ struct le_softc *lesc = (struct le_softc *)sc;
+
+ if (CPU_ISSUN4M && lesc->sc_dma) {
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+
+ if (ifp->if_flags & IFF_LINK0)
+ lesc->sc_dma->sc_regs->csr |= DE_AUI_TP;
+ else if (ifp->if_flags & IFF_LINK1)
+ lesc->sc_dma->sc_regs->csr &= ~DE_AUI_TP;
+
+ delay(20000); /* must not touch le for 20ms */
+ }
+#endif
+}
int
lematch(parent, match, aux)
@@ -125,15 +175,18 @@ leattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
- struct le_softc *sc = (void *)self;
+ struct le_softc *lesc = (struct le_softc *)self;
+ struct am7990_softc *sc = &lesc->sc_am7990;
struct confargs *ca = aux;
int pri;
struct bootpath *bp;
u_long laddr;
- int dmachild = strncmp(parent->dv_xname, "ledma", 5) == 0;
+#if defined(SUN4C) || defined(SUN4M)
+ int sbuschild = strncmp(parent->dv_xname, "sbus", 4) == 0;
+#endif
/* XXX the following declarations should be elsewhere */
- extern void myetheraddr(u_char *);
+ extern void myetheraddr __P((u_char *));
if (ca->ca_ra.ra_nintr != 1) {
printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr);
@@ -142,13 +195,13 @@ leattach(parent, self, aux)
pri = ca->ca_ra.ra_intr[0].int_pri;
printf(" pri %d", pri);
- sc->sc_r1 = (struct lereg1 *)mapiodev(ca->ca_ra.ra_reg, 0,
+ lesc->sc_r1 = (struct lereg1 *)mapiodev(ca->ca_ra.ra_reg, 0,
sizeof(struct lereg1),
ca->ca_bustype);
sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
laddr = (u_long)dvma_malloc(MEMSIZE, &sc->sc_mem, M_NOWAIT);
#if defined (SUN4M)
- if ((laddr & 0xffffff) >= (laddr & 0xffffff) + MEMSIZE)
+ if ((laddr & 0xffffff) >= (laddr & 0xffffff) + MEMSIZE)
panic("if_le: Lance buffer crosses 16MB boundary");
#endif
sc->sc_addr = laddr & 0xffffff;
@@ -156,14 +209,17 @@ leattach(parent, self, aux)
myetheraddr(sc->sc_arpcom.ac_enaddr);
- sc->sc_copytodesc = copytobuf_contig;
- sc->sc_copyfromdesc = copyfrombuf_contig;
- sc->sc_copytobuf = copytobuf_contig;
- sc->sc_copyfrombuf = copyfrombuf_contig;
- sc->sc_zerobuf = zerobuf_contig;
+ sc->sc_copytodesc = am7990_copytobuf_contig;
+ sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
+ sc->sc_copytobuf = am7990_copytobuf_contig;
+ sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
+ sc->sc_zerobuf = am7990_zerobuf_contig;
- sc->sc_arpcom.ac_if.if_name = lecd.cd_name;
- leconfig(sc);
+ sc->sc_rdcsr = lerdcsr;
+ sc->sc_wrcsr = lewrcsr;
+ sc->sc_hwinit = lehwinit;
+
+ am7990_config(sc);
bp = ca->ca_ra.ra_bp;
switch (ca->ca_bustype) {
@@ -173,44 +229,41 @@ leattach(parent, self, aux)
(bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit))
case BUS_SBUS:
- sc->sc_sd.sd_reset = (void *)lereset;
- if (dmachild) {
-#ifdef notyet
- sc->sc_dma = (struct dma_softc *)parent;
- sc->sc_dma->sc_le = sc;
- sc->sc_dma->sc_regs->en_bar = laddr & 0xff000000;
- sbus_establish(&sc->sc_sd, parent);
-#endif
+ lesc->sc_sd.sd_reset = (void *)am7990_reset;
+ if (sbuschild) {
+ lesc->sc_dma = NULL;
+ sbus_establish(&lesc->sc_sd, &sc->sc_dev);
} else {
- sc->sc_dma = NULL;
- sbus_establish(&sc->sc_sd, &sc->sc_dev);
+ lesc->sc_dma = (struct dma_softc *)parent;
+ lesc->sc_dma->sc_le = lesc;
+ lesc->sc_dma->sc_regs->en_bar = laddr & 0xff000000;
+ /* Assume SBus is grandparent */
+ sbus_establish(&lesc->sc_sd, parent);
}
- if (bp != NULL && strcmp(bp->name, lecd.cd_name) == 0 &&
+ if (bp != NULL && strcmp(bp->name, le_cd.cd_name) == 0 &&
SAME_LANCE(bp, ca))
- bootdv = &sc->sc_dev;
+ bp->dev = &sc->sc_dev;
break;
#endif /* SUN4C || SUN4M */
default:
- if (bp != NULL && strcmp(bp->name, lecd.cd_name) == 0 &&
+ if (bp != NULL && strcmp(bp->name, le_cd.cd_name) == 0 &&
sc->sc_dev.dv_unit == bp->val[1])
- bootdv = &sc->sc_dev;
+ bp->dev = &sc->sc_dev;
break;
}
- sc->sc_ih.ih_fun = leintr;
-#if defined(SUN4M) && 0
- if (cputyp == CPU_SUN4M)
- sc->sc_ih.ih_fun = myleintr;
+ lesc->sc_ih.ih_fun = am7990_intr;
+#if defined(SUN4M) /*XXX*/
+ if (CPU_ISSUN4M)
+ lesc->sc_ih.ih_fun = myleintr;
#endif
- sc->sc_ih.ih_arg = sc;
- intr_establish(pri, &sc->sc_ih);
+ lesc->sc_ih.ih_arg = sc;
+ intr_establish(pri, &lesc->sc_ih);
/* now initialize DMA */
- if (sc->sc_dma) {
- dmaenintr(sc->sc_dma);
+ if (lesc->sc_dma) {
+ DMA_ENINTR(lesc->sc_dma);
}
}
-
-#include <dev/ic/am7990.c>
diff --git a/sys/arch/sparc/dev/if_levar.h b/sys/arch/sparc/dev/if_levar.h
index 7361c4eae7a..934d74c932e 100644
--- a/sys/arch/sparc/dev/if_levar.h
+++ b/sys/arch/sparc/dev/if_levar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: if_levar.h,v 1.2 1995/12/11 12:43:29 pk Exp $ */
+/* $NetBSD: if_levar.h,v 1.5 1996/05/07 01:27:32 thorpej Exp $ */
/*-
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
@@ -47,45 +47,10 @@
* This structure contains the output queue for the interface, its address, ...
*/
struct le_softc {
- struct device sc_dev; /* base structure */
- struct arpcom sc_arpcom; /* Ethernet common part */
-
- void (*sc_copytodesc)(); /* Copy to descriptor */
- void (*sc_copyfromdesc)(); /* Copy from descriptor */
-
- void (*sc_copytobuf)(); /* Copy to buffer */
- void (*sc_copyfrombuf)(); /* Copy from buffer */
- void (*sc_zerobuf)(); /* and Zero bytes in buffer */
-
- u_int16_t sc_conf3; /* CSR3 value */
-
- void *sc_mem; /* base address of RAM -- CPU's view */
- u_long sc_addr; /* base address of RAM -- LANCE's view */
- u_long sc_memsize; /* size of RAM */
-
- int sc_nrbuf; /* number of receive buffers */
- int sc_ntbuf; /* number of transmit buffers */
- int sc_last_rd;
- int sc_first_td, sc_last_td, sc_no_td;
-
- int sc_initaddr;
- int sc_rmdaddr;
- int sc_tmdaddr;
- int sc_rbufaddr;
- int sc_tbufaddr;
-
-#ifdef LEDEBUG
- int sc_debug;
-#endif
+ struct am7990_softc sc_am7990; /* glue to MI code */
struct sbusdev sc_sd; /* sbus device */
struct intrhand sc_ih; /* interrupt vectoring */
struct lereg1 *sc_r1; /* LANCE registers */
struct dma_softc *sc_dma; /* pointer to my dma */
};
-
-/* DMA macros for ledma */
-#define DMA_ENINTR(r) ((r->enintr)(r))
-#define DMA_ISINTR(r) ((r->isintr)(r))
-#define DMA_RESET(r) ((r->reset)(r))
-
diff --git a/sys/arch/sparc/dev/kbd.c b/sys/arch/sparc/dev/kbd.c
index 194da8fdd6e..f65228f0848 100644
--- a/sys/arch/sparc/dev/kbd.c
+++ b/sys/arch/sparc/dev/kbd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: kbd.c,v 1.19 1995/07/06 05:35:34 pk Exp $ */
+/* $NetBSD: kbd.c,v 1.23 1996/04/01 17:34:34 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -51,7 +51,6 @@
*/
#include <sys/param.h>
-#include <sys/conf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/kernel.h>
@@ -59,8 +58,11 @@
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/tty.h>
+#include <sys/signalvar.h>
+#include <sys/conf.h>
#include <machine/autoconf.h>
+#include <machine/conf.h>
#include <machine/vuid_event.h>
#include <sparc/dev/event_var.h>
@@ -217,19 +219,10 @@ struct kbd_softc {
} kbd_softc;
/* Prototypes */
-void kbd_ascii(struct tty *);
-void kbd_serial(struct tty *, void (*)(), void (*)());
-static void kbd_getid(void *);
-void kbd_reset(struct kbd_state *);
-static int kbd_translate(int, struct kbd_state *);
-void kbd_rint(int);
-int kbdopen(dev_t, int, int, struct proc *);
-int kbdclose(dev_t, int, int, struct proc *);
-int kbdread(dev_t, struct uio *, int);
-int kbdwrite(dev_t, struct uio *, int);
-int kbdioctl(dev_t, u_long, caddr_t, int, struct proc *);
-int kbdselect(dev_t, int, struct proc *);
-int kbd_docmd(int, int);
+void kbd_reset __P((struct kbd_state *));
+static int kbd_translate __P((int, struct kbd_state *));
+void kbdattach __P((int));
+void kbd_repeat __P((void *arg));
/* set in kbdattach() */
int kbd_repeat_start;
@@ -240,7 +233,8 @@ int kbd_repeat_step;
* This happens before kbd_serial.
*/
void
-kbd_ascii(struct tty *tp)
+kbd_ascii(tp)
+ struct tty *tp;
{
kbd_softc.k_cons = tp;
@@ -251,7 +245,10 @@ kbd_ascii(struct tty *tp)
* We pick up the initial keyboard click state here as well.
*/
void
-kbd_serial(struct tty *tp, void (*iopen)(), void (*iclose)())
+kbd_serial(tp, iopen, iclose)
+ struct tty *tp;
+ void (*iopen) __P((struct tty *));
+ void (*iclose) __P((struct tty *));
{
register struct kbd_softc *k;
register char *cp;
@@ -261,13 +258,11 @@ kbd_serial(struct tty *tp, void (*iopen)(), void (*iclose)())
k->k_open = iopen;
k->k_close = iclose;
-#if defined(SUN4C) || defined(SUN4M)
- if (cputyp != CPU_SUN4) {
+ if (!CPU_ISSUN4) {
cp = getpropstring(optionsnode, "keyboard-click?");
if (cp && strcmp(cp, "true") == 0)
k->k_state.kbd_click = 1;
}
-#endif /* SUN4C || SUN4M */
}
/*
@@ -276,7 +271,8 @@ kbd_serial(struct tty *tp, void (*iopen)(), void (*iclose)())
* send a RESET, so that we can find out what kind of keyboard it is.
*/
void
-kbdattach(int nkbd)
+kbdattach(kbd)
+ int kbd;
{
register struct kbd_softc *k;
register struct tty *tp;
@@ -295,7 +291,8 @@ kbdattach(int nkbd)
}
void
-kbd_reset(register struct kbd_state *ks)
+kbd_reset(ks)
+ register struct kbd_state *ks;
{
/*
* On first identification, wake up anyone waiting for type
@@ -328,7 +325,6 @@ kbd_reset(register struct kbd_state *ks)
break;
default:
printf("Unknown keyboard type %d\n", ks->kbd_id);
- break;
}
ks->kbd_leds = 0;
@@ -338,7 +334,9 @@ kbd_reset(register struct kbd_state *ks)
* Turn keyboard up/down codes into ASCII.
*/
static int
-kbd_translate(register int c, register struct kbd_state *ks)
+kbd_translate(c, ks)
+ register int c;
+ register struct kbd_state *ks;
{
register int down;
@@ -401,7 +399,8 @@ kbd_translate(register int c, register struct kbd_state *ks)
void
-kbd_repeat(void *arg)
+kbd_repeat(arg)
+ void *arg;
{
struct kbd_softc *k = (struct kbd_softc *)arg;
int s = spltty();
@@ -414,7 +413,8 @@ kbd_repeat(void *arg)
}
void
-kbd_rint(register int c)
+kbd_rint(c)
+ register int c;
{
register struct kbd_softc *k = &kbd_softc;
register struct firm_event *fe;
@@ -512,7 +512,11 @@ kbd_rint(register int c)
}
int
-kbdopen(dev_t dev, int flags, int mode, struct proc *p)
+kbdopen(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
{
int s, error;
struct tty *tp;
@@ -548,7 +552,11 @@ kbdopen(dev_t dev, int flags, int mode, struct proc *p)
}
int
-kbdclose(dev_t dev, int flags, int mode, struct proc *p)
+kbdclose(dev, flags, mode, p)
+ dev_t dev;
+ int flags;
+ int mode;
+ struct proc *p;
{
/*
@@ -564,7 +572,10 @@ kbdclose(dev_t dev, int flags, int mode, struct proc *p)
}
int
-kbdread(dev_t dev, struct uio *uio, int flags)
+kbdread(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
{
return (ev_read(&kbd_softc.k_events, uio, flags));
@@ -572,14 +583,22 @@ kbdread(dev_t dev, struct uio *uio, int flags)
/* this routine should not exist, but is convenient to write here for now */
int
-kbdwrite(dev_t dev, struct uio *uio, int flags)
+kbdwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
{
return (EOPNOTSUPP);
}
int
-kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p)
+kbdioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ register caddr_t data;
+ int flag;
+ struct proc *p;
{
register struct kbd_softc *k = &kbd_softc;
register struct kiockey *kmp;
@@ -602,10 +621,11 @@ kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p)
case KIOCGETKEY:
if (((struct okiockey *)data)->kio_station == 118) {
/*
- * This is X11 asking if a type 3 keyboard is
- * really a type 3 keyboard. Say yes.
+ * This is X11 asking (in an inappropriate fashion)
+ * if a type 3 keyboard is really a type 3 keyboard.
+ * Say yes (inappropriately).
*/
- ((struct okiockey *)data)->kio_entry = (u_char) HOLE;
+ ((struct okiockey *)data)->kio_entry = (u_char)HOLE;
return (0);
}
break;
@@ -680,7 +700,6 @@ kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p)
int s;
char leds = *(char *)data;
struct tty *tp = kbd_softc.k_kbd;
-
s = spltty();
if (tp->t_outq.c_cc > 120)
(void) tsleep((caddr_t)&lbolt, TTIPRI,
@@ -699,6 +718,7 @@ kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p)
*(char *)data = k->k_state.kbd_leds;
return (0);
+
case FIONBIO: /* we will remove this someday (soon???) */
return (0);
@@ -722,7 +742,10 @@ kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p)
}
int
-kbdselect(dev_t dev, int rw, struct proc *p)
+kbdselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
{
return (ev_select(&kbd_softc.k_events, rw, p));
@@ -734,7 +757,9 @@ kbdselect(dev_t dev, int rw, struct proc *p)
* is flooding. (The keyboard runs at 1200 baud, or 120 cps.)
*/
int
-kbd_docmd(int cmd, int isuser)
+kbd_docmd(cmd, isuser)
+ int cmd;
+ int isuser;
{
register struct tty *tp = kbd_softc.k_kbd;
register struct kbd_softc *k = &kbd_softc;
diff --git a/sys/arch/sparc/dev/ms.c b/sys/arch/sparc/dev/ms.c
index fb71f4ecb36..365d1c476b2 100644
--- a/sys/arch/sparc/dev/ms.c
+++ b/sys/arch/sparc/dev/ms.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ms.c,v 1.5 1995/08/29 22:15:35 pk Exp $ */
+/* $NetBSD: ms.c,v 1.8 1996/04/01 17:29:52 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -49,15 +49,20 @@
*/
#include <sys/param.h>
-#include <sys/conf.h>
#include <sys/ioctl.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/tty.h>
+#include <sys/signalvar.h>
+#include <sys/conf.h>
#include <machine/vuid_event.h>
+#include <machine/cpu.h>
+#include <machine/kbd.h>
+#include <machine/conf.h>
+
#include <sparc/dev/event_var.h>
/*
@@ -92,7 +97,8 @@ struct ms_softc {
void
ms_serial(tp, iopen, iclose)
struct tty *tp;
- void (*iopen)(), (*iclose)();
+ void (*iopen) __P((struct tty *));
+ void (*iclose) __P((struct tty *));
{
ms_softc.ms_mouse = tp;
@@ -242,13 +248,18 @@ msopen(dev, flags, mode, p)
int flags, mode;
struct proc *p;
{
- int s, error;
if (ms_softc.ms_events.ev_io)
return (EBUSY);
ms_softc.ms_events.ev_io = p;
ev_init(&ms_softc.ms_events); /* may cause sleep */
+ if (CPU_ISSUN4) {
+ /* We need to set the baud rate on the mouse. */
+ ms_softc.ms_mouse->t_ispeed =
+ ms_softc.ms_mouse->t_ospeed = 1200;
+ }
+
(*ms_softc.ms_open)(ms_softc.ms_mouse);
ms_softc.ms_ready = 1; /* start accepting events */
return (0);
@@ -297,8 +308,6 @@ msioctl(dev, cmd, data, flag, p)
int flag;
struct proc *p;
{
- int s;
-
switch (cmd) {
case FIONBIO: /* we will remove this someday (soon???) */
diff --git a/sys/arch/sparc/dev/obio.c b/sys/arch/sparc/dev/obio.c
index f78bbcc2f37..37cf369fe48 100644
--- a/sys/arch/sparc/dev/obio.c
+++ b/sys/arch/sparc/dev/obio.c
@@ -1,7 +1,8 @@
-/* $NetBSD: obio.c,v 1.15 1995/05/27 08:12:51 pk Exp $ */
+/* $NetBSD: obio.c,v 1.24 1996/05/18 12:22:49 mrg Exp $ */
/*
* Copyright (c) 1993, 1994 Theo de Raadt
+ * Copyright (c) 1995 Paul Kranenburg
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,6 +32,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
@@ -48,10 +50,14 @@
#include <machine/ctlreg.h>
#include <sparc/sparc/asm.h>
#include <sparc/sparc/vaddrs.h>
+#include <sparc/dev/sbusvar.h>
struct bus_softc {
- struct device sc_dev; /* base device */
- int nothing;
+ union {
+ struct device scu_dev; /* base device */
+ struct sbus_softc scu_sbus; /* obio is another sbus slot */
+ } bu;
+#define sc_dev bu.scu_dev
};
/* autoconfiguration driver */
@@ -60,17 +66,40 @@ static void obioattach __P((struct device *, struct device *, void *));
static void vmesattach __P((struct device *, struct device *, void *));
static void vmelattach __P((struct device *, struct device *, void *));
-struct cfdriver obiocd = { NULL, "obio", busmatch, obioattach,
- DV_DULL, sizeof(struct bus_softc)
+int busprint __P((void *, char *));
+static int busattach __P((struct device *, void *, void *, int));
+void * bus_map __P((struct rom_reg *, int, int));
+int obio_scan __P((struct device *, void *, void *));
+int vmes_scan __P((struct device *, void *, void *));
+int vmel_scan __P((struct device *, void *, void *));
+int vmeintr __P((void *));
+
+struct cfattach obio_ca = {
+ sizeof(struct bus_softc), busmatch, obioattach
+};
+
+struct cfdriver obio_cd = {
+ NULL, "obio", DV_DULL
};
-struct cfdriver vmelcd = { NULL, "vmel", busmatch, vmelattach,
- DV_DULL, sizeof(struct bus_softc)
+
+struct cfattach vmel_ca = {
+ sizeof(struct bus_softc), busmatch, vmelattach
};
-struct cfdriver vmescd = { NULL, "vmes", busmatch, vmesattach,
- DV_DULL, sizeof(struct bus_softc)
+
+struct cfdriver vmel_cd = {
+ NULL, "vmel", DV_DULL
};
-static int busattach __P((struct device *, void *, void *, int));
+struct cfattach vmes_ca = {
+ sizeof(struct bus_softc), busmatch, vmesattach
+};
+
+struct cfdriver vmes_cd = {
+ NULL, "vmes", DV_DULL
+};
+
+struct intrhand **vmeints;
+
int
busmatch(parent, vcf, aux)
@@ -81,8 +110,12 @@ busmatch(parent, vcf, aux)
register struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
- if (cputyp != CPU_SUN4)
+ if (CPU_ISSUN4M)
+ return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
+
+ if (!CPU_ISSUN4)
return (0);
+
return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
}
@@ -95,27 +128,180 @@ busprint(args, obio)
if (ca->ca_ra.ra_name == NULL)
ca->ca_ra.ra_name = "<unknown>";
+
if (obio)
printf("[%s at %s]", ca->ca_ra.ra_name, obio);
- printf(" addr 0x%x", ca->ca_ra.ra_paddr);
- if (ca->ca_ra.ra_intr[0].int_vec != -1)
+
+ printf(" addr %p", ca->ca_ra.ra_paddr);
+
+ if (CPU_ISSUN4 && ca->ca_ra.ra_intr[0].int_vec != -1)
printf(" vec 0x%x", ca->ca_ra.ra_intr[0].int_vec);
+
return (UNCONF);
}
+
+void
+obioattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+#if defined(SUN4M)
+ register struct bus_softc *sc = (struct bus_softc *)self;
+ struct confargs oca, *ca = args;
+ register struct romaux *ra = &ca->ca_ra;
+ register int node0, node;
+ register char *name;
+ register const char *sp;
+ const char *const *ssp;
+ extern int autoconf_nzs;
+
+ static const char *const special4m[] = {
+ /* find these first */
+ "eeprom",
+ "counter",
+ "auxio",
+ "",
+ /* place device to ignore here */
+ "interrupt",
+ NULL
+ };
+#endif
+
+ if (CPU_ISSUN4) {
+ if (self->dv_unit > 0) {
+ printf(" unsupported\n");
+ return;
+ }
+ printf("\n");
+
+ (void)config_search(obio_scan, self, args);
+ bus_untmp();
+ }
+
+#if defined(SUN4M)
+ if (!CPU_ISSUN4M)
+ return;
+
+ /*
+ * There is only one obio bus (it is in fact one of the Sbus slots)
+ * How about VME?
+ */
+ if (sc->sc_dev.dv_unit > 0) {
+ printf(" unsupported\n");
+ return;
+ }
+
+ printf("\n");
+
+ if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "obio") == 0)
+ oca.ca_ra.ra_bp = ra->ra_bp + 1;
+ else
+ oca.ca_ra.ra_bp = NULL;
+
+ sc->bu.scu_sbus.sc_range = ra->ra_range;
+ sc->bu.scu_sbus.sc_nrange = ra->ra_nrange;
+
+ /*
+ * Loop through ROM children, fixing any relative addresses
+ * and then configuring each device.
+ * We first do the crucial ones, such as eeprom, etc.
+ */
+ node0 = firstchild(ra->ra_node);
+ for (ssp = special4m ; *(sp = *ssp) != 0; ssp++) {
+ if ((node = findnode(node0, sp)) == 0) {
+ printf("could not find %s amongst obio devices\n", sp);
+ panic(sp);
+ }
+ if (!romprop(&oca.ca_ra, sp, node))
+ continue;
+
+ sbus_translate(self, &oca);
+ oca.ca_bustype = BUS_OBIO;
+ (void) config_found(&sc->sc_dev, (void *)&oca, busprint);
+ }
+
+ for (node = node0; node; node = nextsibling(node)) {
+ name = getpropstring(node, "name");
+ for (ssp = special4m ; (sp = *ssp) != NULL; ssp++)
+ if (strcmp(name, sp) == 0)
+ break;
+
+ if (sp != NULL || !romprop(&oca.ca_ra, name, node))
+ continue;
+
+ if (strcmp(name, "zs") == 0)
+ /* XXX - see autoconf.c for this hack */
+ autoconf_nzs++;
+
+ /* Translate into parent address spaces */
+ sbus_translate(self, &oca);
+ oca.ca_bustype = BUS_OBIO;
+ (void) config_found(&sc->sc_dev, (void *)&oca, busprint);
+ }
+#endif
+}
+
+void
+vmesattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ if (CPU_ISSUN4M || self->dv_unit > 0) {
+ printf(" unsupported\n");
+ return;
+ }
+ printf("\n");
+
+ if (vmeints == NULL) {
+ vmeints = (struct intrhand **)malloc(256 *
+ sizeof(struct intrhand *), M_TEMP, M_NOWAIT);
+ bzero(vmeints, 256 * sizeof(struct intrhand *));
+ }
+ (void)config_search(vmes_scan, self, args);
+ bus_untmp();
+}
+
+void
+vmelattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ if (CPU_ISSUN4M || self->dv_unit > 0) {
+ printf(" unsupported\n");
+ return;
+ }
+ printf("\n");
+
+ if (vmeints == NULL) {
+ vmeints = (struct intrhand **)malloc(256 *
+ sizeof(struct intrhand *), M_TEMP, M_NOWAIT);
+ bzero(vmeints, 256 * sizeof(struct intrhand *));
+ }
+ (void)config_search(vmel_scan, self, args);
+ bus_untmp();
+}
+
int
busattach(parent, child, args, bustype)
struct device *parent;
- void *child, *args;
+ void *args, *child;
int bustype;
{
+#if defined(SUN4)
struct cfdata *cf = child;
- register struct bus_softc *sc = (struct bus_softc *)parent;
register struct confargs *ca = args;
struct confargs oca;
caddr_t tmp;
- if (bustype == BUS_OBIO && cputyp == CPU_SUN4) {
+ if (bustype == BUS_OBIO && CPU_ISSUN4) {
+
+ /*
+ * avoid sun4m entries which don't have valid PA's.
+ * no point in even probing them.
+ */
+ if (cf->cf_loc[0] == -1) return 0;
+
/*
* On the 4/100 obio addresses must be mapped at
* 0x0YYYYYYY, but alias higher up (we avoid the
@@ -123,64 +309,69 @@ busattach(parent, child, args, bustype)
* XXX: We also assume that 4/[23]00 obio addresses
* must be 0xZYYYYYYY, where (Z != 0)
*/
- if (cpumod==SUN4_100 && (cf->cf_loc[0] & 0xf0000000))
- return (0);
- if (cpumod!=SUN4_100 && !(cf->cf_loc[0] & 0xf0000000))
- return (0);
+ if (cpumod == SUN4_100 && (cf->cf_loc[0] & 0xf0000000))
+ return 0;
+ if (cpumod != SUN4_100 && !(cf->cf_loc[0] & 0xf0000000))
+ return 0;
}
if (parent->dv_cfdata->cf_driver->cd_indirect) {
printf(" indirect devices not supported\n");
- return (0);
+ return 0;
}
oca.ca_ra.ra_iospace = -1;
oca.ca_ra.ra_paddr = (void *)cf->cf_loc[0];
oca.ca_ra.ra_len = 0;
oca.ca_ra.ra_nreg = 1;
- tmp = NULL;
- if (oca.ca_ra.ra_paddr != (void *)-1)
- tmp = bus_tmp(oca.ca_ra.ra_paddr, bustype);
+ if (oca.ca_ra.ra_paddr)
+ tmp = (caddr_t)bus_tmp(oca.ca_ra.ra_paddr,
+ bustype);
+ else
+ tmp = NULL;
oca.ca_ra.ra_vaddr = tmp;
oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1];
if (bustype == BUS_VME16 || bustype == BUS_VME32)
oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2];
else
oca.ca_ra.ra_intr[0].int_vec = -1;
- oca.ca_ra.ra_nintr = 0;
- if (oca.ca_ra.ra_intr[0].int_pri != -1)
- oca.ca_ra.ra_nintr = 1;
+ oca.ca_ra.ra_nintr = 1;
oca.ca_ra.ra_name = cf->cf_driver->cd_name;
- oca.ca_ra.ra_bp = NULL;
if (ca->ca_ra.ra_bp != NULL &&
- ((bustype == BUS_VME16 && strcmp(ca->ca_ra.ra_bp->name, "vmes") == 0) ||
- (bustype == BUS_VME32 && strcmp(ca->ca_ra.ra_bp->name, "vmel") == 0) ||
- (bustype == BUS_OBIO && strcmp(ca->ca_ra.ra_bp->name, "obio") == 0)))
+ ((bustype == BUS_VME16 && strcmp(ca->ca_ra.ra_bp->name,"vmes") ==0) ||
+ (bustype == BUS_VME32 && strcmp(ca->ca_ra.ra_bp->name,"vmel") ==0) ||
+ (bustype == BUS_OBIO && strcmp(ca->ca_ra.ra_bp->name,"obio") == 0)))
oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1;
+ else
+ oca.ca_ra.ra_bp = NULL;
oca.ca_bustype = bustype;
- if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0)
- return (0);
+ if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0)
+ return 0;
/*
- * check if XXmatch() replaced the temporary mapping with
- * a real mapping. If not, then make sure we don't pass the
- * tmp mapping to the attach routine.
+ * check if XXmatch routine replaced the temporary mapping with
+ * a real mapping. If not, then make sure we don't pass the
+ * tmp mapping to the attach routine.
*/
if (oca.ca_ra.ra_vaddr == tmp)
oca.ca_ra.ra_vaddr = NULL; /* wipe out tmp address */
/*
- * the match routine will set "ra_len" if it wants us to
+ * the match routine will set "ra_len" if it wants us to
* establish a mapping for it.
* (which won't be seen on future XXmatch calls,
* so not as useful as it seems.)
*/
if (oca.ca_ra.ra_len)
- oca.ca_ra.ra_vaddr = bus_map(oca.ca_ra.ra_paddr,
+ oca.ca_ra.ra_vaddr =
+ bus_map(oca.ca_ra.ra_reg,
oca.ca_ra.ra_len, oca.ca_bustype);
config_attach(parent, cf, &oca, busprint);
- return (1);
+ return 1;
+#else
+ return 0;
+#endif
}
int
@@ -191,23 +382,6 @@ obio_scan(parent, child, args)
return busattach(parent, child, args, BUS_OBIO);
}
-void
-obioattach(parent, self, args)
- struct device *parent, *self;
- void *args;
-{
- if (self->dv_unit > 0) {
- printf(" unsupported\n");
- return;
- }
- printf("\n");
-
- (void)config_search(obio_scan, self, args);
- bus_untmp();
-}
-
-struct intrhand **vmeints;
-
int
vmes_scan(parent, child, args)
struct device *parent;
@@ -216,26 +390,6 @@ vmes_scan(parent, child, args)
return busattach(parent, child, args, BUS_VME16);
}
-void
-vmesattach(parent, self, args)
- struct device *parent, *self;
- void *args;
-{
- if (self->dv_unit > 0) {
- printf(" unsupported\n");
- return;
- }
- printf("\n");
-
- if (vmeints == NULL) {
- vmeints = (struct intrhand **)malloc(256 *
- sizeof(struct intrhand *), M_TEMP, M_NOWAIT);
- bzero(vmeints, 256 * sizeof(struct intrhand *));
- }
- (void)config_search(vmes_scan, self, args);
- bus_untmp();
-}
-
int
vmel_scan(parent, child, args)
struct device *parent;
@@ -244,26 +398,6 @@ vmel_scan(parent, child, args)
return busattach(parent, child, args, BUS_VME32);
}
-void
-vmelattach(parent, self, args)
- struct device *parent, *self;
- void *args;
-{
- if (self->dv_unit > 0) {
- printf(" unsupported\n");
- return;
- }
- printf("\n");
-
- if (vmeints == NULL) {
- vmeints = (struct intrhand **)malloc(256 *
- sizeof(struct intrhand *), M_TEMP, M_NOWAIT);
- bzero(vmeints, 256 * sizeof(struct intrhand *));
- }
- (void)config_search(vmel_scan, self, args);
- bus_untmp();
-}
-
int pil_to_vme[] = {
-1, /* pil 0 */
-1, /* pil 1 */
@@ -291,10 +425,17 @@ vmeintr(arg)
struct intrhand *ih;
int i = 0;
- vec = ldcontrolb(AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1);
+#ifdef DIAGNOSTIC
+ if (!CPU_ISSUN4) {
+ panic("vme: spurious interrupt");
+ }
+#endif
+
+ vec = ldcontrolb((caddr_t)
+ (AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1));
if (vec == -1) {
printf("vme: spurious interrupt\n");
- return (0);
+ return 0;
}
for (ih = vmeints[vec]; ih; ih = ih->ih_next)
@@ -307,9 +448,14 @@ void
vmeintr_establish(vec, level, ih)
int vec, level;
struct intrhand *ih;
-{
+{
struct intrhand *ihs;
+ if (!CPU_ISSUN4) {
+ panic("vmeintr_establish: not supported on cpu-type %d",
+ cputyp);
+ }
+
if (vec == -1)
panic("vmeintr_establish: uninitialized vec\n");
@@ -344,14 +490,13 @@ vmeintr_establish(vec, level, ih)
*/
void *
bus_map(pa, len, bustype)
- void *pa;
+ struct rom_reg *pa;
int len;
int bustype;
{
- struct rom_reg rr;
- u_long pf = (u_long)pa >> PGSHIFT;
+ u_long pf = (u_long)(pa->rr_paddr) >> PGSHIFT;
u_long va, pte;
- int pgtype;
+ int pgtype = -1;
switch (bt2pmt[bustype]) {
case PMAP_OBIO:
@@ -370,12 +515,12 @@ bus_map(pa, len, bustype)
pte = getpte(va);
if ((pte & PG_V) != 0 && (pte & PG_TYPE) == pgtype &&
(pte & PG_PFNUM) == pf)
- return ((void *)(va | ((u_long)pa & PGOFSET)));
+ return ((void *)
+ (va | ((u_long)pa->rr_paddr & PGOFSET)) );
/* note: preserve page offset */
}
}
- rr.rr_paddr = pa;
- return mapiodev(&rr, 0, len, bustype);
+ return mapiodev(pa, 0, len, bustype);
}
void *
@@ -387,8 +532,8 @@ bus_tmp(pa, bustype)
int pmtype = bt2pmt[bustype];
pmap_enter(pmap_kernel(), TMPMAP_VA,
- addr | pmtype | PMAP_NC,
- VM_PROT_READ | VM_PROT_WRITE, 1);
+ addr | pmtype | PMAP_NC,
+ VM_PROT_READ | VM_PROT_WRITE, 1);
return ((void *)(TMPMAP_VA | ((u_long) pa & PGOFSET)) );
}
diff --git a/sys/arch/sparc/dev/pfourreg.h b/sys/arch/sparc/dev/pfourreg.h
index de3f656dc35..8ec422c2019 100644
--- a/sys/arch/sparc/dev/pfourreg.h
+++ b/sys/arch/sparc/dev/pfourreg.h
@@ -1,6 +1,7 @@
-/* $Id: pfourreg.h,v 1.2 1995/11/09 21:26:14 deraadt Exp $ */
+/* $NetBSD: pfourreg.h,v 1.1 1996/02/27 22:09:36 thorpej Exp $ */
/*
+ * Copyright (c) 1996 Jason R. Thorpe. All rights reserved.
* Copyright (c) 1995 Theo de Raadt
* All rights reserved.
*
@@ -31,11 +32,18 @@
*/
/*
- * pfour bus registers.
+ * pfour framebuffer registers.
*/
-/* offsets */
-#define PFOUR_REG 0x300000 /* offset from 0x[0f]b000000 */
+/* Offset of bwtwo framebuffer from pfour register */
+#define PFOUR_BW_OFF 0x00100000
+
+/* Offsets for color framebuffers */
+#define PFOUR_COLOR_OFF_OVERLAY 0x00100000
+#define PFOUR_COLOR_OFF_ENABLE 0x00300000
+#define PFOUR_COLOR_OFF_COLOR 0x00500000
+#define PFOUR_COLOR_OFF_END 0x00700000
+#define PFOUR_COLOR_OFF_CMAP 0xfff00000 /* (-0x00100000) */
#define PFOUR_REG_DIAG 0x80
#define PFOUR_REG_READBACKCLR 0x40
@@ -48,6 +56,7 @@
#define PFOUR_REG_FIRSTHALF 0x01
#define PFOUR_REG_RESET 0x01
+#define PFOUR_FBTYPE_MASK 0x7f000000
#define PFOUR_FBTYPE(x) ((x) >> 24)
#define PFOUR_ID_MASK 0xf0
@@ -68,6 +77,4 @@
#define PFOUR_SIZE_1440X1440 0x04
#define PFOUR_SIZE_640X480 0x05
-int pfour_videosize __P((int reg, int *xp, int *yp));
-void pfour_reset __P((void));
-
+#define PFOUR_NOTPFOUR -1
diff --git a/sys/arch/sparc/dev/power.c b/sys/arch/sparc/dev/power.c
new file mode 100644
index 00000000000..02308765505
--- /dev/null
+++ b/sys/arch/sparc/dev/power.c
@@ -0,0 +1,103 @@
+/* $NetBSD: power.c,v 1.2 1996/05/16 15:56:56 abrown Exp $ */
+
+/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Harvard University
+ * and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: power.c,v 1.1 1996/08/11 05:34:25 deraadt Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+
+#include <machine/autoconf.h>
+
+#include <sparc/dev/power.h>
+
+static int powermatch __P((struct device *, void *, void *));
+static void powerattach __P((struct device *, struct device *, void *));
+
+struct cfattach power_ca = {
+ sizeof(struct device), powermatch, powerattach
+};
+
+struct cfdriver power_cd = {
+ NULL, "power", DV_DULL
+};
+
+/*
+ * This is the driver for the "power" register available on some Sun4m
+ * machines. This allows the machine to remove power automatically when
+ * shutdown or halted or whatever.
+ *
+ * XXX: this capability is not utilized in the current kernel.
+ */
+
+static int
+powermatch(parent, vcf, aux)
+ struct device *parent;
+ void *aux, *vcf;
+{
+ register struct confargs *ca = aux;
+
+ if (CPU_ISSUN4M)
+ return (strcmp("power", ca->ca_ra.ra_name) == 0);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+powerattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct confargs *ca = aux;
+ struct romaux *ra = &ca->ca_ra;
+
+ power_reg = mapdev(ra->ra_reg, 0, 0, sizeof(long), ca->ca_bustype);
+
+ printf("\n");
+}
+
+void
+powerdown()
+{
+ *POWER_REG |= POWER_OFF;
+}
diff --git a/sys/arch/sparc/dev/power.h b/sys/arch/sparc/dev/power.h
new file mode 100644
index 00000000000..252195b210c
--- /dev/null
+++ b/sys/arch/sparc/dev/power.h
@@ -0,0 +1,60 @@
+/* $NetBSD: power.h,v 1.2 1996/05/16 15:56:57 abrown Exp $ */
+
+/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Harvard University
+ * and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: power.h,v 1.1 1996/08/11 05:34:25 deraadt Exp $
+ *
+ */
+
+/*
+ * Sun-4m power register. This register allows the computer to power itself
+ * down.
+ */
+
+#define POWER_OFF 0x1 /* remove power */
+
+#define POWER_REG ((volatile u_char *)(power_reg))
+
+#define POWER_BITS "\20\1POWEROFF"
+
+#ifndef _LOCORE
+volatile u_char *power_reg;
+#endif
+
+void powerdown __P((void)); /* power off function */
diff --git a/sys/arch/sparc/dev/rcons_font.h b/sys/arch/sparc/dev/rcons_font.h
index 0583e458e03..3cbc847ea53 100644
--- a/sys/arch/sparc/dev/rcons_font.h
+++ b/sys/arch/sparc/dev/rcons_font.h
@@ -1,4 +1,4 @@
-/* $NetBSD: rcons_font.h,v 1.2 1995/10/08 19:31:44 pk Exp $ */
+/* $NetBSD: rcons_font.h,v 1.3 1995/11/29 22:03:53 pk Exp $ */
/*
* Raster Console font definition; this file exports `console_font',
diff --git a/sys/arch/sparc/dev/sbus.c b/sys/arch/sparc/dev/sbus.c
index 77ba2349467..32e52e31533 100644
--- a/sys/arch/sparc/dev/sbus.c
+++ b/sys/arch/sparc/dev/sbus.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sbus.c,v 1.6 1995/02/01 12:37:28 pk Exp $ */
+/* $NetBSD: sbus.c,v 1.10 1996/04/22 02:35:03 abrown Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -49,6 +49,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/device.h>
#include <machine/autoconf.h>
@@ -56,12 +57,19 @@
#include <sparc/dev/sbusreg.h>
#include <sparc/dev/sbusvar.h>
+int sbus_print __P((void *, char *));
+void sbusreset __P((int));
+
/* autoconfiguration driver */
void sbus_attach __P((struct device *, struct device *, void *));
int sbus_match __P((struct device *, void *, void *));
-struct cfdriver sbuscd = {
- NULL, "sbus", sbus_match, sbus_attach,
- DV_DULL, sizeof(struct sbus_softc)
+
+struct cfattach sbus_ca = {
+ sizeof(struct sbus_softc), sbus_match, sbus_attach
+};
+
+struct cfdriver sbus_cd = {
+ NULL, "sbus", DV_DULL
};
/*
@@ -92,8 +100,9 @@ sbus_match(parent, vcf, aux)
register struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
- if (cputyp==CPU_SUN4)
+ if (CPU_ISSUN4)
return (0);
+
return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
}
@@ -109,8 +118,7 @@ sbus_attach(parent, self, aux)
register struct sbus_softc *sc = (struct sbus_softc *)self;
struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
- register int base, node, slot;
- register int i;
+ register int node;
register char *name;
struct confargs oca;
@@ -131,11 +139,19 @@ sbus_attach(parent, self, aux)
sc->sc_clockfreq = getpropint(node, "clock-frequency", 25*1000*1000);
printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq));
+ /*
+ * Get the SBus burst transfer size if burst transfers are supported
+ */
+ sc->sc_burst = getpropint(node, "burst-sizes", 0);
+
if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "sbus") == 0)
oca.ca_ra.ra_bp = ra->ra_bp + 1;
else
oca.ca_ra.ra_bp = NULL;
+ sc->sc_range = ra->ra_range;
+ sc->sc_nrange = ra->ra_nrange;
+
/*
* Loop through ROM children, fixing any relative addresses
* and then configuring each device.
@@ -144,23 +160,60 @@ sbus_attach(parent, self, aux)
name = getpropstring(node, "name");
if (!romprop(&oca.ca_ra, name, node))
continue;
- base = (int)oca.ca_ra.ra_paddr;
+
+ sbus_translate(self, &oca);
+ oca.ca_bustype = BUS_SBUS;
+ (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print);
+ }
+}
+
+void
+sbus_translate(dev, ca)
+ struct device *dev;
+ struct confargs *ca;
+{
+ struct sbus_softc *sc = (struct sbus_softc *)dev;
+ register int base, slot;
+ register int i;
+
+ if (sc->sc_nrange == 0) {
+ /* Old-style Sbus configuration */
+ base = (int)ca->ca_ra.ra_paddr;
if (SBUS_ABS(base)) {
- oca.ca_slot = SBUS_ABS_TO_SLOT(base);
- oca.ca_offset = SBUS_ABS_TO_OFFSET(base);
+ ca->ca_slot = SBUS_ABS_TO_SLOT(base);
+ ca->ca_offset = SBUS_ABS_TO_OFFSET(base);
} else {
- oca.ca_slot = slot = oca.ca_ra.ra_iospace;
- oca.ca_offset = base;
- oca.ca_ra.ra_paddr = (void *)SBUS_ADDR(slot, base);
+ ca->ca_slot = slot = ca->ca_ra.ra_iospace;
+ ca->ca_offset = base;
+ ca->ca_ra.ra_paddr =
+ (void *)SBUS_ADDR(slot, base);
/* Fix any remaining register banks */
- for (i = 1; i < oca.ca_ra.ra_nreg; i++) {
- base = (int)oca.ca_ra.ra_reg[i].rr_paddr;
- oca.ca_ra.ra_reg[i].rr_paddr =
+ for (i = 1; i < ca->ca_ra.ra_nreg; i++) {
+ base = (int)ca->ca_ra.ra_reg[i].rr_paddr;
+ ca->ca_ra.ra_reg[i].rr_paddr =
(void *)SBUS_ADDR(slot, base);
}
}
- oca.ca_bustype = BUS_SBUS;
- (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print);
+
+ } else {
+
+ ca->ca_slot = ca->ca_ra.ra_iospace;
+ ca->ca_offset = (int)ca->ca_ra.ra_paddr;
+
+ /* Translate into parent address spaces */
+ for (i = 0; i < ca->ca_ra.ra_nreg; i++) {
+ int j, cspace = ca->ca_ra.ra_reg[i].rr_iospace;
+
+ for (j = 0; j < sc->sc_nrange; j++) {
+ if (sc->sc_range[j].cspace == cspace) {
+ (int)ca->ca_ra.ra_reg[i].rr_paddr +=
+ sc->sc_range[j].poffset;
+ (int)ca->ca_ra.ra_reg[i].rr_iospace =
+ sc->sc_range[j].pspace;
+ break;
+ }
+ }
+ }
}
}
@@ -173,7 +226,25 @@ sbus_establish(sd, dev)
register struct sbusdev *sd;
register struct device *dev;
{
- register struct sbus_softc *sc = (struct sbus_softc *)dev->dv_parent;
+ register struct sbus_softc *sc;
+ register struct device *curdev;
+
+ /*
+ * We have to look for the sbus by name, since it is not necessarily
+ * our immediate parent (i.e. sun4m /iommu/sbus/espdma/esp)
+ * We don't just use the device structure of the above-attached
+ * sbus, since we might (in the future) support multiple sbus's.
+ */
+ for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) {
+ if (!curdev || !curdev->dv_xname)
+ panic("sbus_establish: can't find sbus parent for %s",
+ (sd->sd_dev->dv_xname ? sd->sd_dev->dv_xname :
+ "<unknown>"));
+
+ if (strncmp(curdev->dv_xname, "sbus", 4) == 0)
+ break;
+ }
+ sc = (struct sbus_softc *) curdev;
sd->sd_dev = dev;
sd->sd_bchain = sc->sc_sbdev;
@@ -188,7 +259,7 @@ sbusreset(sbus)
int sbus;
{
register struct sbusdev *sd;
- struct sbus_softc *sc = sbuscd.cd_devs[sbus];
+ struct sbus_softc *sc = sbus_cd.cd_devs[sbus];
struct device *dev;
printf("reset %s:", sc->sc_dev.dv_xname);
@@ -200,24 +271,3 @@ sbusreset(sbus)
}
}
}
-
-/*
- * Returns true if this device is in a slave slot, so that drivers
- * can bail rather than fail.
- */
-int
-sbus_slavecheck(self, ca)
- struct device *self;
- struct confargs *ca;
-{
- int slave_only;
-
- slave_only = getpropint(findroot(), "slave-only", 8);
-
- if (slave_only & (1<<ca->ca_slot)) {
- printf("%s: slave sbus slot -- not supported\n",
- self->dv_xname);
- return (1);
- }
- return (0);
-}
diff --git a/sys/arch/sparc/dev/sbusvar.h b/sys/arch/sparc/dev/sbusvar.h
index 72badef900a..72fa1025523 100644
--- a/sys/arch/sparc/dev/sbusvar.h
+++ b/sys/arch/sparc/dev/sbusvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: sbusvar.h,v 1.2 1994/11/20 20:52:27 deraadt Exp $ */
+/* $NetBSD: sbusvar.h,v 1.4 1996/04/22 02:35:05 abrown Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -67,8 +67,11 @@ struct sbus_softc {
struct device sc_dev; /* base device */
int sc_clockfreq; /* clock frequency (in Hz) */
struct sbusdev *sc_sbdev; /* list of all children */
+ struct rom_range *sc_range;
+ int sc_nrange;
+ int sc_burst; /* burst transfer sizes supported */
};
int sbusdev_match __P((struct cfdata *, void *));
void sbus_establish __P((struct sbusdev *, struct device *));
-int sbus_slavecheck __P((struct device *self, struct confargs *ca));
+void sbus_translate __P((struct device *, struct confargs *));
diff --git a/sys/arch/sparc/dev/si.c b/sys/arch/sparc/dev/si.c
index ff0f4e400da..7908739ae4d 100644
--- a/sys/arch/sparc/dev/si.c
+++ b/sys/arch/sparc/dev/si.c
@@ -1,4 +1,4 @@
-/* $NetBSD: si.c,v 1.8 1996/01/01 22:40:56 thorpej Exp $ */
+/* $NetBSD: si.c,v 1.24 1996/05/13 01:53:45 thorpej Exp $ */
/*
* Copyright (c) 1995 Jason R. Thorpe
@@ -67,7 +67,8 @@
* for lots of helpful tips and suggestions. Thanks also to Paul Kranenburg
* and Chris Torek for bits of insight needed along the way. Thanks to
* David Gilbert and Andrew Gillham who risked filesystem life-and-limb
- * for the sake of testing.
+ * for the sake of testing. Andrew Gillham helped work out the bugs
+ * the the 4/100 DMA code.
*/
/*
@@ -116,6 +117,8 @@
#define DEBUG XXX
#endif
+#define COUNT_SW_LEFTOVERS XXX /* See sw DMA completion code */
+
#include <dev/ic/ncr5380reg.h>
#include <dev/ic/ncr5380var.h>
@@ -135,10 +138,6 @@
*/
#define MAX_DMA_LEN 0xE000
-#ifndef DEBUG
-#define DEBUG XXX
-#endif
-
#ifdef DEBUG
int si_debug = 0;
static int si_link_flags = 0 /* | SDEV_DB2 */ ;
@@ -180,6 +179,11 @@ struct si_softc {
* Alternatively, you can patch your kernel with DDB or some other
* mechanism. The sc_options member of the softc is OR'd with
* the value in si_options.
+ *
+ * On the "sw", interrupts (and thus) reselection don't work, so they're
+ * disabled by default. DMA is still a little dangerous, too.
+ *
+ * Note, there's a separate sw_options to make life easier.
*/
#define SI_ENABLE_DMA 0x01 /* Use DMA (maybe polled) */
#define SI_DMA_INTR 0x02 /* DMA completion interrupts */
@@ -187,6 +191,7 @@ struct si_softc {
#define SI_OPTIONS_MASK (SI_ENABLE_DMA|SI_DMA_INTR|SI_DO_RESELECT)
#define SI_OPTIONS_BITS "\10\3RESELECT\2DMA_INTR\1DMA"
int si_options = SI_ENABLE_DMA;
+int sw_options = SI_ENABLE_DMA;
/* How long to wait for DMA before declaring an error. */
int si_dma_intr_timo = 500; /* ticks (sec. X 100) */
@@ -196,6 +201,7 @@ static void si_attach __P((struct device *, struct device *, void *));
static int si_intr __P((void *));
static void si_reset_adapter __P((struct ncr5380_softc *));
static void si_minphys __P((struct buf *));
+static int si_print __P((void *, char *));
void si_dma_alloc __P((struct ncr5380_softc *));
void si_dma_free __P((struct ncr5380_softc *));
@@ -235,15 +241,21 @@ static struct scsi_device si_dev = {
/* The Sun SCSI-3 VME controller. */
-struct cfdriver sicd = {
- NULL, "si", si_match, si_attach,
- DV_DULL, sizeof(struct si_softc), NULL, 0,
+struct cfattach si_ca = {
+ sizeof(struct si_softc), si_match, si_attach
+};
+
+struct cfdriver si_cd = {
+ NULL, "si", DV_DULL
};
/* The Sun "SCSI Weird" 4/100 obio controller. */
-struct cfdriver swcd = {
- NULL, "sw", si_match, si_attach,
- DV_DULL, sizeof(struct si_softc), NULL, 0,
+struct cfattach sw_ca = {
+ sizeof(struct si_softc), si_match, si_attach
+};
+
+struct cfdriver sw_cd = {
+ NULL, "sw", DV_DULL
};
static int
@@ -263,14 +275,14 @@ si_match(parent, vcf, args)
{
struct cfdata *cf = vcf;
struct confargs *ca = args;
- struct romaux *ra = &ca->ca_ra;
+ struct romaux *ra = &ca->ca_ra;
/* Are we looking for the right thing? */
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
/* Nothing but a Sun 4 is going to have these devices. */
- if (cputyp != CPU_SUN4)
+ if (!CPU_ISSUN4)
return (0);
/*
@@ -283,13 +295,20 @@ si_match(parent, vcf, args)
/* Figure out the bus type and look for the appropriate adapter. */
switch (ca->ca_bustype) {
case BUS_VME16:
+ /* AFAIK, the `si' can only exist on the vmes. */
+ if (strcmp(ra->ra_name, "si") || cpumod == SUN4_100)
+ return (0);
break;
case BUS_OBIO:
/* AFAIK, an `sw' can only exist on the obio. */
- if (cpumod != SUN4_100)
+ if (strcmp(ra->ra_name, "sw") || cpumod != SUN4_100)
return (0);
break;
+
+ default:
+ /* Don't know what we ended up with ... */
+ return (0);
}
/* Make sure there is something there... */
@@ -323,17 +342,12 @@ si_attach(parent, self, args)
int i;
/* Pull in the options flags. */
- if (ca->ca_bustype == BUS_OBIO) {
- /*
- * XXX Interrupts and reselect don't work on the "sw".
- * I don't know why (yet). Disable DMA by default, too.
- * It's still a little dangerous.
- */
- sc->sc_options = ncr_sc->sc_dev.dv_cfdata->cf_flags &
- SI_OPTIONS_MASK;
- } else
- sc->sc_options =
- ((ncr_sc->sc_dev.dv_cfdata->cf_flags | si_options) & SI_OPTIONS_MASK);
+ if (ca->ca_bustype == BUS_OBIO)
+ sc->sc_options = sw_options;
+ else
+ sc->sc_options = si_options;
+ sc->sc_options |=
+ (ncr_sc->sc_dev.dv_cfdata->cf_flags & SI_OPTIONS_MASK);
/* Map the controller registers. */
regs = (struct si_regs *)mapiodev(ra->ra_reg, 0,
@@ -392,6 +406,10 @@ si_attach(parent, self, args)
ncr_sc->sc_intr_on = si_obio_intr_on;
ncr_sc->sc_intr_off = si_obio_intr_off;
break;
+
+ default:
+ panic("\nsi_attach: impossible bus type 0x%x", ca->ca_bustype);
+ /* NOTREACHED */
}
ncr_sc->sc_flags = 0;
@@ -442,15 +460,19 @@ si_attach(parent, self, args)
sc->sc_adapter_iv_am =
VME_SUPV_DATA_24 | (ra->ra_intr[0].int_vec & 0xFF);
break;
+
+ default:
+ /* Impossible case handled above. */
+ break;
}
printf(" pri %d\n", ra->ra_intr[0].int_pri);
- if (sc->sc_options)
+ if (sc->sc_options) {
printf("%s: options=%b\n", ncr_sc->sc_dev.dv_xname,
- sc->sc_options, SI_OPTIONS_BITS);
-
+ sc->sc_options, SI_OPTIONS_BITS);
+ }
#ifdef DEBUG
if (si_debug)
- printf("si: Set TheSoftC=%x TheRegs=%x\n", sc, regs);
+ printf("si: Set TheSoftC=%p TheRegs=%p\n", sc, regs);
ncr_sc->sc_link.flags |= si_link_flags;
#endif
@@ -679,7 +701,7 @@ found:
dh->dh_dvma = (long)kdvma_mapin((caddr_t)addr, xlen, 0);
if (dh->dh_dvma == 0) {
/* Can't remap segment */
- printf("si_dma_alloc: can't remap %x/%x, doing PIO\n",
+ printf("si_dma_alloc: can't remap %p/%x, doing PIO\n",
dh->dh_addr, dh->dh_maplen);
dh->dh_flags = 0;
return;
@@ -733,7 +755,6 @@ si_dma_poll(ncr_sc)
{
struct si_softc *sc = (struct si_softc *)ncr_sc;
struct sci_req *sr = ncr_sc->sc_current;
- struct si_dma_handle *dh = sr->sr_dma_hand;
volatile struct si_regs *si = sc->sc_regs;
int tmo, csr_mask, csr;
@@ -864,14 +885,14 @@ si_vme_dma_start(ncr_sc)
*/
data_pa = (u_long)(dh->dh_dvma - DVMA_BASE);
if (data_pa & 1)
- panic("si_dma_start: bad pa=0x%x", data_pa);
+ panic("si_dma_start: bad pa=0x%lx", data_pa);
xlen = ncr_sc->sc_datalen;
xlen &= ~1;
sc->sc_xlen = xlen; /* XXX: or less... */
#ifdef DEBUG
if (si_debug & 2) {
- printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n",
+ printf("si_dma_start: dh=%p, pa=0x%lx, xlen=%d\n",
dh, data_pa, xlen);
}
#endif
@@ -895,7 +916,7 @@ si_vme_dma_start(ncr_sc)
} else {
si->si_csr &= ~SI_CSR_BPCON;
}
-
+
si->dma_addrh = (u_short)(data_pa >> 16);
si->dma_addrl = (u_short)(data_pa & 0xFFFF);
@@ -997,12 +1018,15 @@ si_vme_dma_stop(ncr_sc)
*
* SCSI-3 VME interface is a little funny on writes:
* if we have a disconnect, the dma has overshot by
- * one byte and needs to be incremented. This is
- * true if we have not transferred either all data
- * or no data. XXX - from Matt Jacob
+ * one byte and the resid needs to be incremented.
+ * Only happens for partial transfers.
+ * (Thanks to Matt Jacob)
*/
resid = si->fifo_count & 0xFFFF;
+ if (dh->dh_flags & SIDH_OUT)
+ if ((resid > 0) && (resid < sc->sc_xlen))
+ resid++;
ntrans = sc->sc_xlen - resid;
#ifdef DEBUG
@@ -1162,14 +1186,14 @@ si_obio_dma_start(ncr_sc)
*/
data_pa = (u_long)(dh->dh_dvma - DVMA_BASE);
if (data_pa & 1)
- panic("si_dma_start: bad pa=0x%x", data_pa);
+ panic("si_dma_start: bad pa=0x%lx", data_pa);
xlen = ncr_sc->sc_datalen;
xlen &= ~1;
sc->sc_xlen = xlen; /* XXX: or less... */
#ifdef DEBUG
if (si_debug & 2) {
- printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n",
+ printf("si_dma_start: dh=%p, pa=0x%lx, xlen=%d\n",
dh, data_pa, xlen);
}
#endif
@@ -1260,6 +1284,19 @@ si_obio_dma_eop(ncr_sc)
/* Not needed - DMA was stopped prior to examining sci_csr */
}
+#if (defined(DEBUG) || defined(DIAGNOSTIC)) && !defined(COUNT_SW_LEFTOVERS)
+#define COUNT_SW_LEFTOVERS
+#endif
+#ifdef COUNT_SW_LEFTOVERS
+/*
+ * Let's find out how often these occur. Read these with DDB from time
+ * to time.
+ */
+int sw_3_leftover = 0;
+int sw_2_leftover = 0;
+int sw_1_leftover = 0;
+int sw_0_leftover = 0;
+#endif
void
si_obio_dma_stop(ncr_sc)
@@ -1282,7 +1319,23 @@ si_obio_dma_stop(ncr_sc)
/* First, halt the DMA engine. */
si->sw_csr &= ~SI_CSR_DMA_EN;
+ /*
+ * XXX HARDWARE BUG!
+ * Apparently, some early 4/100 SCSI controllers had a hardware
+ * bug that caused the controller to do illegal memory access.
+ * We see this as SI_CSR_DMA_BUS_ERR (makes sense). To work around
+ * this, we simply need to clean up after ourselves ... there will
+ * be as many as 3 bytes left over. Since we clean up "left-over"
+ * bytes on every read anyway, we just continue to chug along
+ * if SI_CSR_DMA_BUS_ERR is asserted. (This was probably worked
+ * around in hardware later with the "left-over byte" indicator
+ * in the VME controller.)
+ */
+#if 0
if (si->sw_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) {
+#else
+ if (si->sw_csr & (SI_CSR_DMA_CONFLICT)) {
+#endif
printf("sw: DMA error, csr=0x%x, reset\n", si->sw_csr);
sr->sr_xs->error = XS_DRIVER_STUFFUP;
ncr_sc->sc_state |= NCR_ABORTING;
@@ -1334,19 +1387,34 @@ si_obio_dma_stop(ncr_sc)
switch (Dma_addr & 3) {
case 3:
- cp[-3] = (si->sw_bpr & 0xff000000) >> 24;
- cp[-2] = (si->sw_bpr & 0x00ff0000) >> 16;
- cp[-1] = (si->sw_bpr & 0x0000ff00) >> 8;
+ cp[0] = (si->sw_bpr & 0xff000000) >> 24;
+ cp[1] = (si->sw_bpr & 0x00ff0000) >> 16;
+ cp[2] = (si->sw_bpr & 0x0000ff00) >> 8;
+#ifdef COUNT_SW_LEFTOVERS
+ ++sw_3_leftover;
+#endif
break;
case 2:
- cp[-2] = (si->sw_bpr & 0xff000000) >> 24;
- cp[-1] = (si->sw_bpr & 0x00ff0000) >> 16;
+ cp[0] = (si->sw_bpr & 0xff000000) >> 24;
+ cp[1] = (si->sw_bpr & 0x00ff0000) >> 16;
+#ifdef COUNT_SW_LEFTOVERS
+ ++sw_2_leftover;
+#endif
break;
case 1:
- cp[-1] = (si->sw_bpr & 0xff000000) >> 24;
+ cp[0] = (si->sw_bpr & 0xff000000) >> 24;
+#ifdef COUNT_SW_LEFTOVERS
+ ++sw_1_leftover;
+#endif
+ break;
+
+#ifdef COUNT_SW_LEFTOVERS
+ default:
+ ++sw_0_leftover;
break;
+#endif
}
}
diff --git a/sys/arch/sparc/dev/xd.c b/sys/arch/sparc/dev/xd.c
index b2fc2b6bfd7..dd5df1fa016 100644
--- a/sys/arch/sparc/dev/xd.c
+++ b/sys/arch/sparc/dev/xd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: xd.c,v 1.11 1996/01/07 22:03:02 thorpej Exp $ */
+/* $NetBSD: xd.c,v 1.25 1996/04/22 02:42:06 christos Exp $ */
/*
*
@@ -36,7 +36,7 @@
* x d . c x y l o g i c s 7 5 3 / 7 0 5 3 v m e / s m d d r i v e r
*
* author: Chuck Cranor <chuck@ccrc.wustl.edu>
- * id: $Id: xd.c,v 1.7 1996/03/04 20:35:23 chuck Exp $
+ * id: $NetBSD: xd.c,v 1.25 1996/04/22 02:42:06 christos Exp $
* started: 27-Feb-95
* references: [1] Xylogics Model 753 User's Manual
* part number: 166-753-001, Revision B, May 21, 1988.
@@ -61,7 +61,6 @@
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/conf.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
@@ -73,11 +72,14 @@
#include <sys/disk.h>
#include <sys/syslog.h>
#include <sys/dkbad.h>
+#include <sys/conf.h>
+
#include <vm/vm.h>
#include <vm/vm_kern.h>
#include <machine/autoconf.h>
#include <machine/sun_disklabel.h>
+#include <machine/conf.h>
#include <sparc/dev/xdreg.h>
#include <sparc/dev/xdvar.h>
@@ -215,25 +217,15 @@ inline void xdc_rqinit __P((struct xd_iorq *, struct xdc_softc *,
struct xd_softc *, int, u_long, int,
caddr_t, struct buf *));
void xdc_rqtopb __P((struct xd_iorq *, struct xd_iopb *, int, int));
-int xdc_start __P((struct xdc_softc *, int));
+void xdc_start __P((struct xdc_softc *, int));
int xdc_startbuf __P((struct xdc_softc *, struct xd_softc *, struct buf *));
int xdc_submit_iorq __P((struct xdc_softc *, int, int));
void xdc_tick __P((void *));
-int xdc_xdreset __P((struct xdc_softc *, struct xd_softc *));
+void xdc_xdreset __P((struct xdc_softc *, struct xd_softc *));
/* machine interrupt hook */
int xdcintr __P((void *));
-/* {b,c}devsw */
-int xdclose __P((dev_t, int, int));
-int xddump __P((dev_t));
-int xdioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
-int xdopen __P((dev_t, int, int));
-int xdread __P((dev_t, struct uio *));
-int xdwrite __P((dev_t, struct uio *));
-int xdsize __P((dev_t));
-void xdstrategy __P((struct buf *));
-
/* autoconf */
int xdcmatch __P((struct device *, void *, void *));
void xdcattach __P((struct device *, struct device *, void *));
@@ -247,12 +239,21 @@ int xdgetdisklabel __P((struct xd_softc *, void *));
* cfdrivers: device driver interface to autoconfig
*/
-struct cfdriver xdccd = {
- NULL, "xdc", xdcmatch, xdcattach, DV_DULL, sizeof(struct xdc_softc)
+struct cfattach xdc_ca = {
+ sizeof(struct xdc_softc), xdcmatch, xdcattach
+};
+
+
+struct cfdriver xdc_cd = {
+ NULL, "xdc", DV_DULL
+};
+
+struct cfattach xd_ca = {
+ sizeof(struct xd_softc), xdmatch, xdattach
};
-struct cfdriver xdcd = {
- NULL, "xd", xdmatch, xdattach, DV_DISK, sizeof(struct xd_softc)
+struct cfdriver xd_cd = {
+ NULL, "xd", DV_DISK
};
struct xdc_attach_args { /* this is the "aux" args to xdattach */
@@ -313,11 +314,11 @@ xdgetdisklabel(xd, b)
if (sdl->sl_magic == SUN_DKMAGIC)
xd->pcyl = sdl->sl_pcylinders;
else {
- printf("%s: WARNING: no `pcyl' in disk label.\n",
+ printf("%s: WARNING: no `pcyl' in disk label.\n",
xd->sc_dev.dv_xname);
xd->pcyl = xd->sc_dk.dk_label->d_ncylinders +
xd->sc_dk.dk_label->d_acylinders;
- printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n",
+ printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n",
xd->sc_dev.dv_xname, xd->pcyl);
}
@@ -357,9 +358,9 @@ int xdcmatch(parent, match, aux)
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
xdc = (struct xdc *) ra->ra_vaddr;
- if (probeget(&xdc->xdc_csr, 1) == -1)
+ if (probeget((caddr_t) &xdc->xdc_csr, 1) == -1)
return (0);
xdc->xdc_csr = XDC_RESET;
XDC_WAIT(xdc, del, XDC_RESETUSEC, XDC_RESET);
@@ -372,7 +373,7 @@ int xdcmatch(parent, match, aux)
/*
* xdcattach: attach controller
*/
-void
+void
xdcattach(parent, self, aux)
struct device *parent, *self;
void *aux;
@@ -400,7 +401,7 @@ xdcattach(parent, self, aux)
xdc->sc_drives[lcv] = (struct xd_softc *) 0;
/* allocate and zero buffers
- *
+ *
* note: we simplify the code by allocating the max number of iopbs and
* iorq's up front. thus, we avoid linked lists and the costs
* associated with them in exchange for wasting a little memory. */
@@ -511,13 +512,12 @@ xdcattach(parent, self, aux)
* spin up and configure a disk after the system is booted (we can
* call xdattach!).
*/
-int
+int
xdmatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
- struct xdc_softc *xdc = (void *) parent;
struct cfdata *cf = match;
struct xdc_attach_args *xa = aux;
@@ -534,7 +534,7 @@ xdmatch(parent, match, aux)
* xdattach: attach a disk. this can be called from autoconf and also
* from xdopen/xdstrategy.
*/
-void
+void
xdattach(parent, self, aux)
struct device *parent, *self;
void *aux;
@@ -543,7 +543,7 @@ xdattach(parent, self, aux)
struct xd_softc *xd = (void *) self;
struct xdc_softc *xdc = (void *) parent;
struct xdc_attach_args *xa = aux;
- int rqno, err, spt, mb, blk, lcv, fmode, s, newstate;
+ int rqno, err, spt = 0, mb, blk, lcv, fmode, s = 0, newstate;
struct xd_iopb_drive *driopb;
struct dkbad *dkb;
struct bootpath *bp;
@@ -717,9 +717,9 @@ xdattach(parent, self, aux)
if (xa->booting) {
/* restore bootpath! (do this via attach_args again?)*/
bp = bootpath_store(0, NULL);
- if (bp && strcmp("xd", bp->name) == 0 &&
+ if (bp && strcmp("xd", bp->name) == 0 &&
xd->xd_drive == bp->val[0])
- bootdv = &xd->sc_dev;
+ bp->dev = &xd->sc_dev;
}
dk_establish(&xd->sc_dk, &xd->sc_dev); /* XXX */
@@ -743,13 +743,13 @@ done:
/*
* xdclose: close device
*/
-int
-xdclose(dev, flag, fmt)
+int
+xdclose(dev, flag, fmt, p)
dev_t dev;
int flag, fmt;
-
+ struct proc *p;
{
- struct xd_softc *xd = xdcd.cd_devs[DISKUNIT(dev)];
+ struct xd_softc *xd = xd_cd.cd_devs[DISKUNIT(dev)];
int part = DISKPART(dev);
/* clear mask bits */
@@ -770,20 +770,22 @@ xdclose(dev, flag, fmt)
/*
* xddump: crash dump system
*/
-int
-xddump(dev)
- dev_t dev;
-
+int
+xddump(dev, blkno, va, size)
+ dev_t dev;
+ daddr_t blkno;
+ caddr_t va;
+ size_t size;
{
int unit, part;
struct xd_softc *xd;
unit = DISKUNIT(dev);
- if (unit >= xdcd.cd_ndevs)
+ if (unit >= xd_cd.cd_ndevs)
return ENXIO;
part = DISKPART(dev);
- xd = xdcd.cd_devs[unit];
+ xd = xd_cd.cd_devs[unit];
printf("%s%c: crash dump not supported (yet)\n", xd->sc_dev.dv_xname,
'a' + part);
@@ -795,11 +797,11 @@ xddump(dev)
* "dumpsize" == size of dump in clicks "physmem" == size of physical
* memory (clicks, ctob() to get bytes) (normal case: dumpsize ==
* physmem)
- *
+ *
* dump a copy of physical memory to the dump device starting at sector
* "dumplo" in the swap partition (make sure > 0). map in pages as
* we go. use polled I/O.
- *
+ *
* XXX how to handle NON_CONTIG? */
}
@@ -807,7 +809,7 @@ xddump(dev)
/*
* xdioctl: ioctls on XD drives. based on ioctl's of other netbsd disks.
*/
-int
+int
xdioctl(dev, command, addr, flag, p)
dev_t dev;
u_long command;
@@ -822,7 +824,7 @@ xdioctl(dev, command, addr, flag, p)
unit = DISKUNIT(dev);
- if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == NULL)
+ if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == NULL)
return (ENXIO);
/* switch on ioctl type */
@@ -901,11 +903,11 @@ xdioctl(dev, command, addr, flag, p)
* xdopen: open drive
*/
-int
-xdopen(dev, flag, fmt)
+int
+xdopen(dev, flag, fmt, p)
dev_t dev;
int flag, fmt;
-
+ struct proc *p;
{
int unit, part;
struct xd_softc *xd;
@@ -914,7 +916,7 @@ xdopen(dev, flag, fmt)
/* first, could it be a valid target? */
unit = DISKUNIT(dev);
- if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == NULL)
+ if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == NULL)
return (ENXIO);
part = DISKPART(dev);
@@ -954,18 +956,20 @@ xdopen(dev, flag, fmt)
}
int
-xdread(dev, uio)
+xdread(dev, uio, flags)
dev_t dev;
struct uio *uio;
+ int flags;
{
return (physio(xdstrategy, NULL, dev, B_READ, minphys, uio));
}
int
-xdwrite(dev, uio)
+xdwrite(dev, uio, flags)
dev_t dev;
struct uio *uio;
+ int flags;
{
return (physio(xdstrategy, NULL, dev, B_WRITE, minphys, uio));
@@ -976,28 +980,28 @@ xdwrite(dev, uio)
* xdsize: return size of a partition for a dump
*/
-int
+int
xdsize(dev)
dev_t dev;
{
struct xd_softc *xdsc;
- int unit, part, size;
+ int part, size;
/* valid unit? try an open */
- if (xdopen(dev, 0, S_IFBLK) != 0)
+ if (xdopen(dev, 0, S_IFBLK, NULL) != 0)
return (-1);
/* do it */
- xdsc = xdcd.cd_devs[DISKUNIT(dev)];
+ xdsc = xd_cd.cd_devs[DISKUNIT(dev)];
part = DISKPART(dev);
if (xdsc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
size = -1; /* only give valid size for swap partitions */
else
size = xdsc->sc_dk.dk_label->d_partitions[part].p_size;
- if (xdclose(dev, 0, S_IFBLK) != 0)
+ if (xdclose(dev, 0, S_IFBLK, NULL) != 0)
return -1;
return size;
}
@@ -1005,7 +1009,7 @@ xdsize(dev)
* xdstrategy: buffering system interface to xd.
*/
-void
+void
xdstrategy(bp)
struct buf *bp;
@@ -1020,7 +1024,7 @@ xdstrategy(bp)
/* check for live device */
- if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == 0 ||
+ if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == 0 ||
bp->b_blkno < 0 ||
(bp->b_bcount % xd->sc_dk.dk_label->d_secsize) != 0) {
bp->b_error = EINVAL;
@@ -1062,7 +1066,7 @@ xdstrategy(bp)
/*
* now we know we have a valid buf structure that we need to do I/O
* on.
- *
+ *
* note that we don't disksort because the controller has a sorting
* algorithm built into the hardware.
*/
@@ -1115,14 +1119,12 @@ done: /* tells upper layers we are done with this
*
* xdcintr: hardware interrupt.
*/
-int
+int
xdcintr(v)
void *v;
{
struct xdc_softc *xdcsc = v;
- struct xd_softc *xd;
- struct buf *bp;
/* kick the event counter */
@@ -1156,7 +1158,7 @@ xdcintr(v)
* xdc_rqinit: fill out the fields of an I/O request
*/
-inline void
+inline void
xdc_rqinit(rq, xdc, xd, md, blk, cnt, db, bp)
struct xd_iorq *rq;
struct xdc_softc *xdc;
@@ -1181,7 +1183,7 @@ xdc_rqinit(rq, xdc, xd, md, blk, cnt, db, bp)
* xdc_rqtopb: load up an IOPB based on an iorq
*/
-void
+void
xdc_rqtopb(iorq, iopb, cmd, subfun)
struct xd_iorq *iorq;
struct xd_iopb *iopb;
@@ -1218,7 +1220,7 @@ xdc_rqtopb(iorq, iopb, cmd, subfun)
XDPC_RBC | XDPC_ECC2;
ctrl->throttle = XDC_THROTTLE;
#ifdef sparc
- if (cputyp == CPU_SUN4 && cpumod == SUN4_300)
+ if (CPU_ISSUN4 && cpumod == SUN4_300)
ctrl->delay = XDC_DELAY_4_300;
else
ctrl->delay = XDC_DELAY_SPARC;
@@ -1297,7 +1299,7 @@ xdc_rqtopb(iorq, iopb, cmd, subfun)
* If you've already got an IORQ, you can call submit directly (currently
* there is no need to do this). NORM requests are handled seperately.
*/
-int
+int
xdc_cmd(xdcsc, cmd, subfn, unit, block, scnt, dptr, fullmode)
struct xdc_softc *xdcsc;
int cmd, subfn, unit, block, scnt;
@@ -1306,7 +1308,6 @@ xdc_cmd(xdcsc, cmd, subfn, unit, block, scnt, dptr, fullmode)
{
int rqno, submode = XD_STATE(fullmode), retry;
- u_long dp;
struct xd_iorq *iorq;
struct xd_iopb *iopb;
@@ -1364,7 +1365,7 @@ xdc_cmd(xdcsc, cmd, subfn, unit, block, scnt, dptr, fullmode)
* start a buffer running, assumes nfree > 0
*/
-int
+int
xdc_startbuf(xdcsc, xdsc, bp)
struct xdc_softc *xdcsc;
struct xd_softc *xdsc;
@@ -1375,7 +1376,7 @@ xdc_startbuf(xdcsc, xdsc, bp)
struct xd_iorq *iorq;
struct xd_iopb *iopb;
struct buf *wq;
- u_long block, dp;
+ u_long block;
caddr_t dbuf;
if (!xdcsc->nfree)
@@ -1409,7 +1410,7 @@ xdc_startbuf(xdcsc, xdsc, bp)
/*
* load request. we have to calculate the correct block number based
* on partition info.
- *
+ *
* note that iorq points to the buffer as mapped into DVMA space,
* where as the bp->b_data points to its non-DVMA mapping.
*/
@@ -1479,7 +1480,7 @@ xdc_startbuf(xdcsc, xdsc, bp)
*/
-int
+int
xdc_submit_iorq(xdcsc, iorqno, type)
struct xdc_softc *xdcsc;
int iorqno;
@@ -1560,7 +1561,7 @@ xdc_submit_iorq(xdcsc, iorqno, type)
* the caller is interesting in. if freeone is true, then it returns
* when there is a free iorq.
*/
-int
+int
xdc_piodriver(xdcsc, iorqno, freeone)
struct xdc_softc *xdcsc;
char iorqno;
@@ -1638,7 +1639,7 @@ xdc_piodriver(xdcsc, iorqno, freeone)
* xdc_reset: reset one drive. NOTE: assumes xdc was just reset.
* we steal iopb[0] for this, but we put it back when we are done.
*/
-int
+void
xdc_xdreset(xdcsc, xdsc)
struct xdc_softc *xdcsc;
struct xd_softc *xdsc;
@@ -1672,14 +1673,14 @@ xdc_xdreset(xdcsc, xdsc)
* xdc_reset: reset everything: requests are marked as errors except
* a polled request (which is resubmitted)
*/
-int
+int
xdc_reset(xdcsc, quiet, blastmode, error, xdsc)
struct xdc_softc *xdcsc;
int quiet, blastmode, error;
struct xd_softc *xdsc;
{
- int del = 0, lcv, poll = -1, retval = XD_ERR_AOK;
+ int del = 0, lcv, retval = XD_ERR_AOK;
int oldfree = xdcsc->nfree;
/* soft reset hardware */
@@ -1722,7 +1723,7 @@ xdc_reset(xdcsc, quiet, blastmode, error, xdsc)
(vm_offset_t)iorq->buf->b_un.b_addr,
iorq->buf->b_bcount);
disk_unbusy(&xdcsc->reqs[lcv].xd->sc_dk,
- (xdcsc->reqs[lcv].buf->b_bcount -
+ (xdcsc->reqs[lcv].buf->b_bcount -
xdcsc->reqs[lcv].buf->b_resid));
biodone(iorq->buf);
XDC_FREE(xdcsc, lcv); /* add to free list */
@@ -1770,7 +1771,7 @@ xdc_reset(xdcsc, quiet, blastmode, error, xdsc)
* xdc_start: start all waiting buffers
*/
-int
+void
xdc_start(xdcsc, maxio)
struct xdc_softc *xdcsc;
int maxio;
@@ -1790,14 +1791,13 @@ xdc_start(xdcsc, maxio)
* xdc_remove_iorq: remove "done" IOPB's.
*/
-int
+int
xdc_remove_iorq(xdcsc)
struct xdc_softc *xdcsc;
{
int errno, rqno, comm, errs;
struct xdc *xdc = xdcsc->xdc;
- u_long addr;
struct xd_iopb *iopb;
struct xd_iorq *iorq;
struct buf *bp;
@@ -1821,7 +1821,7 @@ xdc_remove_iorq(xdcsc)
/*
* get iopb that is done
- *
+ *
* hmm... I used to read the address of the done IOPB off the VME
* registers and calculate the rqno directly from that. that worked
* until I started putting a load on the controller. when loaded, i
@@ -1889,7 +1889,7 @@ xdc_remove_iorq(xdcsc)
* at the bad144 sector. to exit bad144 mode, we
* must advance the pointers 1 sector and issue a new
* request if there are still sectors left to process
- *
+ *
*/
XDC_ADVANCE(iorq, 1); /* advance 1 sector */
@@ -1957,7 +1957,7 @@ xdc_remove_iorq(xdcsc)
* is in lasterror. also, if iorq->errno == 0, then we recovered
* from that error (otherwise iorq->errno == iorq->lasterror).
*/
-void
+void
xdc_perror(iorq, iopb, still_trying)
struct xd_iorq *iorq;
struct xd_iopb *iopb;
@@ -1990,7 +1990,7 @@ xdc_perror(iorq, iopb, still_trying)
* xdc_error: non-fatal error encountered... recover.
* return AOK if resubmitted, return FAIL if this iopb is done
*/
-int
+int
xdc_error(xdcsc, iorq, iopb, rqno, comm)
struct xdc_softc *xdcsc;
struct xd_iorq *iorq;
@@ -2062,7 +2062,7 @@ xdc_error(xdcsc, iorq, iopb, rqno, comm)
/*
* xdc_tick: make sure xd is still alive and ticking (err, kicking).
*/
-void
+void
xdc_tick(arg)
void *arg;
@@ -2070,7 +2070,7 @@ xdc_tick(arg)
struct xdc_softc *xdcsc = arg;
int lcv, s, reset = 0;
#ifdef XDC_DIAG
- int wait, run, free, done, whd;
+ int wait, run, free, done, whd = 0;
u_char fqc[XDC_MAXIOPB], wqc[XDC_MAXIOPB], mark[XDC_MAXIOPB];
s = splbio();
wait = xdcsc->nwait;
@@ -2100,7 +2100,7 @@ xdc_tick(arg)
printf("\n");
for (lcv = 0; lcv < XDC_MAXIOPB; lcv++) {
if (mark[lcv] == 0)
- printf("MARK: running %d: mode %d done %d errs %d errno 0x%x ttl %d buf %x\n",
+ printf("MARK: running %d: mode %d done %d errs %d errno 0x%x ttl %d buf %p\n",
lcv, xdcsc->reqs[lcv].mode,
xdcsc->iopbase[lcv].done,
xdcsc->iopbase[lcv].errs,
@@ -2154,7 +2154,7 @@ xdc_tick(arg)
* in user code, and is also useful for some debugging. we return
* an error code. called at user priority.
*/
-int
+int
xdc_ioctlcmd(xd, dev, xio)
struct xd_softc *xd;
dev_t dev;
@@ -2248,7 +2248,7 @@ xdc_ioctlcmd(xd, dev, xio)
if (xio->dlen) {
dvmabuf = dvma_malloc(xio->dlen, &buf, M_WAITOK);
if (xio->cmd == XDCMD_WR || xio->cmd == XDCMD_XWR) {
- if (err = copyin(xio->dptr, buf, xio->dlen)) {
+ if ((err = copyin(xio->dptr, buf, xio->dlen)) != 0) {
dvma_free(dvmabuf, xio->dlen, &buf);
return (err);
}
diff --git a/sys/arch/sparc/dev/xdreg.h b/sys/arch/sparc/dev/xdreg.h
index addbe589534..c723d018d0d 100644
--- a/sys/arch/sparc/dev/xdreg.h
+++ b/sys/arch/sparc/dev/xdreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: xdreg.h,v 1.1 1995/06/26 23:07:11 pk Exp $ */
+/* $NetBSD: xdreg.h,v 1.3 1996/03/31 22:38:54 pk Exp $ */
/*
*
@@ -203,9 +203,9 @@ struct xd_iopb {
/*
* some commands overload bytes 6 to 0x13 of the iopb with different meanings.
- * these commands include:
+ * these commands include:
* section 4.2: controller parameters
- * section 4.3: drive parameters
+ * section 4.3: drive parameters
* sectino 4.4: format parameters
*
* note that the commands that overload the iopb are not part of the
@@ -287,7 +287,7 @@ struct xd_iopb_ctrl {
#define XDC_DELAY_SPARC 0
/*
- * drive parameters iopb: redefines bytes: 6, 8, 9, a, b, c, d, e
+ * drive parameters iopb: redefines bytes: 6, 8, 9, a, b, c, d, e
*/
struct xd_iopb_drive {
@@ -311,7 +311,7 @@ struct xd_iopb_drive {
};
/*
- * format parameters iopb: redefines bytes: 6, 8, 9, a, b, c, d, 0x10, 0x11
+ * format parameters iopb: redefines bytes: 6, 8, 9, a, b, c, d, 0x10, 0x11
*/
struct xd_iopb_format {
diff --git a/sys/arch/sparc/dev/xdvar.h b/sys/arch/sparc/dev/xdvar.h
index 5417e3953ac..294f3a8c84b 100644
--- a/sys/arch/sparc/dev/xdvar.h
+++ b/sys/arch/sparc/dev/xdvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: xdvar.h,v 1.2 1996/01/07 22:03:04 thorpej Exp $ */
+/* $NetBSD: xdvar.h,v 1.5 1996/03/31 22:38:56 pk Exp $ */
/*
*
@@ -32,9 +32,9 @@
*/
/*
- * x d v a r . h
+ * x d v a r . h
*
- * this file defines the software structure we use to control the
+ * this file defines the software structure we use to control the
* 753/7053.
*
* author: Chuck Cranor <chuck@ccrc.wustl.edu>
@@ -67,7 +67,7 @@ struct xd_iorq {
#define XD_SUB_MASK 0xf0 /* mask bits for state */
#define XD_SUB_FREE 0x00 /* free */
#define XD_SUB_NORM 0x10 /* normal I/O request */
-#define XD_SUB_WAIT 0x20 /* normal I/O request in the
+#define XD_SUB_WAIT 0x20 /* normal I/O request in the
context of a process */
#define XD_SUB_POLL 0x30 /* polled mode */
#define XD_SUB_DONE 0x40 /* not active, but can't be free'd yet */
@@ -151,12 +151,12 @@ struct xdc_softc {
struct buf sc_wq; /* queue'd IOPBs for this controller */
char freereq[XDC_MAXIOPB]; /* free list (stack) */
char waitq[XDC_MAXIOPB]; /* wait queue */
- char nfree; /* number of iopbs free */
- char nrun; /* number running */
- char nwait; /* number of waiting iopbs */
- char ndone; /* number of done IORQs */
- char waithead; /* head of queue */
- char waitend; /* end of queue */
+ u_char nfree; /* number of iopbs free */
+ u_char nrun; /* number running */
+ u_char nwait; /* number of waiting iopbs */
+ u_char ndone; /* number of done IORQs */
+ u_char waithead; /* head of queue */
+ u_char waitend; /* end of queue */
};
/*
diff --git a/sys/arch/sparc/dev/xio.h b/sys/arch/sparc/dev/xio.h
index e9e22859542..1ad5662b6be 100644
--- a/sys/arch/sparc/dev/xio.h
+++ b/sys/arch/sparc/dev/xio.h
@@ -1,4 +1,4 @@
-/* $NetBSD: xio.h,v 1.1 1995/06/26 23:07:26 pk Exp $ */
+/* $NetBSD: xio.h,v 1.2 1996/03/31 22:38:58 pk Exp $ */
/*
*
@@ -32,9 +32,9 @@
*/
/*
- * x i o . h
+ * x i o . h
*
- * this file defines the software structure we use to ioctl the
+ * this file defines the software structure we use to ioctl the
* 753/7053. this interface isn't set in stone and may (or may not)
* need adjustment.
*
diff --git a/sys/arch/sparc/dev/xy.c b/sys/arch/sparc/dev/xy.c
index bd85ae48a25..2841bd9ba84 100644
--- a/sys/arch/sparc/dev/xy.c
+++ b/sys/arch/sparc/dev/xy.c
@@ -1,4 +1,4 @@
-/* $NetBSD: xy.c,v 1.3 1996/01/07 22:03:05 thorpej Exp $ */
+/* $NetBSD: xy.c,v 1.17 1996/04/22 02:42:04 christos Exp $ */
/*
*
@@ -36,7 +36,7 @@
* x y . c x y l o g i c s 4 5 0 / 4 5 1 s m d d r i v e r
*
* author: Chuck Cranor <chuck@ccrc.wustl.edu>
- * id: $Id: xy.c,v 1.7 1996/03/04 20:35:25 chuck Exp $
+ * id: $NetBSD: xy.c,v 1.17 1996/04/22 02:42:04 christos Exp $
* started: 14-Sep-95
* references: [1] Xylogics Model 753 User's Manual
* part number: 166-753-001, Revision B, May 21, 1988.
@@ -44,7 +44,7 @@
* [2] other NetBSD disk device drivers
* [3] Xylogics Model 450 User's Manual
* part number: 166-017-001, Revision B, 1983.
- * [4] Addendum to Xylogics Model 450 Disk Controller User's
+ * [4] Addendum to Xylogics Model 450 Disk Controller User's
* Manual, Jan. 1985.
* [5] The 451 Controller, Rev. B3, September 2, 1986.
* [6] David Jones <dej@achilles.net>'s unfinished 450/451 driver
@@ -61,7 +61,6 @@
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/conf.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
@@ -73,11 +72,14 @@
#include <sys/disk.h>
#include <sys/syslog.h>
#include <sys/dkbad.h>
+#include <sys/conf.h>
+
#include <vm/vm.h>
#include <vm/vm_kern.h>
#include <machine/autoconf.h>
#include <machine/sun_disklabel.h>
+#include <machine/conf.h>
#include <sparc/dev/xyreg.h>
#include <sparc/dev/xyvar.h>
@@ -151,32 +153,22 @@ int xyc_ioctlcmd __P((struct xy_softc *, dev_t dev, struct xd_iocmd *));
void xyc_perror __P((struct xy_iorq *, struct xy_iopb *, int));
int xyc_piodriver __P((struct xyc_softc *, struct xy_iorq *));
int xyc_remove_iorq __P((struct xyc_softc *));
-int xyc_reset __P((struct xyc_softc *, int, struct xy_iorq *, int,
+int xyc_reset __P((struct xyc_softc *, int, struct xy_iorq *, int,
struct xy_softc *));
inline void xyc_rqinit __P((struct xy_iorq *, struct xyc_softc *,
struct xy_softc *, int, u_long, int,
caddr_t, struct buf *));
void xyc_rqtopb __P((struct xy_iorq *, struct xy_iopb *, int, int));
-int xyc_start __P((struct xyc_softc *, struct xy_iorq *));
+void xyc_start __P((struct xyc_softc *, struct xy_iorq *));
int xyc_startbuf __P((struct xyc_softc *, struct xy_softc *, struct buf *));
int xyc_submit_iorq __P((struct xyc_softc *, struct xy_iorq *, int));
void xyc_tick __P((void *));
int xyc_unbusy __P((struct xyc *, int));
-int xyc_xyreset __P((struct xyc_softc *, struct xy_softc *));
+void xyc_xyreset __P((struct xyc_softc *, struct xy_softc *));
/* machine interrupt hook */
int xycintr __P((void *));
-/* {b,c}devsw */
-int xyclose __P((dev_t, int, int));
-int xydump __P((dev_t));
-int xyioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
-int xyopen __P((dev_t, int, int));
-int xyread __P((dev_t, struct uio *));
-int xywrite __P((dev_t, struct uio *));
-int xysize __P((dev_t));
-void xystrategy __P((struct buf *));
-
/* autoconf */
int xycmatch __P((struct device *, void *, void *));
void xycattach __P((struct device *, struct device *, void *));
@@ -190,12 +182,20 @@ int xygetdisklabel __P((struct xy_softc *, void *));
* cfdrivers: device driver interface to autoconfig
*/
-struct cfdriver xyccd = {
- NULL, "xyc", xycmatch, xycattach, DV_DULL, sizeof(struct xyc_softc)
+struct cfattach xyc_ca = {
+ sizeof(struct xyc_softc), xycmatch, xycattach
+};
+
+struct cfdriver xyc_cd = {
+ NULL, "xyc", DV_DULL
};
-struct cfdriver xycd = {
- NULL, "xy", xymatch, xyattach, DV_DISK, sizeof(struct xy_softc)
+struct cfattach xy_ca = {
+ sizeof(struct xy_softc), xymatch, xyattach
+};
+
+struct cfdriver xy_cd = {
+ NULL, "xy", DV_DISK
};
struct xyc_attach_args { /* this is the "aux" args to xyattach */
@@ -256,11 +256,11 @@ xygetdisklabel(xy, b)
if (sdl->sl_magic == SUN_DKMAGIC)
xy->pcyl = sdl->sl_pcylinders;
else {
- printf("%s: WARNING: no `pcyl' in disk label.\n",
- xy->sc_dev.dv_xname);
+ printf("%s: WARNING: no `pcyl' in disk label.\n",
+ xy->sc_dev.dv_xname);
xy->pcyl = xy->sc_dk.dk_label->d_ncylinders +
xy->sc_dk.dk_label->d_acylinders;
- printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n",
+ printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n",
xy->sc_dev.dv_xname, xy->pcyl);
}
@@ -295,14 +295,13 @@ int xycmatch(parent, match, aux)
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
struct xyc *xyc;
- int del = 0;
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
xyc = (struct xyc *) ra->ra_vaddr;
- if (probeget(&xyc->xyc_rsetup, 1) == -1)
+ if (probeget((caddr_t) &xyc->xyc_rsetup, 1) == -1)
return (0);
if (xyc_unbusy(xyc, XYC_RESETUSEC) == XY_ERR_FAIL)
return(0);
@@ -313,7 +312,7 @@ int xycmatch(parent, match, aux)
/*
* xycattach: attach controller
*/
-void
+void
xycattach(parent, self, aux)
struct device *parent, *self;
void *aux;
@@ -343,10 +342,10 @@ xycattach(parent, self, aux)
for (lcv = 0; lcv < XYC_MAXDEV; lcv++)
xyc->sc_drives[lcv] = (struct xy_softc *) 0;
- /*
+ /*
* allocate and zero buffers
- * check boundaries of the KVA's ... all IOPBs must reside in
- * the same 64K region.
+ * check boundaries of the KVA's ... all IOPBs must reside in
+ * the same 64K region.
*/
pbsz = XYC_MAXIOPB * sizeof(struct xy_iopb);
@@ -359,7 +358,7 @@ xycattach(parent, self, aux)
dvma_free(dtmp2, pbsz, &tmp2);
ultmp = (u_long) dtmp;
if ((ultmp & 0xffff0000) != ((ultmp + pbsz) & 0xffff0000)) {
- printf("%s: can't alloc IOPB mem in 64K\n",
+ printf("%s: can't alloc IOPB mem in 64K\n",
xyc->sc_dev.dv_xname);
return;
}
@@ -374,9 +373,9 @@ xycattach(parent, self, aux)
panic("xyc malloc");
bzero(xyc->reqs, XYC_MAXIOPB * sizeof(struct xy_iorq));
- /*
+ /*
* init iorq to iopb pointers, and non-zero fields in the
- * iopb which never change.
+ * iopb which never change.
*/
for (lcv = 0; lcv < XYC_MAXIOPB; lcv++) {
@@ -414,8 +413,8 @@ xycattach(parent, self, aux)
return;
}
if ((xyc->xyc->xyc_csr & XYC_ADRM) == 0) {
- printf("%s: 24 bit addressing turned off\n",
- xyc->sc_dev.dv_xname);
+ printf("%s: 24 bit addressing turned off\n",
+ xyc->sc_dev.dv_xname);
printf("please set hardware jumpers JM1-JM2=in, JM3-JM4=out\n");
printf("to enable 24 bit mode and this driver\n");
return;
@@ -458,13 +457,12 @@ xycattach(parent, self, aux)
* spin up and configure a disk after the system is booted (we can
* call xyattach!).
*/
-int
+int
xymatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
- struct xyc_softc *xyc = (void *) parent;
struct cfdata *cf = match;
struct xyc_attach_args *xa = aux;
@@ -481,7 +479,7 @@ xymatch(parent, match, aux)
* xyattach: attach a disk. this can be called from autoconf and also
* from xyopen/xystrategy.
*/
-void
+void
xyattach(parent, self, aux)
struct device *parent, *self;
void *aux;
@@ -490,7 +488,7 @@ xyattach(parent, self, aux)
struct xy_softc *xy = (void *) self, *oxy;
struct xyc_softc *xyc = (void *) parent;
struct xyc_attach_args *xa = aux;
- int res, err, spt, mb, blk, lcv, fmode, s, newstate;
+ int err, spt, mb, blk, lcv, fmode, s = 0, newstate;
struct dkbad *dkb;
struct bootpath *bp;
@@ -565,13 +563,13 @@ xyattach(parent, self, aux)
xy->nsect = 1;
xy->sectpercyl = 1;
for (lcv = 0; lcv < 126; lcv++) /* init empty bad144 table */
- xy->dkb.bt_bad[lcv].bt_cyl =
+ xy->dkb.bt_bad[lcv].bt_cyl =
xy->dkb.bt_bad[lcv].bt_trksec = 0xffff;
/* read disk label */
- for (xy->drive_type = 0 ; xy->drive_type <= XYC_MAXDT ;
+ for (xy->drive_type = 0 ; xy->drive_type <= XYC_MAXDT ;
xy->drive_type++) {
- err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, 0, 1,
+ err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, 0, 1,
xa->dvmabuf, fmode);
XYC_DONE(xyc, err);
if (err == XY_ERR_AOK) break;
@@ -605,9 +603,9 @@ xyattach(parent, self, aux)
* 450/451 stupidity: the drive type is encoded into the format
* of the disk. the drive type in the IOPB must match the drive
* type in the format, or you will not be able to do I/O to the
- * disk (you get header not found errors). if you have two drives
- * of different sizes that have the same drive type in their
- * formatting then you are out of luck.
+ * disk (you get header not found errors). if you have two drives
+ * of different sizes that have the same drive type in their
+ * formatting then you are out of luck.
*
* this problem was corrected in the 753/7053.
*/
@@ -624,7 +622,7 @@ xyattach(parent, self, aux)
panic("xy drive size mismatch");
}
}
-
+
/* now set the real drive parameters! */
@@ -645,10 +643,10 @@ xyattach(parent, self, aux)
* last track of the disk (i.e. second cyl of "acyl" area).
*/
- blk = (xy->ncyl + xy->acyl - 1) * (xy->nhead * xy->nsect) +
+ blk = (xy->ncyl + xy->acyl - 1) * (xy->nhead * xy->nsect) +
/* last cyl */
(xy->nhead - 1) * xy->nsect; /* last head */
- err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, blk, 1,
+ err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, blk, 1,
xa->dvmabuf, fmode);
XYC_DONE(xyc, err);
if (err) {
@@ -681,9 +679,9 @@ xyattach(parent, self, aux)
if (xa->booting) {
/* restore bootpath! (do this via attach_args again?)*/
bp = bootpath_store(0, NULL);
- if (bp && strcmp("xy", bp->name) == 0 &&
- xy->xy_drive == bp->val[0])
- bootdv = &xy->sc_dev;
+ if (bp && strcmp("xy", bp->name) == 0 &&
+ xy->xy_drive == bp->val[0])
+ bp->dev = &xy->sc_dev;
}
dk_establish(&xy->sc_dk, &xy->sc_dev); /* XXX */
@@ -707,13 +705,14 @@ done:
/*
* xyclose: close device
*/
-int
-xyclose(dev, flag, fmt)
+int
+xyclose(dev, flag, fmt, p)
dev_t dev;
int flag, fmt;
+ struct proc *p;
{
- struct xy_softc *xy = xycd.cd_devs[DISKUNIT(dev)];
+ struct xy_softc *xy = xy_cd.cd_devs[DISKUNIT(dev)];
int part = DISKPART(dev);
/* clear mask bits */
@@ -734,20 +733,22 @@ xyclose(dev, flag, fmt)
/*
* xydump: crash dump system
*/
-int
-xydump(dev)
- dev_t dev;
-
+int
+xydump(dev, blkno, va, size)
+ dev_t dev;
+ daddr_t blkno;
+ caddr_t va;
+ size_t size;
{
int unit, part;
struct xy_softc *xy;
unit = DISKUNIT(dev);
- if (unit >= xycd.cd_ndevs)
+ if (unit >= xy_cd.cd_ndevs)
return ENXIO;
part = DISKPART(dev);
- xy = xycd.cd_devs[unit];
+ xy = xy_cd.cd_devs[unit];
printf("%s%c: crash dump not supported (yet)\n", xy->sc_dev.dv_xname,
'a' + part);
@@ -759,11 +760,11 @@ xydump(dev)
* "dumpsize" == size of dump in clicks "physmem" == size of physical
* memory (clicks, ctob() to get bytes) (normal case: dumpsize ==
* physmem)
- *
+ *
* dump a copy of physical memory to the dump device starting at sector
* "dumplo" in the swap partition (make sure > 0). map in pages as
* we go. use polled I/O.
- *
+ *
* XXX how to handle NON_CONTIG? */
}
@@ -771,7 +772,7 @@ xydump(dev)
/*
* xyioctl: ioctls on XY drives. based on ioctl's of other netbsd disks.
*/
-int
+int
xyioctl(dev, command, addr, flag, p)
dev_t dev;
u_long command;
@@ -786,7 +787,7 @@ xyioctl(dev, command, addr, flag, p)
unit = DISKUNIT(dev);
- if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == NULL)
+ if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == NULL)
return (ENXIO);
/* switch on ioctl type */
@@ -866,11 +867,11 @@ xyioctl(dev, command, addr, flag, p)
* xyopen: open drive
*/
-int
-xyopen(dev, flag, fmt)
+int
+xyopen(dev, flag, fmt, p)
dev_t dev;
int flag, fmt;
-
+ struct proc *p;
{
int unit, part;
struct xy_softc *xy;
@@ -879,7 +880,7 @@ xyopen(dev, flag, fmt)
/* first, could it be a valid target? */
unit = DISKUNIT(dev);
- if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == NULL)
+ if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == NULL)
return (ENXIO);
part = DISKPART(dev);
@@ -890,7 +891,7 @@ xyopen(dev, flag, fmt)
xa.dvmabuf = (char *)dvma_malloc(XYFM_BPS, &xa.buf, M_NOWAIT);
xa.fullmode = XY_SUB_WAIT;
xa.booting = 0;
- xyattach((struct device *) xy->parent,
+ xyattach((struct device *) xy->parent,
(struct device *) xy, &xa);
dvma_free(xa.dvmabuf, XYFM_BPS, &xa.buf);
if (xy->state == XY_DRIVE_UNKNOWN) {
@@ -920,18 +921,20 @@ xyopen(dev, flag, fmt)
}
int
-xyread(dev, uio)
+xyread(dev, uio, flags)
dev_t dev;
struct uio *uio;
+ int flags;
{
return (physio(xystrategy, NULL, dev, B_READ, minphys, uio));
}
int
-xywrite(dev, uio)
+xywrite(dev, uio, flags)
dev_t dev;
struct uio *uio;
+ int flags;
{
return (physio(xystrategy, NULL, dev, B_WRITE, minphys, uio));
@@ -942,28 +945,28 @@ xywrite(dev, uio)
* xysize: return size of a partition for a dump
*/
-int
+int
xysize(dev)
dev_t dev;
{
struct xy_softc *xysc;
- int unit, part, size;
+ int part, size;
/* valid unit? try an open */
- if (xyopen(dev, 0, S_IFBLK) != 0)
+ if (xyopen(dev, 0, S_IFBLK, NULL) != 0)
return (-1);
/* do it */
- xysc = xycd.cd_devs[DISKUNIT(dev)];
+ xysc = xy_cd.cd_devs[DISKUNIT(dev)];
part = DISKPART(dev);
if (xysc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
size = -1; /* only give valid size for swap partitions */
else
size = xysc->sc_dk.dk_label->d_partitions[part].p_size;
- if (xyclose(dev, 0, S_IFBLK) != 0)
+ if (xyclose(dev, 0, S_IFBLK, NULL) != 0)
return -1;
return size;
}
@@ -972,14 +975,12 @@ xysize(dev)
* xystrategy: buffering system interface to xy.
*/
-void
+void
xystrategy(bp)
struct buf *bp;
{
struct xy_softc *xy;
- struct xyc_softc *parent;
- struct buf *wq;
int s, unit;
struct xyc_attach_args xa;
@@ -987,7 +988,7 @@ xystrategy(bp)
/* check for live device */
- if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == 0 ||
+ if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == 0 ||
bp->b_blkno < 0 ||
(bp->b_bcount % xy->sc_dk.dk_label->d_secsize) != 0) {
bp->b_error = EINVAL;
@@ -1059,14 +1060,12 @@ done: /* tells upper layers we are done with this
*
* xycintr: hardware interrupt.
*/
-int
+int
xycintr(v)
void *v;
{
struct xyc_softc *xycsc = v;
- struct xy_softc *xy;
- struct buf *bp;
/* kick the event counter */
@@ -1094,7 +1093,7 @@ xycintr(v)
* xyc_rqinit: fill out the fields of an I/O request
*/
-inline void
+inline void
xyc_rqinit(rq, xyc, xy, md, blk, cnt, db, bp)
struct xy_iorq *rq;
struct xyc_softc *xyc;
@@ -1120,7 +1119,7 @@ xyc_rqinit(rq, xyc, xy, md, blk, cnt, db, bp)
* xyc_rqtopb: load up an IOPB based on an iorq
*/
-void
+void
xyc_rqtopb(iorq, iopb, cmd, subfun)
struct xy_iorq *iorq;
struct xy_iopb *iopb;
@@ -1190,7 +1189,7 @@ int del;
* xyc_cmd: front end for POLL'd and WAIT'd commands. Returns 0 or error.
* note that NORM requests are handled seperately.
*/
-int
+int
xyc_cmd(xycsc, cmd, subfn, unit, block, scnt, dptr, fullmode)
struct xyc_softc *xycsc;
int cmd, subfn, unit, block, scnt;
@@ -1198,8 +1197,7 @@ xyc_cmd(xycsc, cmd, subfn, unit, block, scnt, dptr, fullmode)
int fullmode;
{
- int submode = XY_STATE(fullmode), retry;
- u_long dp;
+ int submode = XY_STATE(fullmode);
struct xy_iorq *iorq = xycsc->ciorq;
struct xy_iopb *iopb = xycsc->ciopb;
@@ -1208,7 +1206,7 @@ xyc_cmd(xycsc, cmd, subfn, unit, block, scnt, dptr, fullmode)
*/
start:
if (submode == XY_SUB_WAIT && XY_STATE(iorq->mode) != XY_SUB_FREE) {
- if (tsleep(iorq, PRIBIO, "xyc_cmd", 0))
+ if (tsleep(iorq, PRIBIO, "xyc_cmd", 0))
return(XY_ERR_FAIL);
goto start;
}
@@ -1241,7 +1239,7 @@ start:
* start a buffer for running
*/
-int
+int
xyc_startbuf(xycsc, xysc, bp)
struct xyc_softc *xycsc;
struct xy_softc *xysc;
@@ -1251,7 +1249,7 @@ xyc_startbuf(xycsc, xysc, bp)
int partno;
struct xy_iorq *iorq;
struct xy_iopb *iopb;
- u_long block, dp;
+ u_long block;
caddr_t dbuf;
iorq = xysc->xyrq;
@@ -1259,7 +1257,7 @@ xyc_startbuf(xycsc, xysc, bp)
/* get buf */
- if (bp == NULL)
+ if (bp == NULL)
panic("xyc_startbuf null buf");
partno = DISKPART(bp->b_dev);
@@ -1273,7 +1271,7 @@ xyc_startbuf(xycsc, xysc, bp)
/*
* load request. we have to calculate the correct block number based
* on partition info.
- *
+ *
* note that iorq points to the buffer as mapped into DVMA space,
* where as the bp->b_data points to its non-DVMA mapping.
*/
@@ -1283,7 +1281,7 @@ xyc_startbuf(xycsc, xysc, bp)
dbuf = kdvma_mapin(bp->b_data, bp->b_bcount, 0);
if (dbuf == NULL) { /* out of DVMA space */
- printf("%s: warning: out of DVMA space\n",
+ printf("%s: warning: out of DVMA space\n",
xycsc->sc_dev.dv_xname);
return (XY_ERR_FAIL); /* XXX: need some sort of
* call-back scheme here? */
@@ -1327,9 +1325,9 @@ xyc_startbuf(xycsc, xysc, bp)
* time, where as a 451 can take them in chains. [the 450 claims it
* can handle chains, but is appears to be buggy...] iopb are allocated
* in DVMA space at boot up time. each disk gets one iopb, and the
- * controller gets one (for POLL and WAIT commands). what happens if
- * the iopb is busy? for i/o type [1], the buffers are queued at the
- * "buff" layer and * picked up later by the interrupt routine. for case
+ * controller gets one (for POLL and WAIT commands). what happens if
+ * the iopb is busy? for i/o type [1], the buffers are queued at the
+ * "buff" layer and * picked up later by the interrupt routine. for case
* [2] we can only be blocked if there is a WAIT type I/O request being
* run. since this can only happen when we are crashing, we wait a sec
* and then steal the IOPB. for case [3] the process can sleep
@@ -1337,7 +1335,7 @@ xyc_startbuf(xycsc, xysc, bp)
*/
-int
+int
xyc_submit_iorq(xycsc, iorq, type)
struct xyc_softc *xycsc;
struct xy_iorq *iorq;
@@ -1348,7 +1346,7 @@ xyc_submit_iorq(xycsc, iorq, type)
u_long iopbaddr;
#ifdef XYC_DEBUG
- printf("xyc_submit_iorq(%s, addr=0x%x, type=%d)\n",
+ printf("xyc_submit_iorq(%s, addr=0x%x, type=%d)\n",
xycsc->sc_dev.dv_xname, iorq, type);
#endif
@@ -1381,12 +1379,12 @@ xyc_submit_iorq(xycsc, iorq, type)
iopb = xyc_chain(xycsc, iorq); /* build chain */
if (iopb == NULL) { /* nothing doing? */
- if (type == XY_SUB_NORM || type == XY_SUB_NOQ)
+ if (type == XY_SUB_NORM || type == XY_SUB_NOQ)
return(XY_ERR_AOK);
panic("xyc_submit_iorq: xyc_chain failed!\n");
}
iopbaddr = (u_long) iopb - DVMA_BASE;
-
+
XYC_GO(xycsc->xyc, iopbaddr);
/* command now running, wrap it up */
@@ -1434,11 +1432,11 @@ struct xy_iorq *iorq;
xycsc->iopbase[XYC_CTLIOPB].done == 0)
iorq = &xycsc->reqs[XYC_CTLIOPB];
}
- /*
+ /*
* special case: if iorq != NULL then we have a POLL or WAIT request.
* we let these take priority and do them first.
*/
- if (iorq) {
+ if (iorq) {
xycsc->xy_chain[0] = iorq;
iorq->iopb->chen = 0;
return(iorq->iopb);
@@ -1479,9 +1477,9 @@ struct xy_iorq *iorq;
*
* programmed i/o driver. this function takes over the computer
* and drains off the polled i/o request. it returns the status of the iorq
- * the caller is interesting in.
+ * the caller is interesting in.
*/
-int
+int
xyc_piodriver(xycsc, iorq)
struct xyc_softc *xycsc;
struct xy_iorq *iorq;
@@ -1490,7 +1488,6 @@ xyc_piodriver(xycsc, iorq)
int nreset = 0;
int retval = 0;
u_long res;
- struct xyc *xyc = xycsc->xyc;
#ifdef XYC_DEBUG
printf("xyc_piodriver(%s, 0x%x)\n", xycsc->sc_dev.dv_xname, iorq);
#endif
@@ -1534,7 +1531,7 @@ xyc_piodriver(xycsc, iorq)
/* start up any bufs that have queued */
- xyc_start(xycsc, NULL);
+ xyc_start(xycsc, NULL);
return (retval);
}
@@ -1543,7 +1540,7 @@ xyc_piodriver(xycsc, iorq)
* xyc_xyreset: reset one drive. NOTE: assumes xyc was just reset.
* we steal iopb[XYC_CTLIOPB] for this, but we put it back when we are done.
*/
-int
+void
xyc_xyreset(xycsc, xysc)
struct xyc_softc *xycsc;
struct xy_softc *xysc;
@@ -1558,7 +1555,7 @@ xyc_xyreset(xycsc, xysc)
xycsc->ciopb->com = XYCMD_RST;
xycsc->ciopb->unit = xysc->xy_drive;
addr = (u_long) xycsc->ciopb - DVMA_BASE;
-
+
XYC_GO(xycsc->xyc, addr);
del = XYC_RESETUSEC;
@@ -1585,7 +1582,7 @@ xyc_xyreset(xycsc, xysc)
* xyc_reset: reset everything: requests are marked as errors except
* a polled request (which is resubmitted)
*/
-int
+int
xyc_reset(xycsc, quiet, blastmode, error, xysc)
struct xyc_softc *xycsc;
int quiet, error;
@@ -1593,7 +1590,7 @@ xyc_reset(xycsc, quiet, blastmode, error, xysc)
struct xy_softc *xysc;
{
- int del = 0, lcv, poll = -1, retval = XY_ERR_AOK;
+ int del = 0, lcv, retval = XY_ERR_AOK;
/* soft reset hardware */
@@ -1619,7 +1616,7 @@ xyc_reset(xycsc, quiet, blastmode, error, xysc)
/* is it active? */
continue;
- if (blastmode == XY_RSET_ALL ||
+ if (blastmode == XY_RSET_ALL ||
blastmode != iorq) {
/* failed */
iorq->errno = error;
@@ -1666,7 +1663,7 @@ xyc_reset(xycsc, quiet, blastmode, error, xysc)
* xyc_start: start waiting buffers
*/
-int
+void
xyc_start(xycsc, iorq)
struct xyc_softc *xycsc;
struct xy_iorq *iorq;
@@ -1687,10 +1684,10 @@ xyc_start(xycsc, iorq)
}
/*
- * xyc_remove_iorq: remove "done" IOPB's.
+ * xyc_remove_iorq: remove "done" IOPB's.
*/
-int
+int
xyc_remove_iorq(xycsc)
struct xyc_softc *xycsc;
@@ -1770,7 +1767,7 @@ xyc_remove_iorq(xycsc)
* at the bad144 sector. to exit bad144 mode, we
* must advance the pointers 1 sector and issue a new
* request if there are still sectors left to process
- *
+ *
*/
XYC_ADVANCE(iorq, 1); /* advance 1 sector */
@@ -1838,7 +1835,7 @@ xyc_remove_iorq(xycsc)
* is in lasterror. also, if iorq->errno == 0, then we recovered
* from that error (otherwise iorq->errno == iorq->lasterror).
*/
-void
+void
xyc_perror(iorq, iopb, still_trying)
struct xy_iorq *iorq;
struct xy_iopb *iopb;
@@ -1871,7 +1868,7 @@ xyc_perror(iorq, iopb, still_trying)
* xyc_error: non-fatal error encountered... recover.
* return AOK if resubmitted, return FAIL if this iopb is done
*/
-int
+int
xyc_error(xycsc, iorq, iopb, comm)
struct xyc_softc *xycsc;
struct xy_iorq *iorq;
@@ -1939,7 +1936,7 @@ xyc_error(xycsc, iorq, iopb, comm)
/*
* xyc_tick: make sure xy is still alive and ticking (err, kicking).
*/
-void
+void
xyc_tick(arg)
void *arg;
@@ -1976,14 +1973,14 @@ xyc_tick(arg)
*
* XXX missing a few commands (see the 7053 driver for ideas)
*/
-int
+int
xyc_ioctlcmd(xy, dev, xio)
struct xy_softc *xy;
dev_t dev;
struct xd_iocmd *xio;
{
- int s, err, rqno, dummy;
+ int s, err, rqno, dummy = 0;
caddr_t dvmabuf = NULL, buf = NULL;
struct xyc_softc *xycsc;
@@ -2018,7 +2015,7 @@ xyc_ioctlcmd(xy, dev, xio)
if (xio->dlen) {
dvmabuf = dvma_malloc(xio->dlen, &buf, M_WAITOK);
if (xio->cmd == XYCMD_WR) {
- if (err = copyin(xio->dptr, buf, xio->dlen)) {
+ if ((err = copyin(xio->dptr, buf, xio->dlen)) != 0) {
dvma_free(dvmabuf, xio->dlen, &buf);
return (err);
}
@@ -2147,7 +2144,7 @@ int errno;
return(XY_ERA_SOFT); /* an FYI error */
- case XY_ERR_WPRO:
+ case XY_ERR_WPRO:
return(XY_ERA_WPRO); /* write protect */
}
diff --git a/sys/arch/sparc/dev/xyreg.h b/sys/arch/sparc/dev/xyreg.h
index 757e73cfd9c..2508bb97a8e 100644
--- a/sys/arch/sparc/dev/xyreg.h
+++ b/sys/arch/sparc/dev/xyreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: xyreg.h,v 1.1 1995/09/25 20:35:15 chuck Exp $ */
+/* $NetBSD: xyreg.h,v 1.3 1996/03/31 22:39:02 pk Exp $ */
/*
*
@@ -90,9 +90,9 @@ struct xyc {
* add iopb to the chain, and clear AREQ to resume I/O
*
* when the controller is done with a command it may interrupt (if you
- * ask it to) and it will set the XYC_IPND bit in the csr. clear
+ * ask it to) and it will set the XYC_IPND bit in the csr. clear
* the interrupt by writing one to this bit.
- *
+ *
* the format of the iopb is described in section 2.4 of the manual.
* note that it is byte-swapped on the sun.
*/
diff --git a/sys/arch/sparc/dev/xyvar.h b/sys/arch/sparc/dev/xyvar.h
index 5296d9fa202..e7ec8305980 100644
--- a/sys/arch/sparc/dev/xyvar.h
+++ b/sys/arch/sparc/dev/xyvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: xyvar.h,v 1.2 1996/01/07 22:03:06 thorpej Exp $ */
+/* $NetBSD: xyvar.h,v 1.4 1996/03/31 22:39:04 pk Exp $ */
/*
*
@@ -32,9 +32,9 @@
*/
/*
- * x y v a r . h
+ * x y v a r . h
*
- * this file defines the software structure we use to control the
+ * this file defines the software structure we use to control the
* 450/451.
*
* author: Chuck Cranor <chuck@ccrc.wustl.edu>
@@ -67,7 +67,7 @@ struct xy_iorq {
#define XY_SUB_MASK 0xf0 /* mask bits for state */
#define XY_SUB_FREE 0x00 /* free */
#define XY_SUB_NORM 0x10 /* normal I/O request */
-#define XY_SUB_WAIT 0x20 /* normal I/O request in the
+#define XY_SUB_WAIT 0x20 /* normal I/O request in the
context of a process */
#define XY_SUB_POLL 0x30 /* polled mode */
#define XY_SUB_DONE 0x40 /* not active, but can't be free'd yet */
diff --git a/sys/arch/sparc/dev/zs.c b/sys/arch/sparc/dev/zs.c
index c37e8f97041..ee99cb25b5a 100644
--- a/sys/arch/sparc/dev/zs.c
+++ b/sys/arch/sparc/dev/zs.c
@@ -1,4 +1,4 @@
-/* $NetBSD: zs.c,v 1.28 1995/04/21 15:51:26 pk Exp $ */
+/* $NetBSD: zs.c,v 1.37.4.1 1996/06/02 09:07:55 mrg Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -48,17 +48,14 @@
* Zilog Z8530 (ZSCC) driver.
*
* Runs two tty ports (ttya and ttyb) on zs0,
- * and runs a keyboard and mouse on zs1, and
- * possibly two more tty ports (ttyc and ttyd) on zs2.
+ * and runs a keyboard and mouse on zs1.
*
* This driver knows far too much about chip to usage mappings.
*/
-#include "zs.h"
-
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/device.h>
-#include <sys/conf.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
@@ -66,22 +63,26 @@
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
+#include <sys/conf.h>
#include <machine/autoconf.h>
+#include <machine/conf.h>
#include <machine/cpu.h>
#include <sparc/sparc/vaddrs.h>
#include <sparc/sparc/auxreg.h>
+
#include <machine/kbd.h>
#include <dev/ic/z8530reg.h>
+
#include <sparc/dev/zsvar.h>
#ifdef KGDB
#include <machine/remote-sl.h>
#endif
-#define ZSMAJOR 12 /* XXX */
+#define ZSMAJOR 12 /* XXX */
#define ZS_KBD 2 /* XXX */
#define ZS_MOUSE 3 /* XXX */
@@ -103,20 +104,25 @@
#endif
/*
- * Software state per found chip.
+ * Software state per found chip. This would be called `zs_softc',
+ * but the previous driver had a rather different zs_softc....
*/
-struct zs_softc {
- struct device sc_dev; /* base device */
- volatile struct zsdevice *sc_zs; /* chip registers */
- struct evcnt sc_intrcnt;
- struct zs_chanstate sc_cs[2]; /* chan A/B software state */
+struct zsinfo {
+ struct device zi_dev; /* base device */
+ volatile struct zsdevice *zi_zs;/* chip registers */
+ struct zs_chanstate zi_cs[2]; /* channel A and B software state */
};
/* Definition of the driver for autoconfig. */
static int zsmatch __P((struct device *, void *, void *));
static void zsattach __P((struct device *, struct device *, void *));
-struct cfdriver zscd = {
- NULL, "zs", zsmatch, zsattach, DV_TTY, sizeof(struct zs_softc)
+
+struct cfattach zs_ca = {
+ sizeof(struct zsinfo), zsmatch, zsattach
+};
+
+struct cfdriver zs_cd = {
+ NULL, "zs", DV_TTY
};
/* Interrupt handlers. */
@@ -131,31 +137,41 @@ struct zs_chanstate *zslist;
static void zsiopen __P((struct tty *));
static void zsiclose __P((struct tty *));
static void zsstart __P((struct tty *));
-void zsstop __P((struct tty *, int));
static int zsparam __P((struct tty *, struct termios *));
/* Routines purely local to this driver. */
static int zs_getspeed __P((volatile struct zschan *));
+#ifdef KGDB
static void zs_reset __P((volatile struct zschan *, int, int));
+#endif
static void zs_modem __P((struct zs_chanstate *, int));
static void zs_loadchannelregs __P((volatile struct zschan *, u_char *));
/* Console stuff. */
static struct tty *zs_ctty; /* console `struct tty *' */
static int zs_consin = -1, zs_consout = -1;
-static int zscnputc __P((int)); /* console putc function */
+static void zscnputc __P((int)); /* console putc function */
static volatile struct zschan *zs_conschan;
-static struct tty *zs_checkcons __P((struct zs_softc *, int,
- struct zs_chanstate *));
+static struct tty *zs_checkcons __P((struct zsinfo *, int, struct zs_chanstate *));
#ifdef KGDB
/* KGDB stuff. Must reboot to change zs_kgdbunit. */
extern int kgdb_dev, kgdb_rate;
static int zs_kgdb_savedspeed;
static void zs_checkkgdb __P((int, struct zs_chanstate *, struct tty *));
+void zskgdb __P((int));
+static int zs_kgdb_getc __P((void *));
+static void zs_kgdb_putc __P((void *, int));
#endif
-extern void *findzs __P((int));
+static int zsrint __P((struct zs_chanstate *, volatile struct zschan *));
+static int zsxint __P((struct zs_chanstate *, volatile struct zschan *));
+static int zssint __P((struct zs_chanstate *, volatile struct zschan *));
+
+void zsabort __P((void));
+static void zsoverrun __P((int, long *, char *));
+
+#include "zs.h" /* XXX: */
static volatile struct zsdevice *zsaddr[NZS]; /* XXX, but saves work */
/*
@@ -174,10 +190,13 @@ int zshardscope;
int zsshortcuts; /* number of "shortcut" software interrupts */
#ifdef SUN4
-static u_char
+static u_int zs_read __P((volatile struct zschan *, u_int reg));
+static u_int zs_write __P((volatile struct zschan *, u_int, u_int));
+
+static u_int
zs_read(zc, reg)
volatile struct zschan *zc;
- u_char reg;
+ u_int reg;
{
u_char val;
@@ -188,10 +207,10 @@ zs_read(zc, reg)
return val;
}
-static u_char
+static u_int
zs_write(zc, reg, val)
volatile struct zschan *zc;
- u_char reg, val;
+ u_int reg, val;
{
zc->zc_csr = reg;
ZS_DELAY();
@@ -216,7 +235,8 @@ zsmatch(parent, vcf, aux)
if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
return (0);
- if (ca->ca_bustype==BUS_MAIN && cputyp!=CPU_SUN4)
+ if ((ca->ca_bustype == BUS_MAIN && !CPU_ISSUN4) ||
+ (ca->ca_bustype == BUS_OBIO && CPU_ISSUN4M))
return (getpropint(ra->ra_node, "slave", -2) == cf->cf_unit);
ra->ra_len = NBPG;
return (probeget(ra->ra_vaddr, 1) != -1);
@@ -235,7 +255,7 @@ zsattach(parent, dev, aux)
void *aux;
{
register int zs = dev->dv_unit, unit;
- register struct zs_softc *sc;
+ register struct zsinfo *zi;
register struct zs_chanstate *cs;
register volatile struct zsdevice *addr;
register struct tty *tp, *ctp;
@@ -246,7 +266,7 @@ zsattach(parent, dev, aux)
int ringsize;
if ((addr = zsaddr[zs]) == NULL)
- addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs);
+ addr = zsaddr[zs] = findzs(zs);
if (ca->ca_bustype==BUS_MAIN)
if ((void *)addr != ra->ra_vaddr)
panic("zsattach");
@@ -263,36 +283,31 @@ zsattach(parent, dev, aux)
intr_establish(PIL_TTY, &levelsoft);
} else if (pri != prevpri)
panic("broken zs interrupt scheme");
- sc = (struct zs_softc *)dev;
- evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
- sc->sc_zs = addr;
+ zi = (struct zsinfo *)dev;
+ zi->zi_zs = addr;
unit = zs * 2;
- cs = sc->sc_cs;
+ cs = zi->zi_cs;
/* link into interrupt list with order (A,B) (B=A+1) */
cs[0].cs_next = &cs[1];
- cs[0].cs_sc = sc;
cs[1].cs_next = zslist;
- cs[1].cs_sc = sc;
zslist = cs;
cs->cs_unit = unit;
cs->cs_speed = zs_getspeed(&addr->zs_chan[ZS_CHAN_A]);
cs->cs_zc = &addr->zs_chan[ZS_CHAN_A];
- if ((ctp = zs_checkcons(sc, unit, cs)) != NULL)
+ if ((ctp = zs_checkcons(zi, unit, cs)) != NULL)
tp = ctp;
else {
tp = ttymalloc();
tp->t_dev = makedev(ZSMAJOR, unit);
tp->t_oproc = zsstart;
tp->t_param = zsparam;
- }
- cs->cs_ttyp = tp;
#ifdef KGDB
- if (ctp == NULL)
zs_checkkgdb(unit, cs, tp);
#endif
- ringsize = 4096;
+ }
+ cs->cs_ttyp = tp;
if (unit == ZS_KBD) {
/*
* Keyboard: tell /dev/kbd driver how to talk to us.
@@ -302,45 +317,51 @@ zsattach(parent, dev, aux)
kbd_serial(tp, zsiopen, zsiclose);
cs->cs_conk = 1; /* do L1-A processing */
ringsize = 128;
+ } else {
+ if (tp != ctp)
+ tty_attach(tp);
+ ringsize = 4096;
}
+
cs->cs_ringmask = ringsize - 1;
cs->cs_rbuf = malloc((u_long)ringsize * sizeof(*cs->cs_rbuf),
- M_DEVBUF, M_NOWAIT);
+ M_DEVBUF, M_NOWAIT);
unit++;
cs++;
-
cs->cs_unit = unit;
cs->cs_speed = zs_getspeed(&addr->zs_chan[ZS_CHAN_B]);
cs->cs_zc = &addr->zs_chan[ZS_CHAN_B];
- if ((ctp = zs_checkcons(sc, unit, cs)) != NULL)
+ if ((ctp = zs_checkcons(zi, unit, cs)) != NULL)
tp = ctp;
else {
tp = ttymalloc();
tp->t_dev = makedev(ZSMAJOR, unit);
tp->t_oproc = zsstart;
tp->t_param = zsparam;
- }
- cs->cs_ttyp = tp;
-
#ifdef KGDB
- if (ctp == NULL)
zs_checkkgdb(unit, cs, tp);
#endif
- ringsize = 4096;
+ }
+ cs->cs_ttyp = tp;
if (unit == ZS_MOUSE) {
/*
* Mouse: tell /dev/mouse driver how to talk to us.
*/
- tp->t_ispeed = tp->t_ospeed = B1200;
+ tp->t_ispeed = tp->t_ospeed = cs->cs_speed;
tp->t_cflag = CS8;
ms_serial(tp, zsiopen, zsiclose);
ringsize = 128;
+ } else {
+ if (tp != ctp)
+ tty_attach(tp);
+ ringsize = 4096;
}
cs->cs_ringmask = ringsize - 1;
cs->cs_rbuf = malloc((u_long)ringsize * sizeof(*cs->cs_rbuf),
- M_DEVBUF, M_NOWAIT);
+ M_DEVBUF, M_NOWAIT);
}
+#ifdef KGDB
/*
* Put a channel in a known state. Interrupts may be left disabled
* or enabled, as desired.
@@ -376,6 +397,7 @@ zs_reset(zc, inten, speed)
reg[13] = tconst >> 8;
zs_loadchannelregs(zc, reg);
}
+#endif
/*
* Declare the given tty (which is in fact &cons) as a console input
@@ -391,9 +413,8 @@ zsconsole(tp, unit, out, fnstop)
register struct tty *tp;
register int unit;
int out;
- void (**fnstop) __P((struct tty *, int));
+ int (**fnstop) __P((struct tty *, int));
{
- extern int (*v_putc)();
int zs;
volatile struct zsdevice *addr;
@@ -403,7 +424,7 @@ zsconsole(tp, unit, out, fnstop)
zs_consout = unit;
zs = unit >> 1;
if ((addr = zsaddr[zs]) == NULL)
- addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs);
+ addr = zsaddr[zs] = findzs(zs);
zs_conschan = (unit & 1) == 0 ? &addr->zs_chan[ZS_CHAN_A] :
&addr->zs_chan[ZS_CHAN_B];
v_putc = zscnputc;
@@ -417,7 +438,7 @@ zsconsole(tp, unit, out, fnstop)
/*
* Polled console output putchar.
*/
-static int
+static void
zscnputc(c)
int c;
{
@@ -431,10 +452,8 @@ zscnputc(c)
* lowering current ipl. Need a better way.
*/
s = splhigh();
-#ifdef SUN4C /* XXX */
- if (cputyp==CPU_SUN4C && s <= (12 << 8))
+ if (CPU_ISSUN4C && s <= (12 << 8)) /* XXX */
(void) splzs();
-#endif
while ((zc->zc_csr & ZSRR0_TX_READY) == 0)
ZS_DELAY();
zc->zc_data = c;
@@ -447,15 +466,15 @@ zscnputc(c)
* needed. Return console tty if it is to receive console input.
*/
static struct tty *
-zs_checkcons(sc, unit, cs)
- struct zs_softc *sc;
+zs_checkcons(zi, unit, cs)
+ struct zsinfo *zi;
int unit;
struct zs_chanstate *cs;
{
register struct tty *tp;
char *i, *o;
- if ((tp = zs_ctty) == NULL)
+ if ((tp = zs_ctty) == NULL) /* XXX */
return (0);
i = zs_consin == unit ? "input" : NULL;
o = zs_consout == unit ? "output" : NULL;
@@ -483,7 +502,7 @@ zs_checkcons(sc, unit, cs)
tp->t_oproc = zsstart;
}
printf("%s%c: console %s\n",
- sc->sc_dev.dv_xname, (unit & 1) + 'a', i ? (o ? "i/o" : i) : o);
+ zi->zi_dev.dv_xname, (unit & 1) + 'a', i ? (o ? "i/o" : i) : o);
cs->cs_consio = 1;
cs->cs_brkabort = 1;
return (tp);
@@ -568,13 +587,13 @@ zsopen(dev, flags, mode, p)
{
register struct tty *tp;
register struct zs_chanstate *cs;
- struct zs_softc *sc;
+ struct zsinfo *zi;
int unit = minor(dev), zs = unit >> 1, error, s;
- if (zs >= zscd.cd_ndevs || (sc = zscd.cd_devs[zs]) == NULL ||
+ if (zs >= zs_cd.cd_ndevs || (zi = zs_cd.cd_devs[zs]) == NULL ||
unit == ZS_KBD || unit == ZS_MOUSE)
return (ENXIO);
- cs = &sc->sc_cs[unit & 1];
+ cs = &zi->zi_cs[unit & 1];
if (cs->cs_consio)
return (ENXIO); /* ??? */
tp = cs->cs_ttyp;
@@ -595,7 +614,7 @@ zsopen(dev, flags, mode, p)
return (EBUSY);
}
error = 0;
- while (1) {
+ for (;;) {
register int rr0;
/* loop, turning on the device, until carrier present */
@@ -609,8 +628,9 @@ zsopen(dev, flags, mode, p)
tp->t_state & TS_CARR_ON)
break;
tp->t_state |= TS_WOPEN;
- if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
- ttopen, 0)) {
+ error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error) {
if (!(tp->t_state & TS_ISOPEN)) {
zs_modem(cs, 0);
tp->t_state &= ~TS_WOPEN;
@@ -640,11 +660,11 @@ zsclose(dev, flags, mode, p)
{
register struct zs_chanstate *cs;
register struct tty *tp;
- struct zs_softc *sc;
+ struct zsinfo *zi;
int unit = minor(dev), s;
- sc = zscd.cd_devs[unit >> 1];
- cs = &sc->sc_cs[unit & 1];
+ zi = zs_cd.cd_devs[unit >> 1];
+ cs = &zi->zi_cs[unit & 1];
tp = cs->cs_ttyp;
linesw[tp->t_line].l_close(tp, flags);
if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
@@ -682,15 +702,16 @@ zsread(dev, uio, flags)
int flags;
{
register struct zs_chanstate *cs;
- register struct zs_softc *sc;
+ register struct zsinfo *zi;
register struct tty *tp;
int unit = minor(dev);
- sc = zscd.cd_devs[unit >> 1];
- cs = &sc->sc_cs[unit & 1];
+ zi = zs_cd.cd_devs[unit >> 1];
+ cs = &zi->zi_cs[unit & 1];
tp = cs->cs_ttyp;
return (linesw[tp->t_line].l_read(tp, uio, flags));
+
}
int
@@ -700,12 +721,12 @@ zswrite(dev, uio, flags)
int flags;
{
register struct zs_chanstate *cs;
- register struct zs_softc *sc;
+ register struct zsinfo *zi;
register struct tty *tp;
int unit = minor(dev);
- sc = zscd.cd_devs[unit >> 1];
- cs = &sc->sc_cs[unit & 1];
+ zi = zs_cd.cd_devs[unit >> 1];
+ cs = &zi->zi_cs[unit & 1];
tp = cs->cs_ttyp;
return (linesw[tp->t_line].l_write(tp, uio, flags));
@@ -716,18 +737,15 @@ zstty(dev)
dev_t dev;
{
register struct zs_chanstate *cs;
- register struct zs_softc *sc;
+ register struct zsinfo *zi;
int unit = minor(dev);
- sc = zscd.cd_devs[unit >> 1];
- cs = &sc->sc_cs[unit & 1];
+ zi = zs_cd.cd_devs[unit >> 1];
+ cs = &zi->zi_cs[unit & 1];
return (cs->cs_ttyp);
-}
-static int zsrint __P((struct zs_chanstate *, volatile struct zschan *));
-static int zsxint __P((struct zs_chanstate *, volatile struct zschan *));
-static int zssint __P((struct zs_chanstate *, volatile struct zschan *));
+}
/*
* ZS hardware interrupt. Scan all ZS channels. NB: we know here that
@@ -746,64 +764,57 @@ zshard(intrarg)
void *intrarg;
{
register struct zs_chanstate *a;
- struct zs_softc *sc;
#define b (a + 1)
register volatile struct zschan *zc;
register int rr3, intflags = 0, v, i, ringmask;
-
-#define ZSHARD_NEED_SOFTINTR 1
-#define ZSHARD_WAS_SERVICED 2
-#define ZSHARD_CHIP_GOTINTR 4
+ static int zsrint(struct zs_chanstate *, volatile struct zschan *);
+ static int zsxint(struct zs_chanstate *, volatile struct zschan *);
+ static int zssint(struct zs_chanstate *, volatile struct zschan *);
for (a = zslist; a != NULL; a = b->cs_next) {
ringmask = a->cs_ringmask;
rr3 = ZS_READ(a->cs_zc, 3);
if (rr3 & (ZSRR3_IP_A_RX|ZSRR3_IP_A_TX|ZSRR3_IP_A_STAT)) {
- intflags |= (ZSHARD_CHIP_GOTINTR|ZSHARD_WAS_SERVICED);
+ intflags |= 2;
zc = a->cs_zc;
i = a->cs_rbput;
if (rr3 & ZSRR3_IP_A_RX && (v = zsrint(a, zc)) != 0) {
a->cs_rbuf[i++ & ringmask] = v;
- intflags |= ZSHARD_NEED_SOFTINTR;
+ intflags |= 1;
}
if (rr3 & ZSRR3_IP_A_TX && (v = zsxint(a, zc)) != 0) {
a->cs_rbuf[i++ & ringmask] = v;
- intflags |= ZSHARD_NEED_SOFTINTR;
+ intflags |= 1;
}
if (rr3 & ZSRR3_IP_A_STAT && (v = zssint(a, zc)) != 0) {
a->cs_rbuf[i++ & ringmask] = v;
- intflags |= ZSHARD_NEED_SOFTINTR;
+ intflags |= 1;
}
a->cs_rbput = i;
}
if (rr3 & (ZSRR3_IP_B_RX|ZSRR3_IP_B_TX|ZSRR3_IP_B_STAT)) {
- intflags |= (ZSHARD_CHIP_GOTINTR|ZSHARD_WAS_SERVICED);
+ intflags |= 2;
zc = b->cs_zc;
i = b->cs_rbput;
if (rr3 & ZSRR3_IP_B_RX && (v = zsrint(b, zc)) != 0) {
b->cs_rbuf[i++ & ringmask] = v;
- intflags |= ZSHARD_NEED_SOFTINTR;
+ intflags |= 1;
}
if (rr3 & ZSRR3_IP_B_TX && (v = zsxint(b, zc)) != 0) {
b->cs_rbuf[i++ & ringmask] = v;
- intflags |= ZSHARD_NEED_SOFTINTR;
+ intflags |= 1;
}
if (rr3 & ZSRR3_IP_B_STAT && (v = zssint(b, zc)) != 0) {
b->cs_rbuf[i++ & ringmask] = v;
- intflags |= ZSHARD_NEED_SOFTINTR;
+ intflags |= 1;
}
b->cs_rbput = i;
}
- if (intflags & ZSHARD_CHIP_GOTINTR) {
- a->cs_sc->sc_intrcnt.ev_count++;
- intflags &= ~ZSHARD_CHIP_GOTINTR;
- }
}
#undef b
- if (intflags & ZSHARD_NEED_SOFTINTR) {
-#if defined(SUN4C) || defined(SUN4M)
- if (cputyp==CPU_SUN4M || cputyp==CPU_SUN4C) {
+ if (intflags & 1) {
+ if (CPU_ISSUN4COR4M) {
/* XXX -- but this will go away when zshard moves to locore.s */
struct clockframe *p = intrarg;
@@ -817,10 +828,15 @@ zshard(intrarg)
return (zssoft(intrarg));
}
}
+
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ raise(0, PIL_TTY);
+ else
#endif
- ienab_bis(IE_ZSSOFT);
+ ienab_bis(IE_ZSSOFT);
}
- return (intflags & ZSHARD_WAS_SERVICED);
+ return (intflags & 2);
}
static int
@@ -828,11 +844,9 @@ zsrint(cs, zc)
register struct zs_chanstate *cs;
register volatile struct zschan *zc;
{
- register u_int c;
+ register int c = zc->zc_data;
- c = zc->zc_data;
ZS_DELAY();
-
if (cs->cs_conk) {
register struct conk_state *conk = &zsconk_state;
@@ -857,7 +871,7 @@ zsrint(cs, zc)
}
}
#ifdef KGDB
- if (c == FRAME_START && cs->cs_kgdb &&
+ if (c == FRAME_START && cs->cs_kgdb &&
(cs->cs_ttyp->t_state & TS_ISOPEN) == 0) {
zskgdb(cs->cs_unit);
goto clearit;
@@ -910,7 +924,7 @@ zssint(cs, zc)
register struct zs_chanstate *cs;
register volatile struct zschan *zc;
{
- register u_int rr0;
+ register int rr0;
rr0 = zc->zc_csr;
ZS_DELAY();
@@ -938,22 +952,21 @@ zssint(cs, zc)
}
}
if ((rr0 & ZSRR0_BREAK) && cs->cs_brkabort) {
-#ifdef SUN4
/*
* XXX This might not be necessary. Test and
* delete if it isn't.
*/
- if (cputyp==CPU_SUN4) {
+ if (CPU_ISSUN4) {
while (zc->zc_csr & ZSRR0_BREAK)
ZS_DELAY();
}
-#endif
zsabort();
return (0);
}
return (ZRING_MAKE(ZRING_SINT, rr0));
}
+void
zsabort()
{
@@ -970,6 +983,7 @@ zsabort()
* KGDB framing character received: enter kernel debugger. This probably
* should time out after a few seconds to avoid hanging on spurious input.
*/
+void
zskgdb(unit)
int unit;
{
@@ -1133,10 +1147,10 @@ zsioctl(dev, cmd, data, flag, p)
struct proc *p;
{
int unit = minor(dev);
- struct zs_softc *sc = zscd.cd_devs[unit >> 1];
- register struct tty *tp = sc->sc_cs[unit & 1].cs_ttyp;
+ struct zsinfo *zi = zs_cd.cd_devs[unit >> 1];
+ register struct zs_chanstate *cs = &zi->zi_cs[unit & 1];
+ register struct tty *tp = cs->cs_ttyp;
register int error, s;
- register struct zs_chanstate *cs = &sc->sc_cs[unit & 1];
error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p);
if (error >= 0)
@@ -1173,7 +1187,7 @@ zsioctl(dev, cmd, data, flag, p)
break;
}
case TIOCSFLAGS: {
- int userbits, driverbits = 0;
+ int userbits;
error = suser(p->p_ucred, &p->p_acflag);
if (error != 0)
@@ -1230,16 +1244,10 @@ zsioctl(dev, cmd, data, flag, p)
case TIOCCDTR:
zs_modem(cs, 0);
break;
- case TIOCMGET:
- /* XXX: fixme */
- *(int *)data = TIOCM_CAR | TIOCM_CTS | TIOCM_DTR | TIOCM_RTS;
- return (0);
case TIOCMSET:
- /* XXX: fixme */
- zs_modem(cs, *(int *)data & (TIOCM_DTR|TIOCM_RTS));
- return (0);
case TIOCMBIS:
case TIOCMBIC:
+ case TIOCMGET:
default:
return (ENOTTY);
}
@@ -1256,9 +1264,9 @@ zsstart(tp)
register struct zs_chanstate *cs;
register int s, nch;
int unit = minor(tp->t_dev);
- struct zs_softc *sc = zscd.cd_devs[unit >> 1];
+ struct zsinfo *zi = zs_cd.cd_devs[unit >> 1];
- cs = &sc->sc_cs[unit & 1];
+ cs = &zi->zi_cs[unit & 1];
s = spltty();
/*
@@ -1310,16 +1318,16 @@ out:
/*
* Stop output, e.g., for ^S or output flush.
*/
-void
+int
zsstop(tp, flag)
register struct tty *tp;
int flag;
{
register struct zs_chanstate *cs;
register int s, unit = minor(tp->t_dev);
- struct zs_softc *sc = zscd.cd_devs[unit >> 1];
+ struct zsinfo *zi = zs_cd.cd_devs[unit >> 1];
- cs = &sc->sc_cs[unit & 1];
+ cs = &zi->zi_cs[unit & 1];
s = splzs();
if (tp->t_state & TS_BUSY) {
/*
@@ -1330,6 +1338,7 @@ zsstop(tp, flag)
tp->t_state |= TS_FLUSH;
}
splx(s);
+ return 0;
}
/*
@@ -1344,8 +1353,8 @@ zsparam(tp, t)
register struct termios *t;
{
int unit = minor(tp->t_dev);
- struct zs_softc *sc = zscd.cd_devs[unit >> 1];
- register struct zs_chanstate *cs = &sc->sc_cs[unit & 1];
+ struct zsinfo *zi = zs_cd.cd_devs[unit >> 1];
+ register struct zs_chanstate *cs = &zi->zi_cs[unit & 1];
register int tmp, tmp5, cflag, s;
/*
@@ -1519,13 +1528,10 @@ zs_kgdb_getc(arg)
void *arg;
{
register volatile struct zschan *zc = (volatile struct zschan *)arg;
- u_char c;
while ((zc->zc_csr & ZSRR0_RX_READY) == 0)
ZS_DELAY();
- c = zc->zc_data;
- ZS_DELAY();
- return c;
+ return (zc->zc_data);
}
/*
@@ -1567,7 +1573,7 @@ zs_kgdb_init()
}
zs = unit >> 1;
if ((addr = zsaddr[zs]) == NULL)
- addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs);
+ addr = zsaddr[zs] = findzs(zs);
unit &= 1;
zc = unit == 0 ? &addr->zs_chan[ZS_CHAN_A] : &addr->zs_chan[ZS_CHAN_B];
zs_kgdb_savedspeed = zs_getspeed(zc);
diff --git a/sys/arch/sparc/dev/zsvar.h b/sys/arch/sparc/dev/zsvar.h
index 3fef4d3981e..3234fbc7537 100644
--- a/sys/arch/sparc/dev/zsvar.h
+++ b/sys/arch/sparc/dev/zsvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: zsvar.h,v 1.6 1996/01/24 19:52:57 gwr Exp $ */
+/* $NetBSD: zsvar.h,v 1.8 1996/03/31 22:39:08 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -91,8 +91,7 @@ struct zsdevice {
#define ZRING_MAKE(t, v) ((t) | (v) << 8)
struct zs_chanstate {
- struct zs_chanstate *cs_next; /* linked list for zshard() */
- struct zs_softc *cs_sc; /* points to my softc */
+ struct zs_chanstate *cs_next; /* linked list for zshard() */
volatile struct zschan *cs_zc; /* points to hardware regs */
int cs_unit; /* unit number */
struct tty *cs_ttyp; /* ### */
@@ -163,17 +162,22 @@ struct zs_chanstate {
* On the SparcStation the 1.6 microsecond recovery time is
* handled in hardware. On the older Sun4 machine it isn't, and
* software must deal with the problem.
+ *
+ * However, it *is* a problem on some Sun4m's (i.e. the SS20) (XXX: why?).
+ * Thus we leave in the delay.
+ *
+ * XXX: (ABB) Think about this more.
*/
-#ifdef SUN4
+#if defined(SUN4)
+
#define ZS_READ(c, r) zs_read(c, r)
#define ZS_WRITE(c, r, v) zs_write(c, r, v)
-#if defined(SUN4C) || defined(SUN4M)
-#define ZS_DELAY() (cputyp == CPU_SUN4 ? delay(2) : 0)
-#else
-#define ZS_DELAY() delay(2)
-#endif
-#else
+#define ZS_DELAY() (CPU_ISSUN4C ? (0) : delay(1))
+
+#else /* SUN4 */
+
#define ZS_READ(c, r) ((c)->zc_csr = (r), (c)->zc_csr)
#define ZS_WRITE(c, r, v) ((c)->zc_csr = (r), (c)->zc_csr = (v))
-#define ZS_DELAY()
-#endif
+#define ZS_DELAY() (CPU_ISSUN4M ? delay(1) : 0)
+
+#endif /* SUN4 */
diff --git a/sys/arch/sparc/fpu/fpu.c b/sys/arch/sparc/fpu/fpu.c
index 4aa8fba2a29..f5212b9ae2d 100644
--- a/sys/arch/sparc/fpu/fpu.c
+++ b/sys/arch/sparc/fpu/fpu.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu.c,v 1.2 1994/11/20 20:52:33 deraadt Exp $ */
+/* $NetBSD: fpu.c,v 1.3 1996/03/14 19:41:49 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -49,11 +49,13 @@
#include <sys/signal.h>
#include <sys/systm.h>
#include <sys/syslog.h>
+#include <sys/signalvar.h>
#include <machine/instr.h>
#include <machine/reg.h>
#include <sparc/fpu/fpu_emu.h>
+#include <sparc/fpu/fpu_extern.h>
/*
* fpu_execute returns the following error numbers (0 = no error):
@@ -93,6 +95,7 @@ static u_char fpu_codes[] = {
* nor FBfcc instructions. Experiments with `crashme' prove that
* unknown FPops do enter the queue, however.
*/
+void
fpu_cleanup(p, fs)
register struct proc *p;
register struct fpstate *fs;
diff --git a/sys/arch/sparc/fpu/fpu_add.c b/sys/arch/sparc/fpu/fpu_add.c
index d85bb57b3a3..1aa9225c01e 100644
--- a/sys/arch/sparc/fpu/fpu_add.c
+++ b/sys/arch/sparc/fpu/fpu_add.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu_add.c,v 1.2 1994/11/20 20:52:34 deraadt Exp $ */
+/* $NetBSD: fpu_add.c,v 1.3 1996/03/14 19:41:52 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -51,11 +51,16 @@
*/
#include <sys/types.h>
+#ifdef DIAGNOSTIC
+#include <sys/systm.h>
+#endif
#include <machine/reg.h>
+#include <machine/instr.h>
#include <sparc/fpu/fpu_arith.h>
#include <sparc/fpu/fpu_emu.h>
+#include <sparc/fpu/fpu_extern.h>
struct fpn *
fpu_add(fe)
diff --git a/sys/arch/sparc/fpu/fpu_explode.c b/sys/arch/sparc/fpu/fpu_explode.c
index cc992fdad89..ceaa896c02d 100644
--- a/sys/arch/sparc/fpu/fpu_explode.c
+++ b/sys/arch/sparc/fpu/fpu_explode.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu_explode.c,v 1.2 1994/11/20 20:52:41 deraadt Exp $ */
+/* $NetBSD: fpu_explode.c,v 1.3 1996/03/14 19:41:54 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -50,6 +50,7 @@
*/
#include <sys/types.h>
+#include <sys/systm.h>
#include <machine/ieee.h>
#include <machine/instr.h>
@@ -57,6 +58,7 @@
#include <sparc/fpu/fpu_arith.h>
#include <sparc/fpu/fpu_emu.h>
+#include <sparc/fpu/fpu_extern.h>
/*
* N.B.: in all of the following, we assume the FP format is
diff --git a/sys/arch/sparc/fpu/fpu_extern.h b/sys/arch/sparc/fpu/fpu_extern.h
new file mode 100644
index 00000000000..0f2ed79668d
--- /dev/null
+++ b/sys/arch/sparc/fpu/fpu_extern.h
@@ -0,0 +1,76 @@
+/* $NetBSD: fpu_extern.h,v 1.1 1996/03/14 19:41:56 christos Exp $ */
+
+/*
+ * Copyright (c) 1995 Christos Zoulas. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct proc;
+struct fpstate;
+struct trapframe;
+union instr;
+struct fpemu;
+struct fpn;
+
+/* fpu.c */
+void fpu_cleanup __P((struct proc *, struct fpstate *));
+int fpu_emulate __P((struct proc *, struct trapframe *, struct fpstate *));
+int fpu_execute __P((struct fpemu *, union instr));
+
+/* fpu_add.c */
+struct fpn *fpu_add __P((struct fpemu *));
+
+/* fpu_compare.c */
+void fpu_compare __P((struct fpemu *, int));
+
+/* fpu_div.c */
+struct fpn *fpu_div __P((struct fpemu *));
+
+/* fpu_explode.c */
+int fpu_itof __P((struct fpn *, u_int));
+int fpu_stof __P((struct fpn *, u_int));
+int fpu_dtof __P((struct fpn *, u_int, u_int ));
+int fpu_xtof __P((struct fpn *, u_int, u_int , u_int , u_int ));
+void fpu_explode __P((struct fpemu *, struct fpn *, int, int ));
+
+/* fpu_implode.c */
+u_int fpu_ftoi __P((struct fpemu *, struct fpn *));
+u_int fpu_ftos __P((struct fpemu *, struct fpn *));
+u_int fpu_ftod __P((struct fpemu *, struct fpn *, u_int *));
+u_int fpu_ftox __P((struct fpemu *, struct fpn *, u_int *));
+void fpu_implode __P((struct fpemu *, struct fpn *, int, u_int *));
+
+/* fpu_mul.c */
+struct fpn *fpu_mul __P((struct fpemu *));
+
+/* fpu_sqrt.c */
+struct fpn *fpu_sqrt __P((struct fpemu *));
+
+/* fpu_subr.c */
+int fpu_shr __P((register struct fpn *, register int));
+void fpu_norm __P((register struct fpn *));
+struct fpn *fpu_newnan __P((register struct fpemu *));
diff --git a/sys/arch/sparc/fpu/fpu_implode.c b/sys/arch/sparc/fpu/fpu_implode.c
index 492b308f89a..753b0ba9973 100644
--- a/sys/arch/sparc/fpu/fpu_implode.c
+++ b/sys/arch/sparc/fpu/fpu_implode.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu_implode.c,v 1.2 1994/11/20 20:52:42 deraadt Exp $ */
+/* $NetBSD: fpu_implode.c,v 1.3 1996/03/14 19:41:59 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -50,6 +50,7 @@
*/
#include <sys/types.h>
+#include <sys/systm.h>
#include <machine/ieee.h>
#include <machine/instr.h>
@@ -57,6 +58,10 @@
#include <sparc/fpu/fpu_arith.h>
#include <sparc/fpu/fpu_emu.h>
+#include <sparc/fpu/fpu_extern.h>
+
+static int round __P((register struct fpemu *, register struct fpn *));
+static int toinf __P((struct fpemu *, int));
/*
* Round a number (algorithm from Motorola MC68882 manual, modified for
@@ -74,7 +79,7 @@ static int
round(register struct fpemu *fe, register struct fpn *fp)
{
register u_int m0, m1, m2, m3;
- register int gr, s, ret;
+ register int gr, s;
m0 = fp->fp_mant[0];
m1 = fp->fp_mant[1];
diff --git a/sys/arch/sparc/fpu/fpu_subr.c b/sys/arch/sparc/fpu/fpu_subr.c
index 685ae2de34f..45b80c219ba 100644
--- a/sys/arch/sparc/fpu/fpu_subr.c
+++ b/sys/arch/sparc/fpu/fpu_subr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu_subr.c,v 1.2 1994/11/20 20:52:47 deraadt Exp $ */
+/* $NetBSD: fpu_subr.c,v 1.3 1996/03/14 19:42:01 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -49,11 +49,16 @@
*/
#include <sys/types.h>
+#ifdef DIAGNOSTIC
+#include <sys/systm.h>
+#endif
#include <machine/reg.h>
+#include <machine/instr.h>
#include <sparc/fpu/fpu_arith.h>
#include <sparc/fpu/fpu_emu.h>
+#include <sparc/fpu/fpu_extern.h>
/*
* Shift the given number right rsh bits. Any bits that `fall off' will get
diff --git a/sys/arch/sparc/include/ansi.h b/sys/arch/sparc/include/ansi.h
index 6e90c691b78..a74e468804f 100644
--- a/sys/arch/sparc/include/ansi.h
+++ b/sys/arch/sparc/include/ansi.h
@@ -1,4 +1,4 @@
-/* $NetBSD: ansi.h,v 1.3 1994/11/20 20:52:50 deraadt Exp $ */
+/* $NetBSD: ansi.h,v 1.5 1996/03/31 22:21:21 pk Exp $ */
/*-
* Copyright (c) 1990, 1993
@@ -63,12 +63,13 @@
* chosen over a long is that the is*() and to*() routines take ints (says
* ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you
* lose a bit of ANSI conformance, but your programs will still work.
- *
+ *
* Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t
* and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains
* defined for ctype.h.
*/
#define _BSD_WCHAR_T_ int /* wchar_t */
+#define _BSD_WINT_T_ int /* wint_t */
#define _BSD_RUNE_T_ int /* rune_t */
#endif /* _ANSI_H_ */
diff --git a/sys/arch/sparc/include/autoconf.h b/sys/arch/sparc/include/autoconf.h
index 4cb7f4b25f6..1caa73db7ab 100644
--- a/sys/arch/sparc/include/autoconf.h
+++ b/sys/arch/sparc/include/autoconf.h
@@ -1,4 +1,4 @@
-/* $NetBSD: autoconf.h,v 1.9 1995/03/08 15:51:03 pk Exp $ */
+/* $NetBSD: autoconf.h,v 1.16 1996/04/10 20:33:38 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -56,15 +56,19 @@
* (which `is' the CPU, in some sense) gets just the node, with a
* fake name ("mainbus").
*/
-#define RA_MAXVADDR 4 /* max (virtual) addresses per device */
-#define RA_MAXREG 2 /* max # of register banks per device */
+
+#define RA_MAXVADDR 8 /* max (virtual) addresses per device */
+#define RA_MAXREG 16 /* max # of register banks per device */
#define RA_MAXINTR 8 /* max interrupts per device */
+#define RA_MAXRANGE 10 /* max # of bus translations */
+
struct romaux {
const char *ra_name; /* name from FORTH PROM */
int ra_node; /* FORTH PROM node ID */
void *ra_vaddrs[RA_MAXVADDR];/* ROM mapped virtual addresses */
int ra_nvaddrs; /* # of ra_vaddrs[]s, may be 0 */
#define ra_vaddr ra_vaddrs[0] /* compatibility */
+
struct rom_reg {
int rr_iospace; /* register space (obio, etc) */
void *rr_paddr; /* register physical address */
@@ -74,13 +78,23 @@ struct romaux {
#define ra_iospace ra_reg[0].rr_iospace
#define ra_paddr ra_reg[0].rr_paddr
#define ra_len ra_reg[0].rr_len
+
struct rom_intr { /* interrupt information: */
int int_pri; /* priority (IPL) */
int int_vec; /* vector (always 0?) */
} ra_intr[RA_MAXINTR];
int ra_nintr; /* number of interrupt info elements */
+
+ struct rom_range { /* Only used on v3 PROMs */
+ u_int32_t cspace; /* Client space */
+ u_int32_t coffset; /* Client offset */
+ u_int32_t pspace; /* Parent space */
+ u_int32_t poffset; /* Parent offset */
+ u_int32_t size; /* Size in bytes of this range */
+ } ra_range[RA_MAXRANGE];
+ int ra_nrange;
+
struct bootpath *ra_bp; /* used for locating boot device */
- int ra_pfour; /* p4 register, for BUS_PFOUR devices */
};
@@ -95,11 +109,35 @@ struct confargs {
#define BUS_VME16 2
#define BUS_VME32 3
#define BUS_SBUS 4
-#define BUS_PFOUR 5
extern int bt2pmt[];
/*
+ * mapiodev maps an I/O device to a virtual address, returning the address.
+ * mapdev does the real work: you can supply a special virtual address and
+ * it will use that instead of creating one, but you must only do this if
+ * you get it from ../sparc/vaddrs.h.
+ */
+void *mapdev __P((struct rom_reg *pa, int va,
+ int offset, int size, int bustype));
+#define mapiodev(pa, offset, size, bustype) \
+ mapdev(pa, 0, offset, size, bustype)
+/*
+ * REG2PHYS is provided for drivers with a `d_mmap' function.
+ */
+#define REG2PHYS(rr, offset, bt) \
+ (((u_int)(rr)->rr_paddr + (offset)) | \
+ ((CPU_ISSUN4M) \
+ ? ((rr)->rr_iospace << PMAP_SHFT4M) \
+ : bt2pmt[bt]) \
+ )
+
+/* For VME and sun4/obio busses */
+void *bus_map __P((struct rom_reg *, int, int));
+void *bus_tmp __P((void *, int));
+void bus_untmp __P((void));
+
+/*
* The various getprop* functions obtain `properties' from the ROMs.
* getprop() obtains a property as a byte-sequence, and returns its
* length; the others convert or make some other guarantee.
@@ -124,6 +162,7 @@ int romprop __P((struct romaux *ra, const char *name, int node));
* its aux pointer to point to a pointer to the name (the address of
* a romaux structure suffices, for instance).
*/
+struct device;
int matchbyname __P((struct device *, void *cf, void *aux));
/*
@@ -133,36 +172,6 @@ int matchbyname __P((struct device *, void *cf, void *aux));
char *clockfreq __P((int freq));
/*
- * mapiodev maps an I/O device to a virtual address, returning the address.
- * mapdev does the real work: you can supply a special virtual address and
- * it will use that instead of creating one, but you must only do this if
- * you get it from ../sparc/vaddrs.h.
- */
-void *mapdev __P((struct rom_reg *rr, int va, int offset,
- int size, int bustype));
-#define mapiodev(rr, offset, size, bustype) mapdev(rr, 0, offset, size, bustype)
-
-void *bus_map __P((void *pa, int len, int bustype));
-void *bus_tmp __P((void *pa, int bustype));
-void bus_untmp __P((void));
-
-#ifdef notyet
-/*
- * REG2PHYS is provided for drivers with a `d_mmap' function.
- */
-#define REG2PHYS(rr, offset, bt) \
- (((u_int)(rr)->rr_paddr + (offset)) | \
- ((cputyp == CPU_SUN4M) \
- ? ((rr)->rr_iospace << PMAP_SHFT4M) \
- : bt2pmt[bt]) \
- )
-#else
-#define REG2PHYS(rr, offset, bt) \
- (((u_int)(rr)->rr_paddr + (offset)) | (bt2pmt[bt]) \
- )
-#endif
-
-/*
* Memory description arrays. Shared between pmap.c and autoconf.c; no
* one else should use this (except maybe mem.c, e.g., if we fix the VM to
* handle discontiguous physical memory).
@@ -180,14 +189,30 @@ void rominterpret __P((char *));
/* Openprom V2 style boot path */
struct bootpath {
- char name[8]; /* name of this node */
- int val[2]; /* up to two optional values */
+ char name[16]; /* name of this node */
+ int val[3]; /* up to three optional values */
+ struct device *dev; /* device that recognised this component */
};
-struct device *bootdv; /* found during autoconfiguration */
-
-struct bootpath *bootpath_store __P((int, struct bootpath *));
-int sd_crazymap __P((int));
+struct bootpath *bootpath_store __P((int, struct bootpath *));
+int sd_crazymap __P((int));
/* Parse a disk string into a dev_t, return device struct pointer */
struct device *parsedisk __P((char *, int, int, dev_t *));
+
+/* Establish a mountroot_hook, for benefit of floppy drive, mostly. */
+void mountroot_hook_establish __P((void (*) __P((struct device *)),
+ struct device *));
+
+void configure __P((void));
+void bootstrap __P((void));
+int firstchild __P((int));
+int nextsibling __P((int));
+void callrom __P((void));
+struct device *getdevunit __P((char *, int));
+void *findzs __P((int));
+int romgetcursoraddr __P((int **, int **));
+int findroot __P((void));
+int findnode __P((int, const char *));
+int opennode __P((char *));
+int node_has_property __P((int, const char *));
diff --git a/sys/arch/sparc/include/bsd_openprom.h b/sys/arch/sparc/include/bsd_openprom.h
index 1879ea5909d..35a9b3a7c13 100644
--- a/sys/arch/sparc/include/bsd_openprom.h
+++ b/sys/arch/sparc/include/bsd_openprom.h
@@ -1,4 +1,4 @@
-/* $NetBSD: bsd_openprom.h,v 1.3 1995/09/04 09:53:53 pk Exp $ */
+/* $NetBSD: bsd_openprom.h,v 1.11 1996/05/18 12:27:43 mrg Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -39,6 +39,12 @@
*/
/*
+ * Sun4m support by Aaron Brown, Harvard University.
+ * Changes Copyright (c) 1995 The President and Fellows of Harvard College.
+ * All rights reserved.
+ */
+
+/*
* This file defines the interface between the kernel and the Openboot PROM.
* N.B.: this has been tested only on interface versions 0 and 2 (we have
* never seen interface version 1).
@@ -70,12 +76,12 @@
struct v0devops {
int (*v0_open) __P((char *dev));
int (*v0_close) __P((int d));
- int (*v0_rbdev) __P((int d, int nblks, int blkno, caddr_t addr));
- int (*v0_wbdev) __P((int d, int nblks, int blkno, caddr_t addr));
- int (*v0_wnet) __P((int d, int nbytes, caddr_t addr));
- int (*v0_rnet) __P((int d, int nbytes, caddr_t addr));
- int (*v0_rcdev) __P((int d, int nbytes, int, caddr_t addr));
- int (*v0_wcdev) __P((int d, int nbytes, int, caddr_t addr));
+ int (*v0_rbdev) __P((int d, int nblks, int blkno, void *addr));
+ int (*v0_wbdev) __P((int d, int nblks, int blkno, void *addr));
+ int (*v0_wnet) __P((int d, int nbytes, void *addr));
+ int (*v0_rnet) __P((int d, int nbytes, void *addr));
+ int (*v0_rcdev) __P((int d, int nbytes, int, void *addr));
+ int (*v0_wcdev) __P((int d, int nbytes, int, void *addr));
int (*v0_seek) __P((int d, long offset, int whence));
};
@@ -97,7 +103,7 @@ struct v2devops {
int (*v2_fd_phandle) __P((int d));
/* Memory allocation and release. */
- caddr_t (*v2_malloc) __P((caddr_t va, u_int sz));
+ void *(*v2_malloc) __P((caddr_t va, u_int sz));
void (*v2_free) __P((caddr_t va, u_int sz));
/* Device memory mapper. */
@@ -107,12 +113,12 @@ struct v2devops {
/* Device open, close, etc. */
int (*v2_open) __P((char *devpath));
void (*v2_close) __P((int d));
- int (*v2_read) __P((int d, caddr_t buf, int nbytes));
- int (*v2_write) __P((int d, caddr_t buf, int nbytes));
+ int (*v2_read) __P((int d, void *buf, int nbytes));
+ int (*v2_write) __P((int d, void *buf, int nbytes));
void (*v2_seek) __P((int d, int hi, int lo));
- void (*v2_xxx2) __P(()); /* ??? */
- void (*v2_xxx3) __P(()); /* ??? */
+ void (*v2_chain) __P((void)); /* ??? */
+ void (*v2_release) __P((void)); /* ??? */
};
/*
@@ -217,7 +223,7 @@ struct promvec {
void (*pv_printf) __P((const char *fmt, ...));
void (*pv_abort) __P((void)); /* L1-A abort */
int *pv_ticks; /* Ticks since last reset */
- __dead void (*pv_halt) __P((void)); /* Halt! */
+ __dead void (*pv_halt) __P((void)) __attribute__((noreturn));/* Halt! */
void (**pv_synchook) __P((void)); /* "sync" command hook */
/*
@@ -251,13 +257,17 @@ struct promvec {
* easily.
*/
void (*pv_setctxt) __P((int ctxt, caddr_t va, int pmeg));
-
- /* OpenPROM V3 SMP cpu-control directives. */
- int (*pv_cpustart) __P((int cpu_node, caddr_t ctxttbl_paddr,
- int ctxt, caddr_t pc));
- int (*pv_cpustop) __P((int cpu_node));
- int (*pv_cpuidle) __P((int cpu_node));
- int (*pv_cpuresume) __P((int cpu_node));
+#if defined(SUN4M) && defined(notyet)
+ /*
+ * The following are V3 ROM functions to handle MP machines in the
+ * Sun4m series. They have undefined results when run on a uniprocessor!
+ */
+ int (*pv_v3cpustart) __P((u_int module, u_int ctxtbl,
+ int context, caddr_t pc));
+ int (*pv_v3cpustop) __P((u_int module));
+ int (*pv_v3cpuidle) __P((u_int module));
+ int (*pv_v3cpuresume) __P((u_int module));
+#endif
};
/*
@@ -304,6 +314,14 @@ struct nodeops {
*/
int (*no_proplen) __P((int node, caddr_t name));
int (*no_getprop) __P((int node, caddr_t name, caddr_t val));
- int (*no_setprop) __P((int node, caddr_t name, caddr_t val, int len));
+ int (*no_setprop) __P((int node, caddr_t name, caddr_t val,
+ int len));
caddr_t (*no_nextprop) __P((int node, caddr_t name));
};
+
+void romhalt __P((void))
+ __attribute__((__noreturn__));
+void romboot __P((char *))
+ __attribute__((__noreturn__));
+
+extern struct promvec *promvec;
diff --git a/sys/arch/sparc/include/cdefs.h b/sys/arch/sparc/include/cdefs.h
index 286edf32784..36f4990a9cc 100644
--- a/sys/arch/sparc/include/cdefs.h
+++ b/sys/arch/sparc/include/cdefs.h
@@ -30,8 +30,6 @@
__asm__(".stabs msg,30,0,0,0"); \
__asm__(".stabs \"_/**/sym\",1,0,0,0")
#endif
-#else
-#define __warn_references(sym,msg) /* nothing */
#endif
#endif /* !_MACHINE_CDEFS_H_ */
diff --git a/sys/arch/sparc/include/conf.h b/sys/arch/sparc/include/conf.h
new file mode 100644
index 00000000000..fbb10a56edc
--- /dev/null
+++ b/sys/arch/sparc/include/conf.h
@@ -0,0 +1,81 @@
+/* $NetBSD: conf.h,v 1.1 1996/03/30 21:17:55 christos Exp $ */
+
+/*
+ * Copyright (c) 1996 Christos Zoulas. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define mmread mmrw
+#define mmwrite mmrw
+cdev_decl(mm);
+
+/* open, close, ioctl */
+#define cdev_openprom_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) nullop, 0, (dev_type_select((*))) enodev, \
+ (dev_type_mmap((*))) enodev }
+
+cdev_decl(openprom);
+
+cdev_decl(cn);
+
+cdev_decl(zs);
+
+bdev_decl(fd);
+cdev_decl(fd);
+
+cdev_decl(fb);
+
+/* open, close, read, write, ioctl, select */
+#define cdev_gen_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
+ 0, dev_init(c,n,select), (dev_type_mmap((*))) enodev }
+
+cdev_decl(ms);
+
+cdev_decl(kbd);
+
+cdev_decl(bwtwo);
+
+cdev_decl(cgthree);
+
+cdev_decl(cgfour);
+
+cdev_decl(cgsix);
+
+cdev_decl(cgeight);
+
+bdev_decl(xd);
+cdev_decl(xd);
+
+bdev_decl(xy);
+cdev_decl(xy);
+
+bdev_decl(sw);
+cdev_decl(sw);
diff --git a/sys/arch/sparc/include/cpu.h b/sys/arch/sparc/include/cpu.h
index 1dccb549d5d..88c05b45a98 100644
--- a/sys/arch/sparc/include/cpu.h
+++ b/sys/arch/sparc/include/cpu.h
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.17 1995/06/28 02:56:05 cgd Exp $ */
+/* $NetBSD: cpu.h,v 1.21 1996/03/31 22:17:14 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -48,7 +48,7 @@
#define _CPU_H_
/*
- * CTL_MACHDEP definitinos.
+ * CTL_MACHDEP definitions.
*/
#define CPU_MAXID 1 /* no valid machdep ids */
@@ -73,15 +73,6 @@
#define cpu_wait(p) /* nothing */
/*
- * See syscall() for an explanation of the following. Note that the
- * locore bootstrap code follows the syscall stack protocol. The
- * framep argument is unused.
- */
-#define cpu_set_init_frame(p, fp) \
- (p)->p_md.md_tf = (struct trapframe *) \
- ((caddr_t)(p)->p_addr + USPACE - sizeof(struct trapframe))
-
-/*
* Arguments to hardclock, softclock and gatherstats encapsulate the
* previous machine state in an opaque clockframe. The ipl is here
* as well for strayintr (see locore.s:interrupt and intr.c:strayintr).
@@ -114,7 +105,17 @@ union sir {
#define SIR_NET 0
#define SIR_CLOCK 1
-#define setsoftint() ienab_bis(IE_L1)
+#if defined(SUN4M)
+extern void raise __P((int, int));
+#if !(defined(SUN4) || defined(SUN4C))
+#define setsoftint() raise(0,1)
+#else /* both defined */
+#define setsoftint() (cputyp == CPU_SUN4M ? raise(0,1) : ienab_bis(IE_L1))
+#endif /* !4,!4c */
+#else /* 4m not defined */
+#define setsoftint() ienab_bis(IE_L1)
+#endif /* SUN4M */
+
#define setsoftnet() (sir.sir_which[SIR_NET] = 1, setsoftint())
#define setsoftclock() (sir.sir_which[SIR_CLOCK] = 1, setsoftint())
@@ -129,7 +130,7 @@ int want_resched; /* resched() was called */
/*
* Give a profiling tick to the current process when the user profiling
- * buffer pages are invalid. On the sparc, request an ast to send us
+ * buffer pages are invalid. On the sparc, request an ast to send us
* through trap(), marking the proc as needing a profiling tick.
*/
#define need_proftick(p) ((p)->p_flag |= P_OWEUPC, want_ast = 1)
@@ -170,6 +171,65 @@ void vmeintr_establish __P((int vec, int level, struct intrhand *));
*/
void intr_fasttrap __P((int level, void (*vec)(void)));
+/* disksubr.c */
+struct dkbad;
+int isbad __P((struct dkbad *bt, int, int, int));
+/* machdep.c */
+int ldcontrolb __P((caddr_t));
+void dumpconf __P((void));
+caddr_t reserve_dumppages __P((caddr_t));
+/* clock.c */
+struct timeval;
+void lo_microtime __P((struct timeval *));
+int statintr __P((void *));
+int clockintr __P((void *));/* level 10 (clock) interrupt code */
+int statintr __P((void *)); /* level 14 (statclock) interrupt code */
+/* locore.s */
+struct fpstate;
+void savefpstate __P((struct fpstate *));
+void loadfpstate __P((struct fpstate *));
+int probeget __P((caddr_t, int));
+void write_all_windows __P((void));
+void write_user_windows __P((void));
+void proc_trampoline __P((void));
+struct pcb;
+void snapshot __P((struct pcb *));
+struct frame *getfp __P((void));
+int xldcontrolb __P((caddr_t, struct pcb *));
+void copywords __P((const void *, void *, size_t));
+void qcopy __P((const void *, void *, size_t));
+void qzero __P((void *, size_t));
+/* locore2.c */
+void remrq __P((struct proc *));
+/* trap.c */
+void kill_user_windows __P((struct proc *));
+int rwindow_save __P((struct proc *));
+void child_return __P((struct proc *));
+/* amd7930intr.s */
+void amd7930_trap __P((void));
+/* cons.c */
+int cnrom __P((void));
+/* zs.c */
+void zsconsole __P((struct tty *, int, int, int (**)(struct tty *, int)));
+#ifdef KGDB
+void zs_kgdb_init __P((void));
+#endif
+/* fb.c */
+void fb_unblank __P((void));
+/* cache.c */
+void cache_flush __P((caddr_t, u_int));
+/* kgdb_stub.c */
+#ifdef KGDB
+void kgdb_attach __P((int (*)(void *), void (*)(void *, int), void *));
+void kgdb_connect __P((int));
+void kgdb_panic __P((void));
+#endif
+/* vm_machdep.c */
+void cpu_set_kpc __P((struct proc *, void (*)(struct proc *)));
+/* iommu.c */
+void iommu_enter __P((u_int, u_int));
+void iommu_remove __P((u_int, u_int));
+
/*
*
* The SPARC has a Trap Base Register (TBR) which holds the upper 20 bits
@@ -187,7 +247,7 @@ void intr_fasttrap __P((int level, void (*vec)(void)));
struct trapvec {
int tv_instr[4]; /* the four instructions */
};
-extern struct trapvec trapbase[256]; /* the 256 vectors */
+extern struct trapvec *trapbase; /* the 256 vectors */
extern void wzero __P((void *, u_int));
extern void wcopy __P((const void *, void *, u_int));
diff --git a/sys/arch/sparc/include/ctlreg.h b/sys/arch/sparc/include/ctlreg.h
index 154f358b985..1f5d8519aef 100644
--- a/sys/arch/sparc/include/ctlreg.h
+++ b/sys/arch/sparc/include/ctlreg.h
@@ -1,6 +1,8 @@
-/* $NetBSD: ctlreg.h,v 1.8 1995/06/25 21:35:05 pk Exp $ */
+/* $NetBSD: ctlreg.h,v 1.12 1996/05/16 15:57:00 abrown Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -10,6 +12,7 @@
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
@@ -45,95 +48,85 @@
*/
/*
- * Sun-4, 4c, and 4m control registers. (includes address space definitions
+ * Sun4m support by Aaron Brown, Harvard University.
+ * Changes Copyright (c) 1995 The President and Fellows of Harvard College.
+ * All rights reserved.
+ */
+
+/*
+ * Sun 4, 4c, and 4m control registers. (includes address space definitions
* and some registers in control space).
*/
+/*
+ * The Alternate address spaces.
+ */
+
/* 0x00 unused */
/* 0x01 unused */
-#if defined(SUN4C) || defined(SUN4)
#define ASI_CONTROL 0x02 /* cache enable, context reg, etc */
-#define ASI_SEGMAP 0x03 /* segment maps (so we can reach each pmeg) */
-#define ASI_PTE 0x04 /* PTE space (pmegs) */
-#define ASI_REGMAP 0x06 /* region maps (3 level MMUs only) */
-#define ASI_HWFLUSHSEG 0x05 /* hardware assisted version of FLUSHSEG */
-#define ASI_HWFLUSHPG 0x06 /* hardware assisted version of FLUSHPG */
-#define ASI_HWFLUSHCTX 0x07 /* hardware assisted version of FLUSHCTX */
-#endif
-#if defined(SUN4M)
-#define ASI_SRMMUFP 0x03 /* ref mmu flush/probe */
-#define ASI_SRMMUFP_L3 (0<<8) /* probe L3 | flush L3 PTE */
-#define ASI_SRMMUFP_L2 (1<<8) /* probe L2 | flush L2/L3 PTE/PTD's */
-#define ASI_SRMMUFP_L1 (2<<8) /* probe L1 | flush L1/L2/L3 PTE/PTD's*/
-#define ASI_SRMMUFP_L0 (3<<8) /* probe L0 | flush L0/L1/L2/L3 PTE/PTD's */
-#define ASI_SRMMUFP_LN (4<<8) /* probe all | flush all levels */
-
-#define ASI_SRMMU 0x04 /* ref mmu registers */
-#define ASI_SRMMUDIAG 0x06
-#endif
+#define ASI_SEGMAP 0x03 /* [4/4c] segment maps */
+#define ASI_SRMMUFP 0x03 /* [4m] ref mmu flush/probe */
+#define ASI_PTE 0x04 /* [4/4c] PTE space (pmegs) */
+#define ASI_SRMMU 0x04 /* [4m] ref mmu registers */
+#define ASI_REGMAP 0x06 /* [4/3-level MMU ] region maps */
+#define ASI_HWFLUSHSEG 0x05 /* [4/4c] hardware assisted version of FLUSHSEG */
+#define ASI_HWFLUSHPG 0x06 /* [4/4c] hardware assisted version of FLUSHPG */
+#define ASI_SRMMUDIAG 0x06 /* [4m] */
+#define ASI_HWFLUSHCTX 0x07 /* [4/4c] hardware assisted version of FLUSHCTX */
#define ASI_USERI 0x08 /* I-space (user) */
#define ASI_KERNELI 0x09 /* I-space (kernel) */
#define ASI_USERD 0x0a /* D-space (user) */
#define ASI_KERNELD 0x0b /* D-space (kernel) */
-#if defined(SUN4C) || defined(SUN4)
-#define ASI_FLUSHREG 0x7 /* causes hardware to flush cache region */
-#define ASI_FLUSHSEG 0x0c /* causes hardware to flush cache segment */
-#define ASI_FLUSHPG 0x0d /* causes hardware to flush cache page */
-#define ASI_FLUSHCTX 0x0e /* causes hardware to flush cache context */
-#endif
-#if defined(SUN4)
-#define ASI_DCACHE 0x0f /* flush data cache; not used on 4c */
-#endif
+#define ASI_FLUSHREG 0x7 /* [4/4c] flush cache by region */
+#define ASI_FLUSHSEG 0x0c /* [4/4c] flush cache by segment */
+#define ASI_FLUSHPG 0x0d /* [4/4c] flush cache by page */
+#define ASI_FLUSHCTX 0x0e /* [4/4c] flush cache by context */
-#if defined(SUN4M)
-#define ASI_ICACHETAG 0x0c /* instruction cache tag */
-#define ASI_ICACHEDATA 0x0d /* instruction cache data */
-#define ASI_DCACHETAG 0x0e /* data cache tag */
-#define ASI_DCACHEDATA 0x0f /* data cache data */
-#define ASI_IDCACHELFP 0x10 /* ms2 only: flush i&d cache line (page) */
-#define ASI_IDCACHELFS 0x11 /* ms2 only: flush i&d cache line (seg) */
-#define ASI_IDCACHELFR 0x12 /* ms2 only: flush i&d cache line (reg) */
-#define ASI_IDCACHELFC 0x13 /* ms2 only: flush i&d cache line (ctxt) */
-#define ASI_IDCACHELFU 0x14 /* ms2 only: flush i&d cache line (user) */
-#define ASI_BYPASS 0x20 /* sun ref mmu bypass, ie. direct phys access */
-#define ASI_ICACHECLR 0x36 /* ms1 only: instruction cache flash clear */
-#define ASI_DCACHECLR 0x37 /* ms1 only: data cache clear */
-#define ASI_DCACHEDIAG 0x39 /* data cache diagnostic register access */
-#endif
+#define ASI_DCACHE 0x0f /* [4] flush data cache */
-#if defined(SUN4C) || defined(SUN4)
-/* registers in the control space */
-#define AC_CONTEXT 0x30000000 /* context register (byte) */
-#define AC_SYSENABLE 0x40000000 /* system enable register (byte) */
-#define AC_CACHETAGS 0x80000000 /* cache tag base address */
-#define AC_SERIAL 0xf0000000 /* special serial port sneakiness */
- /* AC_SERIAL is not used in the kernel (it is for the PROM) */
-#endif
+#define ASI_ICACHETAG 0x0c /* [4m] instruction cache tag */
+#define ASI_ICACHEDATA 0x0d /* [4m] instruction cache data */
+#define ASI_DCACHETAG 0x0e /* [4m] data cache tag */
+#define ASI_DCACHEDATA 0x0f /* [4m] data cache data */
+#define ASI_IDCACHELFP 0x10 /* [4m] ms2 only: flush i&d cache line (page) */
+#define ASI_IDCACHELFS 0x11 /* [4m] ms2 only: flush i&d cache line (seg) */
+#define ASI_IDCACHELFR 0x12 /* [4m] ms2 only: flush i&d cache line (reg) */
+#define ASI_IDCACHELFC 0x13 /* [4m] ms2 only: flush i&d cache line (ctxt) */
+#define ASI_IDCACHELFU 0x14 /* [4m] ms2 only: flush i&d cache line (user) */
+#define ASI_BYPASS 0x20 /* [4m] sun ref mmu bypass,
+ ie. direct phys access */
+#define ASI_ICACHECLR 0x36 /* [4m] ms1 only: I-cache flash clear */
+#define ASI_DCACHECLR 0x37 /* [4m] ms1 only: D-cache flash clear */
+#define ASI_DCACHEDIAG 0x39 /* [4m] data cache diagnostic register access */
-#if defined(SUN4)
-#define AC_IDPROM 0x00000000 /* ID PROM */
-#define AC_DVMA_ENABLE 0x50000000 /* enable user dvma */
-#define AC_BUS_ERR 0x60000000 /* bus error register */
-#define AC_DIAG_REG 0x70000000 /* diagnostic reg */
-#define AC_DVMA_MAP 0xd0000000 /* user dvma map entries */
-#define AC_VMEINTVEC 0xe0000000 /* vme interrupt vector */
+/*
+ * [4/4c] Registers in the control space (ASI_CONTROL).
+ */
+#define AC_IDPROM 0x00000000 /* [4] ID PROM */
+#define AC_CONTEXT 0x30000000 /* [4/4c] context register (byte) */
+#define AC_SYSENABLE 0x40000000 /* [4/4c] system enable register (byte) */
+#define AC_DVMA_ENABLE 0x50000000 /* [4] enable user dvma */
+#define AC_BUS_ERR 0x60000000 /* [4] bus error register */
+#define AC_SYNC_ERR 0x60000000 /* [4c] sync (memory) error reg */
+#define AC_SYNC_VA 0x60000004 /* [4c] sync error virtual addr */
+#define AC_ASYNC_ERR 0x60000008 /* [4c] async error reg */
+#define AC_ASYNC_VA 0x6000000c /* [4c] async error virtual addr */
+#define AC_DIAG_REG 0x70000000 /* [4] diagnostic reg */
+#define AC_CACHETAGS 0x80000000 /* [4/4c?] cache tag base address */
+#define AC_CACHEDATA 0x90000000 /* [4] cached data [sun4/400?] */
+#define AC_DVMA_MAP 0xd0000000 /* [4] user dvma map entries */
+#define AC_VMEINTVEC 0xe0000000 /* [4] vme interrupt vector */
+#define AC_SERIAL 0xf0000000 /* [4/4c] special serial port sneakiness */
+ /* AC_SERIAL is not used in the kernel (it is for the PROM) */
/* XXX: does not belong here */
#define ME_REG_IERR 0x80 /* memory err ctrl reg error intr pending bit */
-#endif
-
-#if defined(SUN4C)
-#define AC_SYNC_ERR 0x60000000 /* sync (memory) error reg */
-#define AC_SYNC_VA 0x60000004 /* sync error virtual addr */
-#define AC_ASYNC_ERR 0x60000008 /* async error reg */
-#define AC_ASYNC_VA 0x6000000c /* async error virtual addr */
-#define AC_CACHEDATA 0x90000000 /* cached data */
-#endif
-#if defined(SUN4C) || defined(SUN4)
/*
+ * [4/4c]
* Bits in sync error register. Reading the register clears these;
* otherwise they accumulate. The error(s) occurred at the virtual
* address stored in the sync error address register, and may have
@@ -147,13 +140,14 @@
#define SER_TIMEOUT 0x20 /* bus timeout (non-existent mem) */
#define SER_SBUSERR 0x10 /* S-Bus bus error */
#define SER_MEMERR 0x08 /* memory ecc/parity error */
-#define SER_SZERR 0x02 /* size error, whatever that is */
+#define SER_SZERR 0x02 /* [4/vme?] size error, whatever that is */
#define SER_WATCHDOG 0x01 /* watchdog reset (never see this) */
#define SER_BITS \
"\20\20WRITE\10INVAL\7PROT\6TIMEOUT\5SBUSERR\4MEMERR\2SZERR\1WATCHDOG"
/*
+ * [4/4c]
* Bits in async error register (errors from DVMA or Sun-4 cache
* writeback). The corresponding bit is also set in the sync error reg.
*
@@ -168,7 +162,7 @@
#define AER_BITS "\20\10WBINVAL\6TIMEOUT\5DVMAERR"
/*
- * Bits in system enable register.
+ * [4/4c] Bits in system enable register.
*/
#define SYSEN_DVMA 0x20 /* Enable dvma */
#define SYSEN_CACHE 0x10 /* Enable cache */
@@ -176,19 +170,74 @@
#define SYSEN_VIDEO 0x08 /* Enable on-board video */
#define SYSEN_RESET 0x04 /* Reset the hardware */
#define SYSEN_RESETVME 0x02 /* Reset the VME bus */
-#endif
-#if defined(SUN4M)
+
+/*
+ * [4m] Bits in ASI_CONTROL? space, sun4m only.
+ */
+#define MXCC_ENABLE_ADDR 0x1c00a00 /* Enable register for MXCC */
+#define MXCC_ENABLE_BIT 0x4 /* Enable bit for MXCC */
+
+/*
+ * Bits in ASI_SRMMUFP space.
+ * Bits 8-11 determine the type of flush/probe.
+ * Address bits 12-31 hold the page frame.
+ */
+#define ASI_SRMMUFP_L3 (0<<8) /* probe L3 | flush L3 PTE */
+#define ASI_SRMMUFP_L2 (1<<8) /* probe L2 | flush L2/L3 PTE/PTD's */
+#define ASI_SRMMUFP_L1 (2<<8) /* probe L1 | flush L1/L2/L3 PTE/PTD's*/
+#define ASI_SRMMUFP_L0 (3<<8) /* probe L0 | flush L0/L1/L2/L3 PTE/PTD's */
+#define ASI_SRMMUFP_LN (4<<8) /* probe all | flush all levels */
+
+/*
+ * [4m] Registers and bits in the SPARC Reference MMU (ASI_SRMMU).
+ */
#define SRMMU_PCR 0x00000000 /* Processor control register */
#define SRMMU_CXTPTR 0x00000100 /* Context table pointer register */
#define SRMMU_CXR 0x00000200 /* Context register */
#define SRMMU_SFSTAT 0x00000300 /* Synchronous fault status reg */
#define SRMMU_SFADDR 0x00000400 /* Synchronous fault address reg */
+#define SRMMU_AFSTAT 0x00000500 /* Asynchronous fault status reg (HS) */
+#define SRMMU_AFADDR 0x00000600 /* Asynchronous fault address reg (HS)*/
#define SRMMU_TLBCTRL 0x00001000 /* TLB replacement control reg */
-/* Synchronous Fault Status Register bits */
+/* [4m] Bits in SRMMU control register */
+#define SRMMU_PCR_ME 0x00000001 /* MMU Enable */
+#define SRMMU_PCR_NF 0x00000002 /* Fault inhibit bit */
+#define SRMMU_PCR_PSO 0x00000080 /* Partial Store Ordering enable */
+#define SRMMU_PCR_CE 0x00000100 /* HS: Cache enable bit (HyperSPARC) */
+#define SRMMU_PCR_DCE 0x00000100 /* SS: Data cache enable bit */
+#define SRMMU_PCR_ICE 0x00000200 /* SS: SuperSPARC instr. cache enable */
+#define SRMMU_PCR_CM 0x00000400 /* HS: Cache mode: 1 == write-back */
+#define SRMMU_PCR_SB 0x00000400 /* SS: Store buffer enable bit */
+#define SRMMU_PCR_MR 0x00000800 /* HS: Memory reflection: 1 == on */
+#define SRMMU_PCR_MB 0x00000800 /* SS: MBus mode: 0=MXCC, 1=no MXCC */
+#define SRMMU_PCR_CS 0x00001000 /* HS: cache size: 1==256k, 0==128k */
+#define SRMMU_PCR_PE 0x00001000 /* SS: Enable memory parity checking */
+#define SRMMU_PCR_C 0x00002000 /* HS: enable cache when MMU off */
+#define SRMMU_PCR_SSBM 0x00002000 /* SS: 1 iff booting */
+#define SRMMU_PCR_HSBM 0x00004000 /* HS: 1 iff booting */
+#define SRMMU_PCR_SSSE 0x00004000 /* SS: Coherent bus snoop enable */
+#define SRMMU_PCR_AC 0x00008000 /* SS: 1=cache non-MMU accesses */
+#define SRMMU_PCR_TC 0x00010000 /* SS: 1=cache table walks */
+#define SRMMU_PCR_MID 0x00078000 /* HS: MBus module ID MID<3:0> */
+#define SRMMU_PCR_WBE 0x00080000 /* HS: Write buffer enable */
+#define SRMMU_PCR_HSSE 0x00100000 /* HS: Coherent bus snoop enable */
+#define SRMMU_PCR_CWR 0x00200000 /* HS: Cache wrap enable */
+#define SRMMU_PCR_VER 0x0f000000 /* Version of MMU implementation */
+#define SRMMU_PCR_IMPL 0xf0000000 /* Implementation number of MMU */
+
+#ifdef notyet
+#define SRMMU_PCR_INITIAL (SRMMU_PCR_ME | SRMMU_PCR_TC)
+#endif
+
+/* [4m] Bits in the Synchronous Fault Status Register */
+#define SFSR_EM 0x00020000 /* Error mode watchdog reset occurred */
#define SFSR_CS 0x00010000 /* Control Space error */
#define SFSR_PERR 0x00006000 /* Parity error code */
+#define SFSR_SB 0x00008000 /* SS: Store Buffer Error */
+#define SFSR_P 0x00004000 /* SS: Parity error */
+#define SFSR_UC 0x00001000 /* Uncorrectable error */
#define SFSR_TO 0x00000800 /* S-Bus timeout */
#define SFSR_BE 0x00000400 /* S-Bus bus error */
#define SFSR_LVL 0x00000300 /* Pagetable level causing the fault */
@@ -197,7 +246,50 @@
#define SFSR_FAV 0x00000002 /* Fault Address is valid */
#define SFSR_OW 0x00000001 /* Overwritten with new fault */
-/* TLB Replacement Control Register bits */
+#define SFSR_BITS \
+"\20\21CSERR\17PARITY\16SYSERR\15UNCORR\14TIMEOUT\13BUSERR\2FAV\1OW"
+
+/* [4m] Synchronous Fault Types */
+#define SFSR_FT_NONE (0 << 2) /* no fault */
+#define SFSR_FT_INVADDR (1 << 2) /* invalid address fault */
+#define SFSR_FT_PROTERR (2 << 2) /* protection fault */
+#define SFSR_FT_PRIVERR (3 << 2) /* privelege violation */
+#define SFSR_FT_TRANSERR (4 << 2) /* translation fault */
+#define SFSR_FT_BUSERR (5 << 2) /* access bus error */
+#define SFSR_FT_INTERR (6 << 2) /* internal error */
+#define SFSR_FT_RESERVED (7 << 2) /* reserved */
+
+/* [4m] Synchronous Fault Access Types */
+#define SFSR_AT_LDUDATA (0 << 5) /* Load user data */
+#define SFSR_AT_LDSDATA (1 << 5) /* Load supervisor data */
+#define SFSR_AT_LDUTEXT (2 << 5) /* Load user text */
+#define SFSR_AT_LDSTEXT (3 << 5) /* Load supervisor text */
+#define SFSR_AT_STUDATA (4 << 5) /* Store user data */
+#define SFSR_AT_STSDATA (5 << 5) /* Store supervisor data */
+#define SFSR_AT_STUTEXT (6 << 5) /* Store user text */
+#define SFSR_AT_STSTEXT (7 << 5) /* Store supervisor text */
+#define SFSR_AT_SUPERVISOR (1 << 5) /* Set iff supervisor */
+#define SFSR_AT_TEXT (2 << 5) /* Set iff text */
+#define SFSR_AT_STORE (4 << 5) /* Set iff store */
+
+/* [4m] Synchronous Fault PT Levels */
+#define SFSR_LVL_0 (0 << 8) /* Context table entry */
+#define SFSR_LVL_1 (1 << 8) /* Region table entry */
+#define SFSR_LVL_2 (2 << 8) /* Segment table entry */
+#define SFSR_LVL_3 (3 << 8) /* Page table entry */
+
+/* [4m] Asynchronous Fault Status Register bits */
+#define AFSR_AFO 0x00000001 /* Async. fault occurred */
+#define AFSR_AFA 0x000000f0 /* Bits <35:32> of faulting phys addr */
+#define AFSR_AFA_RSHIFT 4 /* Shift to get AFA to bit 0 */
+#define AFSR_AFA_LSHIFT 28 /* Shift to get AFA to bit 32 */
+#define AFSR_BE 0x00000400 /* Bus error */
+#define AFSR_TO 0x00000800 /* Bus timeout */
+#define AFSR_UC 0x00001000 /* Uncorrectable error */
+#define AFSR_SE 0x00002000 /* System error */
+
+#define AFSR_BITS "\20\16SYSERR\15UNCORR\14TIMEOUT\13BUSERR\1AFO"
+
+/* [4m] TLB Replacement Control Register bits */
#define TLBC_DISABLE 0x00000020 /* Disable replacement counter */
#define TLBC_RCNTMASK 0x0000001f /* Replacement counter (0-31) */
-#endif
diff --git a/sys/arch/sparc/include/db_machdep.h b/sys/arch/sparc/include/db_machdep.h
index 1464a723c35..b6028854359 100644
--- a/sys/arch/sparc/include/db_machdep.h
+++ b/sys/arch/sparc/include/db_machdep.h
@@ -1,27 +1,27 @@
-/* $NetBSD: db_machdep.h,v 1.3 1995/02/09 10:34:21 pk Exp $ */
+/* $NetBSD: db_machdep.h,v 1.7 1996/03/31 22:21:28 pk Exp $ */
-/*
+/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
@@ -61,8 +61,8 @@ db_regs_t ddb_regs; /* register state */
#define BKPT_SIZE (4) /* size of breakpoint inst */
#define BKPT_SET(inst) (BKPT_INST)
-#define db_clear_single_step(regs) (0)
-#define db_set_single_step(regs) (0)
+#define db_clear_single_step(regs) (void) (0)
+#define db_set_single_step(regs) (void) (0)
#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BREAKPOINT)
#define IS_WATCHPOINT_TRAP(type, code) (0)
@@ -75,4 +75,8 @@ db_regs_t ddb_regs; /* register state */
#define DB_MACHINE_COMMANDS
+void db_machine_init __P((void));
+int kdb_trap __P((int, struct trapframe *));
+
+
#endif /* _SPARC_DB_MACHDEP_H_ */
diff --git a/sys/arch/sparc/include/eeprom.h b/sys/arch/sparc/include/eeprom.h
index 0f47f5b41f2..902153d3f04 100644
--- a/sys/arch/sparc/include/eeprom.h
+++ b/sys/arch/sparc/include/eeprom.h
@@ -1,5 +1,7 @@
+/* $NetBSD: eeprom.h,v 1.2 1995/08/29 22:11:58 pk Exp $ */
+
/*
- * Copyright (c) 1995 Theo de Raadt
+ * Copyright (c) 1994 Gordon W. Ross
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -10,10 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Theo de Raadt.
- * 4. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
@@ -29,325 +28,156 @@
*/
/*
- * This structure defines the contents of the EEPROM for all Sun
- * Workstations with the SunMon monitor.
+ * Structure/definitions for the Sun3/Sun4 EEPROM.
*
- * The EEPROM is divided into a diagnostic section, a reserved section,
- * a ROM section, and a software section (defined in detail elsewhere).
+ * This information is published in the Sun document:
+ * "PROM User's Manual", part number 800-1736010.
*/
+
/*
* Note that most places where the PROM stores a "true/false" flag,
* the true value is 0x12 and false is the usual zero. Such flags
* all take the values EE_TRUE or EE_FALSE so this file does not
* need to define so many value macros.
*/
-#define EE_TRUE 0x12
-#define EE_FALSE 0x00
-
-struct ee_keymap {
- u_char keymap[128]; /* PROM/EEPROM are 7 bit */
-};
-
-#define PW_SIZE 8 /* max size of a password entry */
-
-struct password_inf {
- u_short bad_counter; /* illegal password count */
- char pw_mode; /* mode */
- char pw_bytes[PW_SIZE]; /* password */
-};
-#define NON_SECURE_MODE 0x00 /* non-secure */
-#define COMMAND_SECURE_MODE 0x01 /* command secure */
-#define FULLY_SECURE_MODE 0x5e /* fully secure */
- /* 0, 2-0x5d, 0x5f-0xff: non secure*/
-
-
-#define MAX_SLOTS 12
-#define CONFIG_SIZE 16 /* bytes of config data for each slot */
+#define EE_TRUE 0x12
+#define EE_FALSE 0
struct eeprom {
- struct ee_diag {
- u_int eed_test; /* 0x000: diagnostic test write area */
- u_short eed_wrcnt[3]; /* 0x004: diag area write count (3 copies) */
- short eed_nu1;
-
- u_char eed_chksum[3]; /* 0x00c: diag area checksum (3 copies) */
- char eed_nu2;
- time_t eed_hwupdate; /* 0x010: date of last hardware update */
-
- char eed_memsize; /* 0x014: MB's of memory in system */
- char eed_memtest; /* 0x015: MB's of memory to test */
-
- char eed_scrsize; /* 0x016: screen size */
-#define EED_SCR_1152X900 0x00
-#define EED_SCR_1024X1024 0x12
-#define EED_SCR_1600X1280 0x13
-#define EED_SCR_1440X1440 0x14
-#define EED_SCR_640X480 0x15
-#define EED_SCR_1280X1024 0x16
-
- char eed_dogaction; /* 0x017: watchdog reset action */
-#define EED_DOG_MONITOR 0x00 /* return to monitor command level */
-#define EED_DOG_REBOOT 0x12 /* perform power on reset and reboot */
-
- char eed_defboot; /* 0x018: default boot? */
-#define EED_DEFBOOT 0x00 /* do default boot */
-#define EED_NODEFBOOT 0x12 /* don't do default boot */
-
- char eed_bootdev[2]; /* 0x019: boot device name (e.g. xy, ie) */
-
- u_char eed_bootctrl; /* 0x01b: controller number */
- u_char eed_bootunit; /* 0x01c: unit number */
- u_char eed_bootpart; /* 0x01d: partition number */
-
- char eed_kbdtype; /* 0x01f: non-Sun keyboard type - for OEM's */
-#define EED_KBD_SUN 0 /* one of the Sun keyboards */
-
- char eed_console; /* 0x01f: console device */
-#define EED_CONS_BW 0x00 /* use b&w monitor */
-#define EED_CONS_TTYA 0x10 /* use tty A port */
-#define EED_CONS_TTYB 0x11 /* use tty B port */
-#define EED_CONS_COLOR 0x12 /* use color monitor */
-#define EED_CONS_P4 0x20 /* use the P4 monitor */
-
- char eed_showlogo; /* 0x020: display Sun logo? */
-#define EED_LOGO 0x00
-#define EED_NOLOGO 0x12
-
- char eed_keyclick; /* 0x021: keyboard click? */
-#define EED_NOKEYCLICK 0x00
-#define EED_KEYCLICK 0x12
-
- char eed_diagdev[2]; /* 0x022: boot device name (e.g. xy, ie) */
- u_char eed_diagctrl; /* 0x024: controller number */
- u_char eed_diagunit; /* 0x025: unit number */
- u_char eed_diagpart; /* 0x026: partition number */
-#define EED_WOB 0x12 /* bring system up white on black */
-
- u_char eed_videobg;
- char eed_diagpath[40]; /* 0x028: boot path of diagnostic */
-#define EED_TERM_34x80 00
-#define EED_TERM_48x120 0x12 /* for large scrn size 1600x1280 */
- char eed_colsize; /* 0x050: number of columns */
- char eed_rowsize; /* 0x051: number of rows */
-
- char eed_nu5[6];
-
- struct eed_tty_def { /* 0x058: tty port defaults */
- char eet_sel_baud; /* user specifies baud rate */
-#define EET_DEFBAUD 0x00
-#define EET_SELBAUD 0x12
- u_char eet_hi_baud; /* upper byte of baud rate */
- u_char eet_lo_baud; /* lower byte of baud rate */
- u_char eet_rtsdtr; /* flag for dtr and rts */
-#define NO_RTSDTR 0x12
- char eet_unused[4];
- } eed_ttya_def, eed_ttyb_def;
-
- char eed_banner[80]; /* 0x068: replacement banner */
- /* last two chars must be \r\n (XXX - why not \0?) */
-
- u_short eed_pattern; /* 0x0b8: test pattern - must contain 0xAA55 */
- short eed_nu6;
- struct eed_conf { /* 0x0bc: system configuration, by slot */
- union {
- struct eec_gen {
- u_char eec_type; /* board type code */
- char eec_size[CONFIG_SIZE - 1];
- } eec_gen;
- char conf_byte[CONFIG_SIZE];
- u_char eec_type; /* type of this board */
-#define EEC_TYPE_NONE 0 /* no board this slot */
-#define EEC_TYPE_CPU 0x01 /* cpu */
- struct eec_cpu {
- u_char eec_type; /* board type */
- u_char eec_cpu_memsize; /* MB's on cpu */
- int eec_cpu_unused:6;
- int eec_cpu_dcp:1; /* dcp? */
- int eec_cpu_68881:1; /* 68881? */
- u_char eec_cpu_cachesize; /* KB's cache */
- } eec_cpu;
- struct eec_cpu_alt {
- u_char eec_type; /* board type */
- u_char memsize; /* MB's on cpu */
- u_char option; /* option flags */
-#define CPU_HAS_DCP 0x02
-#define CPU_HAS_68881 0x01
- u_char cachesize; /* KB's in cache */
- } eec_cpu_alt;
-
-#define EEC_TYPE_MEM 0x02 /* memory board */
- struct eec_mem {
- u_char eec_type; /* board type */
- u_char eec_mem_size; /* MB's on card */
- } eec_mem;
-
-#define EEC_TYPE_COLOR 0x03 /* color frame buffer */
- struct eec_color {
- u_char eec_type; /* board type */
- char eec_color_type;
-#define EEC_COLOR_TYPE_CG2 2 /* cg2 color board */
-#define EEC_COLOR_TYPE_CG3 3 /* cg3 color board */
-#define EEC_COLOR_TYPE_CG5 5 /* cg5 color board */
- } eec_color;
-
-#define EEC_TYPE_BW 0x04 /* b&w frame buffer */
-
-#define EEC_TYPE_FPA 0x05 /* floating point accelerator */
-
-#define EEC_TYPE_DISK 0x06 /* SMD disk controller */
- struct eec_disk {
- u_char eec_type; /* board type */
- char eec_disk_type; /* controller type */
-#define EEC_DISK_TYPE_X450 1
-#define EEC_DISK_TYPE_X451 2
- char eec_disk_ctlr; /* controller number */
- char eec_disk_disks; /* number of disks */
- char eec_disk_cap[4]; /* capacity */
-#define EEC_DISK_NONE 0
-#define EEC_DISK_130 1
-#define EEC_DISK_280 2
-#define EEC_DISK_380 3
-#define EEC_DISK_575 4
-#define EEC_DISK_900 5
- } eec_disk;
-
-#define EEC_TYPE_TAPE 0x07 /* 1/2" tape controller */
- struct eec_tape {
- u_char eec_type; /* board type */
- char eec_tape_type; /* controller type */
-#define EEC_TAPE_TYPE_XT 1 /* Xylogics 472 */
-#define EEC_TAPE_TYPE_MT 2 /* TapeMaster */
- char eec_tape_ctlr; /* controller number */
- char eec_tape_drives; /* number of drives */
- } eec_tape;
-
-#define EEC_TYPE_ETHER 0x08 /* Ethernet controller */
-
-#define EEC_TYPE_TTY 0x09 /* terminal multiplexer */
- struct eec_tty {
- u_char eec_type; /* board type */
- char eec_tty_lines; /* number of lines */
-#define MAX_TTY_LINES 16
- char manufacturer; /* code for maker */
-#define EEC_TTY_UNKNOWN 0
-#define EEC_TTY_SYSTECH 1
-#define EEC_TTY_SUN 2
- } eec_tty;
-
-#define EEC_TYPE_GP 0x0a /* graphics processor/buffer */
- struct eec_gp {
- u_char eec_type; /* board type */
- char eec_gp_type;
-#define EEC_GP_TYPE_GPPLUS 1 /* GP+ graphic processor board */
-#define EEC_GP_TYPE_GP2 2 /* GP2 graphic processor board */
- } eec_gp;
-
-#define EEC_TYPE_DCP 0x0b /* DCP ??? XXX */
-
-#define EEC_TYPE_SCSI 0x0c /* SCSI controller */
- struct eec_scsi {
- u_char eec_type; /* board type */
- char eec_scsi_type; /* host adaptor type */
-#define EEC_SCSI_SUN2 2
-#define EEC_SCSI_SUN3 3
- char eec_scsi_tapes; /* number of tapes */
- char eec_scsi_disks; /* number of disks */
- char eec_scsi_tape_type;
-#define EEC_SCSI_SYSG 1
-#define EEC_SCSI_MT02 2
- char eec_scsi_disk_type;
-#define EEC_SCSI_MD21 1
-#define EEC_SCSI_ADAPT 2
- char eec_scsi_driv_code[2];
-#define EEC_SCSI_D71 1
-#define EEC_SCSI_D141 2
-#define EEC_SCSI_D327 3
- } eec_scsi;
-#define EEC_TYPE_IPC 0x0d
-
-#define EEC_TYPE_GB 0x0e
-
-#define EEC_TYPE_SCSI375 0x0f
-
-#define EEC_TYPE_MAPKIT 0x10
- struct eec_mapkit {
- u_char eec_type; /* board type */
- char eec_mapkit_hw; /* whether INI */
-#define EEC_TYPE_MAPKIT_INI 1
- } eec_mapkit;
-
-#define EEC_TYPE_CHANNEL 0x11
-#define EEC_TYPE_ALM2 0x12
-
-
- struct eec_generic_net {
-#define EEC_TYPE_GENERIC_NET 0x13
- u_char eec_devtype; /* board type */
- u_char eec_mem_type; /* Memory type */
- u_char gn_nu1;
- u_char gn_nu2;
-#define ID_VME 0x0 /* Data buffers are in VME space(Shared) */
-#define ID_DVMA 0x1 /* or DVMA buffer memory type */
- char *dev_reg_ptr;
- } eec_generic_net;
-
-
-#define EEC_TYPE_END 0xff /* end of card cage */
- } eec_un;
- } eed_conf[MAX_SLOTS + 1];
-#define EEPROM_TABLE 0x58 /* 1 indicates alternate key table. */
- u_char which_kbt; /* 0x18C: which keytable? */
-
- /*
- * Note. The following contains the full keyboard id
- * returned by the type4 transmit layout command. It is not
- * necessarily anything to do with locale of operation.
- */
- u_char ee_kb_type;
- u_char ee_kb_id; /* 0x18E: keyboard id in case of EEPROM table */
-#define EEPROM_LOGO 0x12
- u_char otherlogo; /* 0x18F: True if eeprom logo needed */
- struct ee_keymap ee_keytab_lc[1]; /* 0x190: */
- struct ee_keymap ee_keytab_uc[1]; /* 0x210: */
- u_char ee_logo[64][8]; /* 0x290: A 64X64 bit space for custom/OEM designed logo icon */
- struct password_inf ee_password_inf; /* 0x490: reserved */
- char eed_resv[0x500 - 0x49c]; /* 0x49c: reserved */
- } ee_diag;
-
- struct ee_resv { /* reserved area of EEPROM */
- u_short eev_wrcnt[3]; /* 0x500: write count (3 copies) */
- short eev_nu1;
- u_char eev_chksum[3]; /* 0x508: reserved area checksum (3 copies) */
- char eev_nu2;
- char eev_resv[0x600 - 0x50c]; /* 0x50c: */
- } ee_resv;
-
- struct ee_rom { /* ROM area of EEPROM */
- u_short eer_wrcnt[3]; /* 0x600: write count (3 copies) */
- short eer_nu1;
- u_char eer_chksum[3]; /* 0x608: ROM area checksum (3 copies) */
- char eer_nu2;
- char eer_resv[0x700 - 0x60c]; /* 0x60c: */
- } ee_rom;
-
- /*
- * The following area is reserved for software (i.e. UNIX).
- * The actual contents of this area are defined elsewhere.
- */
- struct ee_softresv { /* software area of EEPROM */
- u_short ees_wrcnt[3]; /* 0x700: write count (3 copies) */
- short ees_nu1;
- u_char ees_chksum[3]; /* 0x708: software area checksum (3 copies) */
- char ees_nu2;
- char ees_resv[0x800 - 0x70c]; /* 0x70c: */
- } ee_soft;
+ /* 0x00 */
+ u_char eeTestArea[4]; /* Factory Defined */
+ u_short eeWriteCount[4]; /* || || */
+ u_char eeChecksum[4]; /* || || */
+ time_t eeLastHwUpdate; /* || || */
+
+ /* 0x14 */
+ u_char eeInstalledMem; /* Megabytes */
+ u_char eeMemTestSize; /* || */
+
+ /* 0x16 */
+ u_char eeScreenSize;
+#define EE_SCR_1152X900 0x00
+#define EE_SCR_1024X1024 0x12
+#define EE_SCR_1600X1280 0x13
+#define EE_SCR_1440X1440 0x14
+
+ u_char eeWatchDogDoesReset; /* Watchdog timeout action:
+ * true: reset/reboot
+ * false: return to monitor
+ */
+ /* 0x18 */
+ u_char eeBootDevStored; /* Is the boot device stored:
+ * true: use stored device spec.
+ * false: use default (try all)
+ */
+ /* Stored boot device spec. i.e.: "sd(Ctlr,Unit,Part)" */
+ u_char eeBootDevName[2]; /* xy,xd,sd,ie,le,st,xt,mt,... */
+ u_char eeBootDevCtlr;
+ u_char eeBootDevUnit;
+ u_char eeBootDevPart;
+
+ /* 0x1E */
+ u_char eeKeyboardType; /* zero for sun keyboards */
+ u_char eeConsole; /* What to use for the console */
+#define EE_CONS_BW 0x00 /* - On-board B&W / keyboard */
+#define EE_CONS_TTYA 0x10 /* - serial port A */
+#define EE_CONS_TTYB 0x11 /* - serial port B */
+#define EE_CONS_COLOR 0x12 /* - Color FB / keyboard */
+#define EE_CONS_P4OPT 0x20 /* - Option board on P4 */
+
+ /* 0x20 */
+ u_char eeCustomBanner; /* Is there a custom banner:
+ * true: use text at 0x68
+ * false: use Sun banner
+ */
+
+ u_char eeKeyClick; /* true/false */
+
+ /* Boot device with "Diag" switch in Diagnostic mode: */
+ u_char eeDiagDevName[2];
+ u_char eeDiagDevCtlr;
+ u_char eeDiagDevUnit;
+ u_char eeDiagDevPart;
+
+ /* Video white-on-black (not implemented) */
+ u_char eeWhiteOnBlack; /* true/false */
+
+ /* 0x28 */
+ char eeDiagPath[40]; /* path name of diag program */
+
+ /* 0x50 */
+ u_char eeTtyCols; /* normally 80 */
+ u_char eeTtyRows; /* normally 34 */
+ u_char ee_x52[6]; /* unused */
+
+ /* 0x58 */
+ /* Default parameters for tty A and tty B: */
+ struct eeTtyDef {
+ u_char eetBaudSet; /* Is the baud rate set?
+ * true: use values here
+ * false: use default (9600)
+ */
+ u_char eetBaudHi; /* i.e. 96.. */
+ u_char eetBaudLo; /* ..00 */
+ u_char eetNoRtsDtr; /* true: disable H/W flow
+ * false: enable H/W flow */
+ u_char eet_pad[4];
+ } eeTtyDefA, eeTtyDefB;
+
+ /* 0x68 */
+ char eeBannerString[80]; /* see eeCustomBanner above */
+
+ /* 0xB8 */
+ u_short eeTestPattern; /* must be 0xAA55 */
+ u_short ee_xBA; /* unused */
+
+ /* 0xBC */
+ /* Configuration data. Hopefully we don't need it. */
+ struct eeConf {
+ u_char eecData[16];
+ } eeConf[12+1];
+
+ /* 0x18c */
+ u_char eeAltKeyTable; /* What Key table to use:
+ * 0x58: EEPROM tables
+ * else: PROM key tables
+ */
+ u_char eeKeyboardLocale; /* extended keyboard type */
+ u_char eeKeyboardID; /* for EEPROM key tables */
+ u_char eeCustomLogo; /* true: use eeLogoBitmap */
+
+ /* 0x190 */
+ u_char eeKeymapLC[0x80];
+ u_char eeKeymapUC[0x80];
+
+ /* 0x290 */
+ u_char eeLogoBitmap[64][8]; /* 64x64 bit custom logo */
+
+ /* 0x490 */
+ u_char ee_x490[0x500-0x490]; /* unused */
+
+ /* Other stuff we don't care about... */
+ /* 0x500 */
+ u_char eeReserved[0x100];
+ /* 0x600 */
+ u_char eeROM_Area[0x100];
+ /* 0x700 */
+ u_char eeUnixArea[0x100];
};
-#define EEPROM_BASE 0xffd04000
+/*
+ * The size of the eeprom on machines with the old clock is 2k. However,
+ * on machines with the new clock (and the `eeprom' in the nvram area)
+ * there are only 2040 bytes available. (???). Since we really only
+ * care about the `diagnostic' area, we'll use it's size when dealing
+ * with the eeprom in general.
+ */
+#define EEPROM_SIZE 0x500
-#ifdef _KERNEL
+#ifdef _KERNEL
extern char *eeprom_va;
int eeprom_uio __P((struct uio *));
-#endif /* _KERNEL */
+#endif /* _KERNEL */
+
diff --git a/sys/arch/sparc/include/endian.h b/sys/arch/sparc/include/endian.h
index a7004e09ea6..3d4297321bf 100644
--- a/sys/arch/sparc/include/endian.h
+++ b/sys/arch/sparc/include/endian.h
@@ -1,4 +1,4 @@
-/* $NetBSD: endian.h,v 1.2 1994/11/20 20:53:01 deraadt Exp $ */
+/* $NetBSD: endian.h,v 1.3 1996/02/13 17:04:58 christos Exp $ */
/*
* Copyright (c) 1987, 1991 Regents of the University of California.
@@ -69,10 +69,10 @@ __END_DECLS
#define htonl(x) (x)
#define htons(x) (x)
-#define NTOHL(x) (x)
-#define NTOHS(x) (x)
-#define HTONL(x) (x)
-#define HTONS(x) (x)
+#define NTOHL(x) (void) (x)
+#define NTOHS(x) (void) (x)
+#define HTONL(x) (void) (x)
+#define HTONS(x) (void) (x)
#else
diff --git a/sys/arch/sparc/include/exec.h b/sys/arch/sparc/include/exec.h
index 10c47d28aaa..beac6897c05 100644
--- a/sys/arch/sparc/include/exec.h
+++ b/sys/arch/sparc/include/exec.h
@@ -57,11 +57,4 @@ struct relocation_info_sparc {
};
#define relocation_info relocation_info_sparc
-#define ELF_TARG_CLASS ELFCLASS32
-#define ELF_TARG_DATA ELFDATA2MSB
-#define ELF_TARG_MACH EM_SPARC
-
-#define DO_AOUT /* support a.out */
-#define DO_ELF /* support ELF */
-
#endif /* _SPARC_EXEC_H_ */
diff --git a/sys/arch/sparc/include/fbio.h b/sys/arch/sparc/include/fbio.h
index a80ec853cb2..2eddc2b5d69 100644
--- a/sys/arch/sparc/include/fbio.h
+++ b/sys/arch/sparc/include/fbio.h
@@ -1,4 +1,4 @@
-/* $NetBSD: fbio.h,v 1.3 1994/11/20 20:53:03 deraadt Exp $ */
+/* $NetBSD: fbio.h,v 1.4 1996/03/31 22:21:31 pk Exp $ */
/*
* Copyright (c) 1992 Regents of the University of California.
@@ -154,7 +154,7 @@ struct fbcurpos {
short x;
short y;
};
-
+
#define FB_CUR_SETCUR 0x01
#define FB_CUR_SETPOS 0x02
#define FB_CUR_SETHOT 0x04
@@ -172,14 +172,14 @@ struct fbcursor {
char *image; /* cursor's image bits */
char *mask; /* cursor's mask bits */
};
-
+
/* set/get cursor attributes/shape */
#define FBIOSCURSOR _IOW('F', 24, struct fbcursor)
#define FBIOGCURSOR _IOWR('F', 25, struct fbcursor)
-
+
/* set/get cursor position */
#define FBIOSCURPOS _IOW('F', 26, struct fbcurpos)
#define FBIOGCURPOS _IOW('F', 27, struct fbcurpos)
-
+
/* get max cursor size */
#define FBIOGCURMAX _IOR('F', 28, struct fbcurpos)
diff --git a/sys/arch/sparc/include/fbvar.h b/sys/arch/sparc/include/fbvar.h
index 1b00249ae50..d5f3e8855c5 100644
--- a/sys/arch/sparc/include/fbvar.h
+++ b/sys/arch/sparc/include/fbvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: fbvar.h,v 1.5 1995/10/08 01:40:25 pk Exp $ */
+/* $NetBSD: fbvar.h,v 1.7 1996/02/27 22:09:39 thorpej Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -76,14 +76,26 @@ struct fbdevice {
struct fbdriver *fb_driver; /* pointer to driver */
struct device *fb_device; /* parameter for fbd_unblank */
+ int fb_flags; /* misc. flags */
+#define FB_FORCE 0x00000001 /* force device into /dev/fb */
+#define FB_PFOUR 0x00010000 /* indicates fb is a pfour fb */
+#define FB_USERMASK (FB_FORCE) /* flags that the user can set */
+
+ volatile u_int32_t *fb_pfour; /* pointer to pfour register */
+
#ifdef RASTERCONSOLE
/* Raster console emulator state */
struct rconsole fb_rcons;
#endif
};
-void fbattach __P((struct fbdevice *));
+void fb_attach __P((struct fbdevice *, int));
void fb_setsize __P((struct fbdevice *, int, int, int, int, int));
#ifdef RASTERCONSOLE
void fbrcons_init __P((struct fbdevice *));
#endif
+#if defined(SUN4)
+int fb_pfour_id __P((void *));
+int fb_pfour_get_video __P((struct fbdevice *));
+void fb_pfour_set_video __P((struct fbdevice *, int));
+#endif
diff --git a/sys/arch/sparc/include/ieeefp.h b/sys/arch/sparc/include/ieeefp.h
index 87c19132039..a1e67846b83 100644
--- a/sys/arch/sparc/include/ieeefp.h
+++ b/sys/arch/sparc/include/ieeefp.h
@@ -1,4 +1,4 @@
-/*
+/*
* Written by J.T. Conklin, Apr 6, 1995
* Public domain.
*/
diff --git a/sys/arch/sparc/include/kbd.h b/sys/arch/sparc/include/kbd.h
index 7fe3c4e2653..4cabc471287 100644
--- a/sys/arch/sparc/include/kbd.h
+++ b/sys/arch/sparc/include/kbd.h
@@ -1,4 +1,4 @@
-/* $NetBSD: kbd.h,v 1.4 1995/07/06 05:36:29 pk Exp $ */
+/* $NetBSD: kbd.h,v 1.6 1996/03/31 22:21:35 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -86,3 +86,12 @@
#define LED_COMPOSE 0x2
#define LED_SCROLL_LOCK 0x4
#define LED_CAPS_LOCK 0x8
+
+void kbd_serial __P((struct tty *,
+ void (*)(struct tty *), void (*)(struct tty *)));
+void ms_serial __P((struct tty *,
+ void (*)(struct tty *), void (*)(struct tty *)));
+void kbd_rint __P((int));
+void ms_rint __P((int));
+void kbd_ascii __P((struct tty *));
+int kbd_docmd __P((int, int));
diff --git a/sys/arch/sparc/include/kbio.h b/sys/arch/sparc/include/kbio.h
index 2a2c3b427aa..049bfb79fed 100644
--- a/sys/arch/sparc/include/kbio.h
+++ b/sys/arch/sparc/include/kbio.h
@@ -66,7 +66,7 @@
* Keyboard commands and types are defined in kbd.h as they are actually
* real hardware commands and type numbers.
*/
-struct okiockey { /* Out-dated key translation structure */
+struct okiockey { /* Out-dated key translation structure */
int kio_tablemask; /* whatever */
u_char kio_station; /* key number */
u_char kio_entry; /* HOLE if not present */
@@ -85,12 +85,12 @@ struct kiockey {
* in KIOC[SG]KEY ioctls. Currently, we only have "non-shift" and "shift"
* tables.
*/
-#define KIOC_NOMASK 0x0
-#define KIOC_CAPSMASK 0x1
-#define KIOC_SHIFTMASK 0xe
-#define KIOC_CTRLMASK 0x30
-#define KIOC_ALTGMASK 0x200
-#define KIOC_NUMLMASK 0x800
+#define KIOC_NOMASK 0x0
+#define KIOC_CAPSMASK 0x1
+#define KIOC_SHIFTMASK 0xe
+#define KIOC_CTRLMASK 0x30
+#define KIOC_ALTGMASK 0x200
+#define KIOC_NUMLMASK 0x800
#define HOLE 0x302 /* value for kio_entry to say `really type 3' */
@@ -101,8 +101,8 @@ struct kiockey {
#define KIOCCMD _IOW('k', 8, int) /* X uses this to ring bell */
#define KIOCTYPE _IOR('k', 9, int) /* get keyboard type */
#define KIOCSDIRECT _IOW('k', 10, int) /* keys to console? */
-#define KIOCSKEY _IOW('k', 12, struct kiockey) /* set xlat mode */
-#define KIOCGKEY _IOWR('k', 13, struct kiockey) /* get xlat mode */
+#define KIOCSKEY _IOW('k', 12, struct kiockey) /* set xlat mode */
+#define KIOCGKEY _IOWR('k', 13, struct kiockey) /* get xlat mode */
#define KIOCLAYOUT _IOR('k', 20, int) /* get keyboard layout */
#define KIOCSLED _IOW('k', 14, char) /* set LED state */
#define KIOCGLED _IOR('k', 15, char) /* get LED state */
diff --git a/sys/arch/sparc/include/oldmon.h b/sys/arch/sparc/include/oldmon.h
index 02cbf052656..d18a256f05c 100644
--- a/sys/arch/sparc/include/oldmon.h
+++ b/sys/arch/sparc/include/oldmon.h
@@ -1,4 +1,4 @@
-/* $NetBSD: oldmon.h,v 1.5 1995/09/03 21:36:06 pk Exp $ */
+/* $NetBSD: oldmon.h,v 1.11 1996/03/31 22:21:38 pk Exp $ */
/*
* Copyright (C) 1985 Regents of the University of California
@@ -74,24 +74,56 @@ struct devinfo {
};
/*
+ * A "stand alone I/O request".
+ * This is passed as the main argument to the PROM I/O routines
+ * in the `om_boottable' structure.
+ */
+struct saioreq {
+ char si_flgs;
+ struct om_boottable *si_boottab;/* Points to boottab entry if any */
+ char *si_devdata; /* Device-specific data pointer */
+ int si_ctlr; /* Controller number or address */
+ int si_unit; /* Unit number within controller */
+ long si_boff; /* Partition number within unit */
+ long si_cyloff;
+ long si_offset;
+ long si_bn; /* Block number to R/W */
+ char *si_ma; /* Memory address to R/W */
+ int si_cc; /* Character count to R/W */
+ struct saif *si_sif; /* net if. pointer (set by b_open) */
+ char *si_devaddr; /* Points to mapped in device */
+ char *si_dmaaddr; /* Points to allocated DMA space */
+};
+#define SAIO_F_READ 0x01
+#define SAIO_F_WRITE 0x02
+#define SAIO_F_ALLOC 0x04
+#define SAIO_F_FILE 0x08
+#define SAIO_F_EOF 0x10 /* EOF on device */
+#define SAIO_F_AJAR 0x20 /* Descriptor "ajar" (stopped but not closed) */
+
+
+/*
* The table entry that describes a device. It exists in the PROM; a
* pointer to it is passed in MachMonBootParam. It can be used to locate
* PROM subroutines for opening, reading, and writing the device.
*
* When using this interface, only one device can be open at once.
*
- * NOTE: I am not sure what arguments boot, open, close, and strategy take.
- * What is here is just translated verbatim from the sun monitor code. We
+ * NOTE: I am not sure what arguments boot, open, close, and strategy take.
+ * What is here is just translated verbatim from the sun monitor code. We
* should figure this out eventually if we need it.
*/
struct om_boottable {
char b_devname[2]; /* The name of the device */
- int (*b_probe)(); /* probe() --> -1 or found controller
+ int (*b_probe) __P((void)); /* probe() --> -1 or found controller
number */
- int (*b_boot)(); /* boot(bp) --> -1 or start address */
- int (*b_open)(); /* open(iobp) --> -1 or 0 */
- int (*b_close)(); /* close(iobp) --> -1 or 0 */
- int (*b_strategy)(); /* strategy(iobp,rw) --> -1 or 0 */
+ int (*b_boot) __P((void)); /* boot(bp) --> -1 or start address */
+ int (*b_open)
+ __P((struct saioreq *));/* open(iobp) --> -1 or 0 */
+ int (*b_close)
+ __P((struct saioreq *));/* close(iobp) --> -1 or 0 */
+ int (*b_strategy)
+ __P((struct saioreq *, int));/* strategy(iobp,rw) --> -1 or 0 */
char *b_desc; /* Printable string describing dev */
struct devinfo *b_devinfo; /* info to configure device. */
};
@@ -121,7 +153,7 @@ struct om_bootparam {
*/
struct om_vector {
char *initSp; /* Initial system stack ptr for hardware */
- int (*startMon)(); /* Initial PC for hardware */
+ int (*startMon) __P((void));/* Initial PC for hardware */
int *diagberr; /* Bus err handler for diags */
/* Monitor and hardware revision and identification */
@@ -142,8 +174,8 @@ struct om_vector {
#define PROMDEV_TTYB 2 /* in/out to ttyb */
/* Keyboard input (scanned by monitor nmi routine) */
- int (*getKey)(); /* Get next key if one exists */
- int (*initGetKey)(); /* Initialize get key */
+ int (*getKey) __P((void)); /* Get next key if one exists */
+ int (*initGetKey) __P((void));/* Initialize get key */
u_int *translation; /* Kbd translation selector */
u_char *keyBid; /* Keyboard ID byte */
int *screen_x; /* V2: Screen x pos (R/O) */
@@ -154,10 +186,11 @@ struct om_vector {
char *monId;
/* Frame buffer output and terminal emulation */
- int (*fbWriteChar)(); /* Write a character to FB */
+ int (*fbWriteChar) __P((void));/* Write a character to FB */
int *fbAddr; /* Address of frame buffer */
char **font; /* Font table for FB */
- void (*fbWriteStr) __P((char *, int)); /* Quickly write string to FB */
+ void (*fbWriteStr) __P((char *, int));
+ /* Quickly write string to FB */
/* Reboot interface routine -- resets and reboots system. */
void (*reBoot) __P((char *)); /* e.g. reBoot("xy()vmunix") */
@@ -166,30 +199,30 @@ struct om_vector {
u_char *lineBuf; /* The line input buffer */
u_char **linePtr; /* Cur pointer into linebuf */
int *lineSize; /* length of line in linebuf */
- int (*getLine)(); /* Get line from user */
- u_char (*getNextChar)(); /* Get next char from linebuf */
- u_char (*peekNextChar)(); /* Peek at next char */
+ int (*getLine) __P((void)); /* Get line from user */
+ u_char (*getNextChar) __P((void));/* Get next char from linebuf */
+ u_char (*peekNextChar) __P((void));/* Peek at next char */
int *fbThere; /* =1 if frame buffer there */
- int (*getNum)(); /* Grab hex num from line */
+ int (*getNum) __P((void)); /* Grab hex num from line */
/* Print formatted output to current output sink */
- int (*printf)(); /* Similar to "Kernel printf" */
- int (*printHex)(); /* Format N digits in hex */
+ int (*printf) __P((void)); /* Similar to "Kernel printf" */
+ int (*printHex) __P((void));/* Format N digits in hex */
/* Led stuff */
u_char *leds; /* RAM copy of LED register */
- int (*setLeds)(); /* Sets LED's and RAM copy */
+ int (*setLeds) __P((void)); /* Sets LED's and RAM copy */
- /* Non-maskable interrupt (nmi) information */
- int (*nmiAddr)(); /* Addr for level 7 vector */
- void (*abortEntry) __P((void)); /* Entry for keyboard abort */
+ /* Non-maskable interrupt (nmi) information */
+ int (*nmiAddr) __P((void)); /* Addr for level 7 vector */
+ void (*abortEntry) __P((void));/* Entry for keyboard abort */
int *nmiClock; /* Counts up in msec */
/* Frame buffer type: see <machine/fbio.h> */
int *fbType;
/* Assorted other things */
- u_long romvecVersion; /* Version # of Romvec */
+ u_long romvecVersion; /* Version # of Romvec */
struct globram *globRam; /* monitor global variables */
caddr_t kbdZscc; /* Addr of keyboard in use */
@@ -200,10 +233,12 @@ struct om_vector {
long *resetMap; /* pgmap entry for resetaddr */
/* Really struct pgmapent * */
- __dead void (*exitToMon) __P((void)); /* Exit from user program */
+ __dead void (*exitToMon)
+ __P((void)) __attribute__((noreturn));/* Exit from user program */
u_char **memorybitmap; /* V1: &{0 or &bits} */
- void (*setcxsegmap)(); /* Set seg in any context */
- void (**vector_cmd)(); /* V2: Handler for 'v' cmd */
+ void (*setcxsegmap) /* Set seg in any context */
+ __P((int, caddr_t, int));
+ void (**vector_cmd) __P((u_long, char *));/* V2: Handler for 'v' cmd */
u_long *ExpectedTrapSig;
u_long *TrapVectorTable;
int dummy1z;
@@ -227,9 +262,9 @@ struct om_vector {
/*
* OLDMON_STARTVADDR and OLDMON_ENDVADDR denote the range of the damn monitor.
- *
+ *
* supposedly you can steal pmegs within this range that do not contain
- * valid pages.
+ * valid pages.
*/
#define OLDMON_STARTVADDR 0xFFD00000
#define OLDMON_ENDVADDR 0xFFF00000
@@ -248,33 +283,6 @@ struct om_vector {
#define MONSHORTPAGE 0x0FFFE000
#define MONSHORTSEG 0x0FFE0000
-/*
- * A "stand alone I/O request".
- * This is passed as the main argument to the PROM I/O routines
- * in the `om_boottable' structure.
- */
-struct saioreq {
- char si_flgs;
- struct om_boottable *si_boottab;/* Points to boottab entry if any */
- char *si_devdata; /* Device-specific data pointer */
- int si_ctlr; /* Controller number or address */
- int si_unit; /* Unit number within controller */
- long si_boff; /* Partition number within unit */
- long si_cyloff;
- long si_offset;
- long si_bn; /* Block number to R/W */
- char *si_ma; /* Memory address to R/W */
- int si_cc; /* Character count to R/W */
- struct saif *si_sif; /* net if. pointer (set by b_open) */
- char *si_devaddr; /* Points to mapped in device */
- char *si_dmaaddr; /* Points to allocated DMA space */
-};
-#define SAIO_F_READ 0x01
-#define SAIO_F_WRITE 0x02
-#define SAIO_F_ALLOC 0x04
-#define SAIO_F_FILE 0x08
-#define SAIO_F_EOF 0x10 /* EOF on device */
-#define SAIO_F_AJAR 0x20 /* Descriptor "ajar" (stopped but not closed) */
/*
@@ -288,11 +296,18 @@ struct saioreq {
*/
struct saif {
/* transmit packet, returns zero on success. */
- int (*sif_xmit) __P((void *devdata, char *buf, int len));
+ int (*sif_xmit)(void *devdata, char *buf, int len);
/* wait for packet, zero if none arrived */
- int (*sif_poll) __P((void *devdata, char *buf));
+ int (*sif_poll)(void *devdata, char *buf);
/* reset interface, set addresses, etc. */
- int (*sif_reset) __P((void *devdata, struct saioreq *sip));
+ int (*sif_reset)(void *devdata, struct saioreq *sip);
/* Later (sun4 only) proms have more stuff here. */
};
-#endif /* MACHINE_OLDMON_H */
+
+
+#if defined(SUN4)
+void oldmon_w_trace __P((u_long));
+void oldmon_w_cmd __P((u_long, char *));
+#endif
+
+#endif /* _MACHINE_OLDMON_H */
diff --git a/sys/arch/sparc/include/param.h b/sys/arch/sparc/include/param.h
index da5231519df..ce866af3ca1 100644
--- a/sys/arch/sparc/include/param.h
+++ b/sys/arch/sparc/include/param.h
@@ -1,4 +1,4 @@
-/* $NetBSD: param.h,v 1.16 1995/06/28 02:43:50 cgd Exp $ */
+/* $NetBSD: param.h,v 1.24 1996/05/15 02:13:48 mrg Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -43,17 +43,22 @@
*
* @(#)param.h 8.1 (Berkeley) 6/11/93
*/
-
/*
- * Machine dependent constants for Sun-4c (SPARCstation)
+ * Sun4M support by Aaron Brown, Harvard University.
+ * Changes Copyright (c) 1995 The President and Fellows of Harvard College.
+ * All rights reserved.
*/
+#define _MACHINE sparc
#define MACHINE "sparc"
+#define _MACHINE_ARCH sparc
#define MACHINE_ARCH "sparc"
#define MID_MACHINE MID_SPARC
#ifdef _KERNEL /* XXX */
+#ifndef _LOCORE /* XXX */
#include <machine/cpu.h> /* XXX */
#endif /* XXX */
+#endif /* XXX */
/*
* Round p (pointer or byte index) up to a correctly-aligned value for
@@ -71,7 +76,7 @@
* sun4 only 8192 bytes/page
* sun4c/sun4m only 4096 bytes/page
* sun4/sun4c/sun4m either of the above
- *
+ *
* In the later case NBPG, PGOFSET, and PGSHIFT are encoded in variables
* initialized early in locore.s. Since they are variables, rather than
* simple constants, the kernel will not perform slighly worse.
@@ -87,7 +92,7 @@
#define PGSHIFT SUN4CM_PGSHIFT /* log2(NBPG) */
#endif
#if defined(SUN4) && (defined(SUN4C) || defined(SUN4M))
-#if defined(_KERNEL) && !defined(LOCORE)
+#if defined(_KERNEL) && !defined(_LOCORE)
extern int nbpg, pgofset, pgshift;
#endif
#define NBPG nbpg /* bytes/page */
@@ -124,9 +129,9 @@ extern int nbpg, pgofset, pgshift;
#ifndef NMBCLUSTERS
#ifdef GATEWAY
-#define NMBCLUSTERS 2048 /* map size, max cluster allocation */
+#define NMBCLUSTERS 512 /* map size, max cluster allocation */
#else
-#define NMBCLUSTERS 1024 /* map size, max cluster allocation */
+#define NMBCLUSTERS 256 /* map size, max cluster allocation */
#endif
#endif
@@ -168,11 +173,10 @@ extern int nbpg, pgofset, pgshift;
* in DVMA space.
*/
#ifdef _KERNEL
-#ifndef LOCORE
+#ifndef _LOCORE
extern vm_offset_t dvma_base;
extern vm_offset_t dvma_end;
extern struct map *dvmamap;
-#endif
/*
* The dvma resource map is defined in page units, which are numbered 1 to N.
* Use these macros to convert to/from virtual addresses.
@@ -183,21 +187,17 @@ extern struct map *dvmamap;
extern caddr_t kdvma_mapin __P((caddr_t, int, int));
extern caddr_t dvma_malloc __P((size_t, void *, int));
extern void dvma_free __P((caddr_t, size_t, void *));
-#endif
-
-#ifdef _KERNEL
-#ifndef LOCORE
+extern void delay __P((unsigned int));
#define DELAY(n) delay(n)
-#endif
-#endif
-#ifdef _KERNEL
-#ifndef LOCORE
extern int cputyp;
extern int cpumod;
-#endif
-#endif
+extern int mmumod;
+
+#endif /* _LOCORE */
+#endif /* _KERNEL */
+
/*
* Values for the cputyp variable.
*/
@@ -206,8 +206,76 @@ extern int cpumod;
#define CPU_SUN4M 2
/*
* Values for cpumod (cpu model) variable. XXX currently valid only for sun4
+ * or Sun4M
*/
#define SUN4_100 0x22
#define SUN4_200 0x21
#define SUN4_300 0x23
#define SUN4_400 0x24
+#define SUN4M_MS 0x04 /* MicroSPARC-II */
+#define SUN4M_SS 0x40 /* Generic SuperSPARC */
+#define SUN4M_HS 0x10 /* Generic ROSS sparc product (HyperSPARC) */
+#define SUN4M_RT620 0x1f /* Ross HyperSPARC RT620 */
+#define SUN4M_STP1020N 0x41 /* TI SuperSPARC STP1020N */
+#define SUN4M_STP1020P 0x40 /* TI SuperSPARC STP1020P */
+#define SUN4M_STP1020A 0x40 /* TI SuperSPARC STP1020A */
+
+/* Values for mmumod (mmu model) variable. Valid only for Sun4M */
+#define SUN4M_MMU_HS 0x1 /* ROSS HyperSparc */
+#define SUN4M_MMU_SS 0x0 /* TI SuperSPARC */
+#define SUN4M_MMU_MS1 0x4 /* MicroSPARC-I (??? XXX) */
+#define SUN4M_MMU_MS 0x0 /* MicroSPARC-II (ugh, conflicts w/SS) */
+
+/*
+ * Shorthand CPU-type macros. Enumerate all eight cases.
+ * Let compiler optimize away code conditional on constants.
+ */
+#if defined(SUN4M) && defined(SUN4C) && defined(SUN4)
+# define CPU_ISSUN4M (cputyp == CPU_SUN4M)
+# define CPU_ISSUN4C (cputyp == CPU_SUN4C)
+# define CPU_ISSUN4 (cputyp == CPU_SUN4)
+# define CPU_ISSUN4OR4C (cputyp == CPU_SUN4 || cputyp == CPU_SUN4C)
+# define CPU_ISSUN4COR4M (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M)
+#elif defined(SUN4M) && defined(SUN4C) && !defined(SUN4)
+# define CPU_ISSUN4M (cputyp == CPU_SUN4M)
+# define CPU_ISSUN4C (cputyp == CPU_SUN4C)
+# define CPU_ISSUN4 (0)
+# define CPU_ISSUN4OR4C (cputyp == CPU_SUN4C)
+# define CPU_ISSUN4COR4M (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M)
+#elif defined(SUN4M) && !defined(SUN4C) && defined(SUN4)
+# define CPU_ISSUN4M (cputyp == CPU_SUN4M)
+# define CPU_ISSUN4C (0)
+# define CPU_ISSUN4 (cputyp == CPU_SUN4)
+# define CPU_ISSUN4OR4C (cputyp == CPU_SUN4)
+# define CPU_ISSUN4COR4M (cputyp == CPU_SUN4M)
+#elif defined(SUN4M) && !defined(SUN4C) && !defined(SUN4)
+# define CPU_ISSUN4M (1)
+# define CPU_ISSUN4C (0)
+# define CPU_ISSUN4 (0)
+# define CPU_ISSUN4OR4C (0)
+# define CPU_ISSUN4COR4M (1)
+#elif !defined(SUN4M) && defined(SUN4C) && defined(SUN4)
+# define CPU_ISSUN4M (0)
+# define CPU_ISSUN4C (cputyp == CPU_SUN4C)
+# define CPU_ISSUN4 (cputyp == CPU_SUN4)
+# define CPU_ISSUN4OR4C (1)
+# define CPU_ISSUN4COR4M (cputyp == CPU_SUN4C)
+#elif !defined(SUN4M) && defined(SUN4C) && !defined(SUN4)
+# define CPU_ISSUN4M (0)
+# define CPU_ISSUN4C (1)
+# define CPU_ISSUN4 (0)
+# define CPU_ISSUN4OR4C (1)
+# define CPU_ISSUN4COR4M (1)
+#elif !defined(SUN4M) && !defined(SUN4C) && defined(SUN4)
+# define CPU_ISSUN4M (0)
+# define CPU_ISSUN4C (0)
+# define CPU_ISSUN4 (1)
+# define CPU_ISSUN4OR4C (1)
+# define CPU_ISSUN4COR4M (0)
+#elif !defined(SUN4M) && !defined(SUN4C) && !defined(SUN4)
+# define CPU_ISSUN4M (0)
+# define CPU_ISSUN4C (0)
+# define CPU_ISSUN4 (0)
+# define CPU_ISSUN4OR4C (0)
+# define CPU_ISSUN4COR4M (0)
+#endif
diff --git a/sys/arch/sparc/include/pmap.h b/sys/arch/sparc/include/pmap.h
index 6106e4df3aa..e67de44782d 100644
--- a/sys/arch/sparc/include/pmap.h
+++ b/sys/arch/sparc/include/pmap.h
@@ -1,6 +1,8 @@
-/* $NetBSD: pmap.h,v 1.16 1995/04/13 16:24:40 pk Exp $ */
+/* $NetBSD: pmap.h,v 1.22.4.1 1996/06/12 20:29:01 pk Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -10,19 +12,16 @@
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
+ * @InsertRedistribution@
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
@@ -75,6 +74,9 @@
* requires 3584 segments, while the kernel (including DVMA) requires
* only 512 segments.
*
+ *
+ ** FOR THE SUN4/SUN4C
+ *
* The segment map entry for virtual segment vseg is offset in
* pmap->pm_rsegmap by 0 if pmap is not the kernel pmap, or by
* NUSEG if it is. We keep a pointer called pmap->pm_segmap
@@ -102,13 +104,37 @@
* `stolen' out of the the MMU, we just keep all its PTEs there, and
* have no software copies. Its mmu entries are nonetheless kept on lists
* so that the code that fiddles with mmu lists has something to fiddle.
+ *
+ ** FOR THE SUN4M
+ *
+ * On this architecture, the virtual-to-physical translation (page) tables
+ * are *not* stored within the MMU as they are in the earlier Sun architect-
+ * ures; instead, they are maintained entirely within physical memory (there
+ * is a TLB cache to prevent the high performance hit from keeping all page
+ * tables in core). Thus there is no need to dynamically allocate PMEGs or
+ * SMEGs; only contexts must be shared.
+ *
+ * We maintain two parallel sets of tables: one is the actual MMU-edible
+ * hierarchy of page tables in allocated kernel memory; these tables refer
+ * to each other by physical address pointers in SRMMU format (thus they
+ * are not very useful to the kernel's management routines). The other set
+ * of tables is similar to those used for the Sun4/100's 3-level MMU; it
+ * is a hierarchy of regmap and segmap structures which contain kernel virtual
+ * pointers to each other. These must (unfortunately) be kept in sync.
+ *
*/
#define NKREG ((int)((-(unsigned)KERNBASE) / NBPRG)) /* i.e., 8 */
#define NUREG (256 - NKREG) /* i.e., 248 */
TAILQ_HEAD(mmuhd,mmuentry);
-/* data appearing in both user and kernel pmaps */
+/*
+ * data appearing in both user and kernel pmaps
+ *
+ * note: if we want the same binaries to work on the 4/4c and 4m, we have to
+ * include the fields for both to make sure that the struct kproc
+ * is the same size.
+ */
struct pmap {
union ctxinfo *pm_ctx; /* current context, if any */
int pm_ctxnum; /* current context's number */
@@ -117,10 +143,15 @@ struct pmap {
#endif
int pm_refcount; /* just what it says */
- struct mmuhd pm_reglist; /* MMU regions on this pmap */
- struct mmuhd pm_seglist; /* MMU segments on this pmap */
+ struct mmuhd pm_reglist; /* MMU regions on this pmap (4/4c) */
+ struct mmuhd pm_seglist; /* MMU segments on this pmap (4/4c) */
+
void *pm_regstore;
struct regmap *pm_regmap;
+
+ int *pm_reg_ptps; /* SRMMU-edible region table for 4m */
+ int pm_reg_ptps_pa; /* _Physical_ address of pm_reg_ptps */
+
int pm_gap_start; /* Starting with this vreg there's */
int pm_gap_end; /* no valid mapping until here */
@@ -129,18 +160,29 @@ struct pmap {
struct regmap {
struct segmap *rg_segmap; /* point to NSGPRG PMEGs */
- smeg_t rg_smeg; /* the MMU region number */
+ int *rg_seg_ptps; /* SRMMU-edible segment tables (NULL
+ * indicates invalid region (4m) */
+ smeg_t rg_smeg; /* the MMU region number (4c) */
u_char rg_nsegmap; /* number of valid PMEGS */
};
struct segmap {
int *sg_pte; /* points to NPTESG PTEs */
- pmeg_t sg_pmeg; /* the MMU segment number */
+ pmeg_t sg_pmeg; /* the MMU segment number (4c) */
u_char sg_npte; /* number of valid PTEs per seg */
};
typedef struct pmap *pmap_t;
+#if 0
+struct kvm_cpustate {
+ int kvm_npmemarr;
+ struct memarr kvm_pmemarr[MA_SIZE];
+ int kvm_seginval; /* [4,4c] */
+ struct segmap kvm_segmap_store[NKREG*NSEGRG]; /* [4,4c] */
+}/*not yet used*/;
+#endif
+
#ifdef _KERNEL
#define PMAP_NULL ((pmap_t)0)
@@ -161,17 +203,24 @@ extern vm_offset_t vm_first_phys, vm_num_phys;
#define PMAP_VME16 2 /* etc */
#define PMAP_VME32 3 /* etc */
#define PMAP_NC 4 /* tells pmap_enter to set PG_NC */
-#define PMAP_TNC 7 /* mask to get PG_TYPE & PG_NC */
-/*#define PMAP_IOC 0x00800000 -* IO cacheable, NOT shifted */
+#define PMAP_TYPE4M 0x78 /* mask to get 4m page type */
+#define PMAP_PTESHFT4M 25 /* right shift to put type in pte */
+#define PMAP_SHFT4M 0x3 /* left shift to extract type */
+#define PMAP_TNC \
+ (CPU_ISSUN4M?127:7) /* mask to get PG_TYPE & PG_NC */
+/*#define PMAP_IOC 0x00800000 -* IO cacheable, NOT shifted */
+
+
+#if xxx
void pmap_bootstrap __P((int nmmu, int nctx, int nregion));
int pmap_count_ptes __P((struct pmap *));
-vm_offset_t pmap_prefer __P((vm_offset_t, vm_offset_t));
+void pmap_prefer __P((vm_offset_t, vm_offset_t *));
int pmap_pa_exists __P((vm_offset_t));
-int pmap_dumpsize __P((void));
-int pmap_dumpmmu __P((int (*)__P((dev_t, daddr_t, caddr_t, size_t)),
- daddr_t));
-int mmu_pagein __P((struct pmap *, int va, vm_prot_t prot));
+#endif
+int pmap_dumpsize __P((void));
+int pmap_dumpmmu __P((int (*)__P((dev_t, daddr_t, caddr_t, size_t)),
+ daddr_t));
#define pmap_kernel() (&kernel_pmap_store)
#define pmap_resident_count(pmap) pmap_count_ptes(pmap)
@@ -179,7 +228,144 @@ int mmu_pagein __P((struct pmap *, int va, vm_prot_t prot));
#define PMAP_ACTIVATE(pmap, pcb, iscurproc)
#define PMAP_DEACTIVATE(pmap, pcb)
-#define PMAP_PREFER(pa, va) pmap_prefer((pa), (va))
+#define PMAP_PREFER(fo, ap) pmap_prefer((fo), (ap))
+
+#define PMAP_EXCLUDE_DECLS /* tells MI pmap.h *not* to include decls */
+
+/* FUNCTION DECLARATIONS FOR COMMON PMAP MODULE */
+
+void pmap_bootstrap __P((int nmmu, int nctx, int nregion));
+int pmap_count_ptes __P((struct pmap *));
+void pmap_prefer __P((vm_offset_t, vm_offset_t *));
+int pmap_pa_exists __P((vm_offset_t));
+void *pmap_bootstrap_alloc __P((int));
+void pmap_change_wiring __P((pmap_t, vm_offset_t, boolean_t));
+void pmap_collect __P((pmap_t));
+void pmap_copy __P((pmap_t,
+ pmap_t, vm_offset_t, vm_size_t, vm_offset_t));
+pmap_t pmap_create __P((vm_size_t));
+void pmap_destroy __P((pmap_t));
+void pmap_init __P((void));
+vm_offset_t pmap_map __P((vm_offset_t, vm_offset_t, vm_offset_t, int));
+void pmap_pageable __P((pmap_t,
+ vm_offset_t, vm_offset_t, boolean_t));
+vm_offset_t pmap_phys_address __P((int));
+void pmap_pinit __P((pmap_t));
+void pmap_reference __P((pmap_t));
+void pmap_release __P((pmap_t));
+void pmap_remove __P((pmap_t, vm_offset_t, vm_offset_t));
+void pmap_update __P((void));
+u_int pmap_free_pages __P((void));
+void pmap_init __P((void));
+boolean_t pmap_next_page __P((vm_offset_t *));
+int pmap_page_index __P((vm_offset_t));
+void pmap_virtual_space __P((vm_offset_t *, vm_offset_t *));
+void pmap_redzone __P((void));
+void kvm_uncache __P((caddr_t, int));
+struct user;
+void switchexit __P((vm_map_t, struct user *, int));
+int mmu_pagein __P((struct pmap *pm, int, int));
+#ifdef DEBUG
+int mmu_pagein4m __P((struct pmap *pm, int, int));
+#endif
+
+
+/* SUN4/SUN4C SPECIFIC DECLARATIONS */
+
+#if defined(SUN4) || defined(SUN4C)
+void pmap_clear_modify4_4c __P((vm_offset_t pa));
+void pmap_clear_reference4_4c __P((vm_offset_t pa));
+void pmap_copy_page4_4c __P((vm_offset_t, vm_offset_t));
+void pmap_enter4_4c __P((pmap_t,
+ vm_offset_t, vm_offset_t, vm_prot_t, boolean_t));
+vm_offset_t pmap_extract4_4c __P((pmap_t, vm_offset_t));
+boolean_t pmap_is_modified4_4c __P((vm_offset_t pa));
+boolean_t pmap_is_referenced4_4c __P((vm_offset_t pa));
+void pmap_page_protect4_4c __P((vm_offset_t, vm_prot_t));
+void pmap_protect4_4c __P((pmap_t,
+ vm_offset_t, vm_offset_t, vm_prot_t));
+void pmap_zero_page4_4c __P((vm_offset_t));
+void pmap_changeprot4_4c __P((pmap_t, vm_offset_t, vm_prot_t, int));
+
+#endif
+
+/* SIMILAR DECLARATIONS FOR SUN4M MODULE */
+
+#if defined(SUN4M)
+void pmap_clear_modify4m __P((vm_offset_t pa));
+void pmap_clear_reference4m __P((vm_offset_t pa));
+void pmap_copy_page4m __P((vm_offset_t, vm_offset_t));
+void pmap_enter4m __P((pmap_t,
+ vm_offset_t, vm_offset_t, vm_prot_t, boolean_t));
+vm_offset_t pmap_extract4m __P((pmap_t, vm_offset_t));
+boolean_t pmap_is_modified4m __P((vm_offset_t pa));
+boolean_t pmap_is_referenced4m __P((vm_offset_t pa));
+void pmap_page_protect4m __P((vm_offset_t, vm_prot_t));
+void pmap_protect4m __P((pmap_t,
+ vm_offset_t, vm_offset_t, vm_prot_t));
+void pmap_zero_page4m __P((vm_offset_t));
+void pmap_changeprot4m __P((pmap_t, vm_offset_t, vm_prot_t, int));
+
+#endif /* defined SUN4M */
+
+#if !defined(SUN4M) && (defined(SUN4) || defined(SUN4C))
+
+#define pmap_clear_modify pmap_clear_modify4_4c
+#define pmap_clear_reference pmap_clear_reference4_4c
+#define pmap_copy_page pmap_copy_page4_4c
+#define pmap_enter pmap_enter4_4c
+#define pmap_extract pmap_extract4_4c
+#define pmap_is_modified pmap_is_modified4_4c
+#define pmap_is_referenced pmap_is_referenced4_4c
+#define pmap_page_protect pmap_page_protect4_4c
+#define pmap_protect pmap_protect4_4c
+#define pmap_zero_page pmap_zero_page4_4c
+#define pmap_changeprot pmap_changeprot4_4c
+
+#elif defined(SUN4M) && !(defined(SUN4) || defined(SUN4C))
+
+#define pmap_clear_modify pmap_clear_modify4m
+#define pmap_clear_reference pmap_clear_reference4m
+#define pmap_copy_page pmap_copy_page4m
+#define pmap_enter pmap_enter4m
+#define pmap_extract pmap_extract4m
+#define pmap_is_modified pmap_is_modified4m
+#define pmap_is_referenced pmap_is_referenced4m
+#define pmap_page_protect pmap_page_protect4m
+#define pmap_protect pmap_protect4m
+#define pmap_zero_page pmap_zero_page4m
+#define pmap_changeprot pmap_changeprot4m
+
+#else /* must use function pointers */
+
+extern void (*pmap_clear_modify_p) __P((vm_offset_t pa));
+extern void (*pmap_clear_reference_p) __P((vm_offset_t pa));
+extern void (*pmap_copy_page_p) __P((vm_offset_t, vm_offset_t));
+extern void (*pmap_enter_p) __P((pmap_t,
+ vm_offset_t, vm_offset_t, vm_prot_t, boolean_t));
+extern vm_offset_t (*pmap_extract_p) __P((pmap_t, vm_offset_t));
+extern boolean_t (*pmap_is_modified_p) __P((vm_offset_t pa));
+extern boolean_t (*pmap_is_referenced_p) __P((vm_offset_t pa));
+extern void (*pmap_page_protect_p) __P((vm_offset_t, vm_prot_t));
+extern void (*pmap_protect_p) __P((pmap_t,
+ vm_offset_t, vm_offset_t, vm_prot_t));
+extern void (*pmap_zero_page_p) __P((vm_offset_t));
+extern void (*pmap_changeprot_p) __P((pmap_t, vm_offset_t,
+ vm_prot_t, int));
+
+#define pmap_clear_modify (*pmap_clear_modify_p)
+#define pmap_clear_reference (*pmap_clear_reference_p)
+#define pmap_copy_page (*pmap_copy_page_p)
+#define pmap_enter (*pmap_enter_p)
+#define pmap_extract (*pmap_extract_p)
+#define pmap_is_modified (*pmap_is_modified_p)
+#define pmap_is_referenced (*pmap_is_referenced_p)
+#define pmap_page_protect (*pmap_page_protect_p)
+#define pmap_protect (*pmap_protect_p)
+#define pmap_zero_page (*pmap_zero_page_p)
+#define pmap_changeprot (*pmap_changeprot_p)
+
+#endif
#endif /* _KERNEL */
diff --git a/sys/arch/sparc/include/profile.h b/sys/arch/sparc/include/profile.h
index c34287882bb..0a27b368163 100644
--- a/sys/arch/sparc/include/profile.h
+++ b/sys/arch/sparc/include/profile.h
@@ -1,4 +1,4 @@
-/* $NetBSD: profile.h,v 1.4 1995/08/14 15:44:36 pk Exp $ */
+/* $NetBSD: profile.h,v 1.6 1996/04/08 20:55:36 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -47,25 +47,26 @@
#ifdef PIC
/* Inline expansion of PICCY_SET() (see <machine/asm.h>). */
#define MCOUNT \
- __asm(".global mcount");\
- __asm("mcount:");\
- __asm("add %o7, 8, %o1");\
- __asm("1: call 2f; nop; 2:");\
- __asm("add %o7,__mcount-1b, %o2");\
- __asm("ld [%o2], %o2");\
- __asm("jmpl %o2, %g0");\
- __asm("add %i7, 8, %o0");
+ asm(".global mcount");\
+ asm("mcount:");\
+ asm("add %o7, 8, %o1");\
+ asm("1: call 2f; nop; 2:");\
+ asm("add %o7,__mcount-1b, %o2");\
+ asm("ld [%o2], %o2");\
+ asm("jmpl %o2, %g0");\
+ asm("add %i7, 8, %o0");
#else
#define MCOUNT \
- __asm(".global mcount");\
- __asm("mcount:");\
- __asm("add %i7, 8, %o0");\
- __asm("sethi %hi(__mcount), %o2");\
- __asm("jmpl %o2 + %lo(__mcount), %g0");\
- __asm("add %o7, 8, %o1");
+ asm(".global mcount");\
+ asm("mcount:");\
+ asm("add %i7, 8, %o0");\
+ asm("sethi %hi(__mcount), %o2");\
+ asm("jmpl %o2 + %lo(__mcount), %g0");\
+ asm("add %o7, 8, %o1");
#endif
#define _MCOUNT_DECL static void _mcount
+_MCOUNT_DECL __P((unsigned long, unsigned long));
#ifdef _KERNEL
/*
diff --git a/sys/arch/sparc/include/psl.h b/sys/arch/sparc/include/psl.h
index 9dc8b1baa26..a93b2724348 100644
--- a/sys/arch/sparc/include/psl.h
+++ b/sys/arch/sparc/include/psl.h
@@ -1,4 +1,4 @@
-/* $NetBSD: psl.h,v 1.7 1995/08/13 00:29:56 mycroft Exp $ */
+/* $NetBSD: psl.h,v 1.11 1996/03/31 22:20:14 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -77,25 +77,36 @@
#define PIL_CLOCK 10
-#if defined(_KERNEL) && !defined(LOCORE)
+#if defined(_KERNEL) && !defined(_LOCORE)
+
+static __inline int getpsr __P((void));
+static __inline void setpsr __P((int));
+static __inline int spl0 __P((void));
+static __inline int splhigh __P((void));
+static __inline void splx __P((int));
+
/*
* GCC pseudo-functions for manipulating PSR (primarily PIL field).
*/
-static __inline int getpsr() {
+static __inline int getpsr()
+{
int psr;
__asm __volatile("rd %%psr,%0" : "=r" (psr));
return (psr);
}
-static __inline void setpsr(int newpsr) {
+static __inline void setpsr(newpsr)
+ int newpsr;
+{
__asm __volatile("wr %0,0,%%psr" : : "r" (newpsr));
__asm __volatile("nop");
__asm __volatile("nop");
__asm __volatile("nop");
}
-static __inline int spl0() {
+static __inline int spl0()
+{
int psr, oldipl;
/*
@@ -121,10 +132,28 @@ static __inline int spl0() {
* into the ipl field.)
*/
#define SPL(name, newipl) \
-static __inline int name() { \
+static __inline int name __P((void)); \
+static __inline int name() \
+{ \
+ int psr, oldipl; \
+ __asm __volatile("rd %%psr,%0" : "=r" (psr)); \
+ oldipl = psr & PSR_PIL; \
+ psr &= ~oldipl; \
+ __asm __volatile("wr %0,%1,%%psr" : : \
+ "r" (psr), "n" ((newipl) << 8)); \
+ __asm __volatile("nop; nop; nop"); \
+ return (oldipl); \
+}
+/* A non-priority-decreasing version of SPL */
+#define SPLHOLD(name, newipl) \
+static __inline int name __P((void)); \
+static __inline int name() \
+{ \
int psr, oldipl; \
__asm __volatile("rd %%psr,%0" : "=r" (psr)); \
oldipl = psr & PSR_PIL; \
+ if ((newipl << 8) <= oldipl) \
+ return oldipl; \
psr &= ~oldipl; \
__asm __volatile("wr %0,%1,%%psr" : : \
"r" (psr), "n" ((newipl) << 8)); \
@@ -136,6 +165,17 @@ SPL(splsoftint, 1)
#define splsoftclock splsoftint
#define splsoftnet splsoftint
+/* audio software interrupts are at software level 4 */
+#define PIL_AUSOFT 4
+SPL(splausoft, PIL_AUSOFT)
+
+/* floppy software interrupts are at software level 4 too */
+#define PIL_FDSOFT 4
+SPL(splfdsoft, PIL_FDSOFT)
+
+/* Block devices */
+SPL(splbio, 5)
+
/* network hardware interrupts are at level 6 */
#define PIL_NET 6
SPL(splnet, PIL_NET)
@@ -144,18 +184,11 @@ SPL(splnet, PIL_NET)
#define PIL_TTY 6
SPL(spltty, PIL_TTY)
-/* Memory allocation (must be as high as highest network or tty device) */
+/*
+ * Memory allocation (must be as high as highest network, tty, or disk device)
+ */
SPL(splimp, 7)
-
-/* audio software interrupts are at software level 4 */
-#define PIL_AUSOFT 4
-SPL(splausoft, PIL_AUSOFT)
-
-/* floppy software interrupts are at software level 4 too */
-#define PIL_FDSOFT 4
-SPL(splfdsoft, PIL_FDSOFT)
-
-SPL(splbio, 9)
+SPLHOLD(splpmap, 7)
SPL(splclock, PIL_CLOCK)
@@ -171,7 +204,8 @@ SPL(splaudio, 13)
/* second sparc timer interrupts at level 14 */
SPL(splstatclock, 14)
-static __inline int splhigh() {
+static __inline int splhigh()
+{
int psr, oldipl;
__asm __volatile("rd %%psr,%0" : "=r" (psr));
@@ -182,7 +216,9 @@ static __inline int splhigh() {
}
/* splx does not have a return value */
-static __inline void splx(int newipl) {
+static __inline void splx(newipl)
+ int newipl;
+{
int psr;
__asm __volatile("rd %%psr,%0" : "=r" (psr));
@@ -190,6 +226,6 @@ static __inline void splx(int newipl) {
"r" (psr & ~PSR_PIL), "rn" (newipl));
__asm __volatile("nop; nop; nop");
}
-#endif /* KERNEL && !LOCORE */
+#endif /* KERNEL && !_LOCORE */
#endif /* PSR_IMPL */
diff --git a/sys/arch/sparc/include/pte.h b/sys/arch/sparc/include/pte.h
index 978e6a84d3a..7418188bb85 100644
--- a/sys/arch/sparc/include/pte.h
+++ b/sys/arch/sparc/include/pte.h
@@ -1,6 +1,8 @@
-/* $NetBSD: pte.h,v 1.12 1995/07/05 17:53:41 pk Exp $ */
+/* $NetBSD: pte.h,v 1.17 1996/05/16 15:57:03 abrown Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -9,7 +11,8 @@
* contributed to Berkeley.
*
* All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
+ * must display the following acknowledgements:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
@@ -22,7 +25,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
+ * must display the following acknowledgements:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
@@ -45,11 +49,11 @@
*/
/*
- * Sun-4 (sort of) and 4c (SparcStation) Page Table Entries
- * (Sun call them `Page Map Entries').
+ * Sun-4 (sort of), 4c (SparcStation), and 4m Page Table Entries
+ * (Sun calls them `Page Map Entries').
*/
-#ifndef LOCORE
+#ifndef _LOCORE
/*
* Segment maps contain `pmeg' (Page Map Entry Group) numbers.
* A PMEG is simply an index that names a group of 32 (sun4) or
@@ -83,6 +87,17 @@ typedef u_char smeg_t; /* 8 bits needed per Sun-4 regmap entry */
* (for sun4)
* 3. take the value from (2 or 3) above and concatenate va<17:13> to
* get a `page map entry' index. This gives a 32-bit PTE.
+ **
+ * For sun4m:
+ * 1. Use context_reg<3:0> to index the context table (located at
+ * (context_reg << 2) | ((ctx_tbl_ptr_reg >> 2) << 6) ). This
+ * gives a 32-bit page-table-descriptor (PTP).
+ * 2. Use va<31:24> to index the region table located by the PTP from (1):
+ * PTP<31:6> << 10. This gives another PTP for the segment tables
+ * 3. Use va<23:18> to index the segment table located by the PTP from (2)
+ * as follows: PTP<31:4> << 8. This gives another PTP for the page tbl.
+ * 4. Use va<17:12> to index the page table given by (3)'s PTP:
+ * PTP<31:4> << 8. This gives a 32-bit PTE.
*
* In other words:
*
@@ -105,14 +120,46 @@ typedef u_char smeg_t; /* 8 bits needed per Sun-4 regmap entry */
* va_off:12; (offset within page)
* };
*
+ * struct sun4m_virtual_addr {
+ * u_int va_reg:8, (virtual region)
+ * va_seg:6, (virtual segment within region)
+ * va_pg:6, (virtual page within segment)
+ * va_off:12; (offset within page)
+ * };
+ *
* Then, given any `va':
*
* extern smeg_t regmap[16][1<<8]; (3-level MMU only)
* extern pmeg_t segmap[8][1<<12]; ([16][1<<12] for sun4)
* extern int ptetable[128][1<<6]; ([512][1<<5] for sun4)
*
- * (the above being in the hardware, accessed as Alternate Address Spaces)
+ * extern u_int s4m_ctxmap[16]; (sun4m SRMMU only)
+ * extern u_int s4m_regmap[16][1<<8]; (sun4m SRMMU only)
+ * extern u_int s4m_segmap[1<<8][1<<6]; (sun4m SRMMU only)
+ * extern u_int s4m_pagmap[1<<14][1<<6]; (sun4m SRMMU only)
+ *
+ * (the above being in the hardware, accessed as Alternate Address Spaces on
+ * all machines but the Sun4m SRMMU, in which case the tables are in physical
+ * kernel memory. In the 4m architecture, the tables are not layed out as
+ * 2-dim arrays, but are sparsely allocated as needed, and point to each
+ * other.)
*
+ * if (cputyp==CPU_SUN4M) // SPARC Reference MMU
+ * regptp = s4m_ctxmap[curr_ctx];
+ * if (!(regptp & SRMMU_TEPTD)) TRAP();
+ * segptp = *(u_int *)(((regptp & ~0x3) << 4) | va.va_reg);
+ * if (!(segptp & SRMMU_TEPTD)) TRAP();
+ * pagptp = *(u_int *)(((segptp & ~0x3) << 4) | va.va_seg);
+ * if (!(pagptp & SRMMU_TEPTD)) TRAP();
+ * pte = *(u_int *)(((pagptp & ~0x3) << 4) | va.va_pg);
+ * if (!(pte & SRMMU_TEPTE)) TRAP(); // like PG_V
+ * if (usermode && PTE_PROT_LEVEL(pte) > 0x5) TRAP();
+ * if (writing && !PTE_PROT_LEVEL_ALLOWS_WRITING(pte)) TRAP();
+ * if (!(pte & SRMMU_PG_C)) DO_NOT_USE_CACHE_FOR_THIS_ACCESS();
+ * pte |= SRMMU_PG_U;
+ * if (writing) pte |= PG_M;
+ * physaddr = ((pte & SRMMU_PG_PFNUM) << SRMMU_PGSHIFT)|va.va_off;
+ * return;
* if (mmu_3l)
* physreg = regmap[curr_ctx][va.va_reg];
* physseg = segmap[physreg][va.va_seg];
@@ -147,7 +194,7 @@ extern int mmu_3l;
#define SGOFSET (NBPSG - 1) /* mask for segment offset */
/* number of PTEs that map one segment (not number that fit in one segment!) */
-#if defined(SUN4) && defined(SUN4C)
+#if defined(SUN4) && (defined(SUN4C) || defined(SUN4M))
extern int nptesg;
#define NPTESG nptesg /* (which someone will have to initialize) */
#else
@@ -163,6 +210,12 @@ extern int nptesg;
/* virtual address to virtual page number, for Sun-4 and Sun-4c */
#define VA_SUN4_VPG(va) (((int)(va) >> 13) & 31)
#define VA_SUN4C_VPG(va) (((int)(va) >> 12) & 63)
+#define VA_SUN4M_VPG(va) (((int)(va) >> 12) & 63)
+
+/* virtual address to offset within page */
+#define VA_SUN4_OFF(va) (((int)(va)) & 0x1FFF)
+#define VA_SUN4C_OFF(va) (((int)(va)) & 0xFFF)
+#define VA_SUN4M_OFF(va) (((int)(va)) & 0xFFF)
/* truncate virtual address to region base */
#define VA_ROUNDDOWNTOREG(va) ((int)(va) & ~RGOFSET)
@@ -171,16 +224,29 @@ extern int nptesg;
#define VA_ROUNDDOWNTOSEG(va) ((int)(va) & ~SGOFSET)
/* virtual segment to virtual address (must sign extend on holy MMUs!) */
-#if defined(MMU_3L)
-#define VRTOVA(vr) (mmu_3l \
+#if defined(SUN4M) && !(defined(SUN4C) || defined(SUN4))
+#define VRTOVA(vr) ((int)(vr) << RGSHIFT)
+#define VSTOVA(vr,vs) (((int)(vr) << RGSHIFT) + ((int)(vs) << SGSHIFT))
+#else
+#if defined(MMU_3L) || defined(SUN4M) /* hairy.. */
+#if !defined(MMU_3L)
+#define _PTE_HAIRY_3L_TEST (cputyp==CPU_SUN4M)
+#elif !defined(SUN4M)
+#define _PTE_HAIRY_3L_TEST (mmu_3l)
+#else
+#define _PTE_HAIRY_3L_TEST (mmu_3l || cputyp==CPU_SUN4M)
+#endif
+#define VRTOVA(vr) (_PTE_HAIRY_3L_TEST \
? ((int)(vr) << RGSHIFT) \
: (((int)(vr) << (RGSHIFT+2)) >> 2))
-#define VSTOVA(vr,vs) (mmu_3l \
- ? (((int)vr << RGSHIFT) + ((int)vs << SGSHIFT)) \
- : ((((int)vr << (RGSHIFT+2)) >> 2) + ((int)vs << SGSHIFT)))
+#define VSTOVA(vr,vs) (_PTE_HAIRY_3L_TEST \
+ ? (((int)(vr) << RGSHIFT) + ((int)(vs) << SGSHIFT)) \
+ : ((((int)(vr) << (RGSHIFT+2)) >> 2) + ((int)(vs) << SGSHIFT)))
#else
-#define VRTOVA(vr) (((int)vr << (RGSHIFT+2)) >> 2)
-#define VSTOVA(vr,vs) ((((int)vr << (RGSHIFT+2)) >> 2) + ((int)vs << SGSHIFT))
+#define VRTOVA(vr) (((int)(vr) << (RGSHIFT+2)) >> 2)
+#define VSTOVA(vr,vs) ((((int)(vr) << (RGSHIFT+2)) >> 2) + \
+ ((int)(vs) << SGSHIFT))
+#endif
#endif
extern int mmu_has_hole;
@@ -192,17 +258,30 @@ extern int mmu_has_hole;
#define MMU_HOLE_START 0x20000000
#define MMU_HOLE_END 0xe0000000
+#if defined(SUN4M) /* Optimization: sun4m, sun4c have same page */
+#if defined(SUN4) /* size, so they're used interchangeably */
+#define VA_VPG(va) (cputyp==CPU_SUN4 ? VA_SUN4_VPG(va) : VA_SUN4C_VPG(va))
+#define VA_OFF(VA) (cputyp==CPU_SUN4 ? VA_SUN4_OFF(va) : VA_SUN4C_OFF(va))
+#else
+#define VA_VPG(va) VA_SUN4M_VPG(va)
+#define VA_OFF(va) VA_SUN4M_OFF(va)
+#endif /* defined SUN4 */
+#else /* 4m not defined */
#if defined(SUN4) && defined(SUN4C)
#define VA_VPG(va) (cputyp==CPU_SUN4C ? VA_SUN4C_VPG(va) : VA_SUN4_VPG(va))
+#define VA_OFF(va) (cputyp==CPU_SUN4C ? VA_SUN4C_OFF(va) : VA_SUN4_OFF(va))
#endif
#if defined(SUN4C) && !defined(SUN4)
#define VA_VPG(va) VA_SUN4C_VPG(va)
+#define VA_OFF(va) VA_SUN4C_OFF(va)
#endif
#if !defined(SUN4C) && defined(SUN4)
#define VA_VPG(va) VA_SUN4_VPG(va)
+#define VA_OFF(va) VA_SUN4_OFF(va)
#endif
+#endif /* defined 4m */
-/* there is no `struct pte'; we just use `int' */
+/* there is no `struct pte'; we just use `int'; this is for non-4M only */
#define PG_V 0x80000000
#define PG_PROT 0x60000000 /* both protection bits */
#define PG_W 0x40000000 /* allowed to write */
@@ -212,20 +291,23 @@ extern int mmu_has_hole;
#define PG_OBMEM 0x00000000 /* on board memory */
#define PG_OBIO 0x04000000 /* on board I/O (incl. Sbus on 4c) */
-#ifdef SUN4
#define PG_VME16 0x08000000 /* 16-bit-data VME space */
#define PG_VME32 0x0c000000 /* 32-bit-data VME space */
+#if defined(SUN4M)
+#define PG_SUN4M_OBMEM 0x0 /* No type bits=>obmem on 4m */
+#define PG_SUN4M_OBIO 0xf /* obio maps to 0xf on 4M */
+#define SRMMU_PGTYPE 0xf0000000 /* Top 4 bits of pte PPN give type */
#endif
#define PG_U 0x02000000
#define PG_M 0x01000000
-#define PG_IOC 0x00800000 /* IO-cacheable */
+#define PG_IOC 0x00800000
#define PG_MBZ 0x00780000 /* unused; must be zero (oh really?) */
#define PG_PFNUM 0x0007ffff /* n.b.: only 16 bits on sun4c */
#define PG_TNC_SHIFT 26 /* shift to get PG_TYPE + PG_NC */
#define PG_M_SHIFT 24 /* shift to get PG_M, PG_U */
-
+#define PG_M_SHIFT4M 5 /* shift to get SRMMU_PG_M,R on 4m */
/*efine PG_NOACC 0 ** XXX */
#define PG_KR 0x20000000
#define PG_KW 0x60000000
@@ -245,6 +327,18 @@ struct pte {
pg_mbz:5,
pg_pfnum:19;
};
+#if defined(SUN4M)
+struct srmmu_pte {
+ u_int pg_pfnum:20,
+ pg_c:1,
+ pg_m:1,
+ pg_u:1;
+ enum pgprot { pprot_r_r, pprot_rw_rw, pprot_rx_rx, pprot_rwx_rwx,
+ pprot_x_x, pprot_r_rw, pprot_n_rx, pprot_n_rwx }
+ pg_prot:3; /* prot. bits: pprot_<user>_<supervisor> */
+ u_int pg_must_be_2:2;
+};
+#endif
#endif
/*
@@ -258,48 +352,61 @@ struct pte {
#define PG_PROTUWRITE 6 /* PG_V,PG_W,!PG_S */
#define PG_PROTUREAD 4 /* PG_V,!PG_W,!PG_S */
+/* %%%: Fix above and below for 4m? */
+
/* static __inline int PG_VALID(void *va) {
register int t = va; t >>= PG_VSHIFT; return (t == 0 || t == -1);
} */
-#if defined(SUN4M)
-
-/*
- * Reference MMU PTE bits.
- */
-#define SRPTE_PPN_MASK 0x07ffff00
-#define SRPTE_PPN_SHIFT 8
-#define SRPTE_CACHEABLE 0x00000080 /* Page is cacheable */
-#define SRPTE_MOD 0x00000040 /* Page is modified */
-#define SRPTE_REF 0x00000020 /* Page is referenced */
-#define SRPTE_ACCMASK 0x0000001c /* Access rights mask */
-#define SRPTE_ACCSHIFT 2 /* Access rights shift */
-#define SRPTE_TYPEMASK 0x00000003 /* PTE Type */
-#define SRPTE_PTE 0x00000002 /* A PTE (Page Table Entry) */
-#define SRPTE_PTP 0x00000001 /* A PTP (Page Table Pointer) */
/*
- * Reference MMU access permission bits.
- * format: SRACC_sssuuu,
- * where <sss> denote the supervisor rights
- * and <uuu> denote the user rights
+ * Here are the bit definitions for 4M/SRMMU pte's
*/
-#define SRACC_R__R__ 0
-#define SRACC_RW_RW_ 1
-#define SRACC_R_XR_X 2
-#define SRACC_RWXRWX 3
-#define SRACC___X__X 4
-#define SRACC_RW_R__ 5
-#define SRACC_R_X___ 6
-#define SRACC_RWX___ 7
+ /* MMU TABLE ENTRIES */
+#define SRMMU_TEINVALID 0x0 /* invalid (serves as !valid bit) */
+#define SRMMU_TEPTD 0x1 /* Page Table Descriptor */
+#define SRMMU_TEPTE 0x2 /* Page Table Entry */
+#define SRMMU_TERES 0x3 /* reserved */
+#define SRMMU_TETYPE 0x3 /* mask for table entry type */
+ /* PTE FIELDS */
+#define SRMMU_PPNMASK 0xFFFFFF00
+#define SRMMU_PPNSHIFT 0x8
+#define SRMMU_PPNPASHIFT 0x4 /* shift to put ppn into PAddr */
+#define SRMMU_L1PPNSHFT 0x14
+#define SRMMU_L1PPNMASK 0xFFF00000
+#define SRMMU_L2PPNSHFT 0xE
+#define SRMMU_L2PPNMASK 0xFC000
+#define SRMMU_L3PPNSHFT 0x8
+#define SRMMU_L3PPNMASK 0x3F00
+ /* PTE BITS */
+#define SRMMU_PG_C 0x80 /* cacheable */
+#define SRMMU_PG_M 0x40 /* modified (dirty) */
+#define SRMMU_PG_R 0x20 /* referenced */
+#define SRMMU_PGBITSMSK 0xE0
+ /* PTE PROTECTION */
+#define SRMMU_PROT_MASK 0x1C /* Mask protection bits out of pte */
+#define SRMMU_PROT_SHFT 0x2
+#define PPROT_R_R 0x0 /* These are in the form: */
+#define PPROT_RW_RW 0x4 /* PPROT_<u>_<s> */
+#define PPROT_RX_RX 0x8 /* where <u> is the user-mode */
+#define PPROT_RWX_RWX 0xC /* permission, and <s> is the */
+#define PPROT_X_X 0x10 /* supervisor mode permission. */
+#define PPROT_R_RW 0x14 /* R=read, W=write, X=execute */
+#define PPROT_N_RX 0x18 /* N=none. */
+#define PPROT_N_RWX 0x1C
+#define PPROT_WRITE 0x4 /* set iff write priv. allowed */
+#define PPROT_S 0x18 /* effective S bit */
+#define PPROT_U2S_OMASK 0x18 /* OR with prot. to revoke user priv */
+ /* TABLE SIZES */
+#define SRMMU_L1SIZE 0x100
+#define SRMMU_L2SIZE 0x40
+#define SRMMU_L3SIZE 0x40
/*
* IOMMU PTE bits.
*/
-#define IOPTE_PPN_MASK 0x07ffff00
-#define IOPTE_PPN_SHIFT 8
-#define IOPTE_RSVD 0x000000f1
-#define IOPTE_WRITE 0x00000004
-#define IOPTE_VALID 0x00000002
-
-#endif /* SUN4M */
+#define IOPTE_PPN_MASK 0x07ffff00
+#define IOPTE_PPN_SHIFT 8
+#define IOPTE_RSVD 0x000000f1
+#define IOPTE_WRITE 0x00000004
+#define IOPTE_VALID 0x00000002
diff --git a/sys/arch/sparc/include/signal.h b/sys/arch/sparc/include/signal.h
index 1dad46faf47..e8339c38520 100644
--- a/sys/arch/sparc/include/signal.h
+++ b/sys/arch/sparc/include/signal.h
@@ -1,4 +1,4 @@
-/* $NetBSD: signal.h,v 1.3 1995/01/10 19:01:46 jtc Exp $ */
+/* $NetBSD: signal.h,v 1.4 1996/02/01 22:32:35 mycroft Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -47,12 +47,12 @@
#ifndef _SPARC_SIGNAL_H_
#define _SPARC_SIGNAL_H_
-#ifndef LOCORE
+#ifndef _LOCORE
typedef int sig_atomic_t;
#endif
#ifndef _ANSI_SOURCE
-#ifndef LOCORE
+#ifndef _LOCORE
/*
* Information pushed on stack when a signal is delivered.
@@ -74,14 +74,14 @@ struct sigcontext {
int sc_g1; /* %g1 to restore */
int sc_o0; /* %o0 to restore */
};
-#else /* LOCORE */
+#else /* _LOCORE */
#define SC_SP_OFFSET 8
#define SC_PC_OFFSET 12
#define SC_NPC_OFFSET 16
#define SC_PSR_OFFSET 20
#define SC_G1_OFFSET 24
#define SC_O0_OFFSET 28
-#endif /* LOCORE */
+#endif /* _LOCORE */
/*
* `Code' arguments to signal handlers. The names, and the funny numbering.
diff --git a/sys/arch/sparc/include/sun_disklabel.h b/sys/arch/sparc/include/sun_disklabel.h
index e1070bcf273..8f01b84115d 100644
--- a/sys/arch/sparc/include/sun_disklabel.h
+++ b/sys/arch/sparc/include/sun_disklabel.h
@@ -51,9 +51,9 @@
#define SUN_DKMAGIC 55998
/* These are the guys that Sun's dkinfo needs... */
-#define SUNOS_DKIOCGGEOM _IOR('d', 2, struct sun_dkgeom) /* geometry info */
-#define SUNOS_DKIOCINFO _IOR('d', 8, struct sun_dkctlr) /* controller info */
-#define SUNOS_DKIOCGPART _IOR('d', 4, struct sun_dkpart) /* partition info */
+#define DKIOCGGEOM _IOR('d', 2, struct sun_dkgeom) /* geometry info */
+#define DKIOCINFO _IOR('d', 8, struct sun_dkctlr) /* controller info */
+#define DKIOCGPART _IOR('d', 4, struct sun_dkpart) /* partition info */
/* geometry info */
struct sun_dkgeom {
@@ -108,8 +108,8 @@ struct sun_disklabel { /* total size = 512 bytes */
#ifdef _KERNEL
/* reads sun label in sector at [cp..cp+511] and sets *lp to BSD label */
-int sunos_disklabel __P((caddr_t, struct disklabel *)); /* true on success */
+int sun_disklabel __P((caddr_t, struct disklabel *)); /* true on success */
/* compatability dk ioctl's */
-int sunos_dkioctl __P((struct disk *, u_long, caddr_t, int));
+int sun_dkioctl __P((struct disk *, u_long, caddr_t, int));
#endif
diff --git a/sys/arch/sparc/include/svr4_machdep.h b/sys/arch/sparc/include/svr4_machdep.h
index f8c52bab9bd..d2687a7a896 100644
--- a/sys/arch/sparc/include/svr4_machdep.h
+++ b/sys/arch/sparc/include/svr4_machdep.h
@@ -1,4 +1,4 @@
-/* $NetBSD: svr4_machdep.h,v 1.1 1995/03/31 02:55:59 christos Exp $ */
+/* $NetBSD: svr4_machdep.h,v 1.4 1996/03/31 22:21:45 pk Exp $ */
/*
* Copyright (c) 1994 Christos Zoulas
@@ -64,7 +64,7 @@
typedef int svr4_greg_t;
-typedef struct {
+typedef struct {
svr4_greg_t rwin_lo[8];
svr4_greg_t rwin_in[8];
} svr4_rwindow_t;
@@ -78,7 +78,10 @@ typedef struct {
typedef svr4_greg_t svr4_gregset_t[SVR4_SPARC_MAXREG];
typedef struct {
- double fpu_regs[32];
+ union {
+ u_int fp_ri[32];
+ double fp_rd[16];
+ } fpu_regs;
void *fp_q;
unsigned fp_fsr;
u_char fp_nqel;
@@ -99,5 +102,6 @@ void svr4_getcontext __P((struct proc *, struct svr4_ucontext *,
int, int));
int svr4_setcontext __P((struct proc *p, struct svr4_ucontext *));
void svr4_sendsig __P((sig_t, int, int, u_long));
+int svr4_trap __P((int, struct proc *));
#endif /* !_SPARC_SVR4_MACHDEP_H_ */
diff --git a/sys/arch/sparc/include/trap.h b/sys/arch/sparc/include/trap.h
index 9c1f1529592..86c45589f80 100644
--- a/sys/arch/sparc/include/trap.h
+++ b/sys/arch/sparc/include/trap.h
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.h,v 1.6 1995/07/04 22:58:51 christos Exp $ */
+/* $NetBSD: trap.h,v 1.9 1996/05/16 15:57:04 abrown Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -43,6 +43,11 @@
*
* @(#)trap.h 8.1 (Berkeley) 6/11/93
*/
+/*
+ * Sun4m support by Aaron Brown, Harvard University.
+ * Changes Copyright (c) 1995 The President and Fellows of Harvard College.
+ * All rights reserved.
+ */
#ifndef _MACHINE_TRAP_H
#define _MACHINE_TRAP_H
@@ -87,6 +92,9 @@
/* through 0x27 unused */
#define T_CPEXCEPTION 0x28 /* (9) coprocessor exception */
/* 0x29 unused */
+/* through 0x2a unused */
+#define T_STOREBUFFAULT 0x2b /* SuperSPARC: Store buffer copy-back fault */
+/* 0x2c unused */
/* through 0x7f unused */
/* beginning of `user' vectors (from trap instructions) - all priority 12 */
diff --git a/sys/arch/sparc/include/types.h b/sys/arch/sparc/include/types.h
index 4ac77b33791..b9d0a0a6914 100644
--- a/sys/arch/sparc/include/types.h
+++ b/sys/arch/sparc/include/types.h
@@ -1,4 +1,4 @@
-/* $NetBSD: types.h,v 1.8 1995/12/09 04:41:51 mycroft Exp $ */
+/* $NetBSD: types.h,v 1.9 1996/03/14 00:48:30 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -73,13 +73,9 @@ typedef short int16_t;
typedef unsigned short u_int16_t;
typedef int int32_t;
typedef unsigned int u_int32_t;
-/* LONGLONG */
typedef long long int64_t;
-/* LONGLONG */
typedef unsigned long long u_int64_t;
typedef int32_t register_t;
-#define __FORK_BRAINDAMAGE
-
#endif /* _MACHTYPES_H_ */
diff --git a/sys/arch/sparc/include/vmparam.h b/sys/arch/sparc/include/vmparam.h
index ef899abd76a..78ce9c97cee 100644
--- a/sys/arch/sparc/include/vmparam.h
+++ b/sys/arch/sparc/include/vmparam.h
@@ -1,4 +1,4 @@
-/* $NetBSD: vmparam.h,v 1.6 1995/07/05 18:04:48 pk Exp $ */
+/* $NetBSD: vmparam.h,v 1.10 1996/03/14 19:49:20 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -140,8 +140,8 @@
#define MACHINE_NONCONTIG /* VM <=> pmap interface modifier */
-#if defined (_KERNEL) && !defined(LOCORE)
+#if defined (_KERNEL) && !defined(_LOCORE)
struct vm_map;
vm_offset_t dvma_mapin __P((struct vm_map *, vm_offset_t, int, int));
-int dvma_mapout __P((vm_offset_t, vm_offset_t, int));
+void dvma_mapout __P((vm_offset_t, vm_offset_t, int));
#endif
diff --git a/sys/arch/sparc/sparc/amd7930intr.s b/sys/arch/sparc/sparc/amd7930intr.s
index eaaf1656c2d..001695ab6cf 100644
--- a/sys/arch/sparc/sparc/amd7930intr.s
+++ b/sys/arch/sparc/sparc/amd7930intr.s
@@ -44,10 +44,7 @@
*/
#ifndef AUDIO_C_HANDLER
-#ifndef LOCORE
-#define LOCORE
-#endif
-#include "assym.s"
+#include "assym.h"
#include <sparc/sparc/intreg.h>
/* XXX this goes in a header file -- currently, it's hidden in locore.s */
#define INTREG_ADDR 0xf8002000
@@ -95,14 +92,14 @@ _amd7930_trap:
cmp R_data, R_end
bgu 1f
nop
-
+
ldub [R_amd + AMD_BBRB], %l6 ! *d = amd->bbrb
stb %l6, [ R_data ]
cmp R_data, R_end
inc R_data ! au->au_rdata++
bne 1f ! if (d == e)
st R_data, [%l7 + AU_RDATA]
-
+
sethi %hi(INTREG_ADDR), %l5
ldub [%l5 + %lo(INTREG_ADDR)], %l6
or %l6, IE_L4, %l6
@@ -118,7 +115,7 @@ _amd7930_trap:
cmp R_data, R_end
bgu 2f
nop
-
+
ldub [ R_data ], %l6 ! amd->bbtb = *d
stb %l6, [ R_amd + AMD_BBTB ]
@@ -126,7 +123,7 @@ _amd7930_trap:
inc R_data ! au->au_pdata++
bne 2f ! if (d == e)
st R_data, [%l7 + AU_PDATA]
-
+
sethi %hi(INTREG_ADDR), %l5
ldub [%l5 + %lo(INTREG_ADDR)], %l6
or %l6, IE_L4, %l6
diff --git a/sys/arch/sparc/sparc/autoconf.c b/sys/arch/sparc/sparc/autoconf.c
index fde266bbeae..d5fc9eaf742 100644
--- a/sys/arch/sparc/sparc/autoconf.c
+++ b/sys/arch/sparc/sparc/autoconf.c
@@ -1,35 +1,8 @@
-/* $NetBSD: autoconf.c,v 1.38 1995/10/09 22:34:03 pk Exp $ */
+/* $NetBSD: autoconf.c,v 1.58.2.2 1996/07/02 23:49:54 jtc Exp $ */
/*
- * Copyright (c) 1995 Theo de Raadt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed under OpenBSD by
- * Theo de Raadt for Willowglen Singapore.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -39,6 +12,7 @@
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
@@ -74,6 +48,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/map.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
@@ -84,16 +59,15 @@
#include <sys/dmap.h>
#include <sys/reboot.h>
#include <sys/socket.h>
-#include <sys/systm.h>
-
-#include "fd.h"
-#if NFD > 0
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
-#endif /* NFD */
+#include <sys/malloc.h>
+#include <sys/queue.h>
#include <net/if.h>
+#include <dev/cons.h>
+
+#include <vm/vm.h>
+
#include <machine/autoconf.h>
#include <machine/bsd_openprom.h>
#ifdef SUN4
@@ -102,6 +76,17 @@
#include <sparc/sparc/memreg.h>
#endif
#include <machine/cpu.h>
+#include <machine/ctlreg.h>
+#include <machine/pmap.h>
+#include <sparc/sparc/asm.h>
+#include <sparc/sparc/timerreg.h>
+
+#ifdef DDB
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_extern.h>
+#endif
+
/*
* The following several variables are related to
@@ -111,26 +96,44 @@
int cold; /* if 1, still working on cold-start */
int fbnode; /* node ID of ROM's console frame buffer */
int optionsnode; /* node ID of ROM's options */
-int cpumod; /* CPU model, valid only if cputyp==CPU_SUN4 */
int mmu_3l; /* SUN4_400 models have a 3-level MMU */
-extern struct promvec *promvec;
-
#ifdef KGDB
-extern int kgdb_debug_panic;
+extern int kgdb_debug_panic;
#endif
static int rootnode;
-int findroot __P((void));
void setroot __P((void));
+static char *str2hex __P((char *, int *));
static int getstr __P((char *, int));
static int findblkmajor __P((struct device *));
static struct device *getdisk __P((char *, int, int, dev_t *));
+static int mbprint __P((void *, char *));
+static void crazymap __P((char *, int *));
+int st_crazymap __P((int));
+void swapconf __P((void));
+void sync_crash __P((void));
+int mainbus_match __P((struct device *, void *, void *));
+static void mainbus_attach __P((struct device *, struct device *, void *));
struct bootpath bootpath[8];
+int nbootpath;
static void bootpath_build __P((void));
static void bootpath_fake __P((struct bootpath *, char *));
static void bootpath_print __P((struct bootpath *));
+int search_prom __P((int, char *));
+
+/*
+ * The mountroot_hook is provided as a mechanism for devices to perform
+ * a special function if they're the root device, such as the floppy
+ * drive ejecting the current disk and prompting for a filesystem floppy.
+ */
+struct mountroot_hook {
+ LIST_ENTRY(mountroot_hook) mr_link;
+ struct device *mr_device;
+ void (*mr_func) __P((struct device *));
+};
+LIST_HEAD(, mountroot_hook) mrh_list;
/*
* Most configuration on the SPARC is done by matching OPENPROM Forth
@@ -144,13 +147,11 @@ matchbyname(parent, vcf, aux)
struct cfdata *cf = vcf;
struct confargs *ca = aux;
-#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
printf("WARNING: matchbyname not valid on sun4!");
printf("%s\n", cf->cf_driver->cd_name);
return (0);
}
-#endif
return (strcmp(cf->cf_driver->cd_name, ca->ca_ra.ra_name) == 0);
}
@@ -199,14 +200,13 @@ void getidprom __P((struct idprom *, int size));
void
bootstrap()
{
- int nregion, nsegment, ncontext, node;
+ int nregion = 0, nsegment = 0, ncontext = 0;
extern int msgbufmapped;
#if defined(SUN4)
- extern void oldmon_w_cmd();
- extern struct msgbuf *msgbufp;
-
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
+ extern void oldmon_w_cmd __P((u_long, char *));
+ extern struct msgbuf *msgbufp;
/*
* XXX
* Some boot programs mess up physical page 0, which
@@ -269,50 +269,186 @@ bootstrap()
}
}
#endif /* SUN4 */
-#if defined(SUN4C) || defined(SUN4M)
- if (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) {
- node = findroot();
+
+#if defined(SUN4C)
+ if (CPU_ISSUN4C) {
+ register int node = findroot();
nsegment = getpropint(node, "mmu-npmg", 128);
ncontext = getpropint(node, "mmu-nctx", 8);
}
-#endif /* SUN4C || SUN4M */
+#endif /* SUN4C */
+
+#if defined (SUN4M)
+ if (CPU_ISSUN4M) {
+ nsegment = 0;
+ cpumod = (u_int) getpsr() >> 24;
+ mmumod = (u_int) lda(SRMMU_PCR, ASI_SRMMU) >> 28;
+ /*
+ * We use the max. number of contexts on the micro and
+ * hyper SPARCs. The SuperSPARC would let us use up to 65536
+ * contexts (by powers of 2), but we keep it at 4096 since
+ * the table must be aligned to #context*4. With 4K contexts,
+ * we waste at most 16K of memory. Note that the context
+ * table is *always* page-aligned, so there can always be
+ * 1024 contexts without sacrificing memory space (given
+ * that the chip supports 1024 contexts).
+ *
+ * Currently known limits: MS2=256, HS=4096, SS=65536
+ * some old SS's=4096
+ *
+ * XXX Should this be a tuneable parameter?
+ */
+ switch (mmumod) {
+ case SUN4M_MMU_MS1:
+ ncontext = 64;
+ break;
+ case SUN4M_MMU_MS:
+ ncontext = 256;
+ break;
+ default:
+ ncontext = 4096;
+ break;
+ }
+ }
+#endif /* SUN4M */
+
pmap_bootstrap(ncontext, nregion, nsegment);
- msgbufmapped = 1;
+ msgbufmapped = 1; /* enable message buffer */
#ifdef KGDB
- zs_kgdb_init(); /* XXX */
+ zs_kgdb_init(); /* XXX */
#endif
#ifdef DDB
db_machine_init();
ddb_init();
#endif
-}
+ /*
+ * On sun4ms we have to do some nasty stuff here. We need to map
+ * in the interrupt registers (since we need to find out where
+ * they are from the PROM, since they aren't in a fixed place), and
+ * disable all interrupts. We can't do this easily from locore
+ * since the PROM is ugly to use from assembly. We also need to map
+ * in the counter registers because we can't disable the level 14
+ * (statclock) interrupt, so we need a handler early on (ugh).
+ *
+ * NOTE: We *demand* the psl to stay at splhigh() at least until
+ * we get here. The system _cannot_ take interrupts until we map
+ * the interrupt registers.
+ */
+
+#if defined(SUN4M)
+#define getpte4m(va) lda(((va) & 0xFFFFF000) | ASI_SRMMUFP_L3, ASI_SRMMUFP)
+
+ /* First we'll do the interrupt registers */
+ if (CPU_ISSUN4M) {
+ register int node;
+ struct romaux ra;
+ register u_int pte;
+ register int i;
+ extern void setpte4m __P((u_int, u_int));
+ extern struct timer_4m *timerreg_4m;
+ extern struct counter_4m *counterreg_4m;
+
+ if ((node = opennode("/obio/interrupt")) == 0)
+ if ((node=search_prom(findroot(),"interrupt"))==0)
+ panic("bootstrap: could not get interrupt "
+ "node from prom");
+
+ if (!romprop(&ra, "interrupt", node))
+ panic("bootstrap: could not get interrupt properties");
+ if (ra.ra_nvaddrs < 2)
+ panic("bootstrap: less than 2 interrupt regs. available");
+ if (ra.ra_nvaddrs > 5)
+ panic("bootstrap: cannot support capability of > 4 CPUs");
+
+ for (i = 0; i < ra.ra_nvaddrs - 1; i++) {
+
+ pte = getpte4m((u_int)ra.ra_vaddrs[i]);
+ if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
+ panic("bootstrap: PROM has invalid mapping for "
+ "processor interrupt register %d",i);
+ pte |= PPROT_S;
+
+ /* Duplicate existing mapping */
+
+ setpte4m(PI_INTR_VA + (_MAXNBPG * i), pte);
+ }
+
+ /*
+ * That was the processor register...now get system register;
+ * it is the last returned by the PROM
+ */
+ pte = getpte4m((u_int)ra.ra_vaddrs[i]);
+ if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
+ panic("bootstrap: PROM has invalid mapping for system "
+ "interrupt register");
+ pte |= PPROT_S;
+
+ setpte4m(SI_INTR_VA, pte);
+
+ /* Now disable interrupts */
+ ienab_bis(SINTR_MA);
+
+ /* Send all interrupts to primary processor */
+ *((u_int *)ICR_ITR) = 0;
+
+#ifdef DEBUG
+/* printf("SINTR: mask: 0x%x, pend: 0x%x\n", *(int*)ICR_SI_MASK,
+ *(int*)ICR_SI_PEND);
+*/
+#endif
+
+ /*
+ * Now map in the counters
+ * (XXX: fix for multiple CPUs! We assume 1)
+ * The processor register is the first; the system is the last.
+ * See also timerattach() in clock.c.
+ * This shouldn't be necessary; we ought to keep interrupts off
+ * and/or disable the (level 14) counter...
+ */
+
+ if ((node = opennode("/obio/counter")) == 0)
+ if ((node=search_prom(findroot(),"counter"))==0)
+ panic("bootstrap: could not find counter in OPENPROM");
+
+ if (!romprop(&ra, "counter", node))
+ panic("bootstrap: could not find counter properties");
+
+ counterreg_4m = (struct counter_4m *)ra.ra_vaddrs[0];
+ timerreg_4m = (struct timer_4m *)ra.ra_vaddrs[ra.ra_nvaddrs-1];
+ }
+#endif /* SUN4M */
+}
/*
* bootpath_build: build a bootpath. Used when booting a generic
* kernel to find our root device. Newer proms give us a bootpath,
* for older proms we have to create one. An element in a bootpath
- * has 3 fields: name (device name), val[0], and val[1]. Note that:
+ * has 4 fields: name (device name), val[0], val[1], and val[2]. Note that:
+ * Interpretation of val[] is device-dependent. Some examples:
*
- * if (val[0] == -1) {
+ * if (val[0] == -1) {
* val[1] is a unit number (happens most often with old proms)
* } else {
- * val[0] is a sbus slot, and val[1] is an sbus offset [if sbus]
+ * [sbus device] val[0] is a sbus slot, and val[1] is an sbus offset
+ * [scsi disk] val[0] is target, val[1] is lun, val[2] is partition
+ * [scsi tape] val[0] is target, val[1] is lun, val[2] is file #
* }
+ *
*/
-static void
+
+static void
bootpath_build()
{
register char *cp, *pp;
register struct bootpath *bp;
- int v0val[3];
/*
* On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags
* that were given after the boot command. On SS2s, pv_v0bootargs
* is NULL but *promvec->pv_v2bootargs.v2_bootargs points to
* "vmunix -s" or whatever.
- * ### DO THIS BEFORE pmap_boostrap?
+ * XXX DO THIS BEFORE pmap_boostrap?
*/
bzero(bootpath, sizeof(bootpath));
bp = bootpath;
@@ -332,7 +468,7 @@ bootpath_build()
if (cp == NULL || *cp != '-')
return;
} else {
- /*
+ /*
* Grab boot path from PROM
*/
cp = *promvec->pv_v2bootargs.v2_bootpath;
@@ -348,15 +484,15 @@ bootpath_build()
cp = str2hex(++cp, &bp->val[0]);
if (*cp == ',')
cp = str2hex(++cp, &bp->val[1]);
+ if (*cp == ':')
+ /* XXX - we handle just one char */
+ bp->val[2] = *++cp - 'a', ++cp;
} else {
bp->val[0] = -1; /* no #'s: assume unit 0, no
sbus offset/adddress */
}
-#ifdef notyet
- if (strcmp(bp->name, "iommu") == 0)
- continue;
-#endif
++bp;
+ ++nbootpath;
}
bp->name[0] = 0;
@@ -403,8 +539,9 @@ bootpath_build()
/*
* Fake a ROM generated bootpath.
- * The argument `cp' points to a string such as "xd(0,0,0)bsd"
+ * The argument `cp' points to a string such as "xd(0,0,0)netbsd"
*/
+
static void
bootpath_fake(bp, cp)
struct bootpath *bp;
@@ -412,39 +549,48 @@ bootpath_fake(bp, cp)
{
register char *pp;
int v0val[3];
- char tmpname[8];
-#define BP_APPEND(BP,N,V0,V1) { \
+#define BP_APPEND(BP,N,V0,V1,V2) { \
strcpy((BP)->name, N); \
(BP)->val[0] = (V0); \
(BP)->val[1] = (V1); \
- (BP)++; }
+ (BP)->val[2] = (V2); \
+ (BP)++; \
+ nbootpath++; \
+}
+#if defined(SUN4)
+ if (CPU_ISSUN4M) {
+ printf("twas brillig..\n");
+ return;
+ }
+#endif
pp = cp + 2;
v0val[0] = v0val[1] = v0val[2] = 0;
- if (*pp == '(' /* for vi: ) */
- && *(pp = str2hex(++pp, &v0val[0])) == ','
+ if (*pp == '(' /* for vi: ) */
+ && *(pp = str2hex(++pp, &v0val[0])) == ','
&& *(pp = str2hex(++pp, &v0val[1])) == ',')
(void)str2hex(++pp, &v0val[2]);
-#ifdef SUN4
- if (cputyp == CPU_SUN4) {
+#if defined(SUN4)
+ if (CPU_ISSUN4) {
+ char tmpname[8];
/*
- * xylogics VME dev: xd, xy, xt
+ * xylogics VME dev: xd, xy, xt
* fake looks like: /vmel0/xdc0/xd@1,0
*/
- if (cp[0] == 'x') {
+ if (cp[0] == 'x') {
if (cp[1] == 'd') {/* xd? */
- BP_APPEND(bp,"vmel",-1,0);
+ BP_APPEND(bp, "vmel", -1, 0, 0);
} else {
- BP_APPEND(bp,"vmes",-1,0);
+ BP_APPEND(bp, "vmes", -1, 0, 0);
}
sprintf(tmpname,"x%cc", cp[1]); /* e.g. xdc */
- BP_APPEND(bp,tmpname,-1,v0val[0]);
+ BP_APPEND(bp, tmpname,-1, v0val[0], 0);
sprintf(tmpname,"%c%c", cp[0], cp[1]);
- BP_APPEND(bp,tmpname,v0val[1], v0val[2]); /* e.g. xd */
+ BP_APPEND(bp, tmpname,v0val[1], v0val[2], 0); /* e.g. xd */
return;
}
@@ -453,92 +599,108 @@ bootpath_fake(bp, cp)
* fake looks like: /obio0/le0
*/
if ((cp[0] == 'i' || cp[0] == 'l') && cp[1] == 'e') {
- BP_APPEND(bp,"obio",-1,0);
+ BP_APPEND(bp, "obio", -1, 0, 0);
sprintf(tmpname,"%c%c", cp[0], cp[1]);
- BP_APPEND(bp,tmpname,-1,0);
+ BP_APPEND(bp, tmpname, -1, 0, 0);
return;
}
/*
* scsi: sd, st, sr
- * assume: 4/100 = sw: /obio0/sw0/sd@0,0
- * 4/200 & 4/400 = si/sc: /vmes0/si0/sd@0,0
- * 4/300 = esp: /obio0/esp0/sd@0,0
+ * assume: 4/100 = sw: /obio0/sw0/sd@0,0:a
+ * 4/200 & 4/400 = si/sc: /vmes0/si0/sd@0,0:a
+ * 4/300 = esp: /obio0/esp0/sd@0,0:a
* (note we expect sc to mimic an si...)
*/
- if (cp[0] == 's' &&
+ if (cp[0] == 's' &&
(cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
-
+
+ int target, lun;
+
switch (cpumod) {
case SUN4_200:
case SUN4_400:
- BP_APPEND(bp,"vmes",-1,0);
- BP_APPEND(bp,"si",-1,v0val[0]);
- sprintf(tmpname,"%c%c", cp[0], cp[1]);
- BP_APPEND(bp,tmpname,v0val[1],v0val[2]);
- return;
+ BP_APPEND(bp, "vmes", -1, 0, 0);
+ BP_APPEND(bp, "si", -1, v0val[0], 0);
+ break;
case SUN4_100:
- if (v0val[0] == 0) {
- BP_APPEND(bp,"obio",-1,0);
- BP_APPEND(bp,"sw",-1,v0val[0]);
- } else {
- BP_APPEND(bp,"obio",-1,0);
- BP_APPEND(bp,"si",-1,v0val[0]-1);
- }
- sprintf(tmpname,"%c%c", cp[0], cp[1]);
- BP_APPEND(bp,tmpname,v0val[1],v0val[2]);
- return;
+ BP_APPEND(bp, "obio", -1, 0, 0);
+ BP_APPEND(bp, "sw", -1, v0val[0], 0);
+ break;
case SUN4_300:
- BP_APPEND(bp,"obio",-1,0);
- BP_APPEND(bp,"esp",-1,v0val[0]);
- sprintf(tmpname,"%c%c", cp[0], cp[1]);
- BP_APPEND(bp,tmpname,v0val[1],v0val[2]);
- return;
+ BP_APPEND(bp, "obio", -1, 0, 0);
+ BP_APPEND(bp, "esp", -1, v0val[0], 0);
+ break;
+ default:
+ panic("bootpath_fake: unknown cpumod %d",
+ cpumod);
+ }
+ /*
+ * Deal with target/lun encodings.
+ * Note: more special casing in dk_establish().
+ */
+ if (oldpvec->monId[0] > '1') {
+ target = v0val[1] >> 3; /* new format */
+ lun = v0val[1] & 0x7;
+ } else {
+ target = v0val[1] >> 2; /* old format */
+ lun = v0val[1] & 0x3;
}
- panic("bootpath_fake: unknown cpumod?");
+ sprintf(tmpname, "%c%c", cp[0], cp[1]);
+ BP_APPEND(bp, tmpname, target, lun, v0val[2]);
+ return;
}
return; /* didn't grok bootpath, no change */
}
#endif /* SUN4 */
-
-#ifdef SUN4C
+
+#if defined(SUN4C)
/*
* sun4c stuff
*/
/*
* floppy: fd
- * fake looks like: /fd@0,0
+ * fake looks like: /fd@0,0:a
*/
if (cp[0] == 'f' && cp[1] == 'd') {
- BP_APPEND(bp,"fd",v0val[1],v0val[2]);
+ /*
+ * Assume `fd(c,u,p)' means:
+ * partition `p' on floppy drive `u' on controller `c'
+ */
+ BP_APPEND(bp, "fd", v0val[0], v0val[1], v0val[2]);
return;
}
/*
- * ethenet: le
+ * ethernet: le
* fake looks like: /sbus0/le0
*/
if (cp[0] == 'l' && cp[1] == 'e') {
- BP_APPEND(bp,"sbus",-1,0);
- BP_APPEND(bp,"le",-1,v0val[0]);
+ BP_APPEND(bp, "sbus", -1, 0, 0);
+ BP_APPEND(bp, "le", -1, v0val[0], 0);
return;
}
/*
* scsi: sd, st, sr
- * fake looks like: /sbus0/esp0/sd@3,0
- */
- if (cp[0] == 's' &&
- (cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
- BP_APPEND(bp,"sbus",-1,0);
- BP_APPEND(bp,"esp",-1,v0val[0]);
- if (cp[1] == 'r')
- sprintf(tmpname, "cd"); /* use 'cd', not 'sr'*/
+ * fake looks like: /sbus0/esp0/sd@3,0:a
+ */
+ if (cp[0] == 's' && (cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
+ char tmpname[8];
+ int target, lun;
+
+ BP_APPEND(bp, "sbus", -1, 0, 0);
+ BP_APPEND(bp, "esp", -1, v0val[0], 0);
+ if (cp[1] == 'r')
+ sprintf(tmpname, "cd"); /* netbsd uses 'cd', not 'sr'*/
else
sprintf(tmpname,"%c%c", cp[0], cp[1]);
- BP_APPEND(bp,tmpname,v0val[1], v0val[2]);
+ /* XXX - is TARGET/LUN encoded in v0val[1]? */
+ target = v0val[1];
+ lun = 0;
+ BP_APPEND(bp, tmpname, target, lun, v0val[2]);
return;
}
#endif /* SUN4C */
@@ -547,14 +709,15 @@ bootpath_fake(bp, cp)
/*
* unknown; return
*/
-
+
#undef BP_APPEND
}
/*
* print out the bootpath
*/
-static void
+
+static void
bootpath_print(bp)
struct bootpath *bp;
{
@@ -564,18 +727,22 @@ bootpath_print(bp)
printf("/%s%x", bp->name, bp->val[1]);
else
printf("/%s@%x,%x", bp->name, bp->val[0], bp->val[1]);
+ if (bp->val[2] != 0)
+ printf(":%c", bp->val[2] + 'a');
bp++;
}
printf("\n");
}
+
/*
* save or read a bootpath pointer from the boothpath store.
*
* XXX. required because of SCSI... we don't have control over the "sd"
- * device, so we can't set boot device there. we patch in with
+ * device, so we can't set boot device there. we patch in with
* dk_establish(), and use this to recover the bootpath.
*/
+
struct bootpath *
bootpath_store(storep, bp)
int storep;
@@ -591,7 +758,7 @@ bootpath_store(storep, bp)
return (retval);
}
-/*
+/*
* Set up the sd target mappings for non SUN4 PROMs.
* Find out about the real SCSI target, given the PROM's idea of the
* target of the (boot) device (i.e., the value in bp->v0val[0]).
@@ -603,9 +770,8 @@ crazymap(prop, map)
{
int i;
char *propval;
- struct nodeops *no;
- if (cputyp != CPU_SUN4 && promvec->pv_romvec_vers < 2) {
+ if (!CPU_ISSUN4 && promvec->pv_romvec_vers < 2) {
/*
* Machines with real v0 proms have an `s[dt]-targets' property
* which contains the mapping for us to use. v2 proms donot
@@ -613,7 +779,7 @@ crazymap(prop, map)
*/
propval = getpropstring(optionsnode, prop);
if (propval == NULL || strlen(propval) != 8) {
-build_default_map:
+ build_default_map:
printf("WARNING: %s map is bogus, using default\n",
prop);
for (i = 0; i < 8; ++i)
@@ -640,7 +806,7 @@ build_default_map:
}
}
-int
+int
sd_crazymap(n)
int n;
{
@@ -654,7 +820,7 @@ sd_crazymap(n)
return prom_sd_crazymap[n];
}
-int
+int
st_crazymap(n)
int n;
{
@@ -674,63 +840,76 @@ st_crazymap(n)
* attach it as `mainbus0'. We also set up to handle the PROM `sync'
* command.
*/
+void
configure()
{
struct confargs oca;
register int node = 0;
register char *cp;
- void sync_crash();
+
+ /* Initialize the mountroot_hook list. */
+ LIST_INIT(&mrh_list);
/* build the bootpath */
bootpath_build();
#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
extern struct cfdata cfdata[];
- extern struct cfdriver memregcd, obiocd;
+ extern struct cfdriver memreg_cd, obio_cd;
struct cfdata *cf, *memregcf = NULL;
register short *p;
+ struct rom_reg rr;
- /*
- * On the 4/100 obio addresses must be mapped at
- * 0x0YYYYYYY, but alias higher up (we avoid the
- * alias condition because it causes pmap difficulties)
- * XXX: We also assume that 4/[23]00 obio addresses
- * must be 0xZYYYYYYY, where (Z != 0)
- * make sure we get the correct memreg cfdriver!
- */
for (cf = cfdata; memregcf==NULL && cf->cf_driver; cf++) {
- if (cf->cf_driver != &memregcd)
+ if (cf->cf_driver != &memreg_cd ||
+ cf->cf_loc[0] == -1) /* avoid sun4m memreg0 */
continue;
+ /*
+ * On the 4/100 obio addresses must be mapped at
+ * 0x0YYYYYYY, but alias higher up (we avoid the
+ * alias condition because it causes pmap difficulties)
+ * XXX: We also assume that 4/[23]00 obio addresses
+ * must be 0xZYYYYYYY, where (Z != 0)
+ * make sure we get the correct memreg cfdriver!
+ */
if (cpumod==SUN4_100 && (cf->cf_loc[0] & 0xf0000000))
continue;
if (cpumod!=SUN4_100 && !(cf->cf_loc[0] & 0xf0000000))
continue;
for (p = cf->cf_parents; memregcf==NULL && *p >= 0; p++)
- if (cfdata[*p].cf_driver == &obiocd)
+ if (cfdata[*p].cf_driver == &obio_cd)
memregcf = cf;
}
if (memregcf==NULL)
panic("configure: no memreg found!");
- par_err_reg = (int *)bus_map((void *)memregcf->cf_loc[0],
- NBPG, BUS_OBIO);
+
+ rr.rr_iospace = BUS_OBIO;
+ rr.rr_paddr = (void *)memregcf->cf_loc[0];
+ rr.rr_len = NBPG;
+ par_err_reg = (u_int *)bus_map(&rr, NBPG, BUS_OBIO);
if (par_err_reg == NULL)
panic("configure: ROM hasn't mapped memreg!");
}
#endif
-#if defined(SUN4C) || defined(SUN4M)
- if (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) {
+#if defined(SUN4C)
+ if (CPU_ISSUN4C) {
node = findroot();
cp = getpropstring(node, "device_type");
if (strcmp(cp, "cpu") != 0)
panic("PROM root device type = %s (need CPU)\n", cp);
- *promvec->pv_synchook = sync_crash;
}
#endif
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ node = findroot();
+#endif
+
+ *promvec->pv_synchook = sync_crash;
oca.ca_ra.ra_node = node;
oca.ca_ra.ra_name = cp = "mainbus";
- if (!config_rootfound(cp, (void *)&oca))
+ if (config_rootfound(cp, (void *)&oca) == NULL)
panic("mainbus not configured");
(void)spl0();
@@ -807,7 +986,7 @@ findroot()
int
findnode(first, name)
int first;
- register char *name;
+ register const char *name;
{
register int node;
@@ -828,11 +1007,15 @@ romprop(rp, cp, node)
register int node;
{
register int len;
- union { char regbuf[128]; struct rom_reg rr[RA_MAXREG]; } u;
+ union { char regbuf[256]; struct rom_reg rr[RA_MAXREG]; } u;
static const char pl[] = "property length";
bzero(u.regbuf, sizeof u);
- len = getprop(node, "reg", (void *)u.regbuf, sizeof u.regbuf);
+ len = getprop(node, "reg", (void *)u.regbuf, sizeof(u.regbuf));
+ if (len == -1 &&
+ node_has_property(node, "device_type") &&
+ strcmp(getpropstring(node, "device_type"), "hierarchical") == 0)
+ len = 0;
if (len % sizeof(struct rom_reg)) {
printf("%s \"reg\" %s = %d (need multiple of %d)\n",
cp, pl, len, sizeof(struct rom_reg));
@@ -846,11 +1029,12 @@ romprop(rp, cp, node)
rp->ra_nreg = len / sizeof(struct rom_reg);
bcopy(u.rr, rp->ra_reg, len);
- rp->ra_vaddr = (caddr_t)getpropint(node, "address", 0);
len = getprop(node, "address", (void *)rp->ra_vaddrs,
sizeof(rp->ra_vaddrs));
- if (len == -1)
+ if (len == -1) {
+ rp->ra_vaddr = 0; /* XXX - driver compat */
len = 0;
+ }
if (len & 3) {
printf("%s \"address\" %s = %d (need multiple of 4)\n",
cp, pl, len);
@@ -874,22 +1058,44 @@ romprop(rp, cp, node)
cp, len);
break;
}
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ /* What's in these high bits anyway? */
+ rp->ra_intr[len].int_pri &= 0xf;
+ /* Look at "interrupts" property too? */
+ }
+#endif
+
}
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ len = getprop(node, "ranges", (void *)&rp->ra_range,
+ sizeof rp->ra_range);
+ if (len == -1)
+ len = 0;
+ rp->ra_nrange = len / sizeof(struct rom_range);
+ } else
+#endif
+ rp->ra_nrange = 0;
+
return (1);
}
int
-mainbus_match(parent, cf, aux)
+mainbus_match(parent, self, aux)
struct device *parent;
- struct cfdata *cf;
+ void *self;
void *aux;
{
+ struct cfdata *cf = self;
register struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
}
+int autoconf_nzs = 0; /* must be global so obio.c can see it */
+
/*
* Attach the mainbus.
*
@@ -902,12 +1108,16 @@ mainbus_attach(parent, dev, aux)
struct device *parent, *dev;
void *aux;
{
- struct confargs oca, *ca = aux;
+ struct confargs oca;
+ register const char *const *ssp, *sp = NULL;
+#if defined(SUN4C) || defined(SUN4M)
+ struct confargs *ca = aux;
register int node0, node;
- register const char *cp, *const *ssp, *sp;
+ const char *const *openboot_special;
#define L1A_HACK /* XXX hack to allow L1-A during autoconf */
#ifdef L1A_HACK
- int nzs = 0, audio = 0;
+ int audio = 0;
+#endif
#endif
#if defined(SUN4)
static const char *const oldmon_special[] = {
@@ -917,8 +1127,8 @@ mainbus_attach(parent, dev, aux)
};
#endif /* SUN4 */
-#if defined(SUN4C) || defined(SUN4M)
- static const char *const openboot_special[] = {
+#if defined(SUN4C)
+ static const char *const openboot_special4c[] = {
/* find these first (end with empty string) */
"memory-error", /* as early as convenient, in case of error */
"eeprom",
@@ -936,17 +1146,40 @@ mainbus_attach(parent, dev, aux)
"virtual-memory",
NULL
};
-#endif /* SUN4C || SUN4M */
+#else
+#define openboot_special4c ((void *)0)
+#endif
+#if defined(SUN4M)
+ static const char *const openboot_special4m[] = {
+ /* find these first */
+ "obio", /* smart enough to get eeprom/etc mapped */
+ "",
- printf("\n");
+ /* ignore these (end with NULL) */
+ /*
+ * These are _root_ devices to ignore. Others must be handled
+ * elsewhere.
+ */
+ "SUNW,sx", /* XXX: no driver for SX yet */
+ "eccmemctl",
+ "virtual-memory",
+ "aliases",
+ "memory",
+ "openprom",
+ "options",
+ "packages",
+ /* we also skip any nodes with device_type == "cpu" */
+ NULL
+ };
+#else
+#define openboot_special4m ((void *)0)
+#endif
- /* configure the cpu */
- node = ca->ca_ra.ra_node;
- oca.ca_ra.ra_node = node;
- oca.ca_ra.ra_name = cp = "cpu";
- oca.ca_ra.ra_paddr = 0;
- oca.ca_ra.ra_nreg = 0;
- config_found(dev, (void *)&oca, mbprint);
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ printf(": %s", getpropstring(ca->ca_ra.ra_node, "name"));
+#endif
+ printf("\n");
/*
* Locate and configure the ``early'' devices. These must be
@@ -954,80 +1187,138 @@ mainbus_attach(parent, dev, aux)
* EEPROM contains the Ethernet address for the LANCE chip.
* If the device cannot be located or configured, panic.
*/
+
#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
+ /* Configure the CPU. */
+ bzero(&oca, sizeof(oca));
+ oca.ca_ra.ra_name = "cpu";
+ (void)config_found(dev, (void *)&oca, mbprint);
/* Start at the beginning of the bootpath */
+ bzero(&oca, sizeof(oca));
oca.ca_ra.ra_bp = bootpath;
oca.ca_bustype = BUS_MAIN;
oca.ca_ra.ra_name = "obio";
- if (!config_found(dev, (void *)&oca, mbprint))
- panic(sp);
+ if (config_found(dev, (void *)&oca, mbprint) == NULL)
+ panic("obio missing");
for (ssp = oldmon_special; (sp = *ssp) != NULL; ssp++) {
oca.ca_bustype = BUS_MAIN;
oca.ca_ra.ra_name = sp;
(void)config_found(dev, (void *)&oca, mbprint);
}
+ return;
}
#endif
+
+/*
+ * The rest of this routine is for OBP machines exclusively.
+ */
#if defined(SUN4C) || defined(SUN4M)
- if (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) {
+ openboot_special = CPU_ISSUN4M
+ ? openboot_special4m
+ : openboot_special4c;
+
+ node = ca->ca_ra.ra_node; /* i.e., the root node */
+
+ /* the first early device to be configured is the cpu */
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ /* XXX - what to do on multiprocessor machines? */
+ register const char *cp;
+
+ for (node = firstchild(node); node; node = nextsibling(node)) {
+ cp = getpropstring(node, "device_type");
+ if (strcmp(cp, "cpu") == 0)
+ break;
+ }
+ if (node == 0)
+ panic("None of the CPUs found\n");
+ }
+#endif
+
+ oca.ca_ra.ra_node = node;
+ oca.ca_ra.ra_name = "cpu";
+ oca.ca_ra.ra_paddr = 0;
+ oca.ca_ra.ra_nreg = 0;
+ config_found(dev, (void *)&oca, mbprint);
+
+ node = ca->ca_ra.ra_node; /* re-init root node */
+
+ if (promvec->pv_romvec_vers <= 2)
/* remember which frame buffer, if any, is to be /dev/fb */
fbnode = getpropint(node, "fb", 0);
- /* Find the "options" node */
- node0 = firstchild(node);
- optionsnode = findnode(node0, "options");
- if (optionsnode == 0)
- panic("no options in OPENPROM");
+ /* Find the "options" node */
+ node0 = firstchild(node);
+ optionsnode = findnode(node0, "options");
+ if (optionsnode == 0)
+ panic("no options in OPENPROM");
- /* Start at the beginning of the bootpath */
- oca.ca_ra.ra_bp = bootpath;
+ /* Start at the beginning of the bootpath */
+ oca.ca_ra.ra_bp = bootpath;
- for (ssp = openboot_special; *(sp = *ssp) != 0; ssp++) {
- if ((node = findnode(node0, sp)) == 0) {
- printf("could not find %s in OPENPROM\n", sp);
- panic(sp);
- }
- oca.ca_bustype = BUS_MAIN;
- if (!romprop(&oca.ca_ra, sp, node) ||
- !config_found(dev, (void *)&oca, mbprint))
- panic(sp);
+ for (ssp = openboot_special; *(sp = *ssp) != 0; ssp++) {
+ if ((node = findnode(node0, sp)) == 0) {
+ printf("could not find %s in OPENPROM\n", sp);
+ panic(sp);
}
+ oca.ca_bustype = BUS_MAIN;
+ if (!romprop(&oca.ca_ra, sp, node) ||
+ (config_found(dev, (void *)&oca, mbprint) == NULL))
+ panic(sp);
+ }
- /*
- * Configure the rest of the devices, in PROM order. Skip
- * PROM entries that are not for devices, or which must be
- * done before we get here.
- */
- for (node = node0; node; node = nextsibling(node)) {
- cp = getpropstring(node, "name");
- for (ssp = openboot_special; (sp = *ssp) != NULL; ssp++)
- if (strcmp(cp, sp) == 0)
- break;
- if (sp == NULL && romprop(&oca.ca_ra, cp, node)) {
+ /*
+ * Configure the rest of the devices, in PROM order. Skip
+ * PROM entries that are not for devices, or which must be
+ * done before we get here.
+ */
+ for (node = node0; node; node = nextsibling(node)) {
+ register const char *cp;
+
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) /* skip the CPUs */
+ if (node_has_property(node, "device_type") &&
+ !strcmp(getpropstring(node, "device_type"), "cpu"))
+ continue;
+#endif
+ cp = getpropstring(node, "name");
+ for (ssp = openboot_special; (sp = *ssp) != NULL; ssp++)
+ if (strcmp(cp, sp) == 0)
+ break;
+ if (sp == NULL && romprop(&oca.ca_ra, cp, node)) {
#ifdef L1A_HACK
- if (strcmp(cp, "audio") == 0)
- audio = 1;
- if (strcmp(cp, "zs") == 0)
- nzs++;
- if (audio && nzs >= 2)
- (void) splx(11 << 8); /* XXX */
+ if (strcmp(cp, "audio") == 0)
+ audio = 1;
+ if (strcmp(cp, "zs") == 0)
+ autoconf_nzs++;
+ if (/*audio &&*/ autoconf_nzs >= 2) /*XXX*/
+ (void) splx(11 << 8); /*XXX*/
#endif
- oca.ca_bustype = BUS_MAIN;
- (void) config_found(dev, (void *)&oca, mbprint);
- }
+ oca.ca_bustype = BUS_MAIN;
+ (void) config_found(dev, (void *)&oca, mbprint);
}
}
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ /* Enable device interrupts */
+ ienab_bic(SINTR_MA);
+ }
+#endif
#endif /* SUN4C || SUN4M */
}
-struct cfdriver mainbuscd =
- { NULL, "mainbus", mainbus_match, mainbus_attach,
- DV_DULL, sizeof(struct device) };
+struct cfattach mainbus_ca = {
+ sizeof(struct device), mainbus_match, mainbus_attach
+};
+
+struct cfdriver mainbus_cd = {
+ NULL, "mainbus", DV_DULL
+};
/*
* findzs() is called from the zs driver (which is, at least in theory,
@@ -1040,38 +1331,49 @@ void *
findzs(zs)
int zs;
{
- register int node, addr;
-#ifdef SUN4
+#if defined(SUN4)
#define ZS0_PHYS 0xf1000000
#define ZS1_PHYS 0xf0000000
#define ZS2_PHYS 0xe0000000
- if (cputyp == CPU_SUN4) {
- void *paddr;
+ if (CPU_ISSUN4) {
+ struct rom_reg rr;
+ register void *vaddr;
switch (zs) {
case 0:
- paddr = (void *)ZS0_PHYS;
+ rr.rr_paddr = (void *)ZS0_PHYS;
break;
case 1:
- paddr = (void *)ZS1_PHYS;
+ rr.rr_paddr = (void *)ZS1_PHYS;
break;
case 2:
- paddr = (void *)ZS2_PHYS;
+ rr.rr_paddr = (void *)ZS2_PHYS;
break;
default:
panic("findzs: unknown zs device %d", zs);
}
- addr = (int)bus_map(paddr, NBPG, BUS_OBIO);
- if (addr)
- return ((void *)addr);
+ rr.rr_iospace = BUS_OBIO;
+ rr.rr_len = NBPG;
+ vaddr = bus_map(&rr, NBPG, BUS_OBIO);
+ if (vaddr)
+ return (vaddr);
}
#endif
+
#if defined(SUN4C) || defined(SUN4M)
- if (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) {
+ if (CPU_ISSUN4COR4M) {
+ register int node, addr;
+
node = firstchild(findroot());
+ if (CPU_ISSUN4M) { /* zs is in "obio" tree on Sun4M */
+ node = findnode(node, "obio");
+ if (!node)
+ panic("findzs: no obio node");
+ node = firstchild(node);
+ }
while ((node = findnode(node, "zs")) != 0) {
if (getpropint(node, "slave", -1) == zs) {
if ((addr = getpropint(node, "address", 0)) == 0)
@@ -1082,7 +1384,6 @@ findzs(zs)
}
}
#endif
-bail:
panic("findzs: cannot find zs%d", zs);
/* NOTREACHED */
}
@@ -1105,7 +1406,7 @@ makememarr(ap, max, which)
#endif
#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
switch (which) {
case MEMARR_AVAILPHYS:
ap[0].addr = 0;
@@ -1157,6 +1458,7 @@ makememarr(ap, max, which)
i);
/* FALLTHROUGH */
+ case 3:
case 2:
/*
* Version 2 PROMs use a property array to describe them.
@@ -1219,15 +1521,18 @@ getprop(node, name, buf, bufsiz)
void *buf;
register int bufsiz;
{
+#if defined(SUN4C) || defined(SUN4M)
register struct nodeops *no;
register int len;
+#endif
#if defined(SUN4)
- if (cputyp==CPU_SUN4) {
+ if (CPU_ISSUN4) {
printf("WARNING: getprop not valid on sun4! %s\n", name);
return (0);
}
#endif
+
#if defined(SUN4C) || defined(SUN4M)
no = promvec->pv_nodeops;
len = no->no_proplen(node, name);
@@ -1259,6 +1564,8 @@ getpropstring(node, name)
static char stringbuf[32];
len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1);
+ if (len == -1)
+ len = 0;
stringbuf[len] = '\0'; /* usually unnecessary */
return (stringbuf);
}
@@ -1302,6 +1609,67 @@ nextsibling(node)
return (promvec->pv_nodeops->no_nextnode(node));
}
+char *strchr __P((const char *, int));
+u_int hexatoi __P((const char *));
+
+/* The following recursively searches a PROM tree for a given node */
+int
+search_prom(rootnode, name)
+ register int rootnode;
+ register char *name;
+{
+ register int rtnnode;
+ register int node = rootnode;
+
+ if (node == findroot() || !strcmp("hierarchical",
+ getpropstring(node, "device_type")))
+ node = firstchild(node);
+
+ if (!node)
+ panic("search_prom: null node");
+
+ do {
+ if (strcmp(getpropstring(node, "name"),name) == 0)
+ return node;
+
+ if (node_has_property(node,"device_type") &&
+ (!strcmp(getpropstring(node, "device_type"),"hierarchical")
+ || !strcmp(getpropstring(node, "name"),"iommu"))
+ && (rtnnode = search_prom(node, name)) != 0)
+ return rtnnode;
+
+ } while ((node = nextsibling(node)));
+
+ return 0;
+}
+
+/* The following are used primarily in consinit() */
+
+int
+opennode(path) /* translate phys. device path to node */
+ register char *path;
+{
+ register int fd;
+
+ if (promvec->pv_romvec_vers < 2) {
+ printf("WARNING: opennode not valid on sun4! %s\n", path);
+ return (0);
+ }
+ fd = promvec->pv_v2devops.v2_open(path);
+ if (fd == 0)
+ return 0;
+ return promvec->pv_v2devops.v2_fd_phandle(fd);
+}
+
+int
+node_has_property(node, prop) /* returns 1 if node has given property */
+ register int node;
+ register const char *prop;
+{
+
+ return ((*promvec->pv_nodeops->no_proplen)(node, (caddr_t)prop) != -1);
+}
+
#ifdef RASTERCONSOLE
/* Pass a string to the FORTH PROM to be interpreted */
void
@@ -1332,40 +1700,45 @@ romgetcursoraddr(rowp, colp)
*/
if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009)
sprintf(buf,
- "' line# >body >user %x ! ' column# >body >user %x !",
- rowp, colp);
+ "' line# >body >user %lx ! ' column# >body >user %lx !",
+ (u_long)rowp, (u_long)colp);
else
sprintf(buf,
- "stdout @ is my-self addr line# %x ! addr column# %x !",
- rowp, colp);
+ "stdout @ is my-self addr line# %lx ! addr column# %lx !",
+ (u_long)rowp, (u_long)colp);
*rowp = *colp = NULL;
rominterpret(buf);
return (*rowp == NULL || *colp == NULL);
}
#endif
-volatile void
+void
romhalt()
{
+ if (CPU_ISSUN4COR4M)
+ *promvec->pv_synchook = NULL;
promvec->pv_halt();
panic("PROM exit failed");
}
-volatile void
+void
romboot(str)
char *str;
{
+ if (CPU_ISSUN4COR4M)
+ *promvec->pv_synchook = NULL;
promvec->pv_reboot(str);
panic("PROM boot failed");
}
+void
callrom()
{
#if 0 /* sun4c FORTH PROMs do this for us */
- if (cputyp == CPU_SUN4)
+ if (CPU_ISSUN4)
fb_unblank();
#endif
promvec->pv_abort();
@@ -1374,6 +1747,7 @@ callrom()
/*
* Configure swap space and related parameters.
*/
+void
swapconf()
{
register struct swdevt *swp;
@@ -1433,7 +1807,8 @@ getdisk(str, len, defpart, devp)
if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
printf("use one of:");
- for (dv = alldevs; dv != NULL; dv = dv->dv_next) {
+ for (dv = alldevs.tqh_first; dv != NULL;
+ dv = dv->dv_list.tqe_next) {
if (dv->dv_class == DV_DISK)
printf(" %s[a-h]", dv->dv_xname);
#ifdef NFSCLIENT
@@ -1441,10 +1816,6 @@ getdisk(str, len, defpart, devp)
printf(" %s", dv->dv_xname);
#endif
}
-#if NFD > 0
- if (defpart == 0)
- printf(" fdeject");
-#endif /* NFD */
printf("\n");
}
return (dv);
@@ -1470,7 +1841,7 @@ parsedisk(str, len, defpart, devp)
} else
part = defpart;
- for (dv = alldevs; dv != NULL; dv = dv->dv_next) {
+ for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
if (dv->dv_class == DV_DISK &&
strcmp(str, dv->dv_xname) == 0) {
majdev = findblkmajor(dv);
@@ -1493,11 +1864,29 @@ parsedisk(str, len, defpart, devp)
return (dv);
}
+void
+mountroot_hook_establish(func, dev)
+ void (*func) __P((struct device *));
+ struct device *dev;
+{
+ struct mountroot_hook *mrhp;
+
+ mrhp = (struct mountroot_hook *)malloc(sizeof(struct mountroot_hook),
+ M_DEVBUF, M_NOWAIT);
+ if (mrhp == NULL)
+ panic("no memory for mountroot_hook");
+
+ bzero(mrhp, sizeof(struct mountroot_hook));
+ mrhp->mr_device = dev;
+ mrhp->mr_func = func;
+ LIST_INSERT_HEAD(&mrh_list, mrhp, mr_link);
+}
+
/*
* Attempt to find the device from which we were booted.
* If we can do so, and not instructed not to do so,
* change rootdev to correspond to the load device.
- *
+ *
* XXX Actually, swap and root must be on the same type of device,
* (ie. DV_DISK or DV_IFNET) because of how (*mountroot) is written.
* That should be fixed.
@@ -1510,37 +1899,39 @@ setroot()
register int len, majdev, mindev;
dev_t nrootdev, nswapdev = NODEV;
char buf[128];
- extern int (*mountroot)();
+ extern int (*mountroot) __P((void *));
dev_t temp;
+ struct mountroot_hook *mrhp;
+ struct device *bootdv;
+ struct bootpath *bp;
#if defined(NFSCLIENT)
extern char *nfsbootdevname;
- extern int nfs_mountroot();
+ extern int nfs_mountroot __P((void *));
#endif
#if defined(FFS)
- extern int ffs_mountroot();
+ extern int ffs_mountroot __P((void *));
#endif
+ bp = nbootpath == 0 ? NULL : &bootpath[nbootpath-1];
+ bootdv = bp == NULL ? NULL : bp->dev;
+
+ /*
+ * If `swap generic' and we couldn't determine boot device,
+ * ask the user.
+ */
+ if (mountroot == NULL && bootdv == NULL)
+ boothowto |= RB_ASKNAME;
+
if (boothowto & RB_ASKNAME) {
for (;;) {
printf("root device ");
if (bootdv != NULL)
- printf("(default %s%s)", bootdv->dv_xname,
- bootdv->dv_class == DV_DISK?"a":"");
+ printf("(default %s%c)",
+ bootdv->dv_xname,
+ bootdv->dv_class == DV_DISK
+ ? bp->val[2]+'a' : ' ');
printf(": ");
len = getstr(buf, sizeof(buf));
-#if NFD > 0
- /*
- * I will go punish myself now.
- */
- if (len > 0 && strcmp(buf, "fdeject")==0) {
- struct mtop mtop;
-
- bzero(&mtop, sizeof mtop);
- mtop.mt_op = MTOFFL;
- (void) fdioctl(0, MTIOCTOP, &mtop, 0);
- continue;
- }
-#endif /* NFD */
if (len == 0 && bootdv != NULL) {
strcpy(buf, bootdv->dv_xname);
len = strlen(buf);
@@ -1554,7 +1945,7 @@ setroot()
goto gotswap;
}
}
- dv = getdisk(buf, len, 0, &nrootdev);
+ dv = getdisk(buf, len, bp?bp->val[2]:0, &nrootdev);
if (dv != NULL) {
bootdv = dv;
break;
@@ -1564,7 +1955,6 @@ setroot()
/*
* because swap must be on same device as root, for
* network devices this is easy.
- * XXX: IS THIS STILL TRUE?
*/
if (bootdv->dv_class == DV_IFNET) {
goto gotswap;
@@ -1572,8 +1962,9 @@ setroot()
for (;;) {
printf("swap device ");
if (bootdv != NULL)
- printf("(default %s%s)", bootdv->dv_xname,
- bootdv->dv_class == DV_DISK?"b":"");
+ printf("(default %s%c)",
+ bootdv->dv_xname,
+ bootdv->dv_class == DV_DISK?'b':' ');
printf(": ");
len = getstr(buf, sizeof(buf));
if (len == 0 && bootdv != NULL) {
@@ -1585,6 +1976,11 @@ setroot()
nswapdev = makedev(major(nrootdev),
(minor(nrootdev) & ~ PARTITIONMASK) | 1);
break;
+ case DV_TAPE:
+ case DV_TTY:
+ case DV_DULL:
+ case DV_CPU:
+ break;
}
break;
}
@@ -1600,7 +1996,9 @@ gotswap:
dumpdev = nswapdev;
swdevt[0].sw_dev = nswapdev;
swdevt[1].sw_dev = NODEV;
+
} else if (mountroot == NULL) {
+
/*
* `swap generic': Use the device the ROM told us to use.
*/
@@ -1608,10 +2006,11 @@ gotswap:
if (majdev >= 0) {
/*
* Root and swap are on a disk.
- * Assume that we are supposed to put root on
- * partition a, and swap on partition b.
+ * val[2] of the boot device is the partition number.
+ * Assume swap is on partition b.
*/
- mindev = (bootdv->dv_unit << PARTITIONSHIFT) + 0;
+ int part = bp->val[2];
+ mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part;
rootdev = makedev(majdev, mindev);
nswapdev = dumpdev = makedev(major(rootdev),
(minor(rootdev) & ~ PARTITIONMASK) | 1);
@@ -1630,10 +2029,11 @@ gotswap:
* `root DEV swap DEV': honour rootdev/swdevt.
* rootdev/swdevt/mountroot already properly set.
*/
- return;
+ majdev = major(rootdev);
+ mindev = minor(rootdev);
+ goto gotroot;
}
- if (bootdv == NULL)
- panic("boot device not known");
+
switch (bootdv->dv_class) {
#if defined(NFSCLIENT)
case DV_IFNET:
@@ -1654,6 +2054,41 @@ gotswap:
printf("can't figure root, hope your kernel is right\n");
return;
}
+
+ /*
+ * Make the swap partition on the root drive the primary swap.
+ */
+ mindev &= ~PARTITIONMASK;
+ temp = NODEV;
+ for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
+ if (majdev == major(swp->sw_dev) &&
+ mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
+ temp = swdevt[0].sw_dev;
+ swdevt[0].sw_dev = swp->sw_dev;
+ swp->sw_dev = temp;
+ break;
+ }
+ }
+ if (swp->sw_dev != NODEV) {
+ /*
+ * If dumpdev was the same as the old primary swap device,
+ * move it to the new primary swap device.
+ */
+ if (temp == dumpdev)
+ dumpdev = swdevt[0].sw_dev;
+ }
+
+gotroot:
+ /*
+ * Find mountroot hook and execute.
+ */
+ for (mrhp = mrh_list.lh_first; mrhp != NULL;
+ mrhp = mrhp->mr_link.le_next)
+ if (mrhp->mr_device == bootdv) {
+ (*mrhp->mr_func)(bootdv);
+ break;
+ }
+
}
static int
@@ -1703,7 +2138,7 @@ getstr(cp, size)
}
-/*
+/*
* find a device matching "name" and unit number
*/
struct device *
@@ -1711,7 +2146,7 @@ getdevunit(name, unit)
char *name;
int unit;
{
- struct device *dev = alldevs;
+ struct device *dev = alldevs.tqh_first;
char num[10], fullname[16];
int lunit;
@@ -1725,8 +2160,37 @@ getdevunit(name, unit)
strcat(fullname, num);
while (strcmp(dev->dv_xname, fullname) != 0) {
- if ((dev = dev->dv_next) == NULL)
+ if ((dev = dev->dv_list.tqe_next) == NULL)
return NULL;
}
return dev;
}
+
+
+/*
+ * The $#!@$&%# kernel library doesn't have strchr or atoi. Ugh. We duplicate
+ * here.
+ */
+
+char *
+strchr(p, ch) /* cribbed from libc */
+ register const char *p, ch;
+{
+ for (;; ++p) {
+ if (*p == ch)
+ return((char *)p);
+ if (!*p)
+ return((char *)NULL);
+ }
+ /* NOTREACHED */
+}
+
+u_int
+hexatoi(nptr) /* atoi assuming hex, no 0x */
+ const char *nptr;
+{
+ u_int retval;
+ str2hex((char *)nptr, &retval);
+ return retval;
+}
+
diff --git a/sys/arch/sparc/sparc/auxreg.c b/sys/arch/sparc/sparc/auxreg.c
index 0b40f13f5ea..1b44aee9bbf 100644
--- a/sys/arch/sparc/sparc/auxreg.c
+++ b/sys/arch/sparc/sparc/auxreg.c
@@ -1,4 +1,4 @@
-/* $NetBSD: auxreg.c,v 1.9 1995/12/11 12:45:16 pk Exp $ */
+/* $NetBSD: auxreg.c,v 1.14 1996/04/13 17:40:03 abrown Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -45,6 +45,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
@@ -55,16 +56,23 @@
static int auxregmatch __P((struct device *, void *, void *));
static void auxregattach __P((struct device *, struct device *, void *));
-struct cfdriver auxregcd =
- { 0, "auxreg", auxregmatch, auxregattach, DV_DULL, sizeof(struct device) };
+
+struct cfattach auxreg_ca = {
+ sizeof(struct device), auxregmatch, auxregattach
+};
+
+struct cfdriver auxreg_cd = {
+ 0, "auxreg", DV_DULL
+};
#ifdef BLINK
-static int
+static void blink __P((void *zero));
+
+static void
blink(zero)
void *zero;
{
register int s;
- register fixpt_t lav;
s = splhigh();
LED_FLIP;
@@ -76,7 +84,7 @@ blink(zero)
* full cycle every 3 seconds if loadav = 2
* etc.
*/
- s = (((averunnable[0] + FSCALE) * hz) >> (FSHIFT + 1));
+ s = (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1));
timeout(blink, (caddr_t)0, s);
}
#endif
@@ -90,11 +98,17 @@ auxregmatch(parent, vcf, aux)
void *aux, *vcf;
{
register struct confargs *ca = aux;
- struct cfdata *cf = vcf;
- if (cputyp==CPU_SUN4)
+ switch (cputyp) {
+ case CPU_SUN4:
return (0);
- return (strcmp("auxiliary-io", ca->ca_ra.ra_name) == 0);
+ case CPU_SUN4C:
+ return (strcmp("auxiliary-io", ca->ca_ra.ra_name) == 0);
+ case CPU_SUN4M:
+ return (strcmp("auxio", ca->ca_ra.ra_name) == 0);
+ default:
+ panic("auxregmatch");
+ }
}
/* ARGSUSED */
@@ -116,6 +130,7 @@ auxregattach(parent, self, aux)
unsigned int
auxregbisc(bis, bic)
+ int bis, bic;
{
register int v, s = splhigh();
diff --git a/sys/arch/sparc/sparc/auxreg.h b/sys/arch/sparc/sparc/auxreg.h
index 751e944a7d0..321c9a38a83 100644
--- a/sys/arch/sparc/sparc/auxreg.h
+++ b/sys/arch/sparc/sparc/auxreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: auxreg.h,v 1.3 1995/02/22 21:13:02 pk Exp $ */
+/* $NetBSD: auxreg.h,v 1.5 1996/03/14 21:08:54 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -69,10 +69,12 @@
#define AUXIO_BITS "\20\6FHD\5FDC\4FDS\3FTC\2FEJ\1LED"
-#ifndef LOCORE
+#ifndef _LOCORE
/*
* Copy of AUXIO_REG for the benefit of assembler modules (eg. trap handlers)
* as AUXREG_VA depends on NBPG which is not a constant.
*/
volatile u_char *auxio_reg;
+unsigned int auxregbisc __P((int, int));
#endif
+
diff --git a/sys/arch/sparc/sparc/bsd_fdintr.s b/sys/arch/sparc/sparc/bsd_fdintr.s
index 000cf5eef8f..e0e52a690e8 100644
--- a/sys/arch/sparc/sparc/bsd_fdintr.s
+++ b/sys/arch/sparc/sparc/bsd_fdintr.s
@@ -1,4 +1,4 @@
-/* $NetBSD: bsd_fdintr.s,v 1.4 1995/04/25 20:01:23 pk Exp $ */
+/* $NetBSD: bsd_fdintr.s,v 1.8 1996/03/31 23:45:00 pk Exp $ */
/*
* Copyright (c) 1995 Paul Kranenburg
@@ -32,10 +32,7 @@
*/
#ifndef FDC_C_HANDLER
-#ifndef LOCORE
-#define LOCORE
-#endif
-#include "assym.s"
+#include "assym.h"
#include <sparc/sparc/intreg.h>
#include <sparc/sparc/auxreg.h>
#include <sparc/sparc/vaddrs.h>
@@ -103,7 +100,7 @@ _fdchwintr:
!!ld [R_fdc + FDC_REG_DOR], R_dor ! get chip DOR reg addr
! find out what we are supposed to do
- ld [R_fdc + FDC_ISTATE], %l7 ! examine flags
+ ld [R_fdc + FDC_ISTATE], %l7 ! examine flags
cmp %l7, ISTATE_SENSEI
be sensei
nop
diff --git a/sys/arch/sparc/sparc/cache.c b/sys/arch/sparc/sparc/cache.c
index abc187995f1..35c00087300 100644
--- a/sys/arch/sparc/sparc/cache.c
+++ b/sys/arch/sparc/sparc/cache.c
@@ -1,6 +1,8 @@
-/* $NetBSD: cache.c,v 1.5 1995/04/13 14:32:44 pk Exp $ */
+/* $NetBSD: cache.c,v 1.8.4.1 1996/06/12 20:40:35 pk Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -10,12 +12,14 @@
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
+ *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
@@ -23,6 +27,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
@@ -42,6 +48,7 @@
* SUCH DAMAGE.
*
* @(#)cache.c 8.2 (Berkeley) 10/30/93
+ *
*/
/*
@@ -52,6 +59,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <machine/ctlreg.h>
#include <machine/pte.h>
@@ -62,6 +70,46 @@
enum vactype vactype;
struct cachestats cachestats;
+#if defined(SUN4M)
+int cache_alias_dist; /* Cache anti-aliasing constants */
+int cache_alias_bits;
+#endif
+
+/*
+ * A few quick macros to allow for different ASI's between 4M/4/4C machines
+ */
+#define flushls_ctx(p) do { \
+ CPU_ISSUN4M \
+ ? sta(p, ASI_IDCACHELFC, 0) \
+ : sta(p, ASI_FLUSHCTX, 0); \
+} while (0)
+#define flushls_reg(p) do { \
+ CPU_ISSUN4M \
+ ? sta(p, ASI_IDCACHELFR, 0) \
+ : sta(p, ASI_FLUSHREG, 0); \
+} while (0)
+#define flushls_seg(p) do { \
+ CPU_ISSUN4M \
+ ? sta(p, ASI_IDCACHELFS, 0) \
+ : sta(p, ASI_FLUSHSEG, 0); \
+} while (0)
+#define flushls_pag(p) do { \
+ CPU_ISSUN4M \
+ ? sta(p, ASI_IDCACHELFP, 0) \
+ : sta(p, ASI_FLUSHPG, 0); \
+} while (0)
+#define flushls_usr(p) do { \
+ if (CPU_ISSUN4M) \
+ sta(p, ASI_IDCACHELFU, 0); \
+while(0)
+
+/* XXX: (ABB) need more generic Sun4m cache support */
+#if !defined(SUN4) && !defined(SUN4C)
+#define ASI_HWFLUSHSEG 0x05 /* hardware assisted version of FLUSHSEG */
+#define ASI_HWFLUSHPG 0x06 /* hardware assisted version of FLUSHPG */
+#define ASI_HWFLUSHCTX 0x07 /* hardware assisted version of FLUSHCTX */
+#endif
+
/*
* Enable the cache.
* We need to clear out the valid bits first.
@@ -73,25 +121,116 @@ cache_enable()
ls = cacheinfo.c_linesize;
ts = cacheinfo.c_totalsize;
- for (i = AC_CACHETAGS, lim = i + ts; i < lim; i += ls)
- sta(i, ASI_CONTROL, 0);
- stba(AC_SYSENABLE, ASI_CONTROL,
- lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_CACHE);
- cacheinfo.c_enabled = 1;
+ if (CPU_ISSUN4M) {
+ i = lda(SRMMU_PCR, ASI_SRMMU);
+ switch (mmumod) {
+ case SUN4M_MMU_HS: /* HyperSPARC */
+ /*
+ * First we determine what type of cache we have, and
+ * setup the anti-aliasing constants appropriately.
+ */
+ if (i & SRMMU_PCR_CS) {
+ cache_alias_bits = CACHE_ALIAS_BITS_HS256k;
+ cache_alias_dist = CACHE_ALIAS_DIST_HS256k;
+ } else {
+ cache_alias_bits = CACHE_ALIAS_BITS_HS128k;
+ cache_alias_dist = CACHE_ALIAS_DIST_HS128k;
+ }
+ /* Now reset cache tag memory */
+ for (i = 0, lim = ts; i < lim; i += ls)
+ sta(i, ASI_DCACHETAG, 0);
- printf("cache enabled\n");
+ sta(SRMMU_PCR, ASI_SRMMU, /* Enable write-back cache */
+ lda(SRMMU_PCR, ASI_SRMMU) | SRMMU_PCR_CE |
+ SRMMU_PCR_CM);
+ cacheinfo.c_enabled = 1;
+ vactype = VAC_NONE;
+ /* HyperSPARC uses phys. tagged cache */
+
+ /* XXX: should add support */
+ if (cacheinfo.c_hwflush)
+ panic("cache_enable: can't handle 4M with hw-flush cache");
+
+ printf("cache enabled\n");
+ break;
+
+ case SUN4M_MMU_SS: /* SuperSPARC */
+ if ((cpumod & 0xf0) != (SUN4M_SS & 0xf0)) {
+ printf(
+ "cache NOT enabled for %x/%x cpu/mmu combination\n",
+ cpumod, mmumod);
+ break; /* ugh, SS and MS have same MMU # */
+ }
+ cache_alias_bits = CACHE_ALIAS_BITS_SS;
+ cache_alias_dist = CACHE_ALIAS_DIST_SS;
+
+ /* We "flash-clear" the I/D caches. */
+ sta(0x80000000, ASI_ICACHECLR, 0); /* Unlock */
+ sta(0, ASI_ICACHECLR, 0); /* clear */
+ sta(0x80000000, ASI_DCACHECLR, 0);
+ sta(0, ASI_DCACHECLR, 0);
+
+ /* Turn on caches via MMU */
+ sta(SRMMU_PCR, ASI_SRMMU,
+ lda(SRMMU_PCR,ASI_SRMMU) | SRMMU_PCR_DCE |
+ SRMMU_PCR_ICE);
+ cacheinfo.c_enabled = cacheinfo.dc_enabled = 1;
+
+ /* Now try to turn on MultiCache if it exists */
+ /* XXX (ABB) THIS IS BROKEN MUST FIX */
+ if (0&&(lda(SRMMU_PCR, ASI_SRMMU) & SRMMU_PCR_MB) == 0
+ && cacheinfo.ec_totalsize > 0) {
+ /* Multicache controller */
+ sta(MXCC_ENABLE_ADDR, ASI_CONTROL,
+ lda(MXCC_ENABLE_ADDR, ASI_CONTROL) |
+ MXCC_ENABLE_BIT);
+ cacheinfo.ec_enabled = 1;
+ }
+ printf("cache enabled\n");
+ break;
+ case SUN4M_MMU_MS1: /* MicroSPARC */
+ /* We "flash-clear" the I/D caches. */
+ sta(0, ASI_ICACHECLR, 0); /* clear */
+ sta(0, ASI_DCACHECLR, 0);
+
+ /* Turn on caches via MMU */
+ sta(SRMMU_PCR, ASI_SRMMU,
+ lda(SRMMU_PCR,ASI_SRMMU) | SRMMU_PCR_DCE |
+ SRMMU_PCR_ICE);
+ cacheinfo.c_enabled = cacheinfo.dc_enabled = 1;
+
+ printf("cache enabled\n");
+ break;
+
+ default:
+ printf("Unknown MMU architecture...cache disabled.\n");
+ /* XXX: not HyperSPARC -- guess for now */
+ cache_alias_bits = GUESS_CACHE_ALIAS_BITS;
+ cache_alias_dist = GUESS_CACHE_ALIAS_DIST;
+ }
+
+ } else {
+
+ for (i = AC_CACHETAGS, lim = i + ts; i < lim; i += ls)
+ sta(i, ASI_CONTROL, 0);
-#ifdef notyet
- if (cpumod == SUN4_400) {
stba(AC_SYSENABLE, ASI_CONTROL,
- lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_IOCACHE);
- printf("iocache enabled\n");
- }
+ lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_CACHE);
+ cacheinfo.c_enabled = 1;
+
+ printf("cache enabled\n");
+
+#ifdef notyet
+ if (cpumod == SUN4_400) {
+ stba(AC_SYSENABLE, ASI_CONTROL,
+ lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_IOCACHE);
+ printf("iocache enabled\n");
+ }
#endif
+ }
}
-
/*
* Flush the current context from the cache.
*
@@ -116,11 +255,11 @@ cache_flush_context()
ls = cacheinfo.c_linesize;
i = cacheinfo.c_totalsize >> cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
- sta(p, ASI_FLUSHCTX, 0);
+ flushls_ctx(p);
}
}
-#ifdef MMU_3L
+#if defined(MMU_3L) || defined(SUN4M)
/*
* Flush the given virtual region from the cache.
*
@@ -128,7 +267,7 @@ cache_flush_context()
* now the addresses must include the virtual region number, and
* we use the `flush region' space.
*
- * This function is only called on sun4's with 3-level MMUs; there's
+ * This function is only called on sun4m's or sun4's with 3-level MMUs; there's
* no hw-flush space.
*/
void
@@ -143,7 +282,7 @@ cache_flush_region(vreg)
ls = cacheinfo.c_linesize;
i = cacheinfo.c_totalsize >> cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
- sta(p, ASI_FLUSHREG, 0);
+ flushls_reg(p);
}
#endif
@@ -174,7 +313,7 @@ cache_flush_segment(vreg, vseg)
ls = cacheinfo.c_linesize;
i = cacheinfo.c_totalsize >> cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
- sta(p, ASI_FLUSHSEG, 0);
+ flushls_seg(p);
}
}
@@ -190,6 +329,11 @@ cache_flush_page(va)
register int i, ls;
register char *p;
+#ifdef DEBUG
+ if (va & PGOFSET)
+ panic("cache_flush_page: asked to flush misaligned va %x",va);
+#endif
+
cachestats.cs_npgflush++;
p = (char *)va;
if (cacheinfo.c_hwflush)
@@ -198,7 +342,7 @@ cache_flush_page(va)
ls = cacheinfo.c_linesize;
i = NBPG >> cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
- sta(p, ASI_FLUSHPG, 0);
+ flushls_pag(p);
}
}
@@ -209,6 +353,9 @@ cache_flush_page(va)
*
* We choose the best of (context,segment,page) here.
*/
+
+#define CACHE_FLUSH_MAGIC (cacheinfo.c_totalsize / NBPG)
+
void
cache_flush(base, len)
caddr_t base;
@@ -216,6 +363,25 @@ cache_flush(base, len)
{
register int i, ls, baseoff;
register char *p;
+#if defined(MMU_3L)
+ extern int mmu_3l;
+#endif
+
+#if defined(SUN4M)
+ /*
+ * Although physically tagged, we still need to flush the
+ * data cache after (if we have a write-through cache) or before
+ * (in case of write-back caches) DMA operations.
+ *
+ * SS10s and 20s (supersparcs) use cached DVMA, no need to flush.
+ */
+ if (CPU_ISSUN4M && mmumod != SUN4M_MMU_SS) {
+ /* XXX (ABB) - Need more generic cache interface */
+ /* XXX above test conflicts on MicroSPARC (SUN4M_MMU_MS=_SS) */
+ sta(0, ASI_DCACHECLR, 0);
+ return;
+ }
+#endif
if (vactype == VAC_NONE)
return;
@@ -223,11 +389,12 @@ cache_flush(base, len)
/*
* Figure out how much must be flushed.
*
- * If we need to do 16 pages, we can do a segment in the same
- * number of loop iterations. We can also do the context. If
- * we would need to do two segments, do the whole context.
- * This might not be ideal (e.g., fsck likes to do 65536-byte
- * reads, which might not necessarily be aligned).
+ * If we need to do CACHE_FLUSH_MAGIC pages, we can do a segment
+ * in the same number of loop iterations. We can also do the whole
+ * region. If we need to do between 2 and NSEGRG, do the region.
+ * If we need to do two or more regions, just go ahead and do the
+ * whole context. This might not be ideal (e.g., fsck likes to do
+ * 65536-byte reads, which might not necessarily be aligned).
*
* We could try to be sneaky here and use the direct mapping
* to avoid flushing things `below' the start and `above' the
@@ -245,7 +412,7 @@ cache_flush(base, len)
cachestats.cs_ra[min(i, MAXCACHERANGE)]++;
#endif
- if (i <= 15) {
+ if (i < CACHE_FLUSH_MAGIC) {
/* cache_flush_page, for i pages */
p = (char *)((int)base & ~baseoff);
if (cacheinfo.c_hwflush) {
@@ -255,7 +422,7 @@ cache_flush(base, len)
ls = cacheinfo.c_linesize;
i <<= PGSHIFT - cacheinfo.c_l2linesize;
for (; --i >= 0; p += ls)
- sta(p, ASI_FLUSHPG, 0);
+ flushls_pag(p);
}
return;
}
@@ -263,6 +430,22 @@ cache_flush(base, len)
i = (baseoff + len + SGOFSET) >> SGSHIFT;
if (i == 1)
cache_flush_segment(VA_VREG(base), VA_VSEG(base));
- else
- cache_flush_context();
+ else {
+#if defined(MMU_3L) || defined(SUN4M)
+ baseoff = (u_int)base & RGOFSET;
+ i = (baseoff + len + RGOFSET) >> RGSHIFT;
+ if (i == 1
+#if !defined(MMU_3L)
+ && CPU_ISSUN4M
+#elif !defined(SUN4M)
+ && mmu_3l
+#else
+ && (CPU_ISSUN4M || mmu_3l)
+#endif
+ )
+ cache_flush_region(VA_VREG(base));
+ else
+#endif
+ cache_flush_context();
+ }
}
diff --git a/sys/arch/sparc/sparc/cache.h b/sys/arch/sparc/sparc/cache.h
index 9624e9ae775..6076ee314b6 100644
--- a/sys/arch/sparc/sparc/cache.h
+++ b/sys/arch/sparc/sparc/cache.h
@@ -1,6 +1,8 @@
-/* $NetBSD: cache.h,v 1.5 1995/04/13 14:48:51 pk Exp $ */
+/* $NetBSD: cache.h,v 1.7.4.1 1996/06/12 20:41:22 pk Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -8,11 +10,6 @@
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
- * All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Lawrence Berkeley Laboratory.
- *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -23,6 +20,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
@@ -108,27 +107,48 @@ extern enum vactype vactype; /* XXX move into cacheinfo struct */
* bits that are one position higher.
*/
+/* Some more well-known values: */
+
#define CACHE_ALIAS_DIST_SUN4 0x20000
#define CACHE_ALIAS_DIST_SUN4C 0x10000
#define CACHE_ALIAS_BITS_SUN4 0x1e000
#define CACHE_ALIAS_BITS_SUN4C 0xf000
-#if defined(SUN4) && defined(SUN4C)
-#define CACHE_ALIAS_DIST ((cputyp == CPU_SUN4) ? CACHE_ALIAS_DIST_SUN4 : \
- CACHE_ALIAS_DIST_SUN4C)
-#define CACHE_ALIAS_BITS ((cputyp == CPU_SUN4) ? CACHE_ALIAS_BITS_SUN4 : \
- CACHE_ALIAS_BITS_SUN4C)
-#else
-#if defined(SUN4)
-#define CACHE_ALIAS_DIST CACHE_ALIAS_DIST_SUN4
-#define CACHE_ALIAS_BITS CACHE_ALIAS_BITS_SUN4
-#endif
-#if defined(SUN4C)
-#define CACHE_ALIAS_DIST CACHE_ALIAS_DIST_SUN4C
-#define CACHE_ALIAS_BITS CACHE_ALIAS_BITS_SUN4C
-#endif
-#endif
+#define CACHE_ALIAS_DIST_HS128k 0x20000
+#define CACHE_ALIAS_BITS_HS128k 0x1f000
+#define CACHE_ALIAS_DIST_HS256k 0x40000
+#define CACHE_ALIAS_BITS_HS256k 0x3f000
+
+#define CACHE_ALIAS_DIST_SS 0x0
+#define CACHE_ALIAS_BITS_SS 0x0
+
+#define CACHE_ALIAS_DIST_MS GUESS_CACHE_ALIAS_DIST /* fix! */
+#define CACHE_ALIAS_BITS_MS GUESS_CACHE_ALIAS_BITS /* %%% */
+
+/*
+ * Assuming a tag format where the least significant bits are the byte offset
+ * into the cache line, and the next-most significant bits are the line id,
+ * we can calculate the appropriate aliasing constants. We also assume that
+ * the linesize and total cache size are powers of 2.
+ */
+#define GUESS_CACHE_ALIAS_BITS ((cacheinfo.c_totalsize - 1) & ~PGOFSET)
+#define GUESS_CACHE_ALIAS_DIST (cacheinfo.c_totalsize)
+
+extern int cache_alias_dist; /* If `guessed' */
+extern int cache_alias_bits;
+
+#define CACHE_ALIAS_DIST (CPU_ISSUN4M \
+ ? cache_alias_dist \
+ : (CPU_ISSUN4C \
+ ? CACHE_ALIAS_DIST_SUN4C \
+ : CACHE_ALIAS_DIST_SUN4))
+
+#define CACHE_ALIAS_BITS (CPU_ISSUN4M \
+ ? cache_alias_bits \
+ : (CPU_ISSUN4C \
+ ? CACHE_ALIAS_BITS_SUN4C \
+ : CACHE_ALIAS_BITS_SUN4))
/*
* True iff a1 and a2 are `bad' aliases (will cause cache duplication).
@@ -140,19 +160,35 @@ extern enum vactype vactype; /* XXX move into cacheinfo struct */
*/
void cache_enable __P((void)); /* turn it on */
void cache_flush_context __P((void)); /* flush current context */
-void cache_flush_segment __P((int vreg, int vseg)); /* flush seg in cur ctx */
+void cache_flush_region __P((int)); /* flush region in cur ctx */
+void cache_flush_segment __P((int, int)); /* flush seg in cur ctx */
void cache_flush_page __P((int va)); /* flush page in cur ctx */
-void cache_flush __P((caddr_t base, u_int len));/* flush region */
+void cache_flush __P((caddr_t, u_int)); /* flush region */
/*
* Cache control information.
*/
struct cacheinfo {
int c_totalsize; /* total size, in bytes */
+ /* if split, MAX(icache,dcache) */
int c_enabled; /* true => cache is enabled */
int c_hwflush; /* true => have hardware flush */
int c_linesize; /* line size, in bytes */
int c_l2linesize; /* log2(linesize) */
+ int c_physical; /* true => cache is physical */
+ int c_split; /* true => cache is split */
+ int ic_totalsize; /* instruction cache */
+ int ic_enabled;
+ int ic_linesize;
+ int ic_l2linesize;
+ int dc_totalsize; /* data cache */
+ int dc_enabled;
+ int dc_linesize;
+ int dc_l2linesize;
+ int ec_totalsize; /* external cache info */
+ int ec_enabled;
+ int ec_linesize;
+ int ec_l2linesize;
};
extern struct cacheinfo cacheinfo;
diff --git a/sys/arch/sparc/sparc/clock.c b/sys/arch/sparc/sparc/clock.c
index 1f30672b5b2..d8606c7b21d 100644
--- a/sys/arch/sparc/sparc/clock.c
+++ b/sys/arch/sparc/sparc/clock.c
@@ -1,10 +1,13 @@
-/* $NetBSD: clock.c,v 1.26 1995/12/11 12:45:18 pk Exp $ */
+/* $NetBSD: clock.c,v 1.44 1996/05/16 15:57:12 abrown Exp $ */
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1994 Gordon W. Ross
* Copyright (c) 1993 Adam Glass
+ * Copyright (c) 1996 Paul Kranenburg
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
@@ -12,12 +15,14 @@
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
+ *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
@@ -27,6 +32,8 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
+ * This product includes software developed by Paul Kranenburg.
+ * This product includes software developed by Harvard University.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -44,6 +51,7 @@
* SUCH DAMAGE.
*
* @(#)clock.c 8.1 (Berkeley) 6/11/93
+ *
*/
/*
@@ -57,6 +65,7 @@
#include <sys/proc.h>
#include <sys/resourcevar.h>
#include <sys/malloc.h>
+#include <sys/systm.h>
#ifdef GPROF
#include <sys/gmon.h>
#endif
@@ -65,7 +74,9 @@
#include <machine/autoconf.h>
#include <machine/eeprom.h>
+#include <machine/cpu.h>
+#include <sparc/sparc/vaddrs.h>
#include <sparc/sparc/clockreg.h>
#include <sparc/sparc/intreg.h>
#include <sparc/sparc/timerreg.h>
@@ -84,13 +95,9 @@ int statvar = 8192;
int statmin; /* statclock interval - 1/2*variance */
int timerok;
-#if defined(SUN4)
#include <sparc/sparc/intersil7170.h>
extern struct idprom idprom;
-static int oldclk = 0;
-volatile struct intersil7170 *i7;
-
#define intersil_command(run, interrupt) \
(run | interrupt | INTERSIL_CMD_FREQ_32K | INTERSIL_CMD_24HR_MODE | \
INTERSIL_CMD_NORMAL_MODE)
@@ -105,23 +112,31 @@ volatile struct intersil7170 *i7;
#define intersil_clear(CLOCK) CLOCK->clk_intr_reg
+#if defined(SUN4)
/*
- * OCLOCK support: 4/100's and 4/200's have the old clock.
+ * OCLOCK support: 4/100's and 4/200's have the old clock.
*/
+static int oldclk = 0;
+struct intersil7170 *i7;
+
static long oclk_get_secs __P((void));
static void oclk_get_dt __P((struct date_time *));
static void dt_to_gmt __P((struct date_time *, long *));
static void oclk_set_dt __P((struct date_time *));
static void oclk_set_secs __P((long));
static void gmt_to_dt __P((long *, struct date_time *));
+#endif
static int oclockmatch __P((struct device *, void *, void *));
static void oclockattach __P((struct device *, struct device *, void *));
-struct cfdriver oclockcd =
- { NULL, "oclock", oclockmatch, oclockattach, DV_DULL,
- sizeof(struct device) };
-#endif /* SUN4 */
+struct cfattach oclock_ca = {
+ sizeof(struct device), oclockmatch, oclockattach
+};
+
+struct cfdriver oclock_cd = {
+ NULL, "oclock", DV_DULL
+};
/*
* Sun 4 machines use the old-style (a'la Sun 3) EEPROM. On the
@@ -133,61 +148,84 @@ struct cfdriver oclockcd =
* attached.
*/
char *eeprom_va = NULL;
+#if defined(SUN4)
static int eeprom_busy = 0;
static int eeprom_wanted = 0;
static int eeprom_nvram = 0; /* non-zero if eeprom is on Mostek */
+static int eeprom_take __P((void));
+static void eeprom_give __P((void));
+static int eeprom_update __P((char *, int, int));
+#endif
static int eeprom_match __P((struct device *, void *, void *));
static void eeprom_attach __P((struct device *, struct device *, void *));
-struct cfdriver eepromcd = {
- NULL, "eeprom", eeprom_match, eeprom_attach,
- DV_DULL, sizeof(struct device)
+
+struct cfattach eeprom_ca = {
+ sizeof(struct device), eeprom_match, eeprom_attach
};
-#if defined(SUN4)
-static int eeprom_update __P((char *, int, int));
-static int eeprom_take __P((void));
-static void eeprom_give __P((void));
-#endif
+struct cfdriver eeprom_cd = {
+ NULL, "eeprom", DV_DULL
+};
static int clockmatch __P((struct device *, void *, void *));
static void clockattach __P((struct device *, struct device *, void *));
-struct cfdriver clockcd = {
- NULL, "clock", clockmatch, clockattach,
- DV_DULL, sizeof(struct device)
+
+struct cfattach clock_ca = {
+ sizeof(struct device), clockmatch, clockattach
+};
+
+struct cfdriver clock_cd = {
+ NULL, "clock", DV_DULL
};
static int timermatch __P((struct device *, void *, void *));
static void timerattach __P((struct device *, struct device *, void *));
-struct cfdriver timercd = {
- NULL, "timer", timermatch, timerattach,
- DV_DULL, sizeof(struct device)
+
+struct timer_4m *timerreg_4m; /* XXX - need more cleanup */
+struct counter_4m *counterreg_4m;
+#define timerreg4 ((struct timerreg_4 *)TIMERREG_VA)
+
+struct cfattach timer_ca = {
+ sizeof(struct device), timermatch, timerattach
+};
+
+struct cfdriver timer_cd = {
+ NULL, "timer", DV_DULL
};
+struct chiptime;
+void clk_wenable __P((int));
+void myetheraddr __P((u_char *));
+int chiptotime __P((int, int, int, int, int, int));
+void timetochip __P((struct chiptime *));
+
+int timerblurb = 10; /* Guess a value; used before clock is attached */
/*
* old clock match routine
*/
-
static int
oclockmatch(parent, vcf, aux)
struct device *parent;
void *aux, *vcf;
{
- struct cfdata *cf = vcf;
register struct confargs *ca = aux;
-#if defined(SUN4)
- if (cputyp==CPU_SUN4) {
- if (cpumod == SUN4_100 || cpumod == SUN4_200)
- return (strcmp(oclockcd.cd_name, ca->ca_ra.ra_name) == 0);
+ /* Only these sun4s have oclock */
+ if (!CPU_ISSUN4 || (cpumod != SUN4_100 && cpumod != SUN4_200))
return (0);
- }
-#endif /* SUN4 */
- return (0); /* only sun4 has oclock */
-}
-#if defined(SUN4)
+ /* Check configuration name */
+ if (strcmp(oclock_cd.cd_name, ca->ca_ra.ra_name) != 0)
+ return (0);
+
+ /* Make sure there is something there */
+ if (probeget(ca->ca_ra.ra_vaddr, 1) == -1)
+ return (0);
+
+ return (1);
+}
/* ARGSUSED */
static void
@@ -195,16 +233,16 @@ oclockattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
+#if defined(SUN4)
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
struct idprom *idp;
register int h;
oldclk = 1; /* we've got an oldie! */
- printf("\n");
- i7 = (volatile struct intersil7170 *) mapiodev(ra->ra_reg, 0,
- sizeof(*i7), ca->ca_bustype);
+ i7 = (struct intersil7170 *)
+ mapiodev(ra->ra_reg, 0, sizeof(*i7), ca->ca_bustype);
idp = &idprom;
h = idp->id_machine << 24;
@@ -212,8 +250,36 @@ oclockattach(parent, self, aux)
h |= idp->id_hostid[1] << 8;
h |= idp->id_hostid[2];
hostid = h;
-}
+
+ /*
+ * calibrate delay()
+ */
+ ienab_bic(IE_L14 | IE_L10); /* disable all clock intrs */
+ for (timerblurb = 1; ; timerblurb++) {
+ volatile register char *ireg = &i7->clk_intr_reg;
+ register int ival;
+ *ireg = INTERSIL_INTER_CSECONDS; /* 1/100 sec */
+ intersil_enable(i7); /* enable clock */
+ while ((*ireg & INTERSIL_INTER_PENDING) == 0)
+ /* sync with interrupt */;
+ while ((*ireg & INTERSIL_INTER_PENDING) == 0)
+ /* XXX: do it again, seems to need it */;
+ delay(10000); /* Probe 1/100 sec delay */
+ ival = *ireg; /* clear, save value */
+ intersil_disable(i7); /* disable clock */
+ if (ival & INTERSIL_INTER_PENDING) {
+ printf(" delay constant %d%s\n", timerblurb,
+ (timerblurb == 1) ? " [TOO SMALL?]" : "");
+ break;
+ }
+ if (timerblurb > 10) {
+ printf("\noclock: calibration failing; clamped at %d\n",
+ timerblurb);
+ break;
+ }
+ }
#endif /* SUN4 */
+}
/*
* Sun 4/100, 4/200 EEPROM match routine.
@@ -223,28 +289,31 @@ eeprom_match(parent, vcf, aux)
struct device *parent;
void *aux, *vcf;
{
-#if defined(SUN4)
struct cfdata *cf = vcf;
struct confargs *ca = aux;
- if (cputyp == CPU_SUN4) {
- if (cf->cf_unit != 0)
- return (0);
+ if (!CPU_ISSUN4)
+ return (0);
- if (cpumod == SUN4_100 || cpumod == SUN4_200) {
- if (strcmp(eepromcd.cd_name, ca->ca_ra.ra_name))
- return (0);
- /*
- * Make sure there's something there...
- * This is especially important if we want to
- * use the same kernel on a 4/100 as a 4/200.
- */
- if (probeget(ca->ca_ra.ra_vaddr, 1) != -1)
- return (1);
- }
- }
-#endif /* SUN4 */
- return (0);
+ if (cf->cf_unit != 0)
+ return (0);
+
+ if (cpumod != SUN4_100 && cpumod != SUN4_200)
+ return (0);
+
+ if (strcmp(eeprom_cd.cd_name, ca->ca_ra.ra_name) != 0)
+ return (0);
+
+ /*
+ * Make sure there's something there...
+ * This is especially important if we want to
+ * use the same kernel on a 4/100 as a 4/200.
+ */
+ if (probeget(ca->ca_ra.ra_vaddr, 1) == -1)
+ return (0);
+
+ /* Passed all tests */
+ return (1);
}
static void
@@ -258,8 +327,7 @@ eeprom_attach(parent, self, aux)
printf("\n");
- eeprom_va = (char *)mapiodev(ra->ra_reg, 0,
- sizeof(struct eeprom), ca->ca_bustype);
+ eeprom_va = (char *)mapiodev(ra->ra_reg, 0, EEPROM_SIZE, ca->ca_bustype);
eeprom_nvram = 0;
#endif /* SUN4 */
@@ -274,17 +342,23 @@ clockmatch(parent, vcf, aux)
struct device *parent;
void *aux, *vcf;
{
- struct cfdata *cf = vcf;
register struct confargs *ca = aux;
-#if defined(SUN4)
- if (cputyp==CPU_SUN4) {
- if (cpumod == SUN4_300 || cpumod == SUN4_400)
- return (strcmp(clockcd.cd_name,
- ca->ca_ra.ra_name) == 0);
- return (0);
+ if (CPU_ISSUN4) {
+ /* Only these sun4s have "clock" (others have "oclock") */
+ if (cpumod != SUN4_300 && cpumod != SUN4_400)
+ return (0);
+
+ if (strcmp(clock_cd.cd_name, ca->ca_ra.ra_name) != 0)
+ return (0);
+
+ /* Make sure there is something there */
+ if (probeget(ca->ca_ra.ra_vaddr, 1) == -1)
+ return (0);
+
+ return (1);
}
-#endif /* SUN4 */
+
return (strcmp("eeprom", ca->ca_ra.ra_name) == 0);
}
@@ -299,17 +373,20 @@ clockattach(parent, self, aux)
register struct idprom *idp;
struct confargs *ca = aux;
struct romaux *ra = &ca->ca_ra;
- char *prop;
+ char *prop = NULL;
-#if defined(SUN4)
- if (cputyp == CPU_SUN4)
+ if (CPU_ISSUN4)
prop = "mk48t02";
-#endif
-#if defined(SUN4C) || defined(SUN4M)
- if (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M)
+
+ if (CPU_ISSUN4COR4M)
prop = getpropstring(ra->ra_node, "model");
+
+#ifdef DIAGNOSTIC
+ if (prop == NULL)
+ panic("no prop");
#endif
printf(": %s (eeprom)\n", prop);
+
/*
* We ignore any existing virtual address as we need to map
* this read-only and make it read-write only temporarily,
@@ -322,25 +399,25 @@ clockattach(parent, self, aux)
/*
* the MK48T08 is 8K
*/
- cl = (struct clockreg *)mapiodev(ra->ra_reg, 0, 2 * NBPG,
- ca->ca_bustype);
- pmap_changeprot(pmap_kernel(), (vm_offset_t)cl,
- VM_PROT_READ, 1);
- pmap_changeprot(pmap_kernel(), (vm_offset_t)cl + NBPG,
- VM_PROT_READ, 1);
+ cl = (struct clockreg *)mapiodev(ra->ra_reg, 0, 8192,
+ ca->ca_bustype);
+ pmap_changeprot(pmap_kernel(), (vm_offset_t)cl, VM_PROT_READ, 1);
+ pmap_changeprot(pmap_kernel(), (vm_offset_t)cl + 4096,
+ VM_PROT_READ, 1);
cl = (struct clockreg *)((int)cl + CLK_MK48T08_OFF);
} else {
/*
* the MK48T02 is 2K
*/
- cl = (struct clockreg *)mapiodev(ra->ra_reg, 0, sizeof *clockreg,
- ca->ca_bustype);
+ cl = (struct clockreg *)mapiodev(ra->ra_reg, 0,
+ sizeof *clockreg,
+ ca->ca_bustype);
pmap_changeprot(pmap_kernel(), (vm_offset_t)cl, VM_PROT_READ, 1);
- idp = &cl->cl_idprom;
}
+ idp = &cl->cl_idprom;
#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
idp = &idprom;
if (cpumod == SUN4_300 || cpumod == SUN4_400) {
@@ -349,6 +426,7 @@ clockattach(parent, self, aux)
}
}
#endif
+
h = idp->id_machine << 24;
h |= idp->id_hostid[0] << 16;
h |= idp->id_hostid[1] << 8;
@@ -365,17 +443,31 @@ timermatch(parent, vcf, aux)
struct device *parent;
void *aux, *vcf;
{
- struct cfdata *cf = vcf;
register struct confargs *ca = aux;
-#if defined(SUN4)
- if (cputyp==CPU_SUN4) {
- if (cpumod == SUN4_300 || cpumod == SUN4_400)
- return (strcmp("timer", ca->ca_ra.ra_name) == 0);
- return (0);
+ if (CPU_ISSUN4) {
+ if (cpumod != SUN4_300 && cpumod != SUN4_400)
+ return (0);
+
+ if (strcmp("timer", ca->ca_ra.ra_name) != 0)
+ return (0);
+
+ /* Make sure there is something there */
+ if (probeget(ca->ca_ra.ra_vaddr, 4) == -1)
+ return (0);
+
+ return (1);
}
-#endif /* SUN4 */
- return (strcmp("counter-timer", ca->ca_ra.ra_name) == 0);
+
+ if (CPU_ISSUN4C) {
+ return (strcmp("counter-timer", ca->ca_ra.ra_name) == 0);
+ }
+
+ if (CPU_ISSUN4M) {
+ return (strcmp("counter", ca->ca_ra.ra_name) == 0);
+ }
+
+ return (0);
}
/* ARGSUSED */
@@ -386,16 +478,70 @@ timerattach(parent, self, aux)
{
struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
+ volatile int *cnt = NULL, *lim = NULL;
+ /* XXX: must init to NULL to avoid stupid gcc -Wall warning */
+
+ if (CPU_ISSUN4M) {
+ (void)mapdev(&ra->ra_reg[ra->ra_nreg-1], TIMERREG_VA, 0,
+ sizeof(struct timer_4m), ca->ca_bustype);
+ (void)mapdev(&ra->ra_reg[0], COUNTERREG_VA, 0,
+ sizeof(struct counter_4m), ca->ca_bustype);
+ timerreg_4m = (struct timer_4m *)TIMERREG_VA;
+ counterreg_4m = (struct counter_4m *)COUNTERREG_VA;
+
+ /* Put processor counter in "timer" mode */
+ timerreg_4m->t_cfg = 0;
+
+ cnt = &counterreg_4m->t_counter;
+ lim = &counterreg_4m->t_limit;
+ }
+
+ if (CPU_ISSUN4OR4C) {
+ /*
+ * This time, we ignore any existing virtual address because
+ * we have a fixed virtual address for the timer, to make
+ * microtime() faster (in SUN4/SUN4C kernel only).
+ */
+ (void)mapdev(ra->ra_reg, TIMERREG_VA, 0,
+ sizeof(struct timerreg_4), ca->ca_bustype);
+
+ cnt = &timerreg4->t_c14.t_counter;
+ lim = &timerreg4->t_c14.t_limit;
+ }
+
+ timerok = 1;
- printf("\n");
/*
- * This time, we ignore any existing virtual address because
- * we have a fixed virtual address for the timer, to make
- * microtime() faster.
+ * Calibrate delay() by tweaking the magic constant
+ * until a delay(100) actually reads (at least) 100 us on the clock.
+ * Note: sun4m clocks tick with 500ns periods.
*/
- (void)mapdev(ra->ra_reg, TIMERREG_VA, 0, sizeof(struct timerreg),
- ca->ca_bustype);
- timerok = 1;
+
+ for (timerblurb = 1; ; timerblurb++) {
+ volatile int discard;
+ register int t0, t1;
+
+ /* Reset counter register by writing some large limit value */
+ discard = *lim;
+ *lim = tmr_ustolim(TMR_MASK-1);
+
+ t0 = *cnt;
+ delay(100);
+ t1 = *cnt;
+
+ if (t1 & TMR_LIMIT)
+ panic("delay calibration");
+
+ t0 = (t0 >> TMR_SHIFT) & TMR_MASK;
+ t1 = (t1 >> TMR_SHIFT) & TMR_MASK;
+
+ if (t1 >= t0 + 100)
+ break;
+
+ }
+
+ printf(" delay constant %d\n", timerblurb);
+
/* should link interrupt handlers here, rather than compiled-in? */
}
@@ -418,7 +564,9 @@ clk_wenable(onoff)
prot = --writers == 0 ? VM_PROT_READ : 0;
splx(s);
if (prot)
- pmap_changeprot(pmap_kernel(), (vm_offset_t)clockreg, prot, 1);
+ pmap_changeprot(pmap_kernel(),
+ (vm_offset_t)clockreg & ~(NBPG-1),
+ prot, 1);
}
/*
@@ -432,9 +580,10 @@ myetheraddr(cp)
register struct idprom *idp = &cl->cl_idprom;
#if defined(SUN4)
- if (cputyp == CPU_SUN4)
+ if (CPU_ISSUN4)
idp = &idprom;
#endif
+
cp[0] = idp->id_ether[0];
cp[1] = idp->id_ether[1];
cp[2] = idp->id_ether[2];
@@ -444,56 +593,12 @@ myetheraddr(cp)
}
/*
- * This is easy to do on the machine with new-style clock chips
- * since we have freerunning microsecond timers -- no need to
- * guess at cpu speed factors. We just wait for it to change
- * n times (if we calculated a limit, we might overshoot, and
- * precision is irrelevant here---we want less object code).
- * On machines with the old-style clocks, we've determined good
- * estimates.
- */
-delay(n)
- register int n;
-{
- register int c, t;
-
-#if defined(SUN4)
- if (oldclk) {
- volatile register int lcv;
-
- /*
- * Two cases: 4/100 and 4/200.
- */
- if (cpumod == SUN4_200)
- n = cacheinfo.c_enabled ? (n << 3) : (n << 1);
- else
- n = n << 1;
- while (--n >= 0)
- lcv = n;
- return (0);
- }
-#endif /* SUN4 */
-
- if (timerok==0)
- return (0);
-
- if (timercd.cd_ndevs == 0)
- panic("delay");
- c = TIMERREG->t_c10.t_counter;
- while (--n >= 0) {
- while ((t = TIMERREG->t_c10.t_counter) == c)
- continue;
- c = t;
- }
- return (0);
-}
-
-/*
* Set up the real-time and statistics clocks. Leave stathz 0 only if
* no alternative timer is available.
*
* The frequencies of these clocks must be an even number of microseconds.
*/
+void
cpu_initclocks()
{
register int statint, minint;
@@ -501,22 +606,19 @@ cpu_initclocks()
#if defined(SUN4)
if (oldclk) {
int dummy;
+
profhz = hz = 100;
tick = 1000000 / hz;
i7->clk_intr_reg = INTERSIL_INTER_CSECONDS; /* 1/100 sec */
- ienab_bic(IE_L14 | IE_L10); /* disable all clock intrs */
-
- intersil_disable(i7); /* disable clock */
-
- dummy = intersil_clear(i7); /* clear interrupts */
-
- ienab_bis(IE_L10); /* enable l10 interrupt */
+ ienab_bic(IE_L14 | IE_L10); /* disable all clock intrs */
+ intersil_disable(i7); /* disable clock */
+ dummy = intersil_clear(i7); /* clear interrupts */
+ ienab_bis(IE_L10); /* enable l10 interrupt */
+ intersil_enable(i7); /* enable clock */
- intersil_enable(i7); /* enable clock */
-
- return (0);
+ return;
}
#endif /* SUN4 */
@@ -537,10 +639,27 @@ cpu_initclocks()
minint = statint / 2 + 100;
while (statvar > minint)
statvar >>= 1;
- TIMERREG->t_c10.t_limit = tmr_ustolim(tick);
- TIMERREG->t_c14.t_limit = tmr_ustolim(statint);
+
+ if (CPU_ISSUN4M) {
+ timerreg_4m->t_limit = tmr_ustolim(tick);
+ counterreg_4m->t_limit = tmr_ustolim(statint);
+ }
+
+ if (CPU_ISSUN4OR4C) {
+ timerreg4->t_c10.t_limit = tmr_ustolim(tick);
+ timerreg4->t_c14.t_limit = tmr_ustolim(statint);
+ }
+
statmin = statint - (statvar >> 1);
- ienab_bis(IE_L14 | IE_L10);
+
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ ienab_bic(SINTR_T);
+#endif
+
+ if (CPU_ISSUN4OR4C)
+ ienab_bis(IE_L14 | IE_L10);
+
}
/*
@@ -563,9 +682,18 @@ int
clockintr(cap)
void *cap;
{
- volatile register int discard;
+ register volatile int discard;
+ int s;
extern int rom_console_input;
+ /*
+ * Protect the clearing of the clock interrupt. If we don't
+ * do this, and we're interrupted (by the zs, for example),
+ * the clock stops!
+ * XXX WHY DOES THIS HAPPEN?
+ */
+ s = splhigh();
+
#if defined(SUN4)
if (oldclk) {
discard = intersil_clear(i7);
@@ -575,8 +703,18 @@ clockintr(cap)
}
#endif
/* read the limit register to clear the interrupt */
- discard = TIMERREG->t_c10.t_limit;
+ if (CPU_ISSUN4M) {
+ discard = timerreg_4m->t_limit;
+ }
+
+ if (CPU_ISSUN4OR4C) {
+ discard = timerreg4->t_c10.t_limit;
+ }
+#if defined(SUN4)
forward:
+#endif
+ splx(s);
+
hardclock((struct clockframe *)cap);
if (rom_console_input && cnrom())
setsoftint();
@@ -591,7 +729,7 @@ int
statintr(cap)
void *cap;
{
- volatile register int discard;
+ register volatile int discard;
register u_long newint, r, var;
#if defined(SUN4)
@@ -602,7 +740,20 @@ statintr(cap)
#endif
/* read the limit register to clear the interrupt */
- discard = TIMERREG->t_c14.t_limit;
+ if (CPU_ISSUN4M) {
+ discard = counterreg_4m->t_limit;
+ if (timerok == 0) {
+ /* Stop the clock */
+ counterreg_4m->t_limit = 0;
+ counterreg_4m->t_ss = 0;
+ timerreg_4m->t_cfg = TMR_CFG_USER;
+ return 1;
+ }
+ }
+
+ if (CPU_ISSUN4OR4C) {
+ discard = timerreg4->t_c14.t_limit;
+ }
statclock((struct clockframe *)cap);
/*
@@ -616,7 +767,13 @@ statintr(cap)
} while (r == 0);
newint = statmin + r;
- TIMERREG->t_c14.t_limit = tmr_ustolim(newint);
+ if (CPU_ISSUN4M) {
+ counterreg_4m->t_limit = tmr_ustolim(newint);
+ }
+
+ if (CPU_ISSUN4OR4C) {
+ timerreg4->t_c14.t_limit = tmr_ustolim(newint);
+ }
return (1);
}
@@ -628,6 +785,11 @@ statintr(cap)
#define SECDAY (24 * 60 * 60)
#define SECYR (SECDAY * 365)
+/*
+ * should use something like
+ * #define LEAPYEAR(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+ * but it's unlikely that we'll still be around in 2100.
+ */
#define LEAPYEAR(y) (((y) & 3) == 0)
/*
@@ -637,6 +799,7 @@ statintr(cap)
const short dayyr[12] =
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+int
chiptotime(sec, min, hour, day, mon, year)
register int sec, min, hour, day, mon, year;
{
@@ -672,6 +835,7 @@ struct chiptime {
int year;
};
+void
timetochip(c)
register struct chiptime *c;
{
@@ -720,6 +884,7 @@ timetochip(c)
/*
* Set up the system's time, given a `reasonable' time value.
*/
+void
inittodr(base)
time_t base;
{
@@ -756,7 +921,9 @@ inittodr(base)
clk_wenable(0);
time.tv_sec = chiptotime(sec, min, hour, day, mon, year);
+#if defined(SUN4)
forward:
+#endif
if (time.tv_sec == 0) {
printf("WARNING: bad date in battery clock");
/*
@@ -785,6 +952,7 @@ forward:
* and when rebooting. Do nothing if the time is not yet known, e.g.,
* when crashing during autoconfig.
*/
+void
resettodr()
{
register struct clockreg *cl;
@@ -822,24 +990,24 @@ resettodr()
static long
oclk_get_secs()
{
- struct date_time dt;
- long gmt;
+ struct date_time dt;
+ long gmt;
- oclk_get_dt(&dt);
- dt_to_gmt(&dt, &gmt);
- return (gmt);
+ oclk_get_dt(&dt);
+ dt_to_gmt(&dt, &gmt);
+ return (gmt);
}
static void
oclk_set_secs(secs)
long secs;
{
- struct date_time dt;
- long gmt;
+ struct date_time dt;
+ long gmt;
- gmt = secs;
- gmt_to_dt(&gmt, &dt);
- oclk_set_dt(&dt);
+ gmt = secs;
+ gmt_to_dt(&gmt, &dt);
+ oclk_set_dt(&dt);
}
/*
@@ -851,48 +1019,48 @@ static void
oclk_get_dt(dt)
struct date_time *dt;
{
- int s;
- register volatile char *src, *dst;
+ int s;
+ register volatile char *src, *dst;
- src = (char *) &i7->counters;
+ src = (char *) &i7->counters;
- s = splhigh();
- i7->clk_cmd_reg =
- intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
+ s = splhigh();
+ i7->clk_cmd_reg =
+ intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
- dst = (char *) dt;
- dt++; /* end marker */
- do {
- *dst++ = *src++;
- } while (dst < (char*)dt);
+ dst = (char *) dt;
+ dt++; /* end marker */
+ do {
+ *dst++ = *src++;
+ } while (dst < (char*)dt);
- i7->clk_cmd_reg =
- intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
- splx(s);
+ i7->clk_cmd_reg =
+ intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
+ splx(s);
}
static void
oclk_set_dt(dt)
struct date_time *dt;
{
- int s;
- register volatile char *src, *dst;
+ int s;
+ register volatile char *src, *dst;
- dst = (char *) &i7->counters;
+ dst = (char *) &i7->counters;
- s = splhigh();
- i7->clk_cmd_reg =
- intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
+ s = splhigh();
+ i7->clk_cmd_reg =
+ intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
- src = (char *) dt;
- dt++; /* end marker */
- do {
- *dst++ = *src++;
- } while (src < (char *)dt);
+ src = (char *) dt;
+ dt++; /* end marker */
+ do {
+ *dst++ = *src++;
+ } while (src < (char *)dt);
- i7->clk_cmd_reg =
- intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
- splx(s);
+ i7->clk_cmd_reg =
+ intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
+ splx(s);
}
@@ -904,14 +1072,14 @@ oclk_set_dt(dt)
/* Traditional UNIX base year */
#define POSIX_BASE_YEAR 1970
-#define FEBRUARY 2
+#define FEBRUARY 2
-#define leapyear(year) ((year) % 4 == 0)
-#define days_in_year(a) (leapyear(a) ? 366 : 365)
-#define days_in_month(a) (month_days[(a) - 1])
+#define leapyear(year) ((year) % 4 == 0)
+#define days_in_year(a) (leapyear(a) ? 366 : 365)
+#define days_in_month(a) (month_days[(a) - 1])
static int month_days[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static void
@@ -919,90 +1087,90 @@ gmt_to_dt(tp, dt)
long *tp;
struct date_time *dt;
{
- register int i;
- register long days, secs;
-
- days = *tp / SECDAY;
- secs = *tp % SECDAY;
-
- /* Hours, minutes, seconds are easy */
- dt->dt_hour = secs / 3600;
- secs = secs % 3600;
- dt->dt_min = secs / 60;
- secs = secs % 60;
- dt->dt_sec = secs;
-
- /* Day of week (Note: 1/1/1970 was a Thursday) */
- dt->dt_dow = (days + 4) % 7;
-
- /* Number of years in days */
- i = POSIX_BASE_YEAR;
- while (days >= days_in_year(i)) {
- days -= days_in_year(i);
- i++;
- }
- dt->dt_year = i - CLOCK_BASE_YEAR;
-
- /* Number of months in days left */
- if (leapyear(i))
- days_in_month(FEBRUARY) = 29;
- for (i = 1; days >= days_in_month(i); i++)
- days -= days_in_month(i);
- days_in_month(FEBRUARY) = 28;
- dt->dt_month = i;
-
- /* Days are what is left over (+1) from all that. */
- dt->dt_day = days + 1;
+ register int i;
+ register long days, secs;
+
+ days = *tp / SECDAY;
+ secs = *tp % SECDAY;
+
+ /* Hours, minutes, seconds are easy */
+ dt->dt_hour = secs / 3600;
+ secs = secs % 3600;
+ dt->dt_min = secs / 60;
+ secs = secs % 60;
+ dt->dt_sec = secs;
+
+ /* Day of week (Note: 1/1/1970 was a Thursday) */
+ dt->dt_dow = (days + 4) % 7;
+
+ /* Number of years in days */
+ i = POSIX_BASE_YEAR;
+ while (days >= days_in_year(i)) {
+ days -= days_in_year(i);
+ i++;
+ }
+ dt->dt_year = i - CLOCK_BASE_YEAR;
+
+ /* Number of months in days left */
+ if (leapyear(i))
+ days_in_month(FEBRUARY) = 29;
+ for (i = 1; days >= days_in_month(i); i++)
+ days -= days_in_month(i);
+ days_in_month(FEBRUARY) = 28;
+ dt->dt_month = i;
+
+ /* Days are what is left over (+1) from all that. */
+ dt->dt_day = days + 1;
}
+
static void
dt_to_gmt(dt, tp)
struct date_time *dt;
long *tp;
{
- register int i;
- register long tmp;
- int year;
+ register int i;
+ register long tmp;
+ int year;
- /*
- * Hours are different for some reason. Makes no sense really.
- */
- tmp = 0;
+ /*
+ * Hours are different for some reason. Makes no sense really.
+ */
- if (dt->dt_hour >= 24)
- goto out;
- if (dt->dt_day > 31)
- goto out;
- if (dt->dt_month > 12)
- goto out;
+ tmp = 0;
- year = dt->dt_year + CLOCK_BASE_YEAR;
+ if (dt->dt_hour >= 24) goto out;
+ if (dt->dt_day > 31) goto out;
+ if (dt->dt_month > 12) goto out;
+
+ year = dt->dt_year + CLOCK_BASE_YEAR;
- /*
- * Compute days since start of time
- * First from years, then from months.
- */
- for (i = POSIX_BASE_YEAR; i < year; i++)
- tmp += days_in_year(i);
- if (leapyear(year) && dt->dt_month > FEBRUARY)
- tmp++;
- /* Months */
- for (i = 1; i < dt->dt_month; i++)
- tmp += days_in_month(i);
- tmp += (dt->dt_day - 1);
+ /*
+ * Compute days since start of time
+ * First from years, then from months.
+ */
+ for (i = POSIX_BASE_YEAR; i < year; i++)
+ tmp += days_in_year(i);
+ if (leapyear(year) && dt->dt_month > FEBRUARY)
+ tmp++;
- /* Now do hours */
- tmp = tmp * 24 + dt->dt_hour;
+ /* Months */
+ for (i = 1; i < dt->dt_month; i++)
+ tmp += days_in_month(i);
+ tmp += (dt->dt_day - 1);
- /* Now do minutes */
- tmp = tmp * 60 + dt->dt_min;
+ /* Now do hours */
+ tmp = tmp * 24 + dt->dt_hour;
- /* Now do seconds */
- tmp = tmp * 60 + dt->dt_sec;
+ /* Now do minutes */
+ tmp = tmp * 60 + dt->dt_min;
+
+ /* Now do seconds */
+ tmp = tmp * 60 + dt->dt_sec;
out:
- *tp = tmp;
+ *tp = tmp;
}
#endif /* SUN4 */
@@ -1023,26 +1191,21 @@ microtime(tvp)
{
int s;
static struct timeval lasttime;
+ static struct timeval oneusec = {0, 1};
if (!oldclk) {
lo_microtime(tvp);
return;
}
+
s = splhigh();
*tvp = time;
- tvp->tv_usec;
- while (tvp->tv_usec > 1000000) {
- tvp->tv_sec++;
- tvp->tv_usec -= 1000000;
- }
- if (tvp->tv_sec == lasttime.tv_sec &&
- tvp->tv_usec <= lasttime.tv_usec &&
- (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) {
- tvp->tv_sec++;
- tvp->tv_usec -= 1000000;
- }
- lasttime = *tvp;
splx(s);
+
+ if (timercmp(tvp, &lasttime, <=))
+ timeradd(&lasttime, &oneusec, tvp);
+
+ lasttime = *tvp;
}
#endif /* SUN4 */
@@ -1061,19 +1224,18 @@ eeprom_uio(uio)
u_int cnt, bcnt;
caddr_t buf = NULL;
- if (cputyp != CPU_SUN4)
+ if (!CPU_ISSUN4)
return (ENODEV);
off = uio->uio_offset;
- if (off > sizeof(struct eeprom))
+ if (off > EEPROM_SIZE)
return (EFAULT);
cnt = uio->uio_resid;
- if (cnt > sizeof(struct eeprom) - off)
- cnt = sizeof(struct eeprom) - off;
+ if (cnt > (EEPROM_SIZE - off))
+ cnt = (EEPROM_SIZE - off);
- error = eeprom_take();
- if (error != 0)
+ if ((error = eeprom_take()) != 0)
return (error);
if (eeprom_va == NULL) {
@@ -1087,14 +1249,14 @@ eeprom_uio(uio)
* this, we byte-by-byte copy the eeprom contents into a
* temporary buffer.
*/
- buf = malloc(sizeof(struct eeprom), M_DEVBUF, M_WAITOK);
+ buf = malloc(EEPROM_SIZE, M_DEVBUF, M_WAITOK);
if (buf == NULL) {
error = EAGAIN;
goto out;
}
if (uio->uio_rw == UIO_READ)
- for (bcnt = 0; bcnt < sizeof(struct eeprom); ++bcnt)
+ for (bcnt = 0; bcnt < EEPROM_SIZE; ++bcnt)
*(char *)(buf + bcnt) = *(char *)(eeprom_va + bcnt);
if ((error = uiomove(buf + off, (int)cnt, uio)) != 0)
@@ -1103,7 +1265,7 @@ eeprom_uio(uio)
if (uio->uio_rw != UIO_READ)
error = eeprom_update(buf, off, cnt);
-out:
+ out:
if (buf)
free(buf, M_DEVBUF);
eeprom_give();
@@ -1132,10 +1294,6 @@ eeprom_update(buf, off, cnt)
ep = eeprom_va + off;
bp = buf + off;
- /*
- * XXX: I'm not totally sure if this is necessary, and I don't
- * know if there are any harmful side effects, either.
- */
if (eeprom_nvram)
clk_wenable(1);
@@ -1164,8 +1322,7 @@ eeprom_update(buf, off, cnt)
++bp;
--cnt;
}
-out:
- /* XXX: see above. */
+ out:
if (eeprom_nvram)
clk_wenable(0);
@@ -1186,7 +1343,7 @@ eeprom_take()
goto out;
}
eeprom_busy = 1;
-out:
+ out:
return (error);
}
@@ -1194,6 +1351,7 @@ out:
static void
eeprom_give()
{
+
eeprom_busy = 0;
if (eeprom_wanted) {
eeprom_wanted = 0;
diff --git a/sys/arch/sparc/sparc/conf.c b/sys/arch/sparc/sparc/conf.c
index a409f8c77c5..17f23d77fda 100644
--- a/sys/arch/sparc/sparc/conf.c
+++ b/sys/arch/sparc/sparc/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.6 1996/07/15 14:57:07 mickey Exp $ */
+/* $NetBSD: conf.c,v 1.40 1996/04/11 19:20:03 thorpej Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -52,49 +52,49 @@
#include <sys/tty.h>
#include <sys/conf.h>
-int ttselect __P((dev_t, int, struct proc *));
+#include <machine/conf.h>
-bdev_decl(sw);
+#include "pty.h"
+#include "bpfilter.h"
+#include "tun.h"
+#include "audio.h"
+#include "vnd.h"
+#include "ccd.h"
+#include "ch.h"
+#include "ss.h"
#include "sd.h"
-bdev_decl(sd);
-#include "xd.h"
-bdev_decl(xd);
-#include "xy.h"
-bdev_decl(xy);
#include "st.h"
-bdev_decl(st);
#include "cd.h"
-bdev_decl(cd);
-#include "vnd.h"
-bdev_decl(vnd);
-#define fdopen Fdopen /* conflicts with fdopen() in kern_descrip.c */
-#include "fd.h"
-bdev_decl(fd);
-#undef fdopen
-#include "ccd.h"
-bdev_decl(ccd);
+
+#include "zs.h"
+#include "fdc.h" /* has NFDC and NFD; see files.sparc */
+#include "bwtwo.h"
+#include "cgthree.h"
+#include "cgfour.h"
+#include "cgsix.h"
+#include "cgeight.h"
+#include "xd.h"
+#include "xy.h"
struct bdevsw bdevsw[] =
{
bdev_notdef(), /* 0 */
bdev_notdef(), /* 1 */
bdev_notdef(), /* 2 */
- bdev_disk_init(NXY,xy), /* 3: XY SMD disk */
+ bdev_disk_init(NXY,xy), /* 3: SMD disk */
bdev_swap_init(1,sw), /* 4 */
bdev_notdef(), /* 5 */
bdev_notdef(), /* 6 */
bdev_disk_init(NSD,sd), /* 7: SCSI disk */
bdev_disk_init(NVND,vnd), /* 8: vnode disk driver */
bdev_disk_init(NCCD,ccd), /* 9: concatenated disk driver */
- bdev_disk_init(NXD,xd), /* 10: XD SMD disk */
+ bdev_disk_init(NXD,xd), /* 10: SMD disk */
bdev_tape_init(NST,st), /* 11: SCSI tape */
bdev_notdef(), /* 12 */
bdev_notdef(), /* 13 */
bdev_notdef(), /* 14 */
bdev_notdef(), /* 15 */
-#define fdopen Fdopen /* conflicts with fdopen() in kern_descrip.c */
bdev_disk_init(NFD,fd), /* 16: floppy disk */
-#undef fdopen
bdev_notdef(), /* 17 */
bdev_disk_init(NCD,cd), /* 18: SCSI CD-ROM */
bdev_lkm_dummy(), /* 19 */
@@ -106,86 +106,6 @@ struct bdevsw bdevsw[] =
};
int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]);
-/* open, close, read, write, ioctl, select */
-#define cdev_gen_init(c,n) { \
- dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
- dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
- 0, dev_init(c,n,select), (dev_type_mmap((*))) enodev }
-
-/* open, close, ioctl */
-#define cdev_openprom_init(c,n) { \
- dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
- (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
- (dev_type_stop((*))) nullop, 0, (dev_type_select((*))) enodev, \
- (dev_type_mmap((*))) enodev }
-
-cdev_decl(cn);
-cdev_decl(ctty);
-#define mmread mmrw
-#define mmwrite mmrw
-cdev_decl(mm);
-cdev_decl(sw);
-#include "zs.h"
-cdev_decl(zs);
-cdev_decl(ms);
-cdev_decl(log);
-cdev_decl(sd);
-cdev_decl(st);
-cdev_decl(xd);
-cdev_decl(xy);
-#include "ch.h"
-cdev_decl(ch);
-#include "pty.h"
-#define ptstty ptytty
-#define ptsioctl ptyioctl
-cdev_decl(pts);
-#define ptctty ptytty
-#define ptcioctl ptyioctl
-cdev_decl(ptc);
-cdev_decl(fb);
-dev_decl(fd,open);
-#include "bwtwo.h"
-cdev_decl(bwtwo);
-cdev_decl(kbd);
-#define fdopen Fdopen
-cdev_decl(fd);
-#undef fdopen
-#include "cgthree.h"
-cdev_decl(cgthree);
-#include "cgfour.h"
-cdev_decl(cgfour);
-cdev_decl(cd);
-#include "cgsix.h"
-cdev_decl(cgsix);
-#include "cgeight.h"
-cdev_decl(cgeight);
-#include "audio.h"
-cdev_decl(audio);
-cdev_decl(openprom);
-#include "bpfilter.h"
-cdev_decl(bpf);
-cdev_decl(vnd);
-cdev_decl(ccd);
-#include "tun.h"
-cdev_decl(tun);
-cdev_decl(svr4_net);
-#ifdef LKM
-#define NLKM 1
-#else
-#define NLKM 0
-#endif
-cdev_decl(lkm);
-#include "rnd.h"
-cdev_decl(rnd);
-
-/* open, close, read, ioctl */
-cdev_decl(ipl);
-#ifdef IPFILTER
-#define NIPF 1
-#else
-#define NIPF 0
-#endif
-
struct cdevsw cdevsw[] =
{
cdev_cn_init(1,cn), /* 0: virtual console */
@@ -197,7 +117,7 @@ struct cdevsw cdevsw[] =
cdev_notdef(), /* 6 */
cdev_swap_init(1,sw), /* 7: /dev/drum (swap pseudo-device) */
cdev_notdef(), /* 8 */
- cdev_disk_init(NXY,xy), /* 9: XY SMD disk */
+ cdev_disk_init(NXY,xy), /* 9: SMD disk */
cdev_notdef(), /* 10 */
cdev_notdef(), /* 11 */
cdev_tty_init(NZS,zs), /* 12: zs serial */
@@ -212,7 +132,7 @@ struct cdevsw cdevsw[] =
cdev_ptc_init(NPTY,ptc), /* 21: pseudo-tty master */
cdev_fb_init(1,fb), /* 22: /dev/fb indirect driver */
cdev_disk_init(NCCD,ccd), /* 23: concatenated disk driver */
- cdev_fd_init(1,fd), /* 24: file descriptor pseudo-device */
+ cdev_fd_init(1,filedesc), /* 24: file descriptor pseudo-device */
cdev_notdef(), /* 25 */
cdev_notdef(), /* 26 */
cdev_fb_init(NBWTWO,bwtwo), /* 27: /dev/bwtwo */
@@ -230,12 +150,8 @@ struct cdevsw cdevsw[] =
cdev_fb_init(NCGFOUR,cgfour), /* 39: /dev/cgfour */
cdev_notdef(), /* 40 */
cdev_notdef(), /* 41 */
- cdev_disk_init(NXD,xd), /* 42: XD SMD disk */
-#ifdef COMPAT_SVR4
- cdev_svr4_net_init(1,svr4_net), /* 43: svr4 net pseudo-device */
-#else
- cdev_notdef(), /* 43 */
-#endif
+ cdev_disk_init(NXD,xd), /* 42: SMD disk */
+ cdev_svr4_net_init(NSVR4_NET,svr4_net), /* 43: svr4 net pseudo-device */
cdev_notdef(), /* 44 */
cdev_notdef(), /* 45 */
cdev_notdef(), /* 46 */
@@ -246,14 +162,12 @@ struct cdevsw cdevsw[] =
cdev_notdef(), /* 51 */
cdev_notdef(), /* 52 */
cdev_notdef(), /* 53 */
-#define fdopen Fdopen /* conflicts with fdopen() in kern_descrip.c */
cdev_disk_init(NFD,fd), /* 54: floppy disk */
-#undef fdopen
cdev_fb_init(NCGTHREE,cgthree), /* 55: /dev/cgthree */
cdev_notdef(), /* 56 */
cdev_notdef(), /* 57 */
cdev_disk_init(NCD,cd), /* 58 SCSI CD-ROM */
- cdev_gen_ipf(NIPF,ipl), /* 59 */
+ cdev_notdef(), /* 59 */
cdev_notdef(), /* 60 */
cdev_notdef(), /* 61 */
cdev_notdef(), /* 62 */
@@ -313,7 +227,6 @@ struct cdevsw cdevsw[] =
cdev_lkm_dummy(), /* 116 */
cdev_lkm_dummy(), /* 117 */
cdev_lkm_dummy(), /* 118 */
- cdev_rnd_init(NRND,rnd), /* 119: random data source */
};
int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
@@ -335,6 +248,7 @@ dev_t swapdev = makedev(4, 0);
*
* A minimal stub routine can always return 0.
*/
+int
iskmemdev(dev)
dev_t dev;
{
@@ -342,6 +256,7 @@ iskmemdev(dev)
return (major(dev) == mem_no && minor(dev) < 2);
}
+int
iszerodev(dev)
dev_t dev;
{
@@ -475,6 +390,7 @@ static int chrtoblktbl[] = {
/*
* Routine to convert from character to block device number.
*/
+int
chrtoblk(dev)
dev_t dev;
{
diff --git a/sys/arch/sparc/sparc/cpu.c b/sys/arch/sparc/sparc/cpu.c
index 43437db234b..f4d7d493a50 100644
--- a/sys/arch/sparc/sparc/cpu.c
+++ b/sys/arch/sparc/sparc/cpu.c
@@ -1,6 +1,8 @@
-/* $NetBSD: cpu.c,v 1.14 1995/02/01 12:37:52 pk Exp $ */
+/* $NetBSD: cpu.c,v 1.22.4.1 1996/06/12 20:39:45 pk Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -10,12 +12,14 @@
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
+ *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
@@ -23,6 +27,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
@@ -42,17 +48,24 @@
* SUCH DAMAGE.
*
* @(#)cpu.c 8.5 (Berkeley) 11/23/93
+ *
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/device.h>
+#include <vm/vm.h>
+
#include <machine/autoconf.h>
#include <machine/cpu.h>
#include <machine/reg.h>
+#include <machine/ctlreg.h>
#include <machine/trap.h>
+#include <machine/pmap.h>
#include <sparc/sparc/cache.h>
+#include <sparc/sparc/asm.h>
/* This is declared here so that you must include a CPU for the cache code. */
struct cacheinfo cacheinfo;
@@ -65,14 +78,25 @@ char cpu_model[100];
static void cpu_attach __P((struct device *, struct device *, void *));
int cpu_match __P((struct device *, void *, void *));
-struct cfdriver cpucd =
- { NULL, "cpu", cpu_match, cpu_attach, DV_CPU, sizeof(struct device) };
+struct cfattach cpu_ca = {
+ sizeof(struct device), cpu_match, cpu_attach
+};
+
+struct cfdriver cpu_cd = {
+ NULL, "cpu", DV_CPU
+};
+#if defined(SUN4C) || defined(SUN4M)
static char *psrtoname __P((int, int, int, char *));
+#endif
static char *fsrtoname __P((int, int, int, char *));
#define IU_IMPL(psr) ((u_int)(psr) >> 28)
#define IU_VERS(psr) (((psr) >> 24) & 0xf)
+#if defined(SUN4M)
+#define SRMMU_IMPL(mmusr) ((u_int)(mmusr) >> 28)
+#define SRMMU_VERS(mmusr) (((mmusr) >> 24) & 0xf)
+#endif
#ifdef notdef
/*
@@ -101,7 +125,7 @@ static char *iu_vendor[16] = {
/*
* 4/110 comment: the 4/110 chops off the top 4 bits of an OBIO address.
- * this confuses autoconf. for example, if you try and map
+ * this confuses autoconf. for example, if you try and map
* 0xfe000000 in obio space on a 4/110 it actually maps 0x0e000000.
* this is easy to verify with the PROM. this causes problems
* with devices like "esp0 at obio0 addr 0xfa000000" because the
@@ -135,12 +159,17 @@ cpu_attach(parent, dev, aux)
struct device *dev;
void *aux;
{
- register int node, clk, bug = 0, i, l;
+ register int node, clk, bug = 0, i;
register int impl, vers, fver;
register char *fpuname;
struct confargs *ca = aux;
struct fpstate fpstate;
- char iubuf[40], fpbuf[40];
+ char *sep;
+ char fpbuf[40];
+#if defined(SUN4C) || defined(SUN4M)
+ register int l;
+ char iubuf[40];
+#endif
/*
* Get the FSR and clear any exceptions. If we do not unload
@@ -165,8 +194,9 @@ cpu_attach(parent, dev, aux)
/* tell them what we have */
node = ca->ca_ra.ra_node;
+
#ifdef SUN4
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
clk = 0;
vactype = VAC_WRITEBACK;
switch (cpumod) {
@@ -188,7 +218,6 @@ cpu_attach(parent, dev, aux)
case SUN4_300:
sprintf(cpu_model, "SUN-4/300 series (%s FPU)", fpuname);
bug = 1;
- vactype = VAC_WRITETHROUGH;
cacheinfo.c_totalsize = 128*1024;
cacheinfo.c_hwflush = 0;
cacheinfo.c_linesize = 16;
@@ -204,29 +233,136 @@ cpu_attach(parent, dev, aux)
}
printf(": %s\n", cpu_model);
}
-#endif
+#endif /* SUN4 */
+
#if defined(SUN4C) || defined(SUN4M)
- if (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) {
+ if (CPU_ISSUN4C || CPU_ISSUN4M) {
clk = getpropint(node, "clock-frequency", 0);
- sprintf(cpu_model, "%s (%s @ %s MHz, %s FPU)",
- getpropstring(node, "name"),
- psrtoname(impl, vers, fver, iubuf), clockfreq(clk), fpuname);
+ if (clk == 0) {
+ /*
+ * Try to find it in the OpenPROM root...
+ */
+ clk = getpropint(findroot(), "clock-frequency", 0);
+ }
+ if (CPU_ISSUN4C)
+ sprintf(cpu_model, "%s (%s @ %s MHz, %s FPU)",
+ getpropstring(node, "name"),
+ psrtoname(impl, vers, fver, iubuf),
+ clockfreq(clk), fpuname);
+ else
+ /* On sun4m, the "name" property identifies CPU */
+ sprintf(cpu_model, "%s @ %s MHz, %s FPU",
+ getpropstring(node, "name"),
+ clockfreq(clk), fpuname);
printf(": %s\n", cpu_model);
/*
* Fill in the cache info. Note, vac-hwflush is spelled
* with an underscore on 4/75s.
*/
- cacheinfo.c_totalsize = getpropint(node, "vac-size", 65536);
- cacheinfo.c_hwflush = getpropint(node, "vac_hwflush", 0) |
- getpropint(node, "vac-hwflush", 0);
- cacheinfo.c_linesize = l = getpropint(node, "vac-linesize", 16);
- for (i = 0; (1 << i) < l; i++)
- /* void */;
- if ((1 << i) != l)
- panic("bad cache line size %d", l);
- cacheinfo.c_l2linesize = i;
- vactype = VAC_WRITETHROUGH;
+ /*bzero(&cacheinfo, sizeof(cacheinfo));*/
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ cacheinfo.c_physical = 1;
+ vactype = node_has_property(node, "cache-physical?")
+ ? VAC_NONE
+ : VAC_WRITETHROUGH; /* ??? */
+ /*
+ * Sun4m physical caches are nice since we never
+ * have to flush them. Unfortunately it is a pain
+ * to determine what size they are, since they may
+ * be split...
+ */
+ switch (mmumod) {
+ case SUN4M_MMU_SS:
+ case SUN4M_MMU_MS1:
+ cacheinfo.c_split = 1;
+ cacheinfo.ic_linesize = l =
+ getpropint(node, "icache-line-size", 0);
+ for (i = 0; (1 << i) < l && l; i++)
+ /* void */;
+ if ((1 << i) != l && l)
+ panic("bad icache line size %d", l);
+ cacheinfo.ic_l2linesize = i;
+ cacheinfo.ic_totalsize = l *
+ getpropint(node, "icache-nlines", 64) *
+ getpropint(node, "icache-associativity", 1);
+
+ cacheinfo.dc_linesize = l =
+ getpropint(node, "dcache-line-size",0);
+ for (i = 0; (1 << i) < l && l; i++)
+ /* void */;
+ if ((1 << i) != l && l)
+ panic("bad dcache line size %d", l);
+ cacheinfo.dc_l2linesize = i;
+ cacheinfo.dc_totalsize = l *
+ getpropint(node, "dcache-nlines", 128) *
+ getpropint(node, "dcache-associativity", 1);
+
+ cacheinfo.ec_linesize = l =
+ getpropint(node, "ecache-line-size", 0);
+ for (i = 0; (1 << i) < l && l; i++)
+ /* void */;
+ if ((1 << i) != l && l)
+ panic("bad ecache line size %d", l);
+ cacheinfo.ec_l2linesize = i;
+ cacheinfo.ec_totalsize = l *
+ getpropint(node, "ecache-nlines", 32768) *
+ getpropint(node, "ecache-associativity", 1);
+
+ /*
+ * XXX - The following will have to do until
+ * we have per-cpu cache handling.
+ */
+ cacheinfo.c_l2linesize =
+ min(cacheinfo.ic_l2linesize,
+ cacheinfo.dc_l2linesize);
+ cacheinfo.c_linesize =
+ min(cacheinfo.ic_linesize,
+ cacheinfo.dc_linesize);
+ cacheinfo.c_totalsize =
+ cacheinfo.ic_totalsize +
+ cacheinfo.dc_totalsize;
+ break;
+ case SUN4M_MMU_HS:
+ printf("Warning, guessing on HyperSPARC cache...\n");
+ cacheinfo.c_split = 0;
+ i = lda(SRMMU_PCR, ASI_SRMMU);
+ if (i & SRMMU_PCR_CS)
+ cacheinfo.c_totalsize = 256 * 1024;
+ else
+ cacheinfo.c_totalsize = 128 * 1024;
+ /* manual says it has 4096 lines */
+ cacheinfo.c_linesize = l =
+ cacheinfo.c_totalsize / 4096;
+ for (i = 0; (1 << i) < l; i++)
+ /* void */;
+ if ((1 << i) != l)
+ panic("bad cache line size %d", l);
+ cacheinfo.c_l2linesize = i;
+ break;
+ default:
+ printf("warning: couldn't identify cache\n");
+ cacheinfo.c_totalsize = 0;
+ }
+ } else
+#endif /* SUN4M */
+ {
+ cacheinfo.c_physical = 0;
+ cacheinfo.c_totalsize =
+ getpropint(node, "vac-size", 65536);
+ cacheinfo.c_hwflush =
+ getpropint(node, "vac_hwflush", 0) |
+ getpropint(node, "vac-hwflush", 0);
+ cacheinfo.c_linesize = l =
+ getpropint(node, "vac-linesize", 16);
+ for (i = 0; (1 << i) < l; i++)
+ /* void */;
+ if ((1 << i) != l)
+ panic("bad cache line size %d", l);
+ cacheinfo.c_l2linesize = i;
+ vactype = VAC_WRITETHROUGH;
+ }
/*
* Machines with "buserr-type" 1 have a bug in the cache
@@ -236,19 +372,51 @@ cpu_attach(parent, dev, aux)
bug = (getpropint(node, "buserr-type", 0) == 1);
}
#endif /* SUN4C || SUN4M */
+
if (bug) {
kvm_uncache((caddr_t)trapbase, 1);
printf("%s: cache chip bug; trap page uncached\n",
dev->dv_xname);
}
- if (cacheinfo.c_totalsize) {
+ if (cacheinfo.c_totalsize == 0)
+ return;
+
+ if (!cacheinfo.c_physical) {
printf("%s: %d byte write-%s, %d bytes/line, %cw flush ",
dev->dv_xname, cacheinfo.c_totalsize,
(vactype == VAC_WRITETHROUGH) ? "through" : "back",
cacheinfo.c_linesize,
cacheinfo.c_hwflush ? 'h' : 's');
cache_enable();
+ } else {
+ sep = " ";
+ if (cacheinfo.c_split) {
+ printf("%s: physical", dev->dv_xname);
+ if (cacheinfo.ic_totalsize > 0) {
+ printf("%s%dK instruction (%d b/l)", sep,
+ cacheinfo.ic_totalsize/1024,
+ cacheinfo.ic_linesize);
+ sep = ", ";
+ }
+ if (cacheinfo.dc_totalsize > 0) {
+ printf("%s%dK data (%d b/l)", sep,
+ cacheinfo.dc_totalsize/1024,
+ cacheinfo.dc_linesize);
+ sep = ", ";
+ }
+ if (cacheinfo.ec_totalsize > 0) {
+ printf("%s%dK external (%d b/l)", sep,
+ cacheinfo.ec_totalsize/1024,
+ cacheinfo.ec_linesize);
+ }
+ printf(" ");
+ } else
+ printf("%s: physical %dK combined cache (%d bytes/"
+ "line) ", dev->dv_xname,
+ cacheinfo.c_totalsize/1024,
+ cacheinfo.c_linesize);
+ cache_enable();
}
}
@@ -260,8 +428,6 @@ cpu_attach(parent, dev, aux)
*
* The table contents (and much of the structure here) are from Guy Harris.
*
- * NOTE: we have Sun-4m cpu types here, even though this only runs on the
- * Sun-4c (yet)...
*/
struct info {
u_char valid;
@@ -273,14 +439,16 @@ struct info {
#define ANY 0xff /* match any FPU version (or, later, IU version) */
+#if defined(SUN4C) || defined(SUN4M)
static struct info iu_types[] = {
+ { 1, 0x0, 0x4, 4, "MB86904" },
{ 1, 0x0, 0x0, ANY, "MB86900/1A or L64801" },
{ 1, 0x1, 0x0, ANY, "RT601 or L64811 v1" },
{ 1, 0x1, 0x1, ANY, "RT601 or L64811 v2" },
{ 1, 0x1, 0x3, ANY, "RT611" },
{ 1, 0x1, 0xf, ANY, "RT620" },
{ 1, 0x2, 0x0, ANY, "B5010" },
- { 1, 0x4, 0x0, 0, "TMS390Z50 v0" },
+ { 1, 0x4, 0x0, 0, "TMS390Z50 v0 or TMS390Z55" },
{ 1, 0x4, 0x1, 0, "TMS390Z50 v1" },
{ 1, 0x4, 0x1, 4, "TMS390S10" },
{ 1, 0x5, 0x0, ANY, "MN10501" },
@@ -304,6 +472,7 @@ psrtoname(impl, vers, fver, buf)
sprintf(buf, "IU impl 0x%x vers 0x%x", impl, vers);
return (buf);
}
+#endif /* SUN4C || SUN4M */
/* NB: table order matters here; specific numbers must appear before ANY. */
static struct info fpu_types[] = {
@@ -314,6 +483,7 @@ static struct info fpu_types[] = {
{ 1, 0x0, ANY, 1, "MB86911 or WTL1164/5" },
{ 1, 0x0, ANY, 2, "L64802 or ACT8847" },
{ 1, 0x0, ANY, 3, "WTL3170/2" },
+ { 1, 0x0, 4, 4, "on-chip" }, /* Swift */
{ 1, 0x0, ANY, 4, "L64804" },
/*
@@ -358,8 +528,8 @@ fsrtoname(impl, vers, fver, buf)
for (p = fpu_types; p->valid; p++)
if (p->iu_impl == impl &&
- (p->iu_vers == vers || p->iu_vers == ANY) &
- p->fpu_vers == fver)
+ (p->iu_vers == vers || p->iu_vers == ANY) &&
+ (p->fpu_vers == fver))
return (p->name);
sprintf(buf, "version %x", fver);
return (buf);
diff --git a/sys/arch/sparc/sparc/db_disasm.c b/sys/arch/sparc/sparc/db_disasm.c
index a76ce891a18..901597194d3 100644
--- a/sys/arch/sparc/sparc/db_disasm.c
+++ b/sys/arch/sparc/sparc/db_disasm.c
@@ -1,4 +1,4 @@
-/* $NetBSD: db_disasm.c,v 1.6 1995/04/19 21:24:29 pk Exp $ */
+/* $NetBSD: db_disasm.c,v 1.9 1996/03/31 23:45:07 pk Exp $ */
/*
* Copyright (c) 1994 David S. Miller, davem@nadzieja.rutgers.edu
@@ -33,8 +33,12 @@
#include <sys/param.h>
#include <machine/db_machdep.h>
-#include <ddb/db_sym.h>
#include <machine/instr.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_output.h>
+#include <ddb/db_access.h>
/*
* All Sparc instructions are 32-bits, with the one exception being
@@ -42,8 +46,8 @@
* two instructions...
*
* There are 5 different fields that can be used to identify which
- * operation is encoded into a particular 32-bit insn. There are 3
- * formats for instuctions, which one being used is determined by
+ * operation is encoded into a particular 32-bit insn. There are 3
+ * formats for instuctions, which one being used is determined by
* bits 30-31 of the insn. Here are the bit fields and their names:
*
* 1100 0000 0000 0000 0000 0000 0000 0000 op field, determines format
@@ -52,35 +56,34 @@
* 0000 0000 0000 0000 0010 0000 0000 0000 f3i bit, format 3 only
*/
-#define OP(x) ((x & 0x3) << 30)
-#define OP2(x) ((x & 0x7) << 22)
-#define OP3(x) ((x & 0x3f) << 19)
-#define OPF(x) ((x & 0x1ff) << 5)
-#define F3I(x) ((x & 0x1) << 13)
+#define OP(x) (((x) & 0x3) << 30)
+#define OP2(x) (((x) & 0x7) << 22)
+#define OP3(x) (((x) & 0x3f) << 19)
+#define OPF(x) (((x) & 0x1ff) << 5)
+#define F3I(x) (((x) & 0x1) << 13)
/* various other fields */
-#define A(x) ((x & 0x1) << 29)
-#define P(x) ((x & 0x1) << 19)
-#define X(x) ((x & 0x1) << 12)
-#define FCN(x) ((x & 0x1f) << 25)
-#define OPF(x) ((x & 0x1ff) << 5)
-#define RCOND2(x) ((x & 0x7) << 25)
-#define RCOND34(x) ((x & 0x7) << 10)
-#define COND(x) ((x & 0xf) << 25)
-#define SW_TRAP(x) (x & 0x7f)
-#define SHCNT32(x) (x & 0x1f)
-#define SHCNT64(x) (x & 0x3f)
-#define IMM11(x) (x & 0x7ff)
-#define IMM22(x) (x & 0x3fffff)
-#define DISP19(x) (x & 0x7ffff)
-#define DISP22(x) (x & 0x3fffff)
-#define DISP30(x) (x & 0x3fffffff)
+#define A(x) (((x) & 0x1) << 29)
+#define P(x) (((x) & 0x1) << 19)
+#define X(x) (((x) & 0x1) << 12)
+#define FCN(x) (((x) & 0x1f) << 25)
+#define RCOND2(x) (((x) & 0x7) << 25)
+#define RCOND34(x) (((x) & 0x7) << 10)
+#define COND(x) (((x) & 0xf) << 25)
+#define SW_TRAP(x) ((x) & 0x7f)
+#define SHCNT32(x) ((x) & 0x1f)
+#define SHCNT64(x) ((x) & 0x3f)
+#define IMM11(x) ((x) & 0x7ff)
+#define IMM22(x) ((x) & 0x3fffff)
+#define DISP19(x) ((x) & 0x7ffff)
+#define DISP22(x) ((x) & 0x3fffff)
+#define DISP30(x) ((x) & 0x3fffffff)
/* Register Operand Fields */
-#define RS1(x) ((x & 0x1f) << 14)
-#define RS2(x) (x & 0x1f)
-#define RD(x) ((x & 0x1f) << 25)
+#define RS1(x) (((x) & 0x1f) << 14)
+#define RS2(x) ((x) & 0x1f)
+#define RD(x) (((x) & 0x1f) << 25)
/* FORMAT macros used in sparc_i table to decode each opcode */
#define FORMAT1(a) (OP(a))
@@ -93,7 +96,7 @@
#define OPF_X(x,y) ((((x) & 0x1f) << 4) | ((y) & 0xf))
/* COND condition codes field... */
-#define COND2(x) ((x & 0xf) << 14)
+#define COND2(x) (((x) & 0xf) << 14)
struct sparc_insn {
unsigned long int match;
@@ -790,7 +793,7 @@ struct sparc_insn sparc_i[] = {
};
-vm_offset_t
+db_addr_t
db_disasm(loc, altfmt)
vm_offset_t loc;
boolean_t altfmt;
@@ -883,13 +886,13 @@ db_disasm(loc, altfmt)
db_printf("%%%s", regs[((insn >> 25) & 0x1f)]);
break;
case '3':
- db_printf("%%f%d", ((insn >> 14) & 0x1f));
+ db_printf("%%f%ld", ((insn >> 14) & 0x1f));
break;
case '4':
- db_printf("%%f%d", (insn & 0x1f));
+ db_printf("%%f%ld", (insn & 0x1f));
break;
case 'e':
- db_printf("%%f%d", ((insn >> 25) & 0x1f));
+ db_printf("%%f%ld", ((insn >> 25) & 0x1f));
break;
case 'i':
db_printf("0x%lx", (insn & 0x1fff));
@@ -923,7 +926,7 @@ db_disasm(loc, altfmt)
db_printf("0x%-2.2lx", ((insn >> 5) & 0xff));
break;
case 'o':
- db_printf("%%fcc%d", ((insn >> 25) & 0x3));
+ db_printf("%%fcc%ld", ((insn >> 25) & 0x3));
break;
case 'p':
case '7':
@@ -931,7 +934,7 @@ db_disasm(loc, altfmt)
regs[((insn >> 14) & 0x1f)],
regs[(insn & 0x1f)]);
if (*f_ptr == '7')
- db_printf(" %d", ((insn >> 5) & 0xff));
+ db_printf(" %ld", ((insn >> 5) & 0xff));
break;
case 'q':
case '8':
@@ -948,7 +951,7 @@ db_disasm(loc, altfmt)
db_printf("%%fsr");
break;
case '9':
- db_printf("0x%xl",
+ db_printf("0x%lxl",
((insn & 0xf) | ((insn >> 4) & 0x7)));
break;
case '0':
diff --git a/sys/arch/sparc/sparc/db_interface.c b/sys/arch/sparc/sparc/db_interface.c
index ebee65ddae2..4548b04f27e 100644
--- a/sys/arch/sparc/sparc/db_interface.c
+++ b/sys/arch/sparc/sparc/db_interface.c
@@ -1,27 +1,27 @@
-/* $NetBSD: db_interface.c,v 1.6 1995/04/09 11:51:10 pk Exp $ */
+/* $NetBSD: db_interface.c,v 1.12 1996/05/18 12:27:45 mrg Exp $ */
-/*
+/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
@@ -34,14 +34,19 @@
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/reboot.h>
-#include <sys/systm.h> /* just for boothowto --eichin */
-#include <setjmp.h>
+#include <sys/systm.h>
#include <vm/vm.h>
+#include <dev/cons.h>
+
#include <machine/db_machdep.h>
#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
#include <ddb/db_variables.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_access.h>
+#include <ddb/db_output.h>
#include <machine/bsd_openprom.h>
#include <machine/ctlreg.h>
#include <sparc/sparc/asm.h>
@@ -89,27 +94,33 @@ struct db_variable db_regs[] = {
};
struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
-extern jmp_buf *db_recover;
+extern label_t *db_recover;
int db_active = 0;
extern char *trap_type[];
+void kdb_kbd_trap __P((struct trapframe *));
+static void db_write_text __P((unsigned char *, int));
+void db_prom_cmd __P((db_expr_t, int, db_expr_t, char *));
+
/*
* Received keyboard interrupt sequence.
*/
+void
kdb_kbd_trap(tf)
struct trapframe *tf;
{
if (db_active == 0 && (boothowto & RB_KDB)) {
printf("\n\nkernel: keyboard interrupt\n");
- kdb_trap(-1, 0, tf);
+ kdb_trap(-1, tf);
}
}
/*
* kdb_trap - field a TRACE or BPT trap
*/
+int
kdb_trap(type, tf)
int type;
register struct trapframe *tf;
@@ -152,40 +163,88 @@ kdb_trap(type, tf)
void
db_read_bytes(addr, size, data)
vm_offset_t addr;
- register int size;
+ register size_t size;
register char *data;
{
register char *src;
src = (char *)addr;
- while (--size >= 0)
+ while (size-- > 0)
*data++ = *src++;
}
+/*
+ * XXX - stolen from pmap.c
+ */
+#if defined(SUN4M)
+#define getpte4m(va) lda((va & 0xFFFFF000) | ASI_SRMMUFP_L3, \
+ ASI_SRMMUFP)
+void setpte4m __P((vm_offset_t va, int pte));
+
+#endif
+#define getpte4(va) lda(va, ASI_PTE)
+#define setpte4(va, pte) sta(va, ASI_PTE, pte)
+#if defined(SUN4M) && !(defined(SUN4C) || defined(SUN4))
+#define getpte getpte4m
+#define setpte setpte4m
+#elif defined(SUN4M)
+#define getpte(va) (cputyp==CPU_SUN4M ? getpte4m(va) : getpte4(va))
+#define setpte(va, pte) (cputyp==CPU_SUN4M ? setpte4m(va, pte) \
+ : setpte4(va,pte))
+#else
+#define getpte getpte4
+#define setpte setpte4
+#endif
+
#define splpmap() splimp()
static void
db_write_text(dst, ch)
unsigned char *dst;
int ch;
-{
+{
+ int s, pte0, pte;
vm_offset_t va;
- int s;
s = splpmap();
va = (unsigned long)dst & (~PGOFSET);
+ pte0 = getpte(va);
+
+#if defined(SUN4M)
+#if defined(SUN4) || defined(SUN4C)
+ if (cputyp == CPU_SUN4M) {
+#endif
+ if ((pte0 & SRMMU_TETYPE) != SRMMU_TEPTE) {
+ db_printf(" address %p not a valid page\n", dst);
+ splx(s);
+ return;
+ }
- if (pmap_extract(pmap_kernel(), va) == 0) {
- db_printf(" address 0x%x not a valid page\n", dst);
+ pte = pte0 | PPROT_WRITE;
+ setpte(va, pte);
+
+#if defined(SUN4) || defined(SUN4C)
+ } else {
+#endif
+#endif /* 4m */
+#if defined(SUN4) || defined(SUN4C)
+ if ((pte0 & PG_V) == 0) {
+ db_printf(" address %p not a valid page\n", dst);
splx(s);
return;
}
- pmap_changeprot(pmap_kernel(), va, VM_PROT_ALL, 0);
+ pte = pte0 | PG_W;
+ setpte(va, pte);
+#if defined(SUN4M)
+ }
+#endif
+#endif /* 4/4c */
+
*dst = (unsigned char)ch;
- pmap_protect(pmap_kernel(), va, va, VM_PROT_READ|VM_PROT_EXECUTE);
+ setpte(va, pte0);
splx(s);
}
@@ -195,14 +254,14 @@ db_write_text(dst, ch)
void
db_write_bytes(addr, size, data)
vm_offset_t addr;
- register int size;
+ register size_t size;
register char *data;
{
extern char etext[];
register char *dst;
dst = (char *)addr;
- while (--size >= 0) {
+ while (size-- > 0) {
if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) && (dst < etext))
db_write_text(dst, *data);
else
@@ -212,16 +271,19 @@ db_write_bytes(addr, size, data)
}
-int
+void
Debugger()
{
asm("ta 0x81");
}
void
-db_prom_cmd()
+db_prom_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
{
- extern struct promvec *promvec;
promvec->pv_abort();
}
diff --git a/sys/arch/sparc/sparc/db_trace.c b/sys/arch/sparc/sparc/db_trace.c
index b97cc3d7cb6..8da02ce3082 100644
--- a/sys/arch/sparc/sparc/db_trace.c
+++ b/sys/arch/sparc/sparc/db_trace.c
@@ -1,38 +1,40 @@
-/* $NetBSD: db_trace.c,v 1.4 1995/07/05 18:51:41 pk Exp $ */
+/* $NetBSD: db_trace.c,v 1.8 1996/04/04 23:25:35 pk Exp $ */
-/*
+/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
-#include "param.h"
-#include "proc.h"
+#include <sys/param.h>
+#include <sys/proc.h>
#include <machine/db_machdep.h>
#include <ddb/db_access.h>
#include <ddb/db_sym.h>
-
+#include <ddb/db_interface.h>
+#include <ddb/db_output.h>
+
#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK)
void
@@ -63,7 +65,6 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
while (count--) {
int i;
db_expr_t offset;
- db_sym_t sym;
char *name;
db_addr_t pc;
@@ -71,6 +72,13 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
if (!INKERNEL(pc))
break;
+ /*
+ * Switch to frame that contains arguments
+ */
+ frame = frame->fr_fp;
+ if (!INKERNEL(frame))
+ break;
+
db_find_sym_and_offset(pc, &name, &offset);
if (name == NULL)
name = "?";
@@ -78,11 +86,6 @@ db_stack_trace_cmd(addr, have_addr, count, modif)
db_printf("%s(", name);
/*
- * Switch to frame that contains arguments
- */
- frame = frame->fr_fp;
-
- /*
* Print %i0..%i5, hope these still reflect the
* actual arguments somewhat...
*/
diff --git a/sys/arch/sparc/sparc/disksubr.c b/sys/arch/sparc/sparc/disksubr.c
index 95b97464ec8..4446fd1927f 100644
--- a/sys/arch/sparc/sparc/disksubr.c
+++ b/sys/arch/sparc/sparc/disksubr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: disksubr.c,v 1.11 1996/01/07 22:03:12 thorpej Exp $ */
+/* $NetBSD: disksubr.c,v 1.16 1996/04/28 20:25:59 thorpej Exp $ */
/*
* Copyright (c) 1994, 1995 Gordon W. Ross
@@ -32,6 +32,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/ioccom.h>
#include <sys/device.h>
@@ -58,7 +59,7 @@ static int disklabel_bsd_to_sun __P((struct disklabel *, char *));
extern struct device *bootdv;
-/*
+/*
* find the boot device (if it was a disk). we must check to see if
* unit info in saved bootpath structure matches unit info in our softc.
* note that knowing the device name (e.g. "xd0") is not useful... we
@@ -66,68 +67,56 @@ extern struct device *bootdv;
* (XXX is it worth ifdef'ing this?)
*/
-int
+void
dk_establish(dk, dev)
struct disk *dk;
struct device *dev;
{
struct bootpath *bp = bootpath_store(0, NULL); /* restore bootpath! */
- char name[10];
struct scsibus_softc *sbsc;
- int targ, lun;
+ int target, lun;
if (bp == NULL)
- return -1;
+ return;
/*
* scsi: sd,cd
*/
- if (strncmp("sd", dev->dv_xname, 2) == 0 ||
+ if (strncmp("sd", dev->dv_xname, 2) == 0 ||
strncmp("cd", dev->dv_xname, 2) == 0) {
+
sbsc = (struct scsibus_softc *)dev->dv_parent;
- targ = lun = 0;
-#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
- if (dev->dv_xname[0] == 's' && bp->val[0] == 0) {
- /* disk unit 0 is magic */
- if (sbsc->sc_link[0][0] == NULL) {
- targ = 3; /* remap to 3 */
- lun = 0;
- }
- } else {
- extern struct om_vector *oldpvec;
- if (oldpvec->monId[0] > '1') {
- targ = bp->val[0] >> 3; /* new format */
- lun = bp->val[0] & 0x7;
- } else {
- targ = bp->val[0] >> 2; /* old format */
- lun = bp->val[0] & 0x3;
- }
- }
- } else
-#endif
- {
- lun = bp->val[1];
- targ = (dev->dv_xname[0] == 's')
- ? sd_crazymap(bp->val[0])
- : bp->val[0];
+ target = bp->val[0];
+ lun = bp->val[1];
+
+ if (CPU_ISSUN4 && dev->dv_xname[0] == 's' &&
+ target == 0 && sbsc->sc_link[0][0] == NULL) {
+ /*
+ * disk unit 0 is magic: if there is actually no
+ * target 0 scsi device, the PROM will call
+ * target 3 `sd0'.
+ * XXX - what if someone puts a tape at target 0?
+ */
+ target = 3; /* remap to 3 */
+ lun = 0;
}
- if (sbsc->sc_link[targ][lun] != NULL &&
- sbsc->sc_link[targ][lun]->device_softc == (void *)dev) {
- bootdv = dev; /* got it! */
- return 1;
+ if (CPU_ISSUN4C && dev->dv_xname[0] == 's')
+ target = sd_crazymap(target);
+
+ if (sbsc->sc_link[target][lun] != NULL &&
+ sbsc->sc_link[target][lun]->device_softc == (void *)dev) {
+ bp->dev = dev; /* got it! */
+ return;
}
}
-
- return -1;
}
-/*
+/*
* Attempt to read a disk label from a device
* using the indicated stategy routine.
- * The label must be partly set up before this:
+ * The label must be partly set up before this:
* secpercyl, secsize and anything required for a block i/o read
* operation in the driver's strategy/start routines
* must be filled in before calling us.
@@ -138,8 +127,8 @@ dk_establish(dk, dev)
*/
char *
readdisklabel(dev, strat, lp, clp)
- dev_t dev;
- void (*strat)();
+ dev_t dev;
+ void (*strat) __P((struct buf *));
struct disklabel *lp;
struct cpu_disklabel *clp;
{
@@ -165,7 +154,7 @@ readdisklabel(dev, strat, lp, clp)
bp->b_cylin = 0;
bp->b_bcount = lp->d_secsize;
bp->b_flags = B_BUSY | B_READ;
- (*strat)(bp);
+ (*strat)(bp);
/* if successful, locate disk label within block and validate */
error = biowait(bp);
@@ -215,13 +204,13 @@ setdisklabel(olp, nlp, openmask, clp)
return(EINVAL);
/* special case to allow disklabel to be invalidated */
- if (nlp->d_magic == 0xffffffff) {
+ if (nlp->d_magic == 0xffffffff) {
*olp = *nlp;
return (0);
}
if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
- dkcksum(nlp) != 0)
+ dkcksum(nlp) != 0)
return (EINVAL);
while ((i = ffs((long)openmask)) != 0) {
@@ -233,19 +222,20 @@ setdisklabel(olp, nlp, openmask, clp)
npp = &nlp->d_partitions[i];
if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
return (EBUSY);
- }
+ }
- *olp = *nlp;
- return (0);
+ *olp = *nlp;
+ return (0);
}
/*
* Write disk label back to device after modification.
* Current label is already in clp->cd_block[]
*/
+int
writedisklabel(dev, strat, lp, clp)
dev_t dev;
- void (*strat)();
+ void (*strat) __P((struct buf *));
register struct disklabel *lp;
struct cpu_disklabel *clp;
{
@@ -281,7 +271,7 @@ writedisklabel(dev, strat, lp, clp)
return (error);
}
-/*
+/*
* Determine the size of the transfer, and make sure it is
* within the boundaries of the partition. Adjust transfer
* if needed, and signal errors or early completion.
@@ -300,14 +290,14 @@ bounds_check_with_label(bp, lp, wlabel)
int sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
/* overwriting disk label ? */
- /* XXX should also protect bootstrap in first 8K */
+ /* XXX should also protect bootstrap in first 8K */
if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect &&
(bp->b_flags & B_READ) == 0 && wlabel == 0) {
bp->b_error = EROFS;
goto bad;
}
- /* beyond partition? */
+ /* beyond partition? */
if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
/* if exactly at end of disk, return an EOF */
if (bp->b_blkno == maxsz) {
@@ -321,7 +311,7 @@ bounds_check_with_label(bp, lp, wlabel)
goto bad;
}
bp->b_bcount = sz << DEV_BSHIFT;
- }
+ }
/* calculate cylinder for disksort to order transfers with */
bp->b_resid = (bp->b_blkno + p->p_offset) / lp->d_secpercyl;
@@ -487,7 +477,7 @@ disklabel_bsd_to_sun(lp, cp)
/* move this to compat/sunos */
int
-sunos_dkioctl(dk, cmd, data, partition)
+sun_dkioctl(dk, cmd, data, partition)
struct disk *dk;
u_long cmd;
caddr_t data;
@@ -496,7 +486,7 @@ sunos_dkioctl(dk, cmd, data, partition)
register struct partition *p;
switch (cmd) {
- case SUNOS_DKIOCGGEOM:
+ case DKIOCGGEOM:
#define geom ((struct sun_dkgeom *)data)
bzero(data, sizeof(*geom));
geom->sdkc_ncylinders = dk->dk_label->d_ncylinders;
@@ -510,11 +500,11 @@ sunos_dkioctl(dk, cmd, data, partition)
dk->dk_label->d_ncylinders + dk->dk_label->d_acylinders;
#undef geom
break;
- case SUNOS_DKIOCINFO:
+ case DKIOCINFO:
/* Homey don't do DKIOCINFO */
bzero(data, sizeof(struct sun_dkctlr));
break;
- case SUNOS_DKIOCGPART:
+ case DKIOCGPART:
if (dk->dk_label->d_secpercyl == 0)
return (ERANGE); /* XXX */
p = &dk->dk_label->d_partitions[partition];
@@ -539,6 +529,7 @@ sunos_dkioctl(dk, cmd, data, partition)
int
isbad(bt, cyl, trk, sec)
register struct dkbad *bt;
+ int cyl, trk, sec;
{
register int i;
register long blk, bblk;
diff --git a/sys/arch/sparc/sparc/genassym.c b/sys/arch/sparc/sparc/genassym.c
index f7bc26e3a9a..ac0b0b8e36b 100644
--- a/sys/arch/sparc/sparc/genassym.c
+++ b/sys/arch/sparc/sparc/genassym.c
@@ -1,4 +1,4 @@
-/* $NetBSD: genassym.c,v 1.14 1995/05/04 19:42:36 pk Exp $ */
+/* $NetBSD: genassym.c,v 1.17.4.1 1996/06/12 20:31:21 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -78,6 +78,10 @@
#define off(what, str, mem) def(what, (int)offsetof(str, mem))
+void def __P((char *, int));
+void flush __P((void));
+int main __P((void));
+
void
def(what, where)
char *what;
@@ -100,23 +104,16 @@ flush()
}
}
+int
main()
{
/* general constants */
def("BSD", BSD);
- def("USPACE", USPACE);
def("SUN4_PGSHIFT", SUN4_PGSHIFT);
def("SUN4CM_PGSHIFT", SUN4CM_PGSHIFT);
- def("KERNBASE", KERNBASE);
def("USRSTACK", USRSTACK);
- def("CPU_SUN4", CPU_SUN4);
- def("CPU_SUN4C", CPU_SUN4C);
- def("CPU_SUN4M", CPU_SUN4M);
-
- def("SUN4_400", SUN4_400);
-
/* proc fields and values */
off("P_ADDR", struct proc, p_addr);
off("P_STAT", struct proc, p_stat);
@@ -140,6 +137,15 @@ main()
def("PG_PROTSHIFT", PG_PROTSHIFT);
def("PG_PROTUREAD", PG_PROTUREAD);
def("PG_PROTUWRITE", PG_PROTUWRITE);
+#if defined(SUN4M)
+ def("SRMMU_TETYPE", SRMMU_TETYPE);
+ def("SRMMU_TEPTE", SRMMU_TEPTE);
+ def("SRMMU_PROT_MASK", SRMMU_PROT_MASK);
+ def("PPROT_R_RW", PPROT_R_RW);
+ def("PPROT_RX_RX", PPROT_RX_RX);
+ def("PPROT_RWX_RWX", PPROT_RWX_RWX);
+ def("PPROT_WRITE", PPROT_WRITE);
+#endif
/* FPU state */
off("FS_REGS", struct fpstate, fs_regs);
@@ -218,5 +224,5 @@ main()
flush();
- exit(0);
+ return(0);
}
diff --git a/sys/arch/sparc/sparc/in_cksum.c b/sys/arch/sparc/sparc/in_cksum.c
index 9f2f34c122b..38554d39569 100644
--- a/sys/arch/sparc/sparc/in_cksum.c
+++ b/sys/arch/sparc/sparc/in_cksum.c
@@ -1,8 +1,6 @@
-/* $NetBSD: in_cksum.c,v 1.3 1995/04/26 13:30:03 pk Exp $ */
+/* $NetBSD: in_cksum.c,v 1.5 1996/03/31 23:45:24 pk Exp $ */
/*
- * Copyright (c) 1995 Zubin Dittia.
- * Copyright (c) 1995 Theo de Raadt.
* Copyright (c) 1995 Matthew Green.
* Copyright (c) 1994 Charles Hannum.
* Copyright (c) 1992, 1993
@@ -46,6 +44,7 @@
#include <sys/param.h>
#include <sys/mbuf.h>
+#include <netinet/in.h>
/*
* Checksum routine for Internet Protocol family headers.
@@ -57,81 +56,50 @@
*/
/*
- * The checksum computation code here is significantly faster than its
- * vanilla C counterpart (by significantly, I mean 2-3 times faster if
- * the data is in cache, and 1.5-2 times faster if the data is not in
- * cache).
- * We optimize on three fronts:
- * 1. By using the add-with-carry (addxcc) instruction, we can use
- * 32-bit operations instead of 16-bit operations.
- * 2. By unrolling the main loop to reduce branch overheads.
- * 3. By doing a sequence of load,load,add,add,load,load,add,add,
- * we can avoid the extra stall cycle which is incurred if the
- * instruction immediately following a load tries to use the
- * target register of the load.
- * Another possible optimization is to replace a pair of 32-bit loads
- * with a single 64-bit load (ldd) instruction, but I found that although
- * this improves performance somewhat on Sun4c machines, it actually
- * reduces performance considerably on Sun4m machines (because of their
- * superscaler architecture). So I chose to leave it out.
+ * This idea here is that we do as many 32 bit operations as possible
+ * for maximum efficiency. We also unroll all loops in to assembly.
+ * This gains about 20% extra efficiency over the non-pipelined method.
*
- * Zubin Dittia (zubin@dworkin.wustl.edu)
+ * XXX - this code really needs further performance analysis. At the
+ * moment it has only been run on a SPARC ELC.
*/
-#define Asm __asm __volatile
-#define ADD64 Asm(" ld [%2],%3; ld [%2+4],%4; \
- addcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+8],%3; ld [%2+12],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+16],%3; ld [%2+20],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+24],%3; ld [%2+28],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+32],%3; ld [%2+36],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+40],%3; ld [%2+44],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+48],%3; ld [%2+52],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+56],%3; ld [%2+60],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
+#define Asm __asm __volatile
+#define ADD32 Asm(" ld [%2+28],%%i0; ld [%2+24],%%i1; \
+ ld [%2+20],%%i2; ld [%2+16],%%i3; \
+ ld [%2+12],%%i4; ld [%2+8],%%i5; \
+ ld [%2+4],%%g3; ld [%2],%%g4; \
+ addcc %0,%%i0,%0; addxcc %0,%%i1,%0; \
+ addxcc %0,%%i2,%0; addxcc %0,%%i3,%0; \
+ addxcc %0,%%i4,%0; addxcc %0,%%i5,%0; \
+ addxcc %0,%%g3,%0; addxcc %0,%%g4,%0; \
addxcc %0,0,%0" \
- : "=r" (sum) \
- : "0" (sum), "r" (w), "r" (tmp1), "r" (tmp2))
-#define ADD32 Asm(" ld [%2],%3; ld [%2+4],%4; \
- addcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+8],%3; ld [%2+12],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+16],%3; ld [%2+20],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+24],%3; ld [%2+28],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
+ : "=r" (sum) : "0" (sum), "r" (w) \
+ : "%i0", "%i1", "%i2", "%i3", \
+ "%i4", "%i5", "%g3", "%g4")
+#define ADD16 Asm(" ld [%2+12],%%i0; ld [%2+8],%%i1; \
+ ld [%2+4],%%i2; ld [%2],%%i3; \
+ addcc %0,%%i0,%0; addxcc %0,%%i1,%0; \
+ addxcc %0,%%i2,%0; addxcc %0,%%i3,%0; \
addxcc %0,0,%0" \
- : "=r" (sum) \
- : "0" (sum), "r" (w), "r" (tmp1), "r" (tmp2))
-#define ADD16 Asm(" ld [%2],%3; ld [%2+4],%4; \
- addcc %0,%3,%0; addxcc %0,%4,%0; \
- ld [%2+8],%3; ld [%2+12],%4; \
- addxcc %0,%3,%0; addxcc %0,%4,%0; \
+ : "=r" (sum) : "0" (sum), "r" (w) \
+ : "%i0", "%i1", "%i2", "%i3")
+#define ADD8 Asm(" ld [%2+4],%%i0; ld [%2],%%i1; \
+ addcc %0,%%i0,%0; addxcc %0,%%i1,%0; \
addxcc %0,0,%0" \
- : "=r" (sum) \
- : "0" (sum), "r" (w), "r" (tmp1), "r" (tmp2))
-#define ADD8 Asm(" ld [%2],%3; ld [%2+4],%4; \
- addcc %0,%3,%0; addxcc %0,%4,%0; \
+ : "=r" (sum) : "0" (sum), "r" (w) \
+ : "%i0", "%i1")
+#define ADD4 Asm(" ld [%2],%%i0; addcc %0,%%i0,%0; \
addxcc %0,0,%0" \
- : "=r" (sum) \
- : "0" (sum), "r" (w), "r" (tmp1), "r" (tmp2))
-#define ADD4 Asm(" ld [%2],%3; addcc %0,%3,%0; \
- addxcc %0,0,%0" \
- : "=r" (sum) \
- : "0" (sum), "r" (w), "r" (tmp1))
+ : "=r" (sum) : "0" (sum), "r" (w) \
+ : "%i0")
#define REDUCE {sum = (sum & 0xffff) + (sum >> 16);}
#define ADDCARRY {if (sum > 0xffff) sum -= 0xffff;}
#define ROL {sum = sum << 8;} /* depends on recent REDUCE */
-#define ADDBYTE {ROL; sum += *w; byte_swapped ^= 1;}
-#define ADDSHORT {sum += *(u_short *)w;}
-#define ADVANCE(n) {w += n; mlen -= n;}
+#define ADDB {ROL; sum += *w; byte_swapped ^= 1;}
+#define ADDS {sum += *(u_short *)w;}
+#define SHIFT(n) {w += n; mlen -= n;}
int
in_cksum(m, len)
@@ -143,13 +111,6 @@ in_cksum(m, len)
register int mlen = 0;
int byte_swapped = 0;
- /*
- * Declare two temporary registers for use by the asm code. We
- * allow the compiler to pick which specific machine registers to
- * use, instead of hard-coding this in the asm code above.
- */
- register u_int tmp1, tmp2;
-
for (; m && len; m = m->m_next) {
if (m->m_len == 0)
continue;
@@ -158,7 +119,7 @@ in_cksum(m, len)
if (len < mlen)
mlen = len;
len -= mlen;
-
+
/*
* Ensure that we're aligned on a word boundary here so
* that we can do 32 bit operations below.
@@ -166,50 +127,45 @@ in_cksum(m, len)
if ((3 & (long)w) != 0) {
REDUCE;
if ((1 & (long)w) != 0 && mlen >= 1) {
- ADDBYTE;
- ADVANCE(1);
+ ADDB;
+ SHIFT(1);
}
if ((2 & (long)w) != 0 && mlen >= 2) {
- ADDSHORT;
- ADVANCE(2);
+ ADDS;
+ SHIFT(2);
}
}
-
/*
* Do as many 32 bit operattions as possible using the
- * 64/32/16/8/4 macro's above, using as many as possible of
+ * 32/16/8/4 macro's above, using as many as possible of
* these.
*/
- while (mlen >= 64) {
- ADD64;
- ADVANCE(64);
- }
- if (mlen >= 32) {
+ while (mlen >= 32) {
ADD32;
- ADVANCE(32);
+ SHIFT(32);
}
if (mlen >= 16) {
ADD16;
- ADVANCE(16);
+ SHIFT(16);
}
if (mlen >= 8) {
ADD8;
- ADVANCE(8);
+ SHIFT(8);
}
if (mlen >= 4) {
ADD4;
- ADVANCE(4)
+ SHIFT(4)
}
if (mlen == 0)
continue;
REDUCE;
if (mlen >= 2) {
- ADDSHORT;
- ADVANCE(2);
+ ADDS;
+ SHIFT(2);
}
if (mlen == 1) {
- ADDBYTE;
+ ADDB;
}
}
if (byte_swapped) {
@@ -218,6 +174,5 @@ in_cksum(m, len)
}
REDUCE;
ADDCARRY;
-
return (0xffff ^ sum);
}
diff --git a/sys/arch/sparc/sparc/intersil7170.h b/sys/arch/sparc/sparc/intersil7170.h
index 2ca4e4035ab..b91f526e62e 100644
--- a/sys/arch/sparc/sparc/intersil7170.h
+++ b/sys/arch/sparc/sparc/intersil7170.h
@@ -1,4 +1,4 @@
-/* $NetBSD: intersil7170.h,v 1.1 1994/12/16 22:17:00 deraadt Exp $ */
+/* $NetBSD: intersil7170.h,v 1.3 1996/05/02 18:17:40 pk Exp $ */
/*
* Copyright (c) 1993 Adam Glass
@@ -34,57 +34,57 @@
/*
* Driver support for the intersil7170 used in sun[34]s to provide
* real time clock and time-of-day support.
- *
+ *
* Derived from: datasheet "ICM7170 a uP-Compatible Real-Time Clock"
* document #301680-005, Dec 85
*/
struct date_time { /* from p. 7 of 10 */
- u_char dt_csec;
- u_char dt_hour;
- u_char dt_min;
- u_char dt_sec;
- u_char dt_month;
- u_char dt_day;
- u_char dt_year;
- u_char dt_dow;
+ volatile unsigned char dt_csec;
+ volatile unsigned char dt_hour;
+ volatile unsigned char dt_min;
+ volatile unsigned char dt_sec;
+ volatile unsigned char dt_month;
+ volatile unsigned char dt_day;
+ volatile unsigned char dt_year;
+ volatile unsigned char dt_dow;
};
struct intersil7170 {
struct date_time counters;
- struct date_time clk_ram; /* should be ok as both are word aligned */
- u_char clk_intr_reg;
- u_char clk_cmd_reg;
+ struct date_time clk_ram; /* should be ok as both are word aligned */
+ volatile unsigned char clk_intr_reg;
+ volatile unsigned char clk_cmd_reg;
};
/* bit assignments for command register, p. 6 of 10, write-only */
-#define INTERSIL_CMD_FREQ_32K 0x00
-#define INTERSIL_CMD_FREQ_1M 0x01
-#define INTERSIL_CMD_FREQ_2M 0x02
-#define INTERSIL_CMD_FREQ_4M 0x03
+#define INTERSIL_CMD_FREQ_32K 0x0
+#define INTERSIL_CMD_FREQ_1M 0x1
+#define INTERSIL_CMD_FREQ_2M 0x2
+#define INTERSIL_CMD_FREQ_4M 0x3
-#define INTERSIL_CMD_12HR_MODE 0x00
-#define INTERSIL_CMD_24HR_MODE 0x04
+#define INTERSIL_CMD_12HR_MODE 0x0
+#define INTERSIL_CMD_24HR_MODE 0x4
-#define INTERSIL_CMD_STOP 0x00
-#define INTERSIL_CMD_RUN 0x08
+#define INTERSIL_CMD_STOP 0x0
+#define INTERSIL_CMD_RUN 0x8
-#define INTERSIL_CMD_IDISABLE 0x00
-#define INTERSIL_CMD_IENABLE 0x10
+#define INTERSIL_CMD_IDISABLE 0x0
+#define INTERSIL_CMD_IENABLE 0x10
-#define INTERSIL_CMD_TEST_MODE 0x20
-#define INTERSIL_CMD_NORMAL_MODE 0x00
+#define INTERSIL_CMD_TEST_MODE 0x20
+#define INTERSIL_CMD_NORMAL_MODE 0x0
/* bit assignments for interrupt register r/w, p 7 of 10*/
-#define INTERSIL_INTER_ALARM 0x01 /* r/w */
-#define INTERSIL_INTER_CSECONDS 0x02 /* r/w */
-#define INTERSIL_INTER_DSECONDS 0x04 /* r/w */
-#define INTERSIL_INTER_SECONDS 0x08 /* r/w */
-#define INTERSIL_INTER_MINUTES 0x10 /* r/w */
-#define INTERSIL_INTER_HOURS 0x20 /* r/w */
-#define INTERSIL_INTER_DAYS 0x40 /* r/w */
-#define INTERSIL_INTER_PENDING 0x80 /* read-only */
+#define INTERSIL_INTER_ALARM 0x1 /* r/w */
+#define INTERSIL_INTER_CSECONDS 0x2 /* r/w */
+#define INTERSIL_INTER_DSECONDS 0x4 /* r/w */
+#define INTERSIL_INTER_SECONDS 0x8 /* r/w */
+#define INTERSIL_INTER_MINUTES 0x10 /* r/w */
+#define INTERSIL_INTER_HOURS 0x20 /* r/w */
+#define INTERSIL_INTER_DAYS 0x40 /* r/w */
+#define INTERSIL_INTER_PENDING 0x80 /* read-only */
#define INTERSIL_INTER_BITS "\20\10PENDING\7DAYS\6HRS\5MIN\4SCDS\3DSEC\2CSEC\1ALARM"
diff --git a/sys/arch/sparc/sparc/intr.c b/sys/arch/sparc/sparc/intr.c
index 8d360371173..5173b00616f 100644
--- a/sys/arch/sparc/sparc/intr.c
+++ b/sys/arch/sparc/sparc/intr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: intr.c,v 1.9 1995/07/04 12:34:37 paulus Exp $ */
+/* $NetBSD: intr.c,v 1.13 1996/03/31 23:35:20 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -44,18 +44,45 @@
* @(#)intr.c 8.3 (Berkeley) 11/11/93
*/
+#include "ppp.h"
+
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/socket.h>
#include <vm/vm.h>
+#include <dev/cons.h>
+
#include <net/netisr.h>
+#include <net/if.h>
#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <machine/instr.h>
#include <machine/trap.h>
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#endif
+#ifdef NS
+#include <netns/ns_var.h>
+#endif
+#ifdef ISO
+#include <netiso/iso.h>
+#include <netiso/clnp.h>
+#endif
+#include "ppp.h"
+#if NPPP > 0
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#endif
+
+void strayintr __P((struct clockframe *));
+int soft01intr __P((void *));
/*
* Stray interrupt handler. Clear it if possible.
@@ -69,7 +96,7 @@ strayintr(fp)
int timesince;
printf("stray interrupt ipl %x pc=%x npc=%x psr=%b\n",
- fp->ipl, fp->pc, fp->npc, fp->psr, PSR_BITS);
+ fp->ipl, fp->pc, fp->npc, fp->psr, PSR_BITS);
timesince = time.tv_sec - straytime;
if (timesince <= 10) {
if (++nstray > 9)
@@ -80,10 +107,7 @@ strayintr(fp)
}
}
-extern int clockintr(); /* level 10 (clock) interrupt code */
static struct intrhand level10 = { clockintr };
-
-extern int statintr(); /* level 14 (statclock) interrupt code */
static struct intrhand level14 = { statintr };
/*
@@ -129,7 +153,6 @@ soft01intr(fp)
if (n & (1 << NETISR_ISO))
clnlintr();
#endif
-#include "ppp.h"
#if NPPP > 0
if (n & (1 << NETISR_PPP))
pppintr();
@@ -137,7 +160,7 @@ soft01intr(fp)
}
if (sir.sir_which[SIR_CLOCK]) {
sir.sir_which[SIR_CLOCK] = 0;
- softclock(fp);
+ softclock();
}
}
return (1);
@@ -153,11 +176,11 @@ static struct intrhand level01 = { soft01intr };
struct intrhand *intrhand[15] = {
NULL, /* 0 = error */
&level01, /* 1 = software level 1 + Sbus */
- NULL, /* 2 = Sbus level 2 */
- NULL, /* 3 = SCSI + DMA + Sbus level 3 */
- NULL, /* 4 = software level 4 (tty softint) */
- NULL, /* 5 = Ethernet + Sbus level 4 */
- NULL, /* 6 = software level 6 (not used) */
+ NULL, /* 2 = Sbus level 2 (4m: Sbus L1) */
+ NULL, /* 3 = SCSI + DMA + Sbus level 3 (4m: L2,lpt)*/
+ NULL, /* 4 = software level 4 (tty softint) (scsi) */
+ NULL, /* 5 = Ethernet + Sbus level 4 (4m: Sbus L3) */
+ NULL, /* 6 = software level 6 (not used) (4m: enet)*/
NULL, /* 7 = video + Sbus level 5 */
NULL, /* 8 = Sbus level 6 */
NULL, /* 9 = Sbus level 7 */
@@ -170,7 +193,8 @@ struct intrhand *intrhand[15] = {
static int fastvec; /* marks fast vectors (see below) */
#ifdef DIAGNOSTIC
-extern int sparc_interrupt[];
+extern int sparc_interrupt4m[];
+extern int sparc_interrupt44c[];
#endif
/*
@@ -195,14 +219,17 @@ intr_establish(level, ih)
level);
#ifdef DIAGNOSTIC
/* double check for legal hardware interrupt */
- if (level != 1 && level != 4 && level != 6) {
+ if ((level != 1 && level != 4 && level != 6) || CPU_ISSUN4M ) {
tv = &trapbase[T_L1INT - 1 + level];
- displ = &sparc_interrupt[0] - &tv->tv_instr[1];
+ displ = (CPU_ISSUN4M)
+ ? &sparc_interrupt4m[0] - &tv->tv_instr[1]
+ : &sparc_interrupt44c[0] - &tv->tv_instr[1];
+
/* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */
if (tv->tv_instr[0] != I_MOVi(I_L3, level) ||
tv->tv_instr[1] != I_BA(0, displ) ||
tv->tv_instr[2] != I_RDPSR(I_L0))
- panic("intr_establish(%d, %x)\n%x %x %x != %x %x %x",
+ panic("intr_establish(%d, %p)\n%x %x %x != %x %x %x",
level, ih,
tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2],
I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0));
@@ -243,12 +270,15 @@ intr_fasttrap(level, vec)
panic("intr_fasttrap: already handling level %d interrupts",
level);
#ifdef DIAGNOSTIC
- displ = &sparc_interrupt[0] - &tv->tv_instr[1];
+ displ = (CPU_ISSUN4M)
+ ? &sparc_interrupt4m[0] - &tv->tv_instr[1]
+ : &sparc_interrupt44c[0] - &tv->tv_instr[1];
+
/* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */
if (tv->tv_instr[0] != I_MOVi(I_L3, level) ||
tv->tv_instr[1] != I_BA(0, displ) ||
tv->tv_instr[2] != I_RDPSR(I_L0))
- panic("intr_fasttrap(%d, %x)\n%x %x %x != %x %x %x",
+ panic("intr_fasttrap(%d, %p)\n%x %x %x != %x %x %x",
level, vec,
tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2],
I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0));
diff --git a/sys/arch/sparc/sparc/intreg.h b/sys/arch/sparc/sparc/intreg.h
index 899103353dd..5abbb8342f1 100644
--- a/sys/arch/sparc/sparc/intreg.h
+++ b/sys/arch/sparc/sparc/intreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: intreg.h,v 1.3 1995/06/25 21:34:28 pk Exp $ */
+/* $NetBSD: intreg.h,v 1.5 1996/03/31 23:03:39 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -44,6 +44,8 @@
* @(#)intreg.h 8.1 (Berkeley) 6/11/93
*/
+#include <sparc/sparc/vaddrs.h>
+
/*
* sun4c interrupt enable register.
*
@@ -69,13 +71,22 @@
#define IE_L1 0x02 /* request software level 1 interrupt */
#define IE_ALLIE 0x01 /* enable interrupts */
-#ifndef LOCORE
+#ifndef _LOCORE
void ienab_bis __P((int bis)); /* set given bits */
void ienab_bic __P((int bic)); /* clear given bits */
#endif
#if defined(SUN4M)
-#define ICR_REG_PHYSADR 0x71e00000 /* XXX - phys addr in IOspace */
+#ifdef notyet
+#define IENAB_SYS ((_MAXNBPG * _MAXNCPU) + 0xc)
+#define IENAB_P0 0x0008
+#define IENAB_P1 0x1008
+#define IENAB_P2 0x2008
+#define IENAB_P3 0x3008
+#endif /* notyet */
+#endif
+
+#if defined(SUN4M)
/*
* Interrupt Control Registers, located in IO space.
* (mapped to `locore' for now..)
@@ -83,21 +94,27 @@ void ienab_bic __P((int bic)); /* clear given bits */
* and `System Interrupts'. The `Processor' set corresponds to the 15
* interrupt levels as seen by the CPU. The `System' set corresponds to
* a set of devices supported by the implementing chip-set.
+ *
+ * Briefly, the ICR_PI_* are per-processor interrupts; the ICR_SI_* are
+ * system-wide interrupts, and the ICR_ITR selects the processor to get
+ * the system's interrupts.
*/
-#define ICR_PI_PEND (IE_reg_addr + 0x0)
-#define ICR_PI_CLR (IE_reg_addr + 0x4)
-#define ICR_PI_SET (IE_reg_addr + 0x8)
-#define ICR_SI_PEND (IE_reg_addr + 0x1000)
-#define ICR_SI_MASK (IE_reg_addr + 0x1004)
-#define ICR_SI_CLR (IE_reg_addr + 0x1008)
-#define ICR_SI_SET (IE_reg_addr + 0x100c)
+#define ICR_PI_PEND (PI_INTR_VA + 0x0)
+#define ICR_PI_CLR (PI_INTR_VA + 0x4)
+#define ICR_PI_SET (PI_INTR_VA + 0x8)
+#define ICR_SI_PEND (SI_INTR_VA)
+#define ICR_SI_MASK (SI_INTR_VA + 0x4)
+#define ICR_SI_CLR (SI_INTR_VA + 0x8)
+#define ICR_SI_SET (SI_INTR_VA + 0xc)
+#define ICR_ITR (SI_INTR_VA + 0x10)
+
/*
* Bits in interrupt registers. Software interrupt requests must
* be cleared in software. This is done in locore.s.
* There are separate registers for reading pending interrupts and
* setting/clearing (software) interrupts.
*/
-#define PINTR_SOFTINTR(n) ((n)) << 16)
+#define PINTR_SINTRLEV(n) (1 << (16 + (n)))
#define PINTR_IC 0x8000 /* Level 15 clear */
#define SINTR_MA 0x80000000 /* Mask All interrupts */
diff --git a/sys/arch/sparc/sparc/iommu.c b/sys/arch/sparc/sparc/iommu.c
new file mode 100644
index 00000000000..7a0457f6b65
--- /dev/null
+++ b/sys/arch/sparc/sparc/iommu.c
@@ -0,0 +1,352 @@
+/* $NetBSD: iommu.c,v 1.4 1996/05/21 07:25:07 pk Exp $ */
+
+/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
+ * Copyright (c) 1995 Paul Kranenburg
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
+ * This product includes software developed by Paul Kranenburg.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <vm/vm.h>
+
+#include <machine/autoconf.h>
+#include <machine/ctlreg.h>
+#include <sparc/sparc/asm.h>
+#include <sparc/sparc/vaddrs.h>
+#include <sparc/sparc/iommureg.h>
+
+struct iommu_softc {
+ struct device sc_dev; /* base device */
+ struct iommureg *sc_reg;
+ u_int sc_pagesize;
+ u_int sc_range;
+ u_int sc_dvmabase;
+ iopte_t *sc_ptes;
+ int sc_hasiocache;
+};
+struct iommu_softc *iommu_sc;/*XXX*/
+int has_iocache;
+
+
+/* autoconfiguration driver */
+int iommu_print __P((void *, char *));
+void iommu_attach __P((struct device *, struct device *, void *));
+int iommu_match __P((struct device *, void *, void *));
+
+struct cfattach iommu_ca = {
+ sizeof(struct iommu_softc), iommu_match, iommu_attach
+};
+
+struct cfdriver iommu_cd = {
+ NULL, "iommu", DV_DULL
+};
+
+/*
+ * Print the location of some iommu-attached device (called just
+ * before attaching that device). If `iommu' is not NULL, the
+ * device was found but not configured; print the iommu as well.
+ * Return UNCONF (config_find ignores this if the device was configured).
+ */
+int
+iommu_print(args, iommu)
+ void *args;
+ char *iommu;
+{
+ register struct confargs *ca = args;
+
+ if (iommu)
+ printf("%s at %s", ca->ca_ra.ra_name, iommu);
+ return (UNCONF);
+}
+
+int
+iommu_match(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct cfdata *cf = vcf;
+ register struct confargs *ca = aux;
+ register struct romaux *ra = &ca->ca_ra;
+
+ if (CPU_ISSUN4OR4C)
+ return (0);
+ return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
+}
+
+/*
+ * Attach the iommu.
+ */
+void
+iommu_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+#if defined(SUN4M)
+ register struct iommu_softc *sc = (struct iommu_softc *)self;
+ struct confargs oca, *ca = aux;
+ register struct romaux *ra = &ca->ca_ra;
+ register int node;
+ register char *name;
+ register u_int pbase, pa;
+ register int i, mmupcrsav, s, wierdviking = 0;
+ register iopte_t *tpte_p;
+ extern u_int *kernel_iopte_table;
+ extern u_int kernel_iopte_table_pa;
+
+/*XXX-GCC!*/mmupcrsav=0;
+ iommu_sc = sc;
+ /*
+ * XXX there is only one iommu, for now -- do not know how to
+ * address children on others
+ */
+ if (sc->sc_dev.dv_unit > 0) {
+ printf(" unsupported\n");
+ return;
+ }
+ node = ra->ra_node;
+
+#if 0
+ if (ra->ra_vaddr)
+ sc->sc_reg = (struct iommureg *)ca->ca_ra.ra_vaddr;
+#else
+ /*
+ * Map registers into our space. The PROM may have done this
+ * already, but I feel better if we have our own copy. Plus, the
+ * prom doesn't map the entire register set
+ *
+ * XXX struct iommureg is bigger than ra->ra_len; what are the
+ * other fields for?
+ */
+ sc->sc_reg = (struct iommureg *)
+ mapdev(ra->ra_reg, 0, 0, ra->ra_len, ra->ra_iospace);
+#endif
+
+ sc->sc_hasiocache = node_has_property(node, "cache-coherence?");
+ has_iocache = sc->sc_hasiocache; /* Set global flag */
+
+ sc->sc_pagesize = getpropint(node, "page-size", NBPG),
+ sc->sc_range = (1 << 24) <<
+ ((sc->sc_reg->io_cr & IOMMU_CTL_RANGE) >> IOMMU_CTL_RANGESHFT);
+#if 0
+ sc->sc_dvmabase = (0 - sc->sc_range);
+#endif
+ pbase = (sc->sc_reg->io_bar & IOMMU_BAR_IBA) <<
+ (14 - IOMMU_BAR_IBASHFT);
+
+ /*
+ * Now we build our own copy of the IOMMU page tables. We need to
+ * do this since we're going to change the range to give us 64M of
+ * mappings, and thus we can move DVMA space down to 0xfd000000 to
+ * give us lots of space and to avoid bumping into the PROM, etc.
+ *
+ * XXX Note that this is rather messy.
+ */
+ sc->sc_ptes = (iopte_t *) kernel_iopte_table;
+
+ /*
+ * Now discache the page tables so that the IOMMU sees our
+ * changes.
+ */
+ kvm_uncache((caddr_t)sc->sc_ptes,
+ (((0 - DVMA4M_BASE)/sc->sc_pagesize) * sizeof(iopte_t)) / NBPG);
+
+ /*
+ * Ok. We've got to read in the original table using MMU bypass,
+ * and copy all of its entries to the appropriate place in our
+ * new table, even if the sizes are different.
+ * This is pretty easy since we know DVMA ends at 0xffffffff.
+ *
+ * XXX: PGOFSET, NBPG assume same page size as SRMMU
+ */
+ if ((getpsr() & 0x40000000) && (!(lda(SRMMU_PCR,ASI_SRMMU) & 0x800))) {
+ wierdviking = 1;
+ sta(SRMMU_PCR, ASI_SRMMU, /* set MMU AC bit */
+ ((mmupcrsav = lda(SRMMU_PCR,ASI_SRMMU)) | SRMMU_PCR_AC));
+ }
+
+ for (tpte_p = &sc->sc_ptes[((0 - DVMA4M_BASE)/NBPG) - 1],
+ pa = (u_int)pbase - sizeof(iopte_t) +
+ ((u_int)sc->sc_range/NBPG)*sizeof(iopte_t);
+ tpte_p >= &sc->sc_ptes[0] && pa >= (u_int)pbase;
+ tpte_p--, pa -= sizeof(iopte_t)) {
+
+ IOMMU_FLUSHPAGE(sc,
+ (tpte_p - &sc->sc_ptes[0])*NBPG + DVMA4M_BASE);
+ *tpte_p = lda(pa, ASI_BYPASS);
+ }
+ if (wierdviking) { /* restore mmu after bug-avoidance */
+ sta(SRMMU_PCR, ASI_SRMMU, mmupcrsav);
+ }
+
+ /*
+ * Now we can install our new pagetable into the IOMMU
+ */
+ sc->sc_range = 0 - DVMA4M_BASE;
+ sc->sc_dvmabase = DVMA4M_BASE;
+
+ /* calculate log2(sc->sc_range/16MB) */
+ i = ffs(sc->sc_range/(1 << 24)) - 1;
+ if ((1 << i) != (sc->sc_range/(1 << 24)))
+ panic("bad iommu range: %d\n",i);
+
+ s = splhigh();
+ IOMMU_FLUSHALL(sc);
+
+ sc->sc_reg->io_cr = (sc->sc_reg->io_cr & ~IOMMU_CTL_RANGE) |
+ (i << IOMMU_CTL_RANGESHFT) | IOMMU_CTL_ME;
+ sc->sc_reg->io_bar = (kernel_iopte_table_pa >> 4) & IOMMU_BAR_IBA;
+
+ IOMMU_FLUSHALL(sc);
+ splx(s);
+
+ printf(": version %x/%x, page-size %d, range %dMB\n",
+ (sc->sc_reg->io_cr & IOMMU_CTL_VER) >> 24,
+ (sc->sc_reg->io_cr & IOMMU_CTL_IMPL) >> 28,
+ sc->sc_pagesize,
+ sc->sc_range >> 20);
+
+ /* Propagate bootpath */
+ if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "iommu") == 0)
+ oca.ca_ra.ra_bp = ra->ra_bp + 1;
+ else
+ oca.ca_ra.ra_bp = NULL;
+
+ /*
+ * Loop through ROM children (expect Sbus among them).
+ */
+ for (node = firstchild(node); node; node = nextsibling(node)) {
+ name = getpropstring(node, "name");
+ if (!romprop(&oca.ca_ra, name, node))
+ continue;
+ oca.ca_bustype = BUS_MAIN; /* ??? */
+ (void) config_found(&sc->sc_dev, (void *)&oca, iommu_print);
+ }
+#endif
+}
+
+void
+iommu_enter(va, pa)
+ u_int va, pa;
+{
+ struct iommu_softc *sc = iommu_sc;
+ int pte;
+
+#ifdef DEBUG
+ if (va < sc->sc_dvmabase)
+ panic("iommu_enter: va 0x%x not in DVMA space",va);
+#endif
+
+ pte = atop(pa) << IOPTE_PPNSHFT;
+ pte &= IOPTE_PPN;
+ pte |= IOPTE_V | IOPTE_W | (has_iocache ? IOPTE_C : 0);
+ sc->sc_ptes[atop(va - sc->sc_dvmabase)] = pte;
+ IOMMU_FLUSHPAGE(sc, va);
+}
+
+/*
+ * iommu_clear: clears mappings created by iommu_enter
+ */
+void
+iommu_remove(va, len)
+ register u_int va, len;
+{
+ register struct iommu_softc *sc = iommu_sc;
+
+#ifdef DEBUG
+ if (va < sc->sc_dvmabase)
+ panic("iommu_enter: va 0x%x not in DVMA space", va);
+#endif
+
+ while (len > 0) {
+#ifdef notyet
+#ifdef DEBUG
+ if ((sc->sc_ptes[atop(va - sc->sc_dvmabase)] & IOPTE_V) == 0)
+ panic("iommu_clear: clearing invalid pte at va 0x%x",
+ va);
+#endif
+#endif
+ sc->sc_ptes[atop(va - sc->sc_dvmabase)] = 0;
+ sta(sc->sc_ptes + atop(va - sc->sc_dvmabase), ASI_BYPASS, 0);
+ IOMMU_FLUSHPAGE(sc, va);
+ len -= sc->sc_pagesize;
+ va += sc->sc_pagesize;
+ }
+}
+
+#if 0 /* These registers aren't there??? */
+void
+iommu_error()
+{
+ struct iommu_softc *sc = X;
+ struct iommureg *iop = sc->sc_reg;
+
+ printf("iommu: afsr %x, afar %x\n", iop->io_afsr, iop->io_afar);
+ printf("iommu: mfsr %x, mfar %x\n", iop->io_mfsr, iop->io_mfar);
+}
+int
+iommu_alloc(va, len)
+ u_int va, len;
+{
+ struct iommu_softc *sc = X;
+ int off, tva, pa, iovaddr, pte;
+
+ off = (int)va & PGOFSET;
+ len = round_page(len + off);
+ va -= off;
+
+if ((int)sc->sc_dvmacur + len > 0)
+ sc->sc_dvmacur = sc->sc_dvmabase;
+
+ iovaddr = tva = sc->sc_dvmacur;
+ sc->sc_dvmacur += len;
+ while (len) {
+ pa = pmap_extract(pmap_kernel(), va);
+
+#define IOMMU_PPNSHIFT 8
+#define IOMMU_V 0x00000002
+#define IOMMU_W 0x00000004
+
+ pte = atop(pa) << IOMMU_PPNSHIFT;
+ pte |= IOMMU_V | IOMMU_W;
+ sta(sc->sc_ptes + atop(tva - sc->sc_dvmabase), ASI_BYPASS, pte);
+ sc->sc_reg->io_flushpage = tva;
+ len -= NBPG;
+ va += NBPG;
+ tva += NBPG;
+ }
+ return iovaddr + off;
+}
+#endif
diff --git a/sys/arch/sparc/sparc/iommureg.h b/sys/arch/sparc/sparc/iommureg.h
new file mode 100644
index 00000000000..24c5ac9f8cf
--- /dev/null
+++ b/sys/arch/sparc/sparc/iommureg.h
@@ -0,0 +1,93 @@
+/* $NetBSD: iommureg.h,v 1.2 1996/05/16 15:57:18 abrown Exp $ */
+
+/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
+ * Copyright (c) 1995 Paul Kranenburg
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
+ * This product includes software developed by Paul Kranenburg.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+struct iommureg {
+ u_int32_t io_cr; /* IOMMU control register */
+ u_int32_t io_bar; /* IOMMU PTE base register */
+ u_int32_t io_fill1[3];
+ u_int32_t io_flashclear; /* Flush all TLB entries */
+ u_int32_t io_flushpage; /* Flush page from TLB */
+ u_int32_t io_fill2[0x1000-28];
+ u_int32_t io_afsr; /* Asynchronous Fault Status */
+ u_int32_t io_afar; /* Asynchronous Fault Address */
+ u_int32_t io_sbuscfg0; /* Sbus configuration control */
+ u_int32_t io_sbuscfg1;
+ u_int32_t io_sbuscfg2;
+ u_int32_t io_sbuscfg3;
+ u_int32_t io_mfsr; /* Memory Fault Status */
+ u_int32_t io_mfar; /* Memory Fault Address */
+ u_int32_t io_fill3[0x1000-32];
+ u_int32_t io_mid; /* it might be mud */
+};
+
+#define IOMMU_CTL_IMPL 0xf0000000
+#define IOMMU_CTL_VER 0x0f000000
+#define IOMMU_CTL_RSVD1 0x00ffffe0
+#define IOMMU_CTL_RANGE 0x0000001c
+#define IOMMU_CTL_RANGESHFT 2
+#define IOMMU_CTL_RSVD2 0x00000002
+#define IOMMU_CTL_ME 0x00000001
+
+#define IOMMU_BAR_IBA 0xfffffc00
+#define IOMMU_BAR_IBASHFT 10
+
+/* Flushpage fields */
+#define IOMMU_FLPG_VADDR 0xfffff000
+#define IOMMU_FLUSH_MASK 0xfffff000
+
+#define IOMMU_FLUSHPAGE(sc, va) do { \
+ (sc)->sc_reg->io_flushpage = (va) & IOMMU_FLUSH_MASK; \
+} while (0);
+#define IOMMU_FLUSHALL(sc) do { \
+ (sc)->sc_reg->io_flashclear = 0; \
+} while (0)
+
+/* to pte.h ? */
+typedef u_int32_t iopte_t;
+
+#define IOPTE_PPN 0xffffff00 /* PA<35:12> */
+#define IOPTE_C 0x00000080 /* cacheable */
+#define IOPTE_W 0x00000004 /* writeable */
+#define IOPTE_V 0x00000002 /* valid */
+#define IOPTE_WAZ 0x00000001 /* must write as zero */
+
+#define IOPTE_PPNSHFT 8 /* shift to get ppn from IOPTE */
+#define IOPTE_PPNPASHFT 4 /* shift to get pa from ioppn */
+
+#define IOPTE_BITS "\20\10C\3W\2V\1WAZ"
+
diff --git a/sys/arch/sparc/sparc/kgdb_proto.h b/sys/arch/sparc/sparc/kgdb_proto.h
index edd86775d7f..8d1869a3a47 100644
--- a/sys/arch/sparc/sparc/kgdb_proto.h
+++ b/sys/arch/sparc/sparc/kgdb_proto.h
@@ -1,18 +1,22 @@
-/* $NetBSD: kgdb_proto.h,v 1.2 1994/11/20 20:54:21 deraadt Exp $ */
+/* $NetBSD: kgdb_proto.h,v 1.4 1996/05/16 15:57:19 abrown Exp $ */
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1995
+ * The President and Fellows of Harvard College. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
+ * must display the following acknowledgements:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
+ * This product includes software developed by Harvard University.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -56,6 +60,8 @@
#define KGDB_KILL 0x07
#define KGDB_SIGNAL 0x08
#define KGDB_EXEC 0x09
+#define KGDB_HALT 0x0a
+#define KGDB_BOOT 0x0b
#define KGDB_CMD(x) ((x) & 0x0f)
diff --git a/sys/arch/sparc/sparc/kgdb_stub.c b/sys/arch/sparc/sparc/kgdb_stub.c
index 0739215c3a1..3ba0c5e9975 100644
--- a/sys/arch/sparc/sparc/kgdb_stub.c
+++ b/sys/arch/sparc/sparc/kgdb_stub.c
@@ -1,18 +1,22 @@
-/* $NetBSD: kgdb_stub.c,v 1.2 1994/11/20 20:54:23 deraadt Exp $ */
+/* $NetBSD: kgdb_stub.c,v 1.8 1996/05/16 15:57:20 abrown Exp $ */
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1995
+ * The President and Fellows of Harvard College. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
+ * must display the following acknowledgements:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
+ * This product includes software developed by Harvard University.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -53,12 +57,16 @@
#include <sys/systm.h>
#include <sys/buf.h>
+#include <vm/vm.h>
+
#include <machine/ctlreg.h>
#include <machine/psl.h>
-#include <machine/pte.h>
#include <machine/reg.h>
#include <machine/remote-sl.h>
#include <machine/trap.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <machine/bsd_openprom.h>
#include <sparc/sparc/asm.h>
#include <sparc/sparc/kgdb_proto.h>
@@ -75,12 +83,30 @@ int kgdb_rate = KGDBRATE; /* remote debugging baud rate */
int kgdb_active = 0; /* remote debugging active if != 0 */
int kgdb_debug_panic = 0; /* != 0 waits for remote on panic */
-#define getpte(va) lda(va, ASI_PTE)
-#define setpte(va, pte) sta(va, ASI_PTE, pte)
+#if defined(SUN4M)
+#define getpte4m(va) lda(((vm_offset_t)va & 0xFFFFF000) | \
+ ASI_SRMMUFP_L3, ASI_SRMMUFP)
+void setpte4m __P((vm_offset_t, int));
+#endif
+
+#define getpte4(va) lda(va, ASI_PTE)
+#define setpte4(va, pte) sta(va, ASI_PTE, pte)
+
+void kgdb_copy __P((char *, char *, int));
+void kgdb_zero __P((char *, int));
+static void kgdb_send __P((u_int, u_char *, int));
+static int kgdb_recv __P((u_char *, int *));
+static int computeSignal __P((int));
+void regs_to_gdb __P((struct trapframe *, u_long *));
+void gdb_to_regs __P((struct trapframe *, u_long *));
+int kgdb_trap __P((int, struct trapframe *));
+int kgdb_acc __P((caddr_t, int, int, int));
+void kdb_mkwrite __P((caddr_t, int));
/*
* This little routine exists simply so that bcopy() can be debugged.
*/
+void
kgdb_copy(src, dst, len)
register char *src, *dst;
register int len;
@@ -90,6 +116,16 @@ kgdb_copy(src, dst, len)
*dst++ = *src++;
}
+/* ditto for bzero */
+void
+kgdb_zero(ptr, len)
+ register char *ptr;
+ register int len;
+{
+ while (--len >= 0)
+ *ptr++ = (char) 0;
+}
+
static int (*kgdb_getc) __P((void *));
static void (*kgdb_putc) __P((void *, int));
static void *kgdb_ioarg;
@@ -110,6 +146,7 @@ static void *kgdb_ioarg;
PUTC(c); \
}
+void
kgdb_attach(getfn, putfn, ioarg)
int (*getfn) __P((void *));
void (*putfn) __P((void *, int));
@@ -126,7 +163,7 @@ kgdb_attach(getfn, putfn, ioarg)
*/
static void
kgdb_send(type, bp, len)
- register u_char type;
+ register u_int type;
register u_char *bp;
register int len;
{
@@ -181,7 +218,7 @@ restart:
if (escape)
c = FRAME_START;
break;
-
+
case FRAME_START:
goto restart;
@@ -215,9 +252,9 @@ restart:
/*
* Translate a trap number into a unix compatible signal value.
* (gdb only understands unix signal numbers).
- * ### should this be done at the other end?
+ * XXX should this be done at the other end?
*/
-static int
+static int
computeSignal(type)
int type;
{
@@ -264,9 +301,10 @@ computeSignal(type)
}
/*
- * Trap into kgdb to wait for debugger to connect,
+ * Trap into kgdb to wait for debugger to connect,
* noting on the console why nothing else is going on.
*/
+void
kgdb_connect(verbose)
int verbose;
{
@@ -282,6 +320,7 @@ kgdb_connect(verbose)
/*
* Decide what to do on panic.
*/
+void
kgdb_panic()
{
@@ -330,7 +369,7 @@ regs_to_gdb(tf, gdb_regs)
kgdb_copy((caddr_t)tf->tf_out[6], (caddr_t)&gdb_regs[GDB_L0], 16 * 4);
/* %f0..%f31 -- fake, kernel does not use FP */
- bzero((caddr_t)&gdb_regs[GDB_FP0], 32 * 4);
+ kgdb_zero((caddr_t)&gdb_regs[GDB_FP0], 32 * 4);
/* %y, %psr, %wim, %tbr, %pc, %npc, %fsr, %csr */
gdb_regs[GDB_Y] = tf->tf_y;
@@ -353,7 +392,7 @@ gdb_to_regs(tf, gdb_regs)
{
kgdb_copy((caddr_t)&gdb_regs[1], (caddr_t)&tf->tf_global[1], 15 * 4);
- kgdb_copy((caddr_t)&gdb_regs[GDB_L0], (caddr_t)tf->tf_out[6]);
+ kgdb_copy((caddr_t)&gdb_regs[GDB_L0], (caddr_t)tf->tf_out[6], 16 * 4);
tf->tf_y = gdb_regs[GDB_Y];
tf->tf_psr = gdb_regs[GDB_PSR];
tf->tf_pc = gdb_regs[GDB_PC];
@@ -365,10 +404,10 @@ static u_char inbuffer[SL_RPCSIZE];
static u_char outbuffer[SL_RPCSIZE];
/*
- * This function does all command procesing for interfacing to
+ * This function does all command procesing for interfacing to
* a remote gdb.
*/
-int
+int
kgdb_trap(type, tf)
int type;
register struct trapframe *tf;
@@ -394,7 +433,7 @@ kgdb_trap(type, tf)
/*
* If the packet that woke us up isn't an exec packet,
* ignore it since there is no active debugger. Also,
- * we check that it's not an ack to be sure that the
+ * we check that it's not an ack to be sure that the
* remote side doesn't send back a response after the
* local gdb has exited. Otherwise, the local host
* could trap into gdb if it's running a gdb kernel too.
@@ -415,7 +454,7 @@ kgdb_trap(type, tf)
continue;
/*
* Do the printf *before* we ack the message. This way
- * we won't drop any inbound characters while we're
+ * we won't drop any inbound characters while we're
* doing the polling printf.
*/
printf("kgdb started from device %x\n", kgdb_dev);
@@ -487,7 +526,7 @@ kgdb_trap(type, tf)
}
}
break;
-
+
case KGDB_REG_W:
case KGDB_REG_W | KGDB_DELTA:
cp = inbuffer;
@@ -501,7 +540,7 @@ kgdb_trap(type, tf)
gdb_to_regs(tf, gdb_regs);
outlen = 0;
break;
-
+
case KGDB_MEM_R:
len = inbuffer[0];
kgdb_copy((caddr_t)&inbuffer[1], (caddr_t)&addr, 4);
@@ -541,6 +580,16 @@ kgdb_trap(type, tf)
kgdb_send(out, 0, 0);
return (1);
+ case KGDB_HALT:
+ kgdb_send(out, 0, 0);
+ callrom();
+ /* NOTREACHED */
+
+ case KGDB_BOOT:
+ kgdb_send(out, 0, 0);
+ romboot("");
+ /* NOTREACHED */
+
case KGDB_EXEC:
default:
/* Unknown command. Ack with a null message. */
@@ -552,21 +601,31 @@ kgdb_trap(type, tf)
}
}
-extern int kernacc();
-extern void chgkprot();
extern char *kernel_map; /* XXX! */
extern char *curproc; /* XXX! */
/*
* XXX do kernacc and useracc calls if safe, otherwise use PTE protections.
+ *
+ * Note: kernacc fails currently on the Sun4M port--we use pte bits instead.
+ * Plus this lets us debug kernacc. (%%% XXX)
*/
+int
kgdb_acc(addr, len, rw, usertoo)
caddr_t addr;
int len, rw, usertoo;
{
- extern char end[];
int pte;
+#if defined(SUN4M) /* we just use ptes here...its easier */
+ if (CPU_ISSUN4M) {
+ pte = getpte4m(addr);
+ if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE ||
+ (rw == B_WRITE && (pte & PPROT_WRITE) == 0))
+ return (0);
+ }
+#endif
+
/* XXX icky: valid address but causes timeout */
if (addr >= (caddr_t)0xfffff000)
return (0);
@@ -581,24 +640,42 @@ kgdb_acc(addr, len, rw, usertoo)
if (((int)addr >> PG_VSHIFT) != 0 &&
((int)addr >> PG_VSHIFT) != -1)
return (0);
- pte = getpte(addr);
- if ((pte & PG_V) == 0 || rw == B_WRITE && (pte & PG_W) == 0)
- return (0);
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ pte = getpte4m(addr);
+ if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE ||
+ (rw == B_WRITE && (pte & PPROT_WRITE) == 0))
+ return (0);
+ } else
+#endif
+ {
+ pte = getpte4(addr);
+ if ((pte & PG_V) == 0 ||
+ (rw == B_WRITE && (pte & PG_W) == 0))
+ return (0);
+ }
}
return (1);
}
+void
kdb_mkwrite(addr, len)
register caddr_t addr;
register int len;
{
-
- if (kernel_map != NULL) {
+ if (CPU_ISSUN4OR4C && kernel_map != NULL) {
chgkprot(addr, len, B_WRITE);
return;
}
+
addr = (caddr_t)((int)addr & ~PGOFSET);
for (; len > 0; len -= NBPG, addr += NBPG)
- setpte(addr, getpte(addr) | PG_W);
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ setpte4m((vm_offset_t)addr,
+ getpte4m(addr) | PPROT_WRITE);
+ else
+#endif
+ setpte4(addr, getpte4(addr) | PG_W);
}
#endif
diff --git a/sys/arch/sparc/sparc/locore.s b/sys/arch/sparc/sparc/locore.s
index 33f2e97417d..31721c9ed81 100644
--- a/sys/arch/sparc/sparc/locore.s
+++ b/sys/arch/sparc/sparc/locore.s
@@ -1,40 +1,10 @@
/*
- * Copyright (c) 1995 Theo de Raadt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed under OpenBSD by
- * Theo de Raadt for Willowglen Singapore.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
+ * Copyright (c) 1996 Paul Kranenburg
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
- * All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Theo de Raadt.
- *
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
@@ -43,6 +13,7 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
+ * This product includes software developed by Harvard University.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -56,6 +27,8 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
+ * This product includes software developed by Harvard University.
+ * This product includes software developed by Paul Kranenburg.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -75,12 +48,12 @@
* @(#)locore.s 8.4 (Berkeley) 12/10/93
*/
-#define LOCORE
-#include "assym.s"
+#include "assym.h"
+#include <machine/param.h>
#include <sparc/sparc/intreg.h>
#include <sparc/sparc/timerreg.h>
-#ifdef notyet
#include <sparc/sparc/vaddrs.h>
+#ifdef notyet
#include <sparc/dev/zsreg.h>
#endif
#include <machine/ctlreg.h>
@@ -105,7 +78,7 @@
#endif
/* use as needed to align things on longword boundaries */
-#define ALIGN .align 4
+#define _ALIGN .align 4
/*
* CCFSZ (C Compiler Frame SiZe) is the size of a stack frame required if
@@ -206,7 +179,7 @@ _kgdb_stack:
.globl _cpcb
_cpcb: .word _u0
-/*
+/*
* _cputyp is the current cpu type, used to distinguish between
* the many variations of different sun4* machines. It contains
* the value CPU_SUN4, CPU_SUN4C, or CPU_SUN4M.
@@ -214,6 +187,23 @@ _cpcb: .word _u0
.globl _cputyp
_cputyp:
.word 1
+/*
+ * _cpumod is the current cpu model, used to distinguish between variants
+ * in the Sun4 and Sun4M families. See /sys/arch/sparc/include/param.h for
+ * possible values.
+ */
+ .globl _cpumod
+_cpumod:
+ .word 1
+/*
+ * _mmumod is the current mmu model, used to distinguish between the
+ * various implementations of the SRMMU in the sun4m family of machines.
+ * See /sys/arch/sparc/include/param.h for possible values.
+ */
+ .globl _mmumod
+_mmumod:
+ .word 0
+
#if defined(SUN4C) || defined(SUN4M)
_cputypval:
.asciz "sun4c"
@@ -221,7 +211,7 @@ _cputypval:
_cputypvar:
.asciz "compatible"
_cputypvallen = _cputypvar - _cputypval
- ALIGN
+ _ALIGN
#endif
/*
@@ -230,11 +220,15 @@ _cputypvallen = _cputypvar - _cputypval
*/
.globl _pgshift, _nbpg, _pgofset
_pgshift:
- .word 1
+ .word 0
_nbpg:
- .word 1
+ .word 0
_pgofset:
- .word 1
+ .word 0
+
+ .globl _trapbase
+_trapbase:
+ .word 0
#if defined(SUN4M)
_mapme:
@@ -255,7 +249,7 @@ sun4_notsup:
! before we halt. Sick, eh?
.asciz "NetBSD/sparc: this kernel does not support the sun4\n\r \b"
#endif
- ALIGN
+ _ALIGN
.text
@@ -280,6 +274,10 @@ _msgbuf = KERNBASE
* boot process, so that we can handle NMIs (parity errors) halfway
* sensibly during boot. We use virtual address f8002000 (`page 2')
* for this, wasting a page of physical memory.
+ *
+ * This doesn't work for the Sun4M, which can have 5 or more pages of
+ * registers. Thus we use a reserved piece of the virtual address space, set
+ * up in bootstrap().
*/
IE_reg_addr = KERNBASE + 8192 ! this page not used; points to IEreg
@@ -319,13 +317,19 @@ IE_reg_addr = KERNBASE + 8192 ! this page not used; points to IEreg
mov (type), %l3; b label; mov %psr, %l0; nop
/* hardware interrupts (can be linked or made `fast') */
-#define HARDINT(lev) \
- mov (lev), %l3; b _sparc_interrupt; mov %psr, %l0; nop
+#define HARDINT44C(lev) \
+ mov (lev), %l3; b _sparc_interrupt44c; mov %psr, %l0; nop
+
+ /* hardware interrupts (can be linked or made `fast') */
+#define HARDINT4M(lev) \
+ mov (lev), %l3; b _sparc_interrupt4m; mov %psr, %l0; nop
/* software interrupts (may not be made direct, sorry---but you
should not be using them trivially anyway) */
-#define SOFTINT(lev, bit) \
- mov (lev), %l3; mov (bit), %l4; b softintr; mov %psr, %l0
+#define SOFTINT44C(lev, bit) \
+ mov (lev), %l3; mov (bit), %l4; b softintr_sun44c; mov %psr, %l0
+
+ /* There's no SOFTINT4M(): both hard and soft vector the same way */
/* traps that just call trap() */
#define TRAP(type) VTRAP(type, slowtrap)
@@ -352,16 +356,282 @@ IE_reg_addr = KERNBASE + 8192 ! this page not used; points to IEreg
#ifdef notyet
#define ZS_INTERRUPT b zshard; mov %psr, %l0; nop; nop
#else
-#define ZS_INTERRUPT HARDINT(12)
+#define ZS_INTERRUPT44C HARDINT44C(12)
+#define ZS_INTERRUPT4M HARDINT4M(12)
#endif
- .globl start
- .globl _trapbase
+ .globl start, _kernel_text
+ _kernel_text = start ! for kvm_mkdb(8)
start:
-_trapbase:
+/*
+ * Put sun4 traptable first, since it needs the most stringent aligment (8192)
+ */
+#if defined(SUN4)
+trapbase_sun4:
+ /* trap 0 is special since we cannot receive it */
+ b dostart; nop; nop; nop ! 00 = reset (fake)
+ VTRAP(T_TEXTFAULT, memfault_sun4) ! 01 = instr. fetch fault
+ TRAP(T_ILLINST) ! 02 = illegal instruction
+ TRAP(T_PRIVINST) ! 03 = privileged instruction
+ TRAP(T_FPDISABLED) ! 04 = fp instr, but EF bit off in psr
+ WINDOW_OF ! 05 = window overflow
+ WINDOW_UF ! 06 = window underflow
+ TRAP(T_ALIGN) ! 07 = address alignment error
+ VTRAP(T_FPE, fp_exception) ! 08 = fp exception
+ VTRAP(T_DATAFAULT, memfault_sun4) ! 09 = data fetch fault
+ TRAP(T_TAGOF) ! 0a = tag overflow
+ UTRAP(0x0b)
+ UTRAP(0x0c)
+ UTRAP(0x0d)
+ UTRAP(0x0e)
+ UTRAP(0x0f)
+ UTRAP(0x10)
+ SOFTINT44C(1, IE_L1) ! 11 = level 1 interrupt
+ HARDINT44C(2) ! 12 = level 2 interrupt
+ HARDINT44C(3) ! 13 = level 3 interrupt
+ SOFTINT44C(4, IE_L4) ! 14 = level 4 interrupt
+ HARDINT44C(5) ! 15 = level 5 interrupt
+ SOFTINT44C(6, IE_L6) ! 16 = level 6 interrupt
+ HARDINT44C(7) ! 17 = level 7 interrupt
+ HARDINT44C(8) ! 18 = level 8 interrupt
+ HARDINT44C(9) ! 19 = level 9 interrupt
+ HARDINT44C(10) ! 1a = level 10 interrupt
+ HARDINT44C(11) ! 1b = level 11 interrupt
+ ZS_INTERRUPT44C ! 1c = level 12 (zs) interrupt
+ HARDINT44C(13) ! 1d = level 13 interrupt
+ HARDINT44C(14) ! 1e = level 14 interrupt
+ VTRAP(15, nmi_sun4) ! 1f = nonmaskable interrupt
+ UTRAP(0x20)
+ UTRAP(0x21)
+ UTRAP(0x22)
+ UTRAP(0x23)
+ TRAP(T_CPDISABLED) ! 24 = coprocessor instr, EC bit off in psr
+ UTRAP(0x25)
+ UTRAP(0x26)
+ UTRAP(0x27)
+ TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception
+ UTRAP(0x29)
+ UTRAP(0x2a)
+ UTRAP(0x2b)
+ UTRAP(0x2c)
+ UTRAP(0x2d)
+ UTRAP(0x2e)
+ UTRAP(0x2f)
+ UTRAP(0x30)
+ UTRAP(0x31)
+ UTRAP(0x32)
+ UTRAP(0x33)
+ UTRAP(0x34)
+ UTRAP(0x35)
+ UTRAP(0x36)
+ UTRAP(0x37)
+ UTRAP(0x38)
+ UTRAP(0x39)
+ UTRAP(0x3a)
+ UTRAP(0x3b)
+ UTRAP(0x3c)
+ UTRAP(0x3d)
+ UTRAP(0x3e)
+ UTRAP(0x3f)
+ UTRAP(0x40)
+ UTRAP(0x41)
+ UTRAP(0x42)
+ UTRAP(0x43)
+ UTRAP(0x44)
+ UTRAP(0x45)
+ UTRAP(0x46)
+ UTRAP(0x47)
+ UTRAP(0x48)
+ UTRAP(0x49)
+ UTRAP(0x4a)
+ UTRAP(0x4b)
+ UTRAP(0x4c)
+ UTRAP(0x4d)
+ UTRAP(0x4e)
+ UTRAP(0x4f)
+ UTRAP(0x50)
+ UTRAP(0x51)
+ UTRAP(0x52)
+ UTRAP(0x53)
+ UTRAP(0x54)
+ UTRAP(0x55)
+ UTRAP(0x56)
+ UTRAP(0x57)
+ UTRAP(0x58)
+ UTRAP(0x59)
+ UTRAP(0x5a)
+ UTRAP(0x5b)
+ UTRAP(0x5c)
+ UTRAP(0x5d)
+ UTRAP(0x5e)
+ UTRAP(0x5f)
+ UTRAP(0x60)
+ UTRAP(0x61)
+ UTRAP(0x62)
+ UTRAP(0x63)
+ UTRAP(0x64)
+ UTRAP(0x65)
+ UTRAP(0x66)
+ UTRAP(0x67)
+ UTRAP(0x68)
+ UTRAP(0x69)
+ UTRAP(0x6a)
+ UTRAP(0x6b)
+ UTRAP(0x6c)
+ UTRAP(0x6d)
+ UTRAP(0x6e)
+ UTRAP(0x6f)
+ UTRAP(0x70)
+ UTRAP(0x71)
+ UTRAP(0x72)
+ UTRAP(0x73)
+ UTRAP(0x74)
+ UTRAP(0x75)
+ UTRAP(0x76)
+ UTRAP(0x77)
+ UTRAP(0x78)
+ UTRAP(0x79)
+ UTRAP(0x7a)
+ UTRAP(0x7b)
+ UTRAP(0x7c)
+ UTRAP(0x7d)
+ UTRAP(0x7e)
+ UTRAP(0x7f)
+ SYSCALL ! 80 = sun syscall
+ BPT ! 81 = pseudo breakpoint instruction
+ TRAP(T_DIV0) ! 82 = divide by zero
+ TRAP(T_FLUSHWIN) ! 83 = flush windows
+ TRAP(T_CLEANWIN) ! 84 = provide clean windows
+ TRAP(T_RANGECHECK) ! 85 = ???
+ TRAP(T_FIXALIGN) ! 86 = fix up unaligned accesses
+ TRAP(T_INTOF) ! 87 = integer overflow
+ SYSCALL ! 88 = svr4 syscall
+ SYSCALL ! 89 = bsd syscall
+ BPT_KGDB_EXEC ! 8a = enter kernel gdb on kernel startup
+ STRAP(0x8b)
+ STRAP(0x8c)
+ STRAP(0x8d)
+ STRAP(0x8e)
+ STRAP(0x8f)
+ STRAP(0x90)
+ STRAP(0x91)
+ STRAP(0x92)
+ STRAP(0x93)
+ STRAP(0x94)
+ STRAP(0x95)
+ STRAP(0x96)
+ STRAP(0x97)
+ STRAP(0x98)
+ STRAP(0x99)
+ STRAP(0x9a)
+ STRAP(0x9b)
+ STRAP(0x9c)
+ STRAP(0x9d)
+ STRAP(0x9e)
+ STRAP(0x9f)
+ STRAP(0xa0)
+ STRAP(0xa1)
+ STRAP(0xa2)
+ STRAP(0xa3)
+ STRAP(0xa4)
+ STRAP(0xa5)
+ STRAP(0xa6)
+ STRAP(0xa7)
+ STRAP(0xa8)
+ STRAP(0xa9)
+ STRAP(0xaa)
+ STRAP(0xab)
+ STRAP(0xac)
+ STRAP(0xad)
+ STRAP(0xae)
+ STRAP(0xaf)
+ STRAP(0xb0)
+ STRAP(0xb1)
+ STRAP(0xb2)
+ STRAP(0xb3)
+ STRAP(0xb4)
+ STRAP(0xb5)
+ STRAP(0xb6)
+ STRAP(0xb7)
+ STRAP(0xb8)
+ STRAP(0xb9)
+ STRAP(0xba)
+ STRAP(0xbb)
+ STRAP(0xbc)
+ STRAP(0xbd)
+ STRAP(0xbe)
+ STRAP(0xbf)
+ STRAP(0xc0)
+ STRAP(0xc1)
+ STRAP(0xc2)
+ STRAP(0xc3)
+ STRAP(0xc4)
+ STRAP(0xc5)
+ STRAP(0xc6)
+ STRAP(0xc7)
+ STRAP(0xc8)
+ STRAP(0xc9)
+ STRAP(0xca)
+ STRAP(0xcb)
+ STRAP(0xcc)
+ STRAP(0xcd)
+ STRAP(0xce)
+ STRAP(0xcf)
+ STRAP(0xd0)
+ STRAP(0xd1)
+ STRAP(0xd2)
+ STRAP(0xd3)
+ STRAP(0xd4)
+ STRAP(0xd5)
+ STRAP(0xd6)
+ STRAP(0xd7)
+ STRAP(0xd8)
+ STRAP(0xd9)
+ STRAP(0xda)
+ STRAP(0xdb)
+ STRAP(0xdc)
+ STRAP(0xdd)
+ STRAP(0xde)
+ STRAP(0xdf)
+ STRAP(0xe0)
+ STRAP(0xe1)
+ STRAP(0xe2)
+ STRAP(0xe3)
+ STRAP(0xe4)
+ STRAP(0xe5)
+ STRAP(0xe6)
+ STRAP(0xe7)
+ STRAP(0xe8)
+ STRAP(0xe9)
+ STRAP(0xea)
+ STRAP(0xeb)
+ STRAP(0xec)
+ STRAP(0xed)
+ STRAP(0xee)
+ STRAP(0xef)
+ STRAP(0xf0)
+ STRAP(0xf1)
+ STRAP(0xf2)
+ STRAP(0xf3)
+ STRAP(0xf4)
+ STRAP(0xf5)
+ STRAP(0xf6)
+ STRAP(0xf7)
+ STRAP(0xf8)
+ STRAP(0xf9)
+ STRAP(0xfa)
+ STRAP(0xfb)
+ STRAP(0xfc)
+ STRAP(0xfd)
+ STRAP(0xfe)
+ STRAP(0xff)
+#endif
+
+#if defined(SUN4C)
+trapbase_sun4c:
/* trap 0 is special since we cannot receive it */
b dostart; nop; nop; nop ! 00 = reset (fake)
- VTRAP(T_TEXTFAULT, memfault_bootup) ! 01 = instr. fetch fault (backpatch to memfault)
+ VTRAP(T_TEXTFAULT, memfault_sun4c) ! 01 = instr. fetch fault
TRAP(T_ILLINST) ! 02 = illegal instruction
TRAP(T_PRIVINST) ! 03 = privileged instruction
TRAP(T_FPDISABLED) ! 04 = fp instr, but EF bit off in psr
@@ -369,7 +639,7 @@ _trapbase:
WINDOW_UF ! 06 = window underflow
TRAP(T_ALIGN) ! 07 = address alignment error
VTRAP(T_FPE, fp_exception) ! 08 = fp exception
- VTRAP(T_DATAFAULT, memfault_bootup) ! 09 = data fetch fault (backpatch to memfault)
+ VTRAP(T_DATAFAULT, memfault_sun4c) ! 09 = data fetch fault
TRAP(T_TAGOF) ! 0a = tag overflow
UTRAP(0x0b)
UTRAP(0x0c)
@@ -377,21 +647,21 @@ _trapbase:
UTRAP(0x0e)
UTRAP(0x0f)
UTRAP(0x10)
- SOFTINT(1, IE_L1) ! 11 = level 1 interrupt
- HARDINT(2) ! 12 = level 2 interrupt
- HARDINT(3) ! 13 = level 3 interrupt
- SOFTINT(4, IE_L4) ! 14 = level 4 interrupt
- HARDINT(5) ! 15 = level 5 interrupt
- SOFTINT(6, IE_L6) ! 16 = level 6 interrupt
- HARDINT(7) ! 17 = level 7 interrupt
- HARDINT(8) ! 18 = level 8 interrupt
- HARDINT(9) ! 19 = level 9 interrupt
- HARDINT(10) ! 1a = level 10 interrupt
- HARDINT(11) ! 1b = level 11 interrupt
- ZS_INTERRUPT ! 1c = level 12 (zs) interrupt
- HARDINT(13) ! 1d = level 13 interrupt
- HARDINT(14) ! 1e = level 14 interrupt
- VTRAP(15, nmi) ! 1f = nonmaskable interrupt
+ SOFTINT44C(1, IE_L1) ! 11 = level 1 interrupt
+ HARDINT44C(2) ! 12 = level 2 interrupt
+ HARDINT44C(3) ! 13 = level 3 interrupt
+ SOFTINT44C(4, IE_L4) ! 14 = level 4 interrupt
+ HARDINT44C(5) ! 15 = level 5 interrupt
+ SOFTINT44C(6, IE_L6) ! 16 = level 6 interrupt
+ HARDINT44C(7) ! 17 = level 7 interrupt
+ HARDINT44C(8) ! 18 = level 8 interrupt
+ HARDINT44C(9) ! 19 = level 9 interrupt
+ HARDINT44C(10) ! 1a = level 10 interrupt
+ HARDINT44C(11) ! 1b = level 11 interrupt
+ ZS_INTERRUPT44C ! 1c = level 12 (zs) interrupt
+ HARDINT44C(13) ! 1d = level 13 interrupt
+ HARDINT44C(14) ! 1e = level 14 interrupt
+ VTRAP(15, nmi_sun4c) ! 1f = nonmaskable interrupt
UTRAP(0x20)
UTRAP(0x21)
UTRAP(0x22)
@@ -616,13 +886,278 @@ _trapbase:
STRAP(0xfd)
STRAP(0xfe)
STRAP(0xff)
+#endif
+
+#if defined(SUN4M)
+trapbase_sun4m:
+/* trap 0 is special since we cannot receive it */
+ b dostart; nop; nop; nop ! 00 = reset (fake)
+ VTRAP(T_TEXTFAULT, memfault_sun4m) ! 01 = instr. fetch fault
+ TRAP(T_ILLINST) ! 02 = illegal instruction
+ TRAP(T_PRIVINST) ! 03 = privileged instruction
+ TRAP(T_FPDISABLED) ! 04 = fp instr, but EF bit off in psr
+ WINDOW_OF ! 05 = window overflow
+ WINDOW_UF ! 06 = window underflow
+ TRAP(T_ALIGN) ! 07 = address alignment error
+ VTRAP(T_FPE, fp_exception) ! 08 = fp exception
+ VTRAP(T_DATAFAULT, memfault_sun4m) ! 09 = data fetch fault
+ TRAP(T_TAGOF) ! 0a = tag overflow
+ UTRAP(0x0b)
+ UTRAP(0x0c)
+ UTRAP(0x0d)
+ UTRAP(0x0e)
+ UTRAP(0x0f)
+ UTRAP(0x10)
+ HARDINT4M(1) ! 11 = level 1 interrupt
+ HARDINT4M(2) ! 12 = level 2 interrupt
+ HARDINT4M(3) ! 13 = level 3 interrupt
+ HARDINT4M(4) ! 14 = level 4 interrupt
+ HARDINT4M(5) ! 15 = level 5 interrupt
+ HARDINT4M(6) ! 16 = level 6 interrupt
+ HARDINT4M(7) ! 17 = level 7 interrupt
+ HARDINT4M(8) ! 18 = level 8 interrupt
+ HARDINT4M(9) ! 19 = level 9 interrupt
+ HARDINT4M(10) ! 1a = level 10 interrupt
+ HARDINT4M(11) ! 1b = level 11 interrupt
+ ZS_INTERRUPT4M ! 1c = level 12 (zs) interrupt
+ HARDINT4M(13) ! 1d = level 13 interrupt
+ HARDINT4M(14) ! 1e = level 14 interrupt
+ VTRAP(15, nmi_sun4m) ! 1f = nonmaskable interrupt
+ UTRAP(0x20)
+ UTRAP(0x21)
+ UTRAP(0x22)
+ UTRAP(0x23)
+ TRAP(T_CPDISABLED) ! 24 = coprocessor instr, EC bit off in psr
+ UTRAP(0x25)
+ UTRAP(0x26)
+ UTRAP(0x27)
+ TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception
+ UTRAP(0x29)
+ UTRAP(0x2a)
+ VTRAP(T_STOREBUFFAULT, memfault_sun4m) ! 2b = SuperSPARC store buffer fault
+ UTRAP(0x2c)
+ UTRAP(0x2d)
+ UTRAP(0x2e)
+ UTRAP(0x2f)
+ UTRAP(0x30)
+ UTRAP(0x31)
+ UTRAP(0x32)
+ UTRAP(0x33)
+ UTRAP(0x34)
+ UTRAP(0x35)
+ UTRAP(0x36)
+ UTRAP(0x37)
+ UTRAP(0x38)
+ UTRAP(0x39)
+ UTRAP(0x3a)
+ UTRAP(0x3b)
+ UTRAP(0x3c)
+ UTRAP(0x3d)
+ UTRAP(0x3e)
+ UTRAP(0x3f)
+ UTRAP(0x40)
+ UTRAP(0x41)
+ UTRAP(0x42)
+ UTRAP(0x43)
+ UTRAP(0x44)
+ UTRAP(0x45)
+ UTRAP(0x46)
+ UTRAP(0x47)
+ UTRAP(0x48)
+ UTRAP(0x49)
+ UTRAP(0x4a)
+ UTRAP(0x4b)
+ UTRAP(0x4c)
+ UTRAP(0x4d)
+ UTRAP(0x4e)
+ UTRAP(0x4f)
+ UTRAP(0x50)
+ UTRAP(0x51)
+ UTRAP(0x52)
+ UTRAP(0x53)
+ UTRAP(0x54)
+ UTRAP(0x55)
+ UTRAP(0x56)
+ UTRAP(0x57)
+ UTRAP(0x58)
+ UTRAP(0x59)
+ UTRAP(0x5a)
+ UTRAP(0x5b)
+ UTRAP(0x5c)
+ UTRAP(0x5d)
+ UTRAP(0x5e)
+ UTRAP(0x5f)
+ UTRAP(0x60)
+ UTRAP(0x61)
+ UTRAP(0x62)
+ UTRAP(0x63)
+ UTRAP(0x64)
+ UTRAP(0x65)
+ UTRAP(0x66)
+ UTRAP(0x67)
+ UTRAP(0x68)
+ UTRAP(0x69)
+ UTRAP(0x6a)
+ UTRAP(0x6b)
+ UTRAP(0x6c)
+ UTRAP(0x6d)
+ UTRAP(0x6e)
+ UTRAP(0x6f)
+ UTRAP(0x70)
+ UTRAP(0x71)
+ UTRAP(0x72)
+ UTRAP(0x73)
+ UTRAP(0x74)
+ UTRAP(0x75)
+ UTRAP(0x76)
+ UTRAP(0x77)
+ UTRAP(0x78)
+ UTRAP(0x79)
+ UTRAP(0x7a)
+ UTRAP(0x7b)
+ UTRAP(0x7c)
+ UTRAP(0x7d)
+ UTRAP(0x7e)
+ UTRAP(0x7f)
+ SYSCALL ! 80 = sun syscall
+ BPT ! 81 = pseudo breakpoint instruction
+ TRAP(T_DIV0) ! 82 = divide by zero
+ TRAP(T_FLUSHWIN) ! 83 = flush windows
+ TRAP(T_CLEANWIN) ! 84 = provide clean windows
+ TRAP(T_RANGECHECK) ! 85 = ???
+ TRAP(T_FIXALIGN) ! 86 = fix up unaligned accesses
+ TRAP(T_INTOF) ! 87 = integer overflow
+ SYSCALL ! 88 = svr4 syscall
+ SYSCALL ! 89 = bsd syscall
+ BPT_KGDB_EXEC ! 8a = enter kernel gdb on kernel startup
+ STRAP(0x8b)
+ STRAP(0x8c)
+ STRAP(0x8d)
+ STRAP(0x8e)
+ STRAP(0x8f)
+ STRAP(0x90)
+ STRAP(0x91)
+ STRAP(0x92)
+ STRAP(0x93)
+ STRAP(0x94)
+ STRAP(0x95)
+ STRAP(0x96)
+ STRAP(0x97)
+ STRAP(0x98)
+ STRAP(0x99)
+ STRAP(0x9a)
+ STRAP(0x9b)
+ STRAP(0x9c)
+ STRAP(0x9d)
+ STRAP(0x9e)
+ STRAP(0x9f)
+ STRAP(0xa0)
+ STRAP(0xa1)
+ STRAP(0xa2)
+ STRAP(0xa3)
+ STRAP(0xa4)
+ STRAP(0xa5)
+ STRAP(0xa6)
+ STRAP(0xa7)
+ STRAP(0xa8)
+ STRAP(0xa9)
+ STRAP(0xaa)
+ STRAP(0xab)
+ STRAP(0xac)
+ STRAP(0xad)
+ STRAP(0xae)
+ STRAP(0xaf)
+ STRAP(0xb0)
+ STRAP(0xb1)
+ STRAP(0xb2)
+ STRAP(0xb3)
+ STRAP(0xb4)
+ STRAP(0xb5)
+ STRAP(0xb6)
+ STRAP(0xb7)
+ STRAP(0xb8)
+ STRAP(0xb9)
+ STRAP(0xba)
+ STRAP(0xbb)
+ STRAP(0xbc)
+ STRAP(0xbd)
+ STRAP(0xbe)
+ STRAP(0xbf)
+ STRAP(0xc0)
+ STRAP(0xc1)
+ STRAP(0xc2)
+ STRAP(0xc3)
+ STRAP(0xc4)
+ STRAP(0xc5)
+ STRAP(0xc6)
+ STRAP(0xc7)
+ STRAP(0xc8)
+ STRAP(0xc9)
+ STRAP(0xca)
+ STRAP(0xcb)
+ STRAP(0xcc)
+ STRAP(0xcd)
+ STRAP(0xce)
+ STRAP(0xcf)
+ STRAP(0xd0)
+ STRAP(0xd1)
+ STRAP(0xd2)
+ STRAP(0xd3)
+ STRAP(0xd4)
+ STRAP(0xd5)
+ STRAP(0xd6)
+ STRAP(0xd7)
+ STRAP(0xd8)
+ STRAP(0xd9)
+ STRAP(0xda)
+ STRAP(0xdb)
+ STRAP(0xdc)
+ STRAP(0xdd)
+ STRAP(0xde)
+ STRAP(0xdf)
+ STRAP(0xe0)
+ STRAP(0xe1)
+ STRAP(0xe2)
+ STRAP(0xe3)
+ STRAP(0xe4)
+ STRAP(0xe5)
+ STRAP(0xe6)
+ STRAP(0xe7)
+ STRAP(0xe8)
+ STRAP(0xe9)
+ STRAP(0xea)
+ STRAP(0xeb)
+ STRAP(0xec)
+ STRAP(0xed)
+ STRAP(0xee)
+ STRAP(0xef)
+ STRAP(0xf0)
+ STRAP(0xf1)
+ STRAP(0xf2)
+ STRAP(0xf3)
+ STRAP(0xf4)
+ STRAP(0xf5)
+ STRAP(0xf6)
+ STRAP(0xf7)
+ STRAP(0xf8)
+ STRAP(0xf9)
+ STRAP(0xfa)
+ STRAP(0xfb)
+ STRAP(0xfc)
+ STRAP(0xfd)
+ STRAP(0xfe)
+ STRAP(0xff)
+#endif
/*
- * pad the trap table to max page size
- * trap table size is 0x100 * 4instr * 4byte/instr = 4096 bytes
- * need to .skip 4096 to pad to page size
+ * Pad the trap table to max page size.
+ * Trap table size is 0x100 * 4instr * 4byte/instr = 4096 bytes;
+ * need to .skip 4096 to pad to page size iff. the number of trap tables
+ * defined above is odd.
*/
+#if defined(SUN4) + defined(SUN4C) + defined(SUN4M) - 2 == 0
.skip 4096
+#endif
#ifdef DEBUG
/*
@@ -640,7 +1175,7 @@ _redstack:
.text
Lpanic_red:
.asciz "stack overflow"
- ALIGN
+ _ALIGN
/* set stack pointer redzone to base+minstack; alters base */
#define SET_SP_REDZONE(base, tmp) \
@@ -684,7 +1219,6 @@ Lpanic_red:
#define CHECK_SP_REDZONE(t1, t2)
#endif
-#if defined(SUN4) || defined(SUN4C)
/*
* The window code must verify user stack addresses before using them.
* A user stack pointer is invalid if:
@@ -706,8 +1240,9 @@ Lpanic_red:
* The code below also assumes that PTE_OF_ADDR is safe in a delay
* slot; it is, at it merely sets its `pte' register to a temporary value.
*/
+#if defined(SUN4) || defined(SUN4C)
/* input: addr, output: pte; aux: bad address label */
-#define PTE_OF_ADDR(addr, pte, bad, page_offset) \
+#define PTE_OF_ADDR4_4C(addr, pte, bad, page_offset) \
sra addr, PG_VSHIFT, pte; \
cmp pte, -1; \
be,a 1f; andn addr, page_offset, pte; \
@@ -717,20 +1252,92 @@ Lpanic_red:
1:
/* input: pte; output: condition codes */
-#define CMP_PTE_USER_READ(pte) \
+#define CMP_PTE_USER_READ4_4C(pte) \
lda [pte] ASI_PTE, pte; \
srl pte, PG_PROTSHIFT, pte; \
andn pte, (PG_W >> PG_PROTSHIFT), pte; \
cmp pte, PG_PROTUREAD
/* input: pte; output: condition codes */
-#define CMP_PTE_USER_WRITE(pte) \
+#define CMP_PTE_USER_WRITE4_4C(pte) \
lda [pte] ASI_PTE, pte; \
srl pte, PG_PROTSHIFT, pte; \
cmp pte, PG_PROTUWRITE
#endif
/*
+ * The Sun4M does not have the memory hole that the 4C does. Thus all
+ * we need to do here is clear the page offset from addr.
+ */
+#if defined(SUN4M)
+#define PTE_OF_ADDR4M(addr, pte, bad, page_offset) \
+ andn addr, page_offset, pte
+
+/* note: pmap currently does not use the PPROT_R_R and PPROT_RW_RW cases */
+#define CMP_PTE_USER_READ4M(pte) \
+ or pte, ASI_SRMMUFP_L3, pte; \
+ lda [pte] ASI_SRMMUFP, pte; \
+ and pte, (SRMMU_TETYPE | SRMMU_PROT_MASK), pte; \
+ cmp pte, (SRMMU_TEPTE | PPROT_RWX_RWX); \
+ be 8f; nop; \
+ cmp pte, (SRMMU_TEPTE | PPROT_RX_RX); \
+8:
+
+
+/* note: PTE bit 4 set implies no user writes */
+#define CMP_PTE_USER_WRITE4M(pte) \
+ or pte, ASI_SRMMUFP_L3, pte; \
+ lda [pte] ASI_SRMMUFP, pte; \
+ and pte, (SRMMU_TETYPE | 0x14), pte; \
+ cmp pte, (SRMMU_TEPTE | PPROT_WRITE)
+#endif /* 4m */
+
+#if defined(SUN4M) && !(defined(SUN4C) || defined(SUN4))
+#define PTE_OF_ADDR PTE_OF_ADDR4M
+#define CMP_PTE_USER_WRITE(pte,tmp) CMP_PTE_USER_WRITE4M(pte)
+#define CMP_PTE_USER_READ(pte,tmp) CMP_PTE_USER_READ4M(pte)
+#elif (defined(SUN4C) || defined(SUN4)) && !defined(SUN4M)
+#define PTE_OF_ADDR PTE_OF_ADDR4_4C
+#define CMP_PTE_USER_WRITE(pte,tmp) CMP_PTE_USER_WRITE4_4C(pte)
+#define CMP_PTE_USER_READ(pte,tmp) CMP_PTE_USER_READ4_4C(pte)
+#else /* both defined, ugh */
+#define PTE_OF_ADDR(addr, pte, bad, page_offset) \
+ sethi %hi(_cputyp), pte; \
+ ld [pte + %lo(_cputyp)], pte; \
+ cmp pte, CPU_SUN4M; \
+ bne 2f; nop; \
+ PTE_OF_ADDR4M(addr, pte, bad, page_offset); \
+ b,a 3f; \
+2: \
+ PTE_OF_ADDR4_4C(addr, pte, bad, page_offset); \
+3:
+
+#define CMP_PTE_USER_READ(pte, tmp) \
+ sethi %hi(_cputyp), tmp; \
+ ld [tmp + %lo(_cputyp)], tmp; \
+ cmp tmp, CPU_SUN4M; \
+ bne 1f; nop; \
+ CMP_PTE_USER_READ4M(pte); \
+ b,a 2f; \
+1: \
+ CMP_PTE_USER_READ4_4C(pte); \
+2:
+
+#define CMP_PTE_USER_WRITE(pte, tmp) \
+ sethi %hi(_cputyp), tmp; \
+ ld [tmp + %lo(_cputyp)], tmp; \
+ cmp tmp, CPU_SUN4M; \
+ bne 1f; nop; \
+ CMP_PTE_USER_WRITE4M(pte); \
+ b,a 2f; \
+1: \
+ CMP_PTE_USER_WRITE4_4C(pte); \
+2:
+
+#endif
+
+
+/*
* The calculations in PTE_OF_ADDR and CMP_PTE_USER_* are rather slow:
* in particular, according to Gordon Irlam of the University of Adelaide
* in Australia, these consume at least 18 cycles on an SS1 and 37 on an
@@ -998,16 +1605,17 @@ ctw_user:
sethi %hi(_pgofset), %g6 ! trash %g6=curpcb
ld [%g6 + %lo(_pgofset)], %g6
PTE_OF_ADDR(%sp, %g7, ctw_invalid, %g6)
- CMP_PTE_USER_WRITE(%g7) ! likewise if not writable
+ CMP_PTE_USER_WRITE(%g7, %g5) ! likewise if not writable
bne ctw_invalid
EMPTY
+ /* Note side-effect of SLT_IF_1PAGE_RW: decrements %g6 by 62 */
SLT_IF_1PAGE_RW(%sp, %g7, %g6)
bl,a ctw_merge ! all ok if only 1
std %l0, [%sp]
add %sp, 7*8, %g5 ! check last addr too
- add %g6, 62, %g6
+ add %g6, 62, %g6 ! restore %g6 to `pgofset'
PTE_OF_ADDR(%g5, %g7, ctw_invalid, %g6)
- CMP_PTE_USER_WRITE(%g7)
+ CMP_PTE_USER_WRITE(%g7, %g6)
be,a ctw_merge ! all ok: store <l0,l1> and merge
std %l0, [%sp]
@@ -1098,13 +1706,6 @@ ctw_invalid:
* %l4 = %y, until we call mem_access_fault (then onto trapframe)
* %l5 = IE_reg_addr, if async mem error
*
- * We know about the layout of the error registers here.
- * addr reg
- * ---- ---
- * a AC_SYNC_ERR
- * a+4 AC_SYNC_VA
- * a+8 AC_ASYNC_ERR
- * a+12 AC_ASYNC_VA
*/
#if defined(SUN4)
@@ -1135,7 +1736,7 @@ memfault_sun4:
! as I got some parity errors and the
! correct bits were not on?
std %g6, [%sp + CCFSZ + 40]
- bz,a xnormal_mem_fault ! no, just a regular fault
+ bz,a 0f ! no, just a regular fault
wr %l0, PSR_ET, %psr ! (and reenable traps)
/* memory error = death for now XXX */
@@ -1146,11 +1747,11 @@ memfault_sun4:
call _callrom
nop
-xnormal_mem_fault:
+0:
/*
- * have to make SUN4 emulate SUN4C. SUN4C code expects SER in
- * %o1 and the offending VA in %o2, everything else remains the
- * same, but we must figure out if SER_WRITE should be set.
+ * have to make SUN4 emulate SUN4C. 4C code expects
+ * SER in %o1 and the offending VA in %o2, everything else is ok.
+ * (must figure out if SER_WRITE should be set)
*/
set AC_BUS_ERR, %o0 ! bus error register
cmp %l3, T_TEXTFAULT ! text fault always on PC
@@ -1166,18 +1767,30 @@ xnormal_mem_fault:
sethi %hi(SER_WRITE), %o5 ! damn SER_WRITE wont fit simm13
! or %lo(SER_WRITE), %o5, %o5! not necessary since %lo is zero
or %o5, %o1, %o1 ! set SER_WRITE
- ba normal_mem_fault
- nop ! XXX make efficient later
+#if defined(SUN4C) || defined(SUN4M)
+ ba,a normal_mem_fault
+ !!nop ! XXX make efficient later
+#endif /* SUN4C || SUN4M */
#endif /* SUN4 */
-#if defined(SUN4C)
memfault_sun4c:
+#if defined(SUN4C)
TRAP_SETUP(-CCFSZ-80)
INCR(_cnt+V_FAULTS) ! cnt.v_faults++ (clobbers %o0,%o1)
st %g1, [%sp + CCFSZ + 20] ! save g1
rd %y, %l4 ! save y
+ /*
+ * We know about the layout of the error registers here.
+ * addr reg
+ * ---- ---
+ * a AC_SYNC_ERR
+ * a+4 AC_SYNC_VA
+ * a+8 AC_ASYNC_ERR
+ * a+12 AC_ASYNC_VA
+ */
+
#if AC_SYNC_ERR + 4 != AC_SYNC_VA || \
AC_SYNC_ERR + 8 != AC_ASYNC_ERR || AC_SYNC_ERR + 12 != AC_ASYNC_VA
help help help ! I, I, I wanna be a lifeguard
@@ -1266,17 +1879,58 @@ memfault_sun4m:
st %g1, [%sp + CCFSZ + 20] ! save g1
rd %y, %l4 ! save y
- mov SRMMU_SFSTAT, %o0
+ set SRMMU_SFADDR, %o0
std %g2, [%sp + CCFSZ + 24] ! save g2, g3
- lda [%o0] ASI_SRMMU, %o1 ! srmmu fault status
- mov SRMMU_SFADDR, %o0
+ lda [%o0] ASI_SRMMU, %o2 ! sync virt addr; must be read first
+ set SRMMU_SFSTAT, %o0
+ lda [%o0] ASI_SRMMU, %o1 ! get sync fault status register
std %g4, [%sp + CCFSZ + 32] ! (sneak g4,g5 in here)
- lda [%o0] ASI_SRMMU, %o2 ! srmmu fault address
- ! XXX check for memory errors?
- std %g6, [%sp + CCFSZ + 40]
- b normal_mem_fault ! no, just a regular fault
- wr %l0, PSR_ET, %psr ! (and reenable traps)
- /* NOTREACHED */
+
+ /* Now test for a HyperSPARC. If we have one, get the async status */
+ sethi %hi(_mmumod), %o3 ! get MMU model
+ ld [%o3 + %lo(_mmumod)], %o3
+ cmp %o3, SUN4M_MMU_HS ! is it hypersparc?
+ std %g6, [%sp + CCFSZ + 40] ! sneak in g6, g7
+ be 1f ! yup, skip ahead
+
+ clr %o3 ! clear %o3 and %o4, not hypersparc
+ b 2f
+ clr %o4
+1:
+ set SRMMU_AFSTAT, %o3 ! must read status before fault on HS
+ lda [%o3] ASI_SRMMU, %o3 ! get async fault status
+ set SRMMU_AFADDR, %o4
+ lda [%o4] ASI_SRMMU, %o4 ! get async fault address
+2:
+ wr %l0, PSR_ET, %psr ! reenable traps
+
+ /* Finish stackframe, call C trap handler */
+ std %l0, [%sp + CCFSZ + 0] ! set tf.tf_psr, tf.tf_pc
+ mov %l3, %o0 ! (argument: type)
+ st %l2, [%sp + CCFSZ + 8] ! set tf.tf_npc
+ st %l4, [%sp + CCFSZ + 12] ! set tf.tf_y
+ std %i0, [%sp + CCFSZ + 48] ! tf.tf_out[0], etc
+ std %i2, [%sp + CCFSZ + 56]
+ std %i4, [%sp + CCFSZ + 64]
+ std %i6, [%sp + CCFSZ + 72]
+ call _mem_access_fault4m ! mem_access_fault(type, sfsr, sfva,
+ ! afsr, afva, &tf);
+ add %sp, CCFSZ, %o5 ! (argument: &tf)
+
+ ldd [%sp + CCFSZ + 0], %l0 ! load new values
+ ldd [%sp + CCFSZ + 8], %l2
+ wr %l3, 0, %y
+ ld [%sp + CCFSZ + 20], %g1
+ ldd [%sp + CCFSZ + 24], %g2
+ ldd [%sp + CCFSZ + 32], %g4
+ ldd [%sp + CCFSZ + 40], %g6
+ ldd [%sp + CCFSZ + 48], %i0
+ ldd [%sp + CCFSZ + 56], %i2
+ ldd [%sp + CCFSZ + 64], %i4
+ ldd [%sp + CCFSZ + 72], %i6
+
+ b return_from_trap ! go return
+ wr %l0, 0, %psr ! (but first disable traps again)
#endif /* SUN4M */
normal_mem_fault:
@@ -1315,14 +1969,6 @@ normal_mem_fault:
b return_from_trap ! go return
wr %l0, 0, %psr ! (but first disable traps again)
-/* At bootup, we have to point the data/text fault trap table entry
- * somewhere by default. Make the machine watchdog so that we can
- * see what happened by looking at %tbr and %pc under the PROM.
- */
-memfault_bootup:
- call 0
- nop
- /* NOTREACHED */
/*
* fp_exception has to check to see if we are trying to save
@@ -1340,8 +1986,6 @@ fp_exception:
EMPTY
sethi %hi(savefpcont), %l4 ! yes, "return" to the special code
or %lo(savefpcont), %l4, %l4
- wr %l0, 0x0, %psr
- nop; nop; nop;
jmp %l4
rett %l4 + 4
@@ -1621,8 +2265,8 @@ syscall:
ldd [%sp + CCFSZ + 0], %l0 ! new %psr, new pc
ldd [%sp + CCFSZ + 8], %l2 ! new npc, new %y
wr %l3, 0, %y
- /* see `dostart' for the reason for this label */
-init_syscall_ret:
+ /* see `proc_trampoline' for the reason for this label */
+return_from_syscall:
ld [%sp + CCFSZ + 20], %g1
ldd [%sp + CCFSZ + 24], %g2
ldd [%sp + CCFSZ + 32], %g4
@@ -1662,7 +2306,7 @@ init_syscall_ret:
* represents one or many requests)
* (3) we never announce a stray interrupt (because of (1), another
* interrupt request can come in while we're in the handler. If
- * the handler deal with everything for both the original & the
+ * the handler deals with everything for both the original & the
* new request, we'll erroneously report a stray interrupt when
* we take the software interrupt for the new request.
*
@@ -1683,11 +2327,13 @@ init_syscall_ret:
* this contains the psr, pc, npc, and interrupt level.
*/
.comm _intrhand, 15 * 8 ! intrhand[0..14]; 0 => error
-softintr:
+softintr_sun44c:
sethi %hi(IE_reg_addr), %l6
ldub [%l6 + %lo(IE_reg_addr)], %l5
andn %l5, %l4, %l5
stb %l5, [%l6 + %lo(IE_reg_addr)]
+
+softintr_common:
INTR_SETUP(-CCFSZ-80)
std %g2, [%sp + CCFSZ + 24] ! save registers
INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1)
@@ -1731,10 +2377,31 @@ softintr:
wr %l0, 0, %psr
/*
- * _sparc_interrupt is exported for paranoia checking (see intr.c).
+ * _sparc_interrupt{44c,4m} is exported for paranoia checking
+ * (see intr.c).
*/
- .globl _sparc_interrupt
-_sparc_interrupt:
+#if defined(SUN4M)
+ .globl _sparc_interrupt4m
+_sparc_interrupt4m:
+ mov 1, %l4
+ sethi %hi(ICR_PI_PEND), %l5
+ ld [%l5 + %lo(ICR_PI_PEND)], %l5
+ sll %l4, %l3, %l4
+ andcc %l5, %l4, %g0
+ bne _sparc_interrupt_common
+ nop
+
+ ! a soft interrupt; clear bit in interrupt-pending register
+ ! XXX - this is CPU0's register set.
+ sethi %hi(ICR_PI_CLR), %l6
+ sll %l4, 16, %l5
+ st %l5, [%l6 + %lo(ICR_PI_CLR)]
+ b,a softintr_common
+#endif
+
+ .globl _sparc_interrupt44c
+_sparc_interrupt44c:
+_sparc_interrupt_common:
INTR_SETUP(-CCFSZ-80)
std %g2, [%sp + CCFSZ + 24] ! save registers
INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1)
@@ -1821,7 +2488,9 @@ zshard:
* except that we already know the problem is not a `normal' fault,
* and that we must be extra-careful with interrupt enables.
*/
-nmi:
+
+#if defined(SUN4)
+nmi_sun4:
INTR_SETUP(-CCFSZ-80)
INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1)
/*
@@ -1830,33 +2499,40 @@ nmi:
*/
sethi %hi(IE_reg_addr), %o0
ldub [%o0 + %lo(IE_reg_addr)], %o1
- andn %o1, IE_ALLIE, %o1
+ andn %o0, IE_ALLIE, %o1
stb %o1, [%o0 + %lo(IE_reg_addr)]
wr %l0, PSR_ET, %psr ! okay, turn traps on again
std %g2, [%sp + CCFSZ + 0] ! save g2, g3
rd %y, %l4 ! save y
- ! must read the sync error register too.
-#if defined(SUN4) && (defined(SUN4C) || defined(SUN4M))
- sethi %hi(_cputyp), %o0 ! what cpu are we running on?
- ld [%o0 + %lo(_cputyp)], %o0
- cmp %o0, CPU_SUN4
- bne 1f
- nop
-#endif
-#if defined(SUN4)
std %g4, [%sp + CCFSZ + 8] ! save g4, g5
mov %g1, %l5 ! save g1, g6, g7
mov %g6, %l6
mov %g7, %l7
#if defined(SUN4C) || defined(SUN4M)
- b 2f
- nop
+ b,a nmi_common
#endif /* SUN4C || SUN4M */
-#endif /* SUN4 */
-1:
-#if defined(SUN4C) || defined(SUN4M)
+#endif
+
+#if defined(SUN4C)
+nmi_sun4c:
+ INTR_SETUP(-CCFSZ-80)
+ INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1)
+ /*
+ * Level 15 interrupts are nonmaskable, so with traps off,
+ * disable all interrupts to prevent recursion.
+ */
+ sethi %hi(IE_reg_addr), %o0
+ ldub [%o0 + %lo(IE_reg_addr)], %o1
+ andn %o0, IE_ALLIE, %o1
+ stb %o1, [%o0 + %lo(IE_reg_addr)]
+ wr %l0, PSR_ET, %psr ! okay, turn traps on again
+
+ std %g2, [%sp + CCFSZ + 0] ! save g2, g3
+ rd %y, %l4 ! save y
+
+ ! must read the sync error register too.
set AC_SYNC_ERR, %o0
lda [%o0] ASI_CONTROL, %o1 ! sync err reg
inc 4, %o0
@@ -1869,8 +2545,12 @@ nmi:
lda [%o0] ASI_CONTROL, %o3 ! async err reg
inc 4, %o0
lda [%o0] ASI_CONTROL, %o4 ! async virt addr
-#endif /* SUN4C || SUN4M */
-2:
+#if defined(SUN4M)
+ !!b,a nmi_common
+#endif /* SUN4M */
+#endif /* SUN4C */
+
+nmi_common:
! and call C code
call _memerr ! memerr(0, ser, sva, aer, ava)
clr %o0
@@ -1890,6 +2570,84 @@ nmi:
b return_from_trap
wr %l4, 0, %y ! restore y
+#if defined(SUN4M)
+nmi_sun4m:
+ INTR_SETUP(-CCFSZ-80)
+ INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1)
+ /*
+ * Level 15 interrupts are nonmaskable, so with traps off,
+ * disable all interrupts to prevent recursion.
+ */
+ sethi %hi(ICR_SI_SET), %o0
+ set SINTR_MA, %o1
+ st %o1, [%o0 + %lo(ICR_SI_SET)]
+
+ /* Now clear the NMI */
+
+ sethi %hi(ICR_PI_CLR), %o0
+ set PINTR_IC, %o1
+ st %o1, [%o0 + %lo(ICR_PI_CLR)]
+
+ wr %l0, PSR_ET, %psr ! okay, turn traps on again
+
+ std %g2, [%sp + CCFSZ + 0] ! save g2, g3
+ rd %y, %l4 ! save y
+
+ ! now read sync error registers
+ set SRMMU_SFADDR, %o0
+ lda [%o0] ASI_SRMMU, %o2 ! sync virt addr
+ set SRMMU_SFSTAT, %o0
+ lda [%o0] ASI_SRMMU, %o1 ! sync err reg
+ std %g4, [%sp + CCFSZ + 8] ! save g4,g5
+
+ /* Now test for a HyperSPARC. If we have one, get the async status */
+
+ sethi %hi(_mmumod), %o3 ! get MMU model
+ ld [%o3 + %lo(_mmumod)], %o3
+ cmp %o3, SUN4M_MMU_HS ! is it hypersparc?
+ be 1f ! yup, skip ahead
+
+ clr %o3 ! clear %o3 and %o4, not hypersparc
+ b 2f
+ clr %o4
+1:
+ set SRMMU_AFSTAT, %o3 ! read status first on hypersparc
+ lda [%o3] ASI_SRMMU, %o3 ! get async fault status
+ set SRMMU_AFADDR, %o4
+ lda [%o4] ASI_SRMMU, %o4 ! get async fault address
+2:
+ /* Finish stackframe, call C trap handler */
+ mov %g1, %l5 ! save g1,g6,g7
+ mov %g6, %l6
+ mov %g7, %l7
+ clr %o5
+
+ call _memerr4m ! memerr4m(0, sfsr, sfva, afsr, afva)
+ clr %o0
+
+ mov %l5, %g1 ! restore g1 through g7
+ ldd [%sp + CCFSZ + 0], %g2
+ ldd [%sp + CCFSZ + 8], %g4
+ wr %l0, 0, %psr ! re-disable traps
+ mov %l6, %g6
+ mov %l7, %g7
+
+ ! enable interrupts again (safe, we disabled traps again above)
+ sethi %hi(ICR_SI_CLR), %o0
+ set SINTR_MA, %o1
+ st %o1, [%o0 + %lo(ICR_SI_CLR)]
+
+ b return_from_trap
+ wr %l4, 0, %y ! restore y
+#endif /* SUN4M */
+
+#ifdef GPROF
+ .globl window_of, winof_user
+ .globl window_uf, winuf_user, winuf_ok, winuf_invalid
+ .globl return_from_trap, rft_kernel, rft_user, rft_invalid
+ .globl softtrap, slowtrap
+ .globl clean_trap_window, syscall
+#endif
/*
* Window overflow trap handler.
@@ -2064,7 +2822,7 @@ winuf_user:
sethi %hi(_pgofset), %l4
ld [%l4 + %lo(_pgofset)], %l4
PTE_OF_ADDR(%sp, %l7, winuf_invalid, %l4)
- CMP_PTE_USER_READ(%l7) ! if first page not readable,
+ CMP_PTE_USER_READ(%l7, %l5) ! if first page not readable,
bne winuf_invalid ! it is invalid
EMPTY
SLT_IF_1PAGE_RW(%sp, %l7, %l4) ! first page is readable
@@ -2073,7 +2831,7 @@ winuf_user:
add %sp, 7*8, %l5
add %l4, 62, %l4
PTE_OF_ADDR(%l5, %l7, winuf_invalid, %l4)
- CMP_PTE_USER_READ(%l7) ! check second page too
+ CMP_PTE_USER_READ(%l7, %l5) ! check second page too
be,a winuf_ok ! enter window X and goto ok
restore %g0, 1, %l1 ! (and then set %l1 to 1)
@@ -2095,12 +2853,7 @@ winuf_invalid:
* only window, and it is a user window).
*/
save %g0, %g0, %g0 ! back to R
-#ifdef SUN_AS /* this gives `as' mild heartburn */
save %g0, 1, %l4 ! back to T, then %l4 = 1
-#else
- save %g0, %g0, %g0 ! back to T
- mov 1, %l4 ! and set %l4 = 1
-#endif
sethi %hi(_cpcb), %l6
ld [%l6 + %lo(_cpcb)], %l6
st %l4, [%l6 + PCB_UW] ! pcb_uw = 1
@@ -2293,7 +3046,7 @@ rft_user:
sethi %hi(_pgofset), %l3
ld [%l3 + %lo(_pgofset)], %l3
PTE_OF_ADDR(%fp, %l7, rft_invalid, %l3)
- CMP_PTE_USER_READ(%l7) ! try first page
+ CMP_PTE_USER_READ(%l7, %l5) ! try first page
bne rft_invalid ! no good
EMPTY
SLT_IF_1PAGE_RW(%fp, %l7, %l3)
@@ -2302,7 +3055,7 @@ rft_user:
add %fp, 7*8, %l5
add %l3, 62, %l3
PTE_OF_ADDR(%l5, %l7, rft_invalid, %l3)
- CMP_PTE_USER_READ(%l7) ! check 2nd page too
+ CMP_PTE_USER_READ(%l7, %l5) ! check 2nd page too
be,a rft_user_ok
wr %g0, 0, %wim
@@ -2579,9 +3332,8 @@ dostart:
is_sun4m:
#if defined(SUN4M)
+ set trapbase_sun4m, %g6
mov SUN4CM_PGSHIFT, %g5
-
- set memfault_sun4m, %o1 ! ptr to our memfault routine
b start_havetype
mov CPU_SUN4M, %g4
#else
@@ -2596,12 +3348,12 @@ is_sun4m:
#endif
is_sun4c:
#if defined(SUN4C)
+ set trapbase_sun4c, %g6
mov SUN4CM_PGSHIFT, %g5
set AC_CONTEXT, %g1 ! paranoia: set context to kernel
stba %g0, [%g1] ASI_CONTROL
- set memfault_sun4c, %o1 ! ptr to our memfault routine
b start_havetype
mov CPU_SUN4C, %g4 ! XXX CPU_SUN4
#else
@@ -2630,12 +3382,12 @@ is_sun4c:
#endif
is_sun4:
#if defined(SUN4)
+ set trapbase_sun4, %g6
mov SUN4_PGSHIFT, %g5
set AC_CONTEXT, %g1 ! paranoia: set context to kernel
stba %g0, [%g1] ASI_CONTROL
- set memfault_sun4, %o1 ! ptr to our memfault routine
b start_havetype
mov CPU_SUN4, %g4
#else
@@ -2653,41 +3405,6 @@ is_sun4:
start_havetype:
/*
- * Back-patch the T_{TEXT,DATA}FAULT vectors to branch to the
- * correct memfault routine. There is a different memfault routine
- * for each processor. Here we carefully synthesize the offsets
- * and merge them into the "ba" instruction which already exists.
- */
- set KERNBASE, %o2 ! unmapped as yet
- sub %o1, %o2, %o1
- set _trapbase-KERNBASE, %o2 ! and store in trap table
- set 0xffc00000, %o4 ! 22bit offset in "bcc" instruction
-
- ! patch instr fetch fault vector to point to our memfault routine
- ld [%o2 + (16*T_TEXTFAULT+4)], %o3 ! fetch "ba" instruction
- and %o3, %o4, %o3 ! mask out garbage
- sub %o1, %o2, %o5 ! generate relative offset
- sub %o5, (16*T_TEXTFAULT+4), %o5
- srl %o5, 2, %o5 ! long-word offset
- or %o3, %o5, %o3 ! merge into "ba" instruction
- st %o3, [%o2 + (16*T_TEXTFAULT+4)]
-
- ! patch data fetch fault vector to point to our memfault routine
- ld [%o2 + (16*T_DATAFAULT+4)], %o3 ! fetch "ba" instruction
- and %o3, %o4, %o3 ! mask out garbage
- sub %o1, %o2, %o5 ! generate relative offset
- sub %o5, (16*T_DATAFAULT+4), %o5
- srl %o5, 2, %o5 ! long-word offset
- or %o3, %o5, %o3 ! merge into "ba" instruction
- st %o3, [%o2 + (16*T_DATAFAULT+4)]
-
- /*
- * XXX
- * We just modified the text segment. We should flush that cache
- * line!
- */
-
- /*
* Step 1: double map low RAM (addresses [0.._end-start-1])
* to KERNBASE (addresses [KERNBASE.._end-1]). None of these
* are `bad' aliases (since they are all on segment boundaries)
@@ -2746,17 +3463,16 @@ start_havetype:
stb %l1, [%l0]
b startmap_done
nop
-#endif /* SUN4C */
1:
+#endif /* SUN4C */
#if defined(SUN4)
cmp %g4, CPU_SUN4
bne 2f
#if defined(MMU_3L)
set AC_IDPROM+1, %l3
lduba [%l3] ASI_CONTROL, %l3
- cmp %l3, SUN4_400
+ cmp %l3, 0x24 ! XXX - SUN4_400
bne no_3mmu
- nop
add %l0, 2, %l0 ! get to proper half-word in RG space
add %l1, 2, %l1
lduha [%l0] ASI_REGMAP, %l4 ! regmap[highva] = regmap[lowva];
@@ -2775,6 +3491,7 @@ no_3mmu:
add %l3, %l0, %l0 ! (and lowva += segsz)
remap_done:
+
/*
* Now map the interrupt enable register and clear any interrupts,
* enabling NMIs. Note that we will not take NMIs until we change
@@ -2792,8 +3509,8 @@ remap_done:
nop; nop ! paranoia
stb %l1, [%l0]
b,a startmap_done
-#endif /* SUN4 */
2:
+#endif /* SUN4 */
#if defined(SUN4M)
cmp %g4, CPU_SUN4M ! skip for sun4m!
bne 3f
@@ -2860,10 +3577,10 @@ remap_notvik:
srl %l1, 22, %o2 ! note: 22 == RGSHIFT - 2
add %o1, %o2, %o1
sta %l4, [%o1] ASI_BYPASS
- b,a startmap_done
+ !b,a startmap_done
-#endif /* SUN4M */
3:
+#endif /* SUN4M */
! botch! We should blow up.
startmap_done:
@@ -2911,6 +3628,10 @@ startmap_done:
wr %l0, PSR_ET, %psr
nop; nop; nop
+ /* Export actual trapbase */
+ sethi %hi(_trapbase), %o0
+ st %g6, [%o0+%lo(_trapbase)]
+
/*
* Step 2: clear BSS. This may just be paranoia; the boot
* loader might already do it for us; but what the hell.
@@ -2941,7 +3662,7 @@ startmap_done:
call init_tables
st %o0, [%o1 + %lo(_nwindows)]
-#ifdef SUN4
+#if defined(SUN4)
/*
* Some sun4 models have fewer than 8 windows. For extra
* speed, we do not need to save/restore those windows
@@ -2957,18 +3678,15 @@ noplab: nop
set wb1, %l0
st %l1, [%l0 + 6*4]
st %l1, [%l0 + 7*4]
- set wb2, %l0
- st %l1, [%l0 + 6*4]
- st %l1, [%l0 + 7*4]
1:
#endif
/*
* Step 4: change the trap base register, now that our trap handlers
* will function (they need the tables we just set up).
+ * This depends on the fact that bzero does not use %g6.
*/
- set _trapbase, %l0
- wr %l0, 0, %tbr
+ wr %g6, 0, %tbr
nop; nop; nop ! paranoia
@@ -2984,17 +3702,7 @@ noplab: nop
*/
call _main
clr %o0 ! our frame arg is ignored
-
- /*
- * Here we finish up as in syscall, but simplified. We need to
- * fiddle pc and npc a bit, as execve() / setregs() have only set
- * npc, in anticipation that trap.c will advance past the trap
- * instruction; but we bypass that, so we must do it manually.
- */
- mov PSR_S, %l0 ! user psr (no need to load it)
- ld [%sp + CCFSZ + 8], %l1 ! pc = npc from execve
- b init_syscall_ret
- add %l1, 4, %l2 ! npc = pc+4
+ /*NOTREACHED*/
/*
* The following code is copied to the top of the user stack when each
@@ -3239,20 +3947,20 @@ _svr4_esigcode:
/*
* Primitives
- */
+ */
#ifdef GPROF
.globl mcount
#define ENTRY(x) \
- .globl _##x; _##x: ; \
+ .globl _/**/x; _/**/x: ; \
save %sp, -CCFSZ, %sp; \
call mcount; \
nop; \
restore
#else
-#define ENTRY(x) .globl _##x; _##x:
+#define ENTRY(x) .globl _/**/x; _/**/x:
#endif
-#define ALTENTRY(x) .globl _##x; _##x:
+#define ALTENTRY(x) .globl _/**/x; _/**/x:
/*
* getfp() - get stack frame pointer
@@ -3287,7 +3995,7 @@ ENTRY(copyinstr)
call _panic
or %lo(2f), %o0, %o0
2: .asciz "copyinstr"
- ALIGN
+ _ALIGN
/*
* copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
@@ -3315,7 +4023,7 @@ ENTRY(copyoutstr)
call _panic
or %lo(2f), %o0, %o0
2: .asciz "copyoutstr"
- ALIGN
+ _ALIGN
Lcsdocopy:
! sethi %hi(_cpcb), %o4 ! (done earlier)
@@ -3395,10 +4103,10 @@ ENTRY(copystr)
or %lo(5f), %o0, %o0
5:
.asciz "copystr"
- ALIGN
+ _ALIGN
#endif
-/*
+/*
* Copyin(src, dst, len)
*
* Copy specified amount of data from user space into the kernel.
@@ -3458,25 +4166,6 @@ Lcopyfault:
jmp %g7 + 8
mov EFAULT, %o0
-/* Force the cpu to complete all pending store operations
- * and flush it's on chip write buffers. This is the sun4c/sun4
- * version and will only be called when servicing a memory
- * error so that we do not loop indefinately.
- */
-ENTRY(sun4c_sun4_storebuf_flush)
- set AC_CONTEXT, %o1
- lduba [%o1] ASI_CONTROL, %o0 ! load context reg
- stba %o0, [%o1] ASI_CONTROL ! store same value, flush begins
- nop
- nop
- nop
- /* Pipeline is now clear */
- nop
- nop
- nop
- /* Store buffer is empty, safe to return now. */
- retl
- nop
/*
* Write all user windows presently in the CPU back to the user's stack.
@@ -3615,7 +4304,7 @@ ENTRY(switchexit)
/*
* When no processes are on the runq, switch
- * idles here watiing for something to come ready.
+ * idles here waiting for something to come ready.
* The registers are set up as noted above.
*/
.globl idle
@@ -3644,7 +4333,7 @@ Lsw_panic_srun:
1: .asciz "switch rq"
2: .asciz "switch wchan"
3: .asciz "switch SRUN"
- ALIGN
+ _ALIGN
/*
* cpu_switch() picks a process to run and runs it, saving the current
@@ -3698,7 +4387,7 @@ ENTRY(cpu_switch)
st %g0, [%g7 + %lo(_curproc)] ! curproc = NULL;
wr %g1, 0, %psr ! (void) spl0();
nop; nop; nop ! paranoia
- wr %g1, PIL_CLOCK <<8 , %psr ! (void) splclock();
+ wr %g1, PIL_CLOCK << 8 , %psr ! (void) splclock();
Lsw_scan:
nop; nop; nop ! paranoia
@@ -3877,7 +4566,7 @@ Lsw_load:
ld [%o3 + VM_PMAP_CTX], %o0! if (vm->vm_pmap.pm_ctx != NULL)
tst %o0
bnz,a Lsw_havectx ! goto havecontext;
- ld [%o3 + VM_PMAP_CTXNUM], %o0
+ ld [%o3 + VM_PMAP_CTXNUM], %o0 ! load context number
/* p does not have a context: call ctx_alloc to get one */
save %sp, -CCFSZ, %sp
@@ -3888,7 +4577,7 @@ Lsw_load:
/* p does have a context: just switch to it */
Lsw_havectx:
-! ld [%o3 + VM_PMAP_CTXNUM], %o0 ! (done in delay slot)
+ ! context is in %o0
#if (defined(SUN4) || defined(SUN4C)) && defined(SUN4M)
sethi %hi(_cputyp), %o1 ! what cpu are we running on?
ld [%o1 + %lo(_cputyp)], %o1
@@ -3898,16 +4587,14 @@ Lsw_havectx:
#endif
#if defined(SUN4) || defined(SUN4C)
set AC_CONTEXT, %o1
- stba %o0, [%o1] ASI_CONTROL ! setcontext(vm->vm_pmap.pm_ctxnum);
retl
- nop
+ stba %o0, [%o1] ASI_CONTROL ! setcontext(vm->vm_pmap.pm_ctxnum);
#endif
1:
#if defined(SUN4M)
set SRMMU_CXR, %o1
- stba %o0, [%o1] ASI_SRMMU ! setcontext(vm->vm_pmap.pm_ctxnum);
retl
- nop
+ sta %o0, [%o1] ASI_SRMMU ! setcontext(vm->vm_pmap.pm_ctxnum);
#endif
Lsw_sameproc:
@@ -3923,21 +4610,10 @@ Lsw_sameproc:
/*
* Snapshot the current process so that stack frames are up to date.
- * This is called from two places:
- * - just before a crash dump, for the stack update;
- * - in cpu_fork(), before copying the kernel stack.
- * In the latter case the pcb and stack will be copied to the child,
- * and the child will be made runnable. Eventually switch() will run
- * it. When it does, we want its pcb_pc set so that we can appear
- * to return 1 from cpu_fork(), so we store the current sp and psr
- * in the given pcb, and set its pcb_pc to our return-1 code (offset
- * by -8 due to call/ret conventions). This is not useful in the crash
- * dump code but it is easiest to do it anyway.
+ * Only used just before a crash dump.
*/
ENTRY(snapshot)
st %o6, [%o0 + PCB_SP] ! save sp
- set 1f - 8, %o1 ! set child-return pc
- st %o1, [%o0 + PCB_PC]
rd %psr, %o1 ! save psr
st %o1, [%o0 + PCB_PSR]
@@ -3946,13 +4622,34 @@ ENTRY(snapshot)
* 7 of each. Minor tweak: the 7th restore is
* done after a ret.
*/
-wb2: SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE
+ SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE
restore; restore; restore; restore; restore; restore; ret; restore
-1: /* this is reached only after a child gets chosen in switch() */
- mov 1, %i0 ! return 1 from cpu_fork
- ret
- restore
+
+/*
+ * cpu_set_kpc() and cpu_fork() arrange for proc_trampoline() to run
+ * after after a process gets chosen in switch(). The stack frame will
+ * contain a function pointer in %l0, and an argument to pass to it in %l2.
+ *
+ * If the function *(%l0) returns, we arrange for an immediate return
+ * to user mode. This happens in two known cases: after execve(2) of init,
+ * and when returning a child to user mode after a fork(2).
+ */
+ENTRY(proc_trampoline)
+ call %l0 ! re-use current frame
+ mov %l1, %o0
+
+ /*
+ * Here we finish up as in syscall, but simplified. We need to
+ * fiddle pc and npc a bit, as execve() / setregs() /cpu_set_kpc()
+ * have only set npc, in anticipation that trap.c will advance past
+ * the trap instruction; but we bypass that, so we must do it manually.
+ */
+ mov PSR_S, %l0 ! user psr (no need to load it)
+ !?wr %g0, 2, %wim ! %wim = 2
+ ld [%sp + CCFSZ + 8], %l1 ! pc = tf->tf_npc from execve/fork
+ b return_from_syscall
+ add %l1, 4, %l2 ! npc = pc+4
/*
* {fu,su}{,i}{byte,word}
@@ -4109,10 +4806,6 @@ ENTRY(subyte)
*/
ENTRY(probeget)
! %o0 = addr, %o1 = (1,2,4)
- set KERNBASE, %o2
- cmp %o0, %o2 ! if addr < KERNBASE
- blu Lfsbadaddr ! go return error
- EMPTY
sethi %hi(_cpcb), %o2
ld [%o2 + %lo(_cpcb)], %o2 ! cpcb->pcb_onfault = Lfserr;
set Lfserr, %o5
@@ -4136,10 +4829,6 @@ ENTRY(probeget)
*/
ENTRY(probeset)
! %o0 = addr, %o1 = (1,2,4), %o2 = val
- set KERNBASE, %o3
- cmp %o0, %o3 ! if addr < KERNBASE
- blu Lfsbadaddr ! go return error
- EMPTY
sethi %hi(_cpcb), %o3
ld [%o3 + %lo(_cpcb)], %o3 ! cpcb->pcb_onfault = Lfserr;
set Lfserr, %o5
@@ -4702,10 +5391,36 @@ ENTRY(loadfpstate)
* ienab_bic(bic) int bic;
*
* Set and clear bits in the interrupt register.
+ */
+
+#if defined(SUN4M) && (defined(SUN4) || defined(SUN4C))
+ENTRY(ienab_bis)
+ sethi %hi(_cputyp), %o1
+ ld [%o1 + %lo(_cputyp)], %o1
+ cmp %o1, CPU_SUN4M
+ be,a _ienab_bis_4m
+ nop
+ b,a _ienab_bis_4c
+
+ENTRY(ienab_bic)
+ sethi %hi(_cputyp), %o1
+ ld [%o1 + %lo(_cputyp)], %o1
+ cmp %o1, CPU_SUN4M
+ be,a _ienab_bic_4m
+ nop
+ b,a _ienab_bic_4c
+#endif
+
+#if defined(SUN4) || defined(SUN4C)
+/*
* Since there are no read-modify-write instructions for this,
* and one of the interrupts is nonmaskable, we must disable traps.
*/
+#if defined(SUN4M)
+ENTRY(ienab_bis_4c)
+#else
ENTRY(ienab_bis)
+#endif
! %o0 = bits to set
rd %psr, %o2
wr %o2, PSR_ET, %psr ! disable traps
@@ -4719,7 +5434,11 @@ ENTRY(ienab_bis)
retl
nop
+#if defined(SUN4M)
+ENTRY(ienab_bic_4c)
+#else
ENTRY(ienab_bic)
+#endif
! %o0 = bits to clear
rd %psr, %o2
wr %o2, PSR_ET, %psr ! disable traps
@@ -4732,6 +5451,47 @@ ENTRY(ienab_bic)
nop
retl
nop
+#endif
+
+#if defined(SUN4M)
+/*
+ * sun4m has separate registers for clearing/setting the interrupt mask.
+ */
+#if defined(SUN4) || defined(SUN4C)
+ENTRY(ienab_bis_4m)
+#else
+ENTRY(ienab_bis)
+#endif
+ set ICR_SI_SET, %o1
+ retl
+ st %o0, [%o1]
+
+#if defined(SUN4) || defined(SUN4C)
+ENTRY(ienab_bic_4m)
+#else
+ENTRY(ienab_bic)
+#endif
+ set ICR_SI_CLR, %o1
+ retl
+ st %o0, [%o1]
+
+/*
+ * raise(cpu, level)
+ */
+ENTRY(raise)
+ ! *(ICR_PI_SET + cpu*_MAXNBPG) = PINTR_SINTRLEV(level)
+ sethi %hi(1 << 16), %o2
+ sll %o2, %o1, %o2
+ set ICR_PI_SET, %o1
+ set _MAXNBPG, %o3
+1:
+ subcc %o0, 1, %o0
+ bpos,a 1b
+ add %o1, %o3, %o1
+ retl
+ st %o2, [%o1]
+
+#endif /* SUN4M */
/*
* ffs(), using table lookup.
@@ -4805,15 +5565,14 @@ ENTRY(ffs)
* Vol 33 No 1.
*/
.data
- .globl __randseed
-__randseed:
+randseed:
.word 1
.text
ENTRY(random)
sethi %hi(16807), %o1
wr %o1, %lo(16807), %y
- sethi %hi(__randseed), %g1
- ld [%g1 + %lo(__randseed)], %o0
+ sethi %hi(randseed), %g1
+ ld [%g1 + %lo(randseed)], %o0
andcc %g0, 0, %o2
mulscc %o2, %o0, %o2
mulscc %o2, %o0, %o2
@@ -4842,13 +5601,13 @@ ENTRY(random)
bneg 1f
sethi %hi(0x7fffffff), %o1
retl
- st %o0, [%g1 + %lo(__randseed)]
+ st %o0, [%g1 + %lo(randseed)]
1:
or %o1, %lo(0x7fffffff), %o1
add %o0, 1, %o0
and %o1, %o0, %o0
retl
- st %o0, [%g1 + %lo(__randseed)]
+ st %o0, [%g1 + %lo(randseed)]
/*
* void lo_microtime(struct timeval *tv)
@@ -4872,37 +5631,86 @@ ENTRY(microtime)
#endif
sethi %hi(_time), %g2
sethi %hi(TIMERREG_VA), %g3
+
+/* blech, sun4m has microsecond counter at a different location */
+#if (defined(SUN4) || defined(SUN4C)) && !defined(SUN4M)
+#define r_aardvark %lo(TIMERREG_VA)
+#elif !(defined(SUN4) || defined(SUN4C)) && defined(SUN4M)
+#define r_aardvark %lo(TIMERREG_VA) + 4
+#else
+ sethi %hi(_cputyp), %g4
+ ld [%g4 + %lo(_cputyp)], %g4
+ or %g3, %lo(TIMERREG_VA), %g3
+ cmp %g4, CPU_SUN4M
+ be,a 1f
+ add %g3, 4, %g3
1:
+#define r_aardvark 0
+#endif
+2:
ldd [%g2+%lo(_time)], %o2 ! time.tv_sec & time.tv_usec
- ld [%g3+%lo(TIMERREG_VA)], %o4 ! usec counter
+ ld [%g3+r_aardvark], %o4 ! usec counter
ldd [%g2+%lo(_time)], %g4 ! see if time values changed
cmp %g4, %o2
- bne 1b ! if time.tv_sec changed
+ bne 2b ! if time.tv_sec changed
cmp %g5, %o3
- bne 1b ! if time.tv_usec changed
+ bne 2b ! if time.tv_usec changed
tst %o4
- bpos 2f ! reached limit?
+ bpos 3f ! reached limit?
srl %o4, TMR_SHIFT, %o4 ! convert counter to usec
sethi %hi(_tick), %g4 ! bump usec by 1 tick
ld [%g4+%lo(_tick)], %o1
set TMR_MASK, %g5
add %o1, %o3, %o3
and %o4, %g5, %o4
-2:
+3:
add %o4, %o3, %o3
set 1000000, %g5 ! normalize usec value
cmp %o3, %g5
- bl,a 3f
+ bl,a 4f
st %o2, [%o0] ! (should be able to std here)
add %o2, 1, %o2 ! overflow
sub %o3, %g5, %o3
st %o2, [%o0] ! (should be able to std here)
-3:
+4:
retl
st %o3, [%o0+4]
-#if defined(KGDB) || defined(DDB)
+/*
+ * delay function
+ *
+ * void delay(N) -- delay N microseconds
+ *
+ * Register usage: %o0 = "N" number of usecs to go (counts down to zero)
+ * %o1 = "timerblurb" (stays constant)
+ * %o2 = counter for 1 usec (counts down from %o1 to zero)
+ *
+ */
+
+ENTRY(delay) ! %o0 = n
+ subcc %o0, %g0, %g0
+ be 2f
+
+ sethi %hi(_timerblurb), %o1
+ ld [%o1 + %lo(_timerblurb)], %o1 ! %o1 = timerblurb
+
+ addcc %o1, %g0, %o2 ! %o2 = cntr (start @ %o1), clear CCs
+ ! first time through only
+
+ ! delay 1 usec
+1: bne 1b ! come back here if not done
+ subcc %o2, 1, %o2 ! %o2 = %o2 - 1 [delay slot]
+
+ subcc %o0, 1, %o0 ! %o0 = %o0 - 1
+ bne 1b ! done yet?
+ addcc %o1, %g0, %o2 ! reinit %o2 and CCs [delay slot]
+ ! harmless if not branching
+2:
+ retl ! return
+ nop ! [delay slot]
+
+#if defined(KGDB) || defined(DDB) || defined(DIAGNOSTIC)
/*
* Write all windows (user or otherwise), except the current one.
*
@@ -4939,7 +5747,7 @@ ENTRY(setjmp)
Lpanic_ljmp:
.asciz "longjmp botch"
- ALIGN
+ _ALIGN
ENTRY(longjmp)
addcc %o1, %g0, %g6 ! compute v ? v : 1 in a global register
@@ -4968,7 +5776,7 @@ Llongjmpbotch:
bge,a 3f
mov %o2, %sp ! it is OK, put it in place
b,a Llongjmpbotch
-3:
+3:
jmp %o3 + 8 ! success, return %g6
mov %g6, %o0
@@ -5005,7 +5813,7 @@ _intrnames:
.asciz "lev13"
.asciz "prof"
_eintrnames:
- ALIGN
+ _ALIGN
_intrcnt:
.skip 4*15
_eintrcnt:
diff --git a/sys/arch/sparc/sparc/locore2.c b/sys/arch/sparc/sparc/locore2.c
index 614dc6d707b..c44c604b200 100644
--- a/sys/arch/sparc/sparc/locore2.c
+++ b/sys/arch/sparc/sparc/locore2.c
@@ -1,4 +1,4 @@
-/* $NetBSD: locore2.c,v 1.5 1994/11/20 20:54:28 deraadt Exp $ */
+/* $NetBSD: locore2.c,v 1.6 1996/03/14 21:09:15 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -50,9 +50,12 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
+#include <machine/cpu.h>
+
int whichqs;
/*
@@ -81,6 +84,7 @@ setrunqueue(p)
* Remove process p from its run queue, which should be the one
* indicated by its priority. Calls should be made at splstatclock().
*/
+void
remrq(p)
register struct proc *p;
{
diff --git a/sys/arch/sparc/sparc/machdep.c b/sys/arch/sparc/sparc/machdep.c
index 9529ea31b0e..03dc4fc1a3b 100644
--- a/sys/arch/sparc/sparc/machdep.c
+++ b/sys/arch/sparc/sparc/machdep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.45 1995/05/16 21:16:37 mycroft Exp $ */
+/* $NetBSD: machdep.c,v 1.64 1996/05/19 04:12:56 mrg Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -75,13 +75,16 @@
#include <sys/exec.h>
#include <sys/sysctl.h>
-#include <machine/bsd_openprom.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+
#include <machine/autoconf.h>
#include <machine/frame.h>
#include <machine/cpu.h>
-
-#include <vm/vm_kern.h>
-#include <vm/vm_page.h>
+#include <machine/pmap.h>
+#include <machine/oldmon.h>
+#include <machine/bsd_openprom.h>
#include <sparc/sparc/asm.h>
#include <sparc/sparc/cache.h>
@@ -109,7 +112,7 @@ int physmem;
extern struct msgbuf msgbuf;
struct msgbuf *msgbufp = &msgbuf;
-int msgbufmapped = 0; /* maps late; so that printf works early */
+int msgbufmapped = 0; /* not mapped until pmap_bootstrap */
/*
* safepri is a safe priority for sleep to set for a spin-wait
@@ -125,7 +128,9 @@ vm_offset_t dvma_base, dvma_end;
struct map *dvmamap;
static int ndvmamap; /* # of entries in dvmamap */
-caddr_t allocsys();
+caddr_t allocsys __P((caddr_t));
+void dumpsys __P((void));
+void stackdump __P((void));
/*
* Machine-dependent startup code
@@ -166,8 +171,10 @@ cpu_startup()
* and then give everything true virtual addresses.
*/
sz = (int)allocsys((caddr_t)0);
+
if ((v = (caddr_t)kmem_alloc(kernel_map, round_page(sz))) == 0)
panic("startup: no room for tables");
+
if (allocsys(v) - v != sz)
panic("startup: table size inconsistency");
@@ -176,12 +183,15 @@ cpu_startup()
* in that they usually occupy more virtual memory than physical.
*/
size = MAXBSIZE * nbuf;
+
buffer_map = kmem_suballoc(kernel_map, (vm_offset_t *)&buffers,
&maxaddr, size, TRUE);
+
minaddr = (vm_offset_t)buffers;
if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0,
&minaddr, size, FALSE) != KERN_SUCCESS)
panic("startup: cannot allocate buffers");
+
base = bufpages / nbuf;
residual = bufpages % nbuf;
if (base >= MAXBSIZE) {
@@ -189,6 +199,7 @@ cpu_startup()
base = MAXBSIZE;
residual = 0;
}
+
for (i = 0; i < nbuf; i++) {
vm_size_t curbufsize;
vm_offset_t curbuf;
@@ -211,23 +222,15 @@ cpu_startup()
* limits the number of processes exec'ing at any time.
*/
exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
- 16*NCARGS, TRUE);
+ 16*NCARGS, TRUE);
/*
* Allocate a map for physio. Others use a submap of the kernel
* map, but we want one completely separate, even though it uses
* the same pmap.
*/
-#if defined(SUN4M) && 0
- if (cputyp == CPU_SUN4M) {
- dvma_base = DVMA4M_BASE;
- dvma_end = (vm_offset_t)(0 - NBPG); /* want 4BG, but cant express */
- } else
-#endif
- {
- dvma_base = DVMA_BASE;
- dvma_end = DVMA_END;
- }
+ dvma_base = CPU_ISSUN4M ? DVMA4M_BASE : DVMA_BASE;
+ dvma_end = CPU_ISSUN4M ? DVMA4M_END : DVMA_END;
phys_map = vm_map_create(pmap_kernel(), dvma_base, dvma_end, 1);
if (phys_map == NULL)
panic("unable to create DVMA map");
@@ -261,7 +264,7 @@ cpu_startup()
#ifdef DEBUG
pmapdebug = opmapdebug;
#endif
- printf("avail mem = %d\n", ptoa(cnt.v_free_count));
+ printf("avail mem = %ld\n", ptoa(cnt.v_free_count));
printf("using %d buffers containing %d bytes of memory\n",
nbuf, bufpages * CLBYTES);
@@ -280,7 +283,7 @@ cpu_startup()
*/
pmap_enter(pmap_kernel(), MSGBUF_VA, 0x0, VM_PROT_READ|VM_PROT_WRITE, 1);
- if (cputyp == CPU_SUN4)
+ if (CPU_ISSUN4)
msgbufp = (struct msgbuf *)(MSGBUF_VA + 4096);
else
msgbufp = (struct msgbuf *)MSGBUF_VA;
@@ -320,7 +323,7 @@ allocsys(v)
valloc(msghdrs, struct msg, msginfo.msgtql);
valloc(msqids, struct msqid_ds, msginfo.msgmni);
#endif
-
+
/*
* Determine how many buffers to allocate (enough to
* hold 5% of total physical memory, but at least 16).
@@ -386,9 +389,9 @@ setregs(p, pack, stack, retval)
}
bzero((caddr_t)tf, sizeof *tf);
tf->tf_psr = psr;
- tf->tf_pc = pack->ep_entry & ~3;
+ tf->tf_npc = pack->ep_entry & ~3;
tf->tf_global[1] = (int)PS_STRINGS;
- tf->tf_global[2] = tf->tf_global[7] = tf->tf_npc = tf->tf_pc+4;
+ tf->tf_global[2] = tf->tf_global[7] = tf->tf_npc;
stack -= sizeof(struct rwindow);
tf->tf_out[6] = stack;
retval[1] = 0;
@@ -417,6 +420,7 @@ struct sigframe {
/*
* machine dependent system variables.
*/
+int
cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
@@ -474,10 +478,10 @@ sendsig(catcher, sig, mask, code)
#ifdef DEBUG
if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
- printf("sendsig: %s[%d] sig %d newusp %x scp %x\n",
+ printf("sendsig: %s[%d] sig %d newusp %p scp %p\n",
p->p_comm, p->p_pid, sig, fp, &fp->sf_sc);
#endif
- /*
+ /*
* Now set up the signal frame. We build it in kernel space
* and then copy it out. We probably ought to just build it
* directly in user space....
@@ -527,7 +531,7 @@ sendsig(catcher, sig, mask, code)
}
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
- printf("sendsig: %s[%d] sig %d scp %x\n",
+ printf("sendsig: %s[%d] sig %d scp %p\n",
p->p_comm, p->p_pid, sig, &fp->sf_sc);
#endif
/*
@@ -580,7 +584,7 @@ sys_sigreturn(p, v, retval)
sigexit(p, SIGILL);
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
- printf("sigreturn: %s[%d], sigcntxp %x\n",
+ printf("sigreturn: %s[%d], sigcntxp %p\n",
p->p_comm, p->p_pid, SCARG(uap, sigcntxp));
#endif
scp = SCARG(uap, sigcntxp);
@@ -617,9 +621,12 @@ boot(howto)
{
int i;
static char str[4]; /* room for "-sd\0" */
- extern volatile void romhalt(void);
- extern volatile void romboot(char *);
- extern struct promvec *promvec;
+ extern int cold;
+
+ if (cold) {
+ printf("halted\n\n");
+ romhalt();
+ }
fb_unblank();
boothowto = howto;
@@ -641,17 +648,15 @@ boot(howto)
resettodr();
}
(void) splhigh(); /* ??? */
-
if (howto & RB_HALT) {
+ doshutdownhooks();
printf("halted\n\n");
-#if defined(SUN4M) || defined(SUN4C)
- if (cputyp==CPU_SUN4M || cputyp==CPU_SUN4C)
- *promvec->pv_synchook = NULL;
-#endif
romhalt();
}
if (howto & RB_DUMP)
dumpsys();
+
+ doshutdownhooks();
printf("rebooting\n\n");
i = 1;
if (howto & RB_SINGLE)
@@ -663,10 +668,6 @@ boot(howto)
str[i] = 0;
} else
str[0] = 0;
-#if defined(SUN4M) || defined(SUN4C)
- if (cputyp==CPU_SUN4M || cputyp==CPU_SUN4C)
- *promvec->pv_synchook = NULL;
-#endif
romboot(str);
/*NOTREACHED*/
}
@@ -675,6 +676,7 @@ u_long dumpmag = 0x8fca0101; /* magic number for savecore */
int dumpsize = 0; /* also for savecore */
long dumplo = 0;
+void
dumpconf()
{
register int nblks, nmem;
@@ -729,6 +731,7 @@ reserve_dumppages(p)
/*
* Write a crash dump.
*/
+void
dumpsys()
{
register int psize;
@@ -755,7 +758,7 @@ dumpsys()
dumpconf();
if (dumplo < 0)
return;
- printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
+ printf("\ndumping to dev %x, offset %ld\n", dumpdev, dumplo);
psize = (*bdevsw[major(dumpdev)].d_psize)(dumpdev);
printf("dump ");
@@ -767,10 +770,17 @@ dumpsys()
dump = bdevsw[major(dumpdev)].d_dump;
for (mp = pmemarr, nmem = npmemarr; --nmem >= 0; mp++) {
- register unsigned i, n;
+ register unsigned i = 0, n;
register maddr = mp->addr;
- for (i = 0; i < mp->len; i += n) {
+ if (maddr == 0) {
+ /* Skip first page at physical address 0 */
+ maddr += NBPG;
+ i += NBPG;
+ blkno += btodb(NBPG);
+ }
+
+ for (; i < mp->len; i += n) {
n = mp->len - i;
if (n > BYTES_PER_DUMP)
n = BYTES_PER_DUMP;
@@ -825,15 +835,16 @@ dumpsys()
* get the fp and dump the stack as best we can. don't leave the
* current stack page
*/
+void
stackdump()
{
- struct frame *fp = (struct frame *)getfp(), *sfp;
+ struct frame *fp = getfp(), *sfp;
sfp = fp;
- printf("Frame pointer is at 0x%x\n", fp);
+ printf("Frame pointer is at %p\n", fp);
printf("Call traceback:\n");
while (fp && ((u_long)fp >> PGSHIFT) == ((u_long)sfp >> PGSHIFT)) {
- printf(" pc = %x args = (%x, %x, %x, %x, %x, %x) fp = %x\n",
+ printf(" pc = %x args = (%x, %x, %x, %x, %x, %x, %x) fp = %p\n",
fp->fr_pc, fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2],
fp->fr_arg[3], fp->fr_arg[4], fp->fr_arg[5], fp->fr_arg[6],
fp->fr_fp);
@@ -846,28 +857,28 @@ int bt2pmt[] = {
PMAP_OBIO,
PMAP_VME16,
PMAP_VME32,
- PMAP_OBIO,
PMAP_OBIO
};
/*
* Map an I/O device given physical address and size in bytes, e.g.,
*
- * mydev = (struct mydev *)mapdev(myioaddr, 0, 0,
- * sizeof(struct mydev), pmtype);
- *
+ * mydev = (struct mydev *)mapdev(myioaddr, 0,
+ * 0, sizeof(struct mydev), pmtype);
+ *
* See also machine/autoconf.h.
*/
void *
-mapdev(rr, virt, offset, size, bustype)
- register struct rom_reg *rr;
+mapdev(phys, virt, offset, size, bustype)
+ register struct rom_reg *phys;
register int offset, virt, size;
register int bustype;
{
- register vm_offset_t v, pa;
+ register vm_offset_t v;
+ register vm_offset_t pa;
register void *ret;
static vm_offset_t iobase;
- int pmtype;
+ unsigned int pmtype;
if (iobase == NULL)
iobase = IODEV_BASE;
@@ -883,19 +894,17 @@ mapdev(rr, virt, offset, size, bustype)
if (iobase > IODEV_END) /* unlikely */
panic("mapiodev");
}
- ret = (void *)(v | (((u_long)rr->rr_paddr + offset) & PGOFSET));
+ ret = (void *)(v | (((u_long)phys->rr_paddr + offset) & PGOFSET));
/* note: preserve page offset */
- pa = trunc_page(rr->rr_paddr + offset);
-#ifdef notyet
- pmtype = (cputyp == CPU_SUN4M)
- ? (rr->rr_iospace << PMAP_SHFT4M)
+
+ pa = trunc_page(phys->rr_paddr + offset);
+ pmtype = (CPU_ISSUN4M)
+ ? (phys->rr_iospace << PMAP_SHFT4M)
: bt2pmt[bustype];
-#else
- pmtype = bt2pmt[bustype];
-#endif
+
do {
pmap_enter(pmap_kernel(), v, pa | pmtype | PMAP_NC,
- VM_PROT_READ | VM_PROT_WRITE, 1);
+ VM_PROT_READ | VM_PROT_WRITE, 1);
v += PAGE_SIZE;
pa += PAGE_SIZE;
} while ((size -= PAGE_SIZE) > 0);
@@ -923,12 +932,10 @@ oldmon_w_trace(va)
u_long va;
{
u_long stop;
- extern u_long *par_err_reg;
- volatile u_long *memreg = (u_long *) par_err_reg;
struct frame *fp;
if (curproc)
- printf("curproc = %x, pid %d\n", curproc, curproc->p_pid);
+ printf("curproc = %p, pid %d\n", curproc, curproc->p_pid);
else
printf("no curproc\n");
@@ -939,19 +946,19 @@ oldmon_w_trace(va)
#define round_up(x) (( (x) + (NBPG-1) ) & (~(NBPG-1)) )
- printf("\nstack trace with sp = %x\n", va);
+ printf("\nstack trace with sp = %lx\n", va);
stop = round_up(va);
- printf("stop at %x\n", stop);
+ printf("stop at %lx\n", stop);
fp = (struct frame *) va;
while (round_up((u_long) fp) == stop) {
- printf(" %x(%x, %x, %x, %x, %x, %x) fp %x\n", fp->fr_pc,
- fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2], fp->fr_arg[3],
+ printf(" %x(%x, %x, %x, %x, %x, %x, %x) fp %p\n", fp->fr_pc,
+ fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2], fp->fr_arg[3],
fp->fr_arg[4], fp->fr_arg[5], fp->fr_arg[6], fp->fr_fp);
fp = fp->fr_fp;
if (fp == NULL)
break;
}
- printf("end of stack trace\n");
+ printf("end of stack trace\n");
}
void
@@ -968,7 +975,7 @@ oldmon_w_cmd(va, ar)
printf("w: case 4\n");
break;
default:
- printf("w: unknown case %d\n", va);
+ printf("w: unknown case %ld\n", va);
break;
}
break;
@@ -981,15 +988,21 @@ oldmon_w_cmd(va, ar)
}
#endif /* SUN4 */
-u_int
+int
ldcontrolb(addr)
caddr_t addr;
{
struct pcb *xpcb;
extern struct user *proc0paddr;
- u_long saveonfault, res;
+ u_long saveonfault;
+ int res;
int s;
+ if (CPU_ISSUN4M) {
+ printf("warning: ldcontrolb called in sun4m\n");
+ return 0;
+ }
+
s = splhigh();
if (curproc == NULL)
xpcb = (struct pcb *)proc0paddr;
@@ -997,7 +1010,7 @@ caddr_t addr;
xpcb = &curproc->p_addr->u_pcb;
saveonfault = (u_long)xpcb->pcb_onfault;
- res = xldcontrolb(addr, xpcb);
+ res = xldcontrolb(addr, xpcb);
xpcb->pcb_onfault = (caddr_t)saveonfault;
splx(s);
diff --git a/sys/arch/sparc/sparc/mem.c b/sys/arch/sparc/sparc/mem.c
index bef3cf01e07..ff531dca56f 100644
--- a/sys/arch/sparc/sparc/mem.c
+++ b/sys/arch/sparc/sparc/mem.c
@@ -1,4 +1,4 @@
-/* $NetBSD: mem.c,v 1.11 1995/05/29 23:57:16 pk Exp $ */
+/* $NetBSD: mem.c,v 1.13 1996/03/30 21:12:16 christos Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@@ -45,14 +45,16 @@
*/
#include <sys/param.h>
-#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
#include <sparc/sparc/vaddrs.h>
#include <machine/eeprom.h>
+#include <machine/conf.h>
#include <vm/vm.h>
@@ -62,9 +64,10 @@ caddr_t zeropage;
/*ARGSUSED*/
int
-mmopen(dev, flag, mode)
+mmopen(dev, flag, mode, p)
dev_t dev;
int flag, mode;
+ struct proc *p;
{
return (0);
@@ -72,9 +75,10 @@ mmopen(dev, flag, mode)
/*ARGSUSED*/
int
-mmclose(dev, flag, mode)
+mmclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
+ struct proc *p;
{
return (0);
diff --git a/sys/arch/sparc/sparc/memreg.c b/sys/arch/sparc/sparc/memreg.c
index 8c2a3e95b6a..a2b5bf67ddc 100644
--- a/sys/arch/sparc/sparc/memreg.c
+++ b/sys/arch/sparc/sparc/memreg.c
@@ -1,4 +1,4 @@
-/* $NetBSD: memreg.c,v 1.7 1995/02/01 12:37:53 pk Exp $ */
+/* $NetBSD: memreg.c,v 1.13 1996/03/31 22:52:08 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -12,6 +12,7 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
+ * This product includes software developed by Harvard University.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,6 +26,7 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
+ * This product includes software developed by Harvard University.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -45,6 +47,7 @@
*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/device.h>
#include <machine/autoconf.h>
@@ -52,11 +55,26 @@
#include <sparc/sparc/memreg.h>
#include <sparc/sparc/vaddrs.h>
+#include <sparc/sparc/asm.h>
+
+#include <machine/reg.h> /* for trapframe */
+#include <machine/trap.h> /* for trap types */
static int memregmatch __P((struct device *, void *, void *));
static void memregattach __P((struct device *, struct device *, void *));
-struct cfdriver memregcd =
- { 0, "memreg", memregmatch, memregattach, DV_DULL, sizeof(struct device) };
+
+struct cfattach memreg_ca = {
+ sizeof(struct device), memregmatch, memregattach
+};
+
+struct cfdriver memreg_cd = {
+ 0, "memreg", DV_DULL
+};
+
+void memerr __P((int, u_int, u_int, u_int, u_int));
+#if defined(SUN4M)
+static void hardmemerr4m __P((int, u_int, u_int));
+#endif
/*
* The OPENPROM calls this "memory-error".
@@ -69,7 +87,7 @@ memregmatch(parent, vcf, aux)
struct cfdata *cf = vcf;
register struct confargs *ca = aux;
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
if (ca->ca_bustype == BUS_OBIO)
return (strcmp(cf->cf_driver->cd_name,
ca->ca_ra.ra_name) == 0);
@@ -87,14 +105,14 @@ memregattach(parent, self, aux)
register struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
if (par_err_reg == NULL)
panic("memregattach");
ra->ra_vaddr = (caddr_t)par_err_reg;
} else {
- par_err_reg = ra->ra_vaddr ? (volatile int *)ra->ra_vaddr :
- (volatile int *)mapiodev(ra->ra_reg, 0, sizeof(int),
- ca->ca_bustype);
+ par_err_reg = ra->ra_vaddr ? (volatile u_int *)ra->ra_vaddr :
+ (volatile u_int *)mapiodev(ra->ra_reg, 0, sizeof(int),
+ ca->ca_bustype);
}
printf("\n");
}
@@ -106,14 +124,16 @@ memregattach(parent, self, aux)
* and take the page out of the page pool, but for now...
*/
-extern void sun4c_sun4_storebuf_flush(void);
-
void
memerr(issync, ser, sva, aer, ava)
- int issync, ser, sva, aer, ava;
+ int issync;
+ u_int ser, sva, aer, ava;
{
- sun4c_sun4_storebuf_flush(); /* prevent loops... */
- if (cputyp == CPU_SUN4) {
+
+ /* XXX Ugh! Clean up this switch and all the ifdefs! */
+ switch (cputyp) {
+#if defined(SUN4)
+ case CPU_SUN4:
if (par_err_reg) {
printf("mem err: ser=%b sva=%x\n", ser, SER_BITS, sva);
printf("parity error register = %b\n",
@@ -122,17 +142,155 @@ memerr(issync, ser, sva, aer, ava)
printf("mem err: ser=? sva=?\n");
printf("parity error register not mapped yet!\n"); /* XXX */
}
- } else {
+#ifdef DEBUG
+ callrom();
+#else
+ panic("memory error"); /* XXX */
+#endif
+ break;
+#endif /* Sun4 */
+
+#if defined(SUN4C)
+ case CPU_SUN4C:
printf("%ssync mem err: ser=%b sva=%x aer=%b ava=%x\n",
- issync ? "" : "a", ser, SER_BITS, sva, aer & 0xff,
- AER_BITS, ava);
+ issync ? "" : "a", ser, SER_BITS,
+ sva, aer & 0xff, AER_BITS, ava);
if (par_err_reg)
printf("parity error register = %b\n",
*par_err_reg, PER_BITS);
- }
#ifdef DEBUG
- callrom();
+ callrom();
#else
- panic("memory error"); /* XXX */
+ panic("memory error"); /* XXX */
#endif
+ break;
+#endif /* Sun4C */
+
+#if defined(SUN4M)
+ case CPU_SUN4M:
+ hardmemerr4m(2, ser, sva);
+ break;
+#endif /* Sun4M */
+ default:
+ break;
+ }
+}
+
+
+#if defined(SUN4M)
+/*
+ * hardmemerr4m: called upon fatal memory error. Print a message and panic.
+ * Note that issync is not really an indicator of whether or not the error
+ * was synchronous; if it is set, it means that the fsr/faddr pair correspond
+ * to the MMU's fault status register; if clear, they correspond to the
+ * HyperSPARC asynchronous error register. If issync==2, then both decodings
+ * of the error register are printed.
+ */
+
+static void
+hardmemerr4m(issync, fsr, faddr)
+ int issync;
+ u_int fsr, faddr;
+{
+ switch (issync) {
+ case 1:
+ if ((fsr & SFSR_FT) == SFSR_FT_NONE)
+ return;
+ panic("mem err: sfsr=%b sfaddr=%x", fsr, SFSR_BITS, faddr);
+ break;
+ case 0:
+ if (!(fsr & AFSR_AFO))
+ return;
+ panic("async (HS) mem err: afsr=%b afaddr=%x physaddr=%x%x",
+ fsr, AFSR_BITS, faddr,
+ (fsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, faddr);
+ break;
+ default: /* unknown; print both decodings*/
+ panic("Unknown mem err: if sync, fsr=%b fva=%x; if async, fsr"
+ "=%b fa=%x pa=%x%x", fsr, SFSR_BITS, faddr, fsr,
+ AFSR_BITS, faddr, (fsr & AFSR_AFA) >> AFSR_AFA_RSHIFT,
+ faddr);
+ break;
+ }
+}
+
+/*
+ * Memerr4m: handle a non-trivial memory fault. These include HyperSPARC
+ * asynchronous faults, SuperSPARC store-buffer copyback failures, and
+ * data faults without a valid faulting VA. We try to retry the operation
+ * once, and then fail if we get called again.
+ */
+
+static int addrold = (int) 0xdeadbeef; /* We pick an unlikely address */
+static int addroldtop = (int) 0xdeadbeef;
+static int oldtype = -1;
+
+void
+memerr4m(type, sfsr, sfva, afsr, afva, tf)
+ register unsigned type;
+ register u_int sfsr;
+ register u_int sfva;
+ register u_int afsr;
+ register u_int afva;
+ register struct trapframe *tf;
+{
+ if ((afsr & AFSR_AFO) != 0) { /* HS async fault! */
+
+ printf("HyperSPARC async cache memory failure at phys 0x%x%x. "
+ "Ignoring.\n", (afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT,
+ afva);
+
+ if (afva == addrold && (afsr & AFSR_AFA) == addroldtop)
+ hardmemerr4m(0, afsr, afva);
+ /* NOTREACHED */
+
+ oldtype = -1;
+ addrold = afva;
+ addroldtop = afsr & AFSR_AFA;
+
+ } else if (type == T_STOREBUFFAULT) {
+ /* We try to reenable the store buffers to force a retry */
+
+ printf("store buffer copy-back failure at 0x%x. Retrying...\n",
+ sfva);
+
+ if (oldtype == T_STOREBUFFAULT || addrold == sfva)
+ hardmemerr4m(1, sfsr, sfva);
+ /* NOTREACHED */
+
+ oldtype = T_STOREBUFFAULT;
+ addrold = sfva;
+
+ sta(SRMMU_PCR, ASI_SRMMU, lda(SRMMU_PCR, ASI_SRMMU) |
+ SRMMU_PCR_SB); /* reenable store buffer */
+
+ } else if (type == T_DATAFAULT && !(sfsr & SFSR_FAV)) { /* bizarre */
+ /* XXX: Should handle better. See SuperSPARC manual pg. 9-35 */
+
+ printf("warning: got data fault with no faulting address."
+ " Ignoring.\n");
+
+ if (oldtype == T_DATAFAULT)
+ hardmemerr4m(1, sfsr, sfva);
+ /* NOTREACHED */
+
+ oldtype = T_DATAFAULT;
+ } else if (type == 0) { /* NMI */
+ printf("ERROR: got NMI with sfsr=0x%b, sfva=0x%x, afsr=0x%b, "
+ "afaddr=0x%x. Retrying...\n",
+ sfsr,SFSR_BITS,sfva,afsr, AFSR_BITS,afva);
+ if (oldtype == 0 || addrold == sfva)
+ hardmemerr4m(1, sfsr, sfva); /* XXX: async? */
+ /* NOTREACHED */
+
+ oldtype = 0;
+ addrold = sfva;
+ } else /* something we don't know about?!? */ {
+ panic("memerr4m: unknown fatal memory error. type=%d, sfsr=%b,"
+ " sfva=%x, afsr=%b, afaddr=%x",
+ type, sfsr, SFSR_BITS, sfva, afsr, AFSR_BITS, afva);
+ }
+
+ return;
}
+#endif /* 4m */
diff --git a/sys/arch/sparc/sparc/memreg.h b/sys/arch/sparc/sparc/memreg.h
index 428a93f53c6..be25a8f76c0 100644
--- a/sys/arch/sparc/sparc/memreg.h
+++ b/sys/arch/sparc/sparc/memreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: memreg.h,v 1.2 1994/11/20 20:54:33 deraadt Exp $ */
+/* $NetBSD: memreg.h,v 1.4 1996/03/31 22:52:13 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -48,7 +48,7 @@
* Sun-4c memory error register.
* The register is a single word.
*/
-volatile int *par_err_reg; /* virtual address; NULL if not yet mapped */
+volatile u_int *par_err_reg; /* virtual address; NULL if not yet mapped */
/*
* Bits in parity error register.
@@ -64,3 +64,11 @@ volatile int *par_err_reg; /* virtual address; NULL if not yet mapped */
#define PER_BYTE3 0x01 /* error occurred in byte 3 (bits 7..0) */
#define PER_BITS "\20\10ERR\7MULTI\6TEST\5ENABLE\4BYTE0\3BYTE1\2BYTE2\1BYTE3"
+
+
+
+/*
+ * sun4m ...
+ */
+struct trapframe;
+void memerr4m __P((unsigned, u_int, u_int, u_int, u_int, struct trapframe *));
diff --git a/sys/arch/sparc/sparc/openprom.c b/sys/arch/sparc/sparc/openprom.c
index b0e61849690..15c9ac1293f 100644
--- a/sys/arch/sparc/sparc/openprom.c
+++ b/sys/arch/sparc/sparc/openprom.c
@@ -1,4 +1,4 @@
-/* $NetBSD: openprom.c,v 1.5 1995/01/10 16:47:03 pk Exp $ */
+/* $NetBSD: openprom.c,v 1.8 1996/03/31 23:45:34 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -50,32 +50,39 @@
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
+#include <sys/conf.h>
#include <machine/bsd_openprom.h>
#include <machine/openpromio.h>
+#include <machine/autoconf.h>
+#include <machine/conf.h>
static int lastnode; /* speed hack */
extern int optionsnode; /* node ID of ROM's options */
-extern int findroot(); /* returns node ID of top node */
extern struct promvec *promvec;
+static int openpromcheckid __P((int, int));
+static int openpromgetstr __P((int, char *, char **));
+
int
-openpromopen(dev, flags, mode)
+openpromopen(dev, flags, mode, p)
dev_t dev;
int flags, mode;
+ struct proc *p;
{
#if defined(SUN4)
if (cputyp==CPU_SUN4)
return (ENODEV);
-#endif
+#endif
return (0);
}
int
-openpromclose(dev, flags, mode)
+openpromclose(dev, flags, mode, p)
dev_t dev;
int flags, mode;
+ struct proc *p;
{
return (0);
diff --git a/sys/arch/sparc/sparc/pmap.c b/sys/arch/sparc/sparc/pmap.c
index be83605c3ab..226bf7f6715 100644
--- a/sys/arch/sparc/sparc/pmap.c
+++ b/sys/arch/sparc/sparc/pmap.c
@@ -1,6 +1,8 @@
-/* $NetBSD: pmap.c,v 1.47 1995/07/05 18:52:32 pk Exp $ */
+/* $NetBSD: pmap.c,v 1.60.4.1 1996/06/12 20:36:30 pk Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -10,12 +12,14 @@
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
+ *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
@@ -23,8 +27,10 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by Aaron Brown and
+ * Harvard University.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -42,6 +48,7 @@
* SUCH DAMAGE.
*
* @(#)pmap.c 8.4 (Berkeley) 2/5/94
+ *
*/
/*
@@ -73,10 +80,9 @@
#ifdef DEBUG
#define PTE_BITS "\20\40V\37W\36S\35NC\33IO\32U\31M"
+#define PTE_BITS4M "\20\10C\7M\6R\5ACC3\4ACC2\3ACC1\2TYP2\1TYP1"
#endif
-extern struct promvec *promvec;
-
/*
* The SPARCstation offers us the following challenges:
*
@@ -85,10 +91,11 @@ extern struct promvec *promvec;
* This is a write-through cache on the 4c and a write-back cache
* on others.
*
- * 2. An MMU that acts like a cache. There is not enough space
- * in the MMU to map everything all the time. Instead, we need
+ * 2. (4/4c only) An MMU that acts like a cache. There is not enough
+ * space in the MMU to map everything all the time. Instead, we need
* to load MMU with the `working set' of translations for each
- * process.
+ * process. The sun4m does not act like a cache; tables are maintained
+ * in physical memory.
*
* 3. Segmented virtual and physical spaces. The upper 12 bits of
* a virtual address (the virtual segment) index a segment table,
@@ -97,10 +104,11 @@ extern struct promvec *promvec;
* next 5 or 6 bits of the virtual address---select the particular
* `Page Map Entry' for the page. We call the latter a PTE and
* call each Page Map Entry Group a pmeg (for want of a better name).
+ * Note that the sun4m has an unsegmented 36-bit physical space.
*
* Since there are no valid bits in the segment table, the only way
* to have an invalid segment is to make one full pmeg of invalid PTEs.
- * We use the last one (since the ROM does as well).
+ * We use the last one (since the ROM does as well) (sun4/4c only)
*
* 4. Discontiguous physical pages. The Mach VM expects physical pages
* to be in one sequential lump.
@@ -134,10 +142,13 @@ struct pmap_stats {
#define PDB_CTX_STEAL 0x0800
#define PDB_MMUREG_ALLOC 0x1000
#define PDB_MMUREG_STEAL 0x2000
-int pmapdebug = 0x0;
+#define PDB_CACHESTUFF 0x4000
+int pmapdebug = 0;
#endif
+#if 0
#define splpmap() splimp()
+#endif
/*
* First and last managed physical addresses.
@@ -168,10 +179,15 @@ struct pvlist {
/*
* Flags in pv_flags. Note that PV_MOD must be 1 and PV_REF must be 2
* since they must line up with the bits in the hardware PTEs (see pte.h).
+ * Sun4M bits are different (reversed), and at a different location in the
+ * pte. Now why did they do that?
*/
#define PV_MOD 1 /* page modified */
#define PV_REF 2 /* page referenced */
#define PV_NC 4 /* page cannot be cached */
+#define PV_REF4M 1 /* page referenced on sun4m */
+#define PV_MOD4M 2 /* page modified on 4m (why reversed?!?) */
+#define PV_C4M 4 /* page _can_ be cached on 4m */
/*efine PV_ALLF 7 ** all of the above */
struct pvlist *pv_table; /* array of entries, one per physical page */
@@ -184,6 +200,9 @@ struct pvlist *pv_table; /* array of entries, one per physical page */
* it is in the MMU, however; that is true iff pm_segmap[VA_VSEG(va)]
* does not point to the invalid PMEG.
*
+ * In the older SPARC architectures (pre-4m), page tables are cached in the
+ * MMU. The following discussion applies to these architectures:
+ *
* If a virtual segment is valid and loaded, the correct PTEs appear
* in the MMU only. If it is valid and unloaded, the correct PTEs appear
* in the pm_pte[VA_VSEG(va)] only. However, some effort is made to keep
@@ -214,6 +233,17 @@ struct pvlist *pv_table; /* array of entries, one per physical page */
* or locked. The LRU list is for user processes; the locked list is
* for kernel entries; both are doubly linked queues headed by `mmuhd's.
* The free list is a simple list, headed by a free list pointer.
+ *
+ * In the sun4m architecture using the SPARC Reference MMU (SRMMU), three
+ * levels of page tables are maintained in physical memory. We use the same
+ * structures as with the 3-level old-style MMU (pm_regmap, pm_segmap,
+ * rg_segmap, sg_pte, etc) to maintain kernel-edible page tables; we also
+ * build a parallel set of physical tables that can be used by the MMU.
+ * (XXX: This seems redundant, but is it necessary for the unified kernel?)
+ *
+ * If a virtual segment is valid, its entries will be in both parallel lists.
+ * If it is not valid, then its entry in the kernel tables will be zero, and
+ * its entry in the MMU tables will either be nonexistent or zero as well.
*/
struct mmuentry {
TAILQ_ENTRY(mmuentry) me_list; /* usage list link */
@@ -235,9 +265,16 @@ int reginval; /* the invalid region number */
#endif
/*
+ * (sun4/4c)
* A context is simply a small number that dictates which set of 4096
* segment map entries the MMU uses. The Sun 4c has eight such sets.
* These are alloted in an `almost MRU' fashion.
+ * (sun4m)
+ * A context is simply a small number that indexes the context table, the
+ * root-level page table mapping 4G areas. Each entry in this table points
+ * to a 1st-level region table. A SPARC reference MMU will usually use 16
+ * such contexts, but some offer as many as 64k contexts; the theoretical
+ * maximum is 2^32 - 1, but this would create overlarge context tables.
*
* Each context is either free or attached to a pmap.
*
@@ -255,9 +292,12 @@ union ctxinfo *ctx_freelist; /* context free list */
int ctx_kick; /* allocation rover when none free */
int ctx_kickdir; /* ctx_kick roves both directions */
+char *ctxbusyvector; /* [4m] tells what contexts are busy */
+int *ctx_phys_tbl; /* [4m] SRMMU-edible context table */
+
caddr_t vpage[2]; /* two reserved MD virtual pages */
caddr_t vmmap; /* one reserved MI vpage for /dev/mem */
-caddr_t vdumppages; /* 32KB worth of reserved dump pages */
+caddr_t vdumppages; /* 32KB worth of reserved dump pages */
#ifdef MMU_3L
smeg_t tregion;
@@ -266,6 +306,17 @@ struct pmap kernel_pmap_store; /* the kernel's pmap */
struct regmap kernel_regmap_store[NKREG]; /* the kernel's regmap */
struct segmap kernel_segmap_store[NKREG*NSEGRG];/* the kernel's segmaps */
+#ifdef SUN4M
+u_int *kernel_regtable_store; /* 1k of storage to map the kernel */
+u_int *kernel_segtable_store; /* 2k of storage to map the kernel */
+u_int *kernel_pagtable_store; /* 128k of storage to map the kernel */
+
+u_int *kernel_iopte_table; /* 64k of storage for iommu */
+u_int kernel_iopte_table_pa;
+
+static int cant_cache_pagetables = 0; /* 1 if page tables are uncachable */
+#endif
+
#define MA_SIZE 32 /* size of memory descriptor arrays */
struct memarr pmemarr[MA_SIZE];/* physical memory regions */
int npmemarr; /* number of entries in pmemarr */
@@ -276,81 +327,351 @@ int cpmemarr; /* pmap_next_page() state */
next free physical page */
/*static*/ vm_offset_t virtual_avail; /* first free virtual page number */
/*static*/ vm_offset_t virtual_end; /* last free virtual page number */
+#ifdef SUN4M
+#if 0 /* not needed anymore */
+static void * pmap_bootstrap_malloc __P((unsigned long, int, int));
+
+caddr_t minipool_start;
+caddr_t minipool_current;
+#define MINIPOOL_SIZE 8192 /* number of bytes to reserve for early malloc */
+ /* (must be multiple of pagesize) */
+#endif
+#endif
int mmu_has_hole;
vm_offset_t prom_vstart; /* For /dev/kmem */
vm_offset_t prom_vend;
-#ifdef SUN4
+#if defined(SUN4)
/*
- * segfixmask: on some systems (4/110) "getsegmap()" returns a partly
- * invalid value. getsegmap returns a 16 bit value on the sun4, but
- * only the first 8 or so bits are valid (the rest are *supposed* to
- * be zero. on the 4/110 the bits that are supposed to be zero are
- * all one instead. e.g. KERNBASE is usually mapped by pmeg number zero.
- * on a 4/300 getsegmap(KERNBASE) == 0x0000, but
+ * [sun4]: segfixmask: on some systems (4/110) "getsegmap()" returns a
+ * partly invalid value. getsegmap returns a 16 bit value on the sun4,
+ * but only the first 8 or so bits are valid (the rest are *supposed* to
+ * be zero. On the 4/110 the bits that are supposed to be zero are
+ * all one instead. e.g. KERNBASE is usually mapped by pmeg number zero.
+ * On a 4/300 getsegmap(KERNBASE) == 0x0000, but
* on a 4/100 getsegmap(KERNBASE) == 0xff00
*
- * this confuses mmu_reservemon() and causes it to not reserve the PROM's
- * pmegs. then the PROM's pmegs get used during autoconfig and everything
+ * This confuses mmu_reservemon() and causes it to not reserve the PROM's
+ * pmegs. Then the PROM's pmegs get used during autoconfig and everything
* falls apart! (not very fun to debug, BTW.)
*
* solution: mask the invalid bits in the getsetmap macro.
*/
static u_long segfixmask = 0xffffffff; /* all bits valid to start */
+#else
+#define segfixmask 0xffffffff /* It's in getsegmap's scope */
#endif
/*
* pseudo-functions for mnemonic value
- * NB: setsegmap should be stba for 4c, but stha works and makes the
- * code right for the Sun-4 as well.
*/
-#define getcontext() lduba(AC_CONTEXT, ASI_CONTROL)
-#define setcontext(c) stba(AC_CONTEXT, ASI_CONTROL, c)
-#if defined(SUN4) && !defined(SUN4C)
-#define getsegmap(va) (lduha(va, ASI_SEGMAP) & segfixmask)
-#define setsegmap(va, pmeg) stha(va, ASI_SEGMAP, pmeg)
+#define getcontext() (CPU_ISSUN4M \
+ ? lda(SRMMU_CXR, ASI_SRMMU) \
+ : lduba(AC_CONTEXT, ASI_CONTROL))
+#define setcontext(c) (CPU_ISSUN4M \
+ ? sta(SRMMU_CXR, ASI_SRMMU, c) \
+ : stba(AC_CONTEXT, ASI_CONTROL, c))
+
+#define getsegmap(va) (CPU_ISSUN4C \
+ ? lduba(va, ASI_SEGMAP) \
+ : (lduha(va, ASI_SEGMAP) & segfixmask))
+#define setsegmap(va, pmeg) (CPU_ISSUN4C \
+ ? stba(va, ASI_SEGMAP, pmeg) \
+ : stha(va, ASI_SEGMAP, pmeg))
+
+/* 3-level sun4 MMU only: */
+#define getregmap(va) ((unsigned)lduha((va)+2, ASI_REGMAP) >> 8)
+#define setregmap(va, smeg) stha((va)+2, ASI_REGMAP, (smeg << 8))
+
+#if defined(SUN4M)
+#define getpte4m(va) lda((va & 0xFFFFF000) | ASI_SRMMUFP_L3, \
+ ASI_SRMMUFP)
+void setpte4m __P((vm_offset_t va, int pte));
+void setptesw4m __P((struct pmap *pm, vm_offset_t va, int pte));
+u_int getptesw4m __P((struct pmap *pm, vm_offset_t va));
#endif
-#if !defined(SUN4) && defined(SUN4C)
-#define getsegmap(va) lduba(va, ASI_SEGMAP)
-#define setsegmap(va, pmeg) stba(va, ASI_SEGMAP, pmeg)
+
+#if defined(SUN4) || defined(SUN4C)
+#define getpte4(va) lda(va, ASI_PTE)
+#define setpte4(va, pte) sta(va, ASI_PTE, pte)
#endif
-#if defined(SUN4) && defined(SUN4C)
-#define getsegmap(va) (cputyp==CPU_SUN4C ? lduba(va, ASI_SEGMAP) \
- : (lduha(va, ASI_SEGMAP) & segfixmask))
-#define setsegmap(va, pmeg) (cputyp==CPU_SUN4C ? stba(va, ASI_SEGMAP, pmeg) \
- : stha(va, ASI_SEGMAP, pmeg))
+
+/* Function pointer messiness for supporting multiple sparc architectures
+ * within a single kernel: notice that there are two versions of many of the
+ * functions within this file/module, one for the sun4/sun4c and the other
+ * for the sun4m. For performance reasons (since things like pte bits don't
+ * map nicely between the two architectures), there are separate functions
+ * rather than unified functions which test the cputyp variable. If only
+ * one architecture is being used, then the non-suffixed function calls
+ * are macro-translated into the appropriate xxx4_4c or xxx4m call. If
+ * multiple architectures are defined, the calls translate to (*xxx_p),
+ * i.e. they indirect through function pointers initialized as appropriate
+ * to the run-time architecture in pmap_bootstrap. See also pmap.h.
+ */
+
+#if defined(SUN4M)
+static void mmu_setup4m_L1 __P((int, caddr_t, struct pmap *, caddr_t *));
+static void mmu_setup4m_L2 __P((int, caddr_t, struct regmap *, caddr_t *,
+ struct segmap *));
+static int mmu_setup4m_L3 __P((int, caddr_t));
+/*static*/ void mmu_reservemon4m __P((struct pmap *, caddr_t *));
+
+/*static*/ void pmap_rmk4m __P((struct pmap *, vm_offset_t, vm_offset_t,
+ int, int));
+/*static*/ void pmap_rmu4m __P((struct pmap *, vm_offset_t, vm_offset_t,
+ int, int));
+/*static*/ void pmap_enk4m __P((struct pmap *, vm_offset_t, vm_prot_t,
+ int, struct pvlist *, int));
+/*static*/ void pmap_enu4m __P((struct pmap *, vm_offset_t, vm_prot_t,
+ int, struct pvlist *, int));
+/*static*/ void pv_changepte4m __P((struct pvlist *, int, int));
+/*static*/ int pv_syncflags4m __P((struct pvlist *));
+/*static*/ int pv_link4m __P((struct pvlist *, struct pmap *, vm_offset_t));
+/*static*/ void pv_unlink4m __P((struct pvlist *, struct pmap *, vm_offset_t));
#endif
-#if defined(SUN4) && defined(MMU_3L)
-#define getregmap(va) ((unsigned)lduha(va+2, ASI_REGMAP) >> 8)
-#define setregmap(va, smeg) stha(va+2, ASI_REGMAP, (smeg << 8))
+
+#if defined(SUN4) || defined(SUN4C)
+/*static*/ void mmu_reservemon4_4c __P((int *, int *));
+/*static*/ void pmap_rmk4_4c __P((struct pmap *, vm_offset_t, vm_offset_t,
+ int, int));
+/*static*/ void pmap_rmu4_4c __P((struct pmap *, vm_offset_t, vm_offset_t,
+ int, int));
+/*static*/ void pmap_enk4_4c __P((struct pmap *, vm_offset_t, vm_prot_t,
+ int, struct pvlist *, int));
+/*static*/ void pmap_enu4_4c __P((struct pmap *, vm_offset_t, vm_prot_t,
+ int, struct pvlist *, int));
+/*static*/ void pv_changepte4_4c __P((struct pvlist *, int, int));
+/*static*/ int pv_syncflags4_4c __P((struct pvlist *));
+/*static*/ int pv_link4_4c __P((struct pvlist *, struct pmap *, vm_offset_t));
+/*static*/ void pv_unlink4_4c __P((struct pvlist *, struct pmap *, vm_offset_t));
#endif
-#define getpte(va) lda(va, ASI_PTE)
-#define setpte(va, pte) sta(va, ASI_PTE, pte)
+#if !defined(SUN4M) && (defined(SUN4) || defined(SUN4C))
+#define pmap_rmk pmap_rmk4_4c
+#define pmap_rmu pmap_rmu4_4c
+
+#elif defined(SUN4M) && !(defined(SUN4) || defined(SUN4C))
+#define pmap_rmk pmap_rmk4m
+#define pmap_rmu pmap_rmu4m
+
+#else /* must use function pointers */
+
+/* function pointer declarations */
+/* from pmap.h: */
+void (*pmap_clear_modify_p) __P((vm_offset_t pa));
+void (*pmap_clear_reference_p) __P((vm_offset_t pa));
+void (*pmap_copy_page_p) __P((vm_offset_t, vm_offset_t));
+void (*pmap_enter_p) __P((pmap_t,
+ vm_offset_t, vm_offset_t, vm_prot_t, boolean_t));
+vm_offset_t (*pmap_extract_p) __P((pmap_t, vm_offset_t));
+boolean_t (*pmap_is_modified_p) __P((vm_offset_t pa));
+boolean_t (*pmap_is_referenced_p) __P((vm_offset_t pa));
+void (*pmap_page_protect_p) __P((vm_offset_t, vm_prot_t));
+void (*pmap_protect_p) __P((pmap_t,
+ vm_offset_t, vm_offset_t, vm_prot_t));
+void (*pmap_zero_page_p) __P((vm_offset_t));
+void (*pmap_changeprot_p) __P((pmap_t, vm_offset_t,
+ vm_prot_t, int));
+/* local: */
+void (*pmap_rmk_p) __P((struct pmap *, vm_offset_t, vm_offset_t,
+ int, int));
+void (*pmap_rmu_p) __P((struct pmap *, vm_offset_t, vm_offset_t,
+ int, int));
+
+#define pmap_rmk (*pmap_rmk_p)
+#define pmap_rmu (*pmap_rmu_p)
-/*----------------------------------------------------------------*/
+#endif
-#define HWTOSW(pg) (pg)
-#define SWTOHW(pg) (pg)
+/* --------------------------------------------------------------*/
-#ifdef MMU_3L
-#define CTX_USABLE(pm,rp) ((pm)->pm_ctx && \
- (!mmu_3l || (rp)->rg_smeg != reginval))
+/*
+ * Next we have some Sun4m-specific routines which have no 4/4c
+ * counterparts, or which are 4/4c macros.
+ */
+
+#if defined(SUN4M)
+
+/* Macros which implement SRMMU TLB flushing/invalidation */
+
+#define tlb_flush_page(va) sta((va & ~0xfff) | ASI_SRMMUFP_L3, ASI_SRMMUFP,0)
+#define tlb_flush_segment(vreg, vseg) sta((vreg << RGSHIFT) | (vseg << SGSHIFT)\
+ | ASI_SRMMUFP_L2, ASI_SRMMUFP,0)
+#define tlb_flush_context() sta(ASI_SRMMUFP_L1, ASI_SRMMUFP, 0)
+#define tlb_flush_all() sta(ASI_SRMMUFP_LN, ASI_SRMMUFP, 0)
+
+static u_int VA2PA __P((caddr_t));
+
+/*
+ * VA2PA(addr) -- converts a virtual address to a physical address using
+ * the MMU's currently-installed page tables. As a side effect, the address
+ * translation used may cause the associated pte to be encached. The correct
+ * context for VA must be set before this is called.
+ *
+ * This routine should work with any level of mapping, as it is used
+ * during bootup to interact with the ROM's initial L1 mapping of the kernel.
+ */
+static __inline u_int
+VA2PA(addr)
+ register caddr_t addr;
+{
+ register u_int pte;
+
+ /* we'll use that handy SRMMU flush/probe! %%%: make consts below! */
+ /* Try each level in turn until we find a valid pte. Otherwise panic */
+
+ pte = lda(((u_int)addr & ~0xfff) | ASI_SRMMUFP_L3, ASI_SRMMUFP);
+ if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE)
+ return (((pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT) |
+ ((u_int)addr & 0xfff));
+
+ /* A `TLB Flush Entire' is required before any L0, L1 or L2 probe */
+ tlb_flush_all();
+
+ pte = lda(((u_int)addr & ~0xfff) | ASI_SRMMUFP_L2, ASI_SRMMUFP);
+ if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE)
+ return (((pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT) |
+ ((u_int)addr & 0x3ffff));
+ pte = lda(((u_int)addr & ~0xfff) | ASI_SRMMUFP_L1, ASI_SRMMUFP);
+ if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE)
+ return (((pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT) |
+ ((u_int)addr & 0xffffff));
+ pte = lda(((u_int)addr & ~0xfff) | ASI_SRMMUFP_L0, ASI_SRMMUFP);
+ if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE)
+ return (((pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT) |
+ ((u_int)addr & 0xffffffff));
+
+ panic("VA2PA: Asked to translate unmapped VA %p", addr);
+}
+
+/*
+ * Get the page table entry (PTE) for va by looking it up in the software
+ * page tables. These are the same tables that are used by the MMU; this
+ * routine allows easy access to the page tables even if the context
+ * corresponding to the table is not loaded or selected.
+ * This routine should NOT be used if there is any chance that the desired
+ * pte is in the TLB cache, since it will return stale data in that case.
+ * For that case, and for general use, use getpte4m, which is much faster
+ * and avoids walking in-memory page tables if the page is in the cache.
+ * Note also that this routine only works if a kernel mapping has been
+ * installed for the given page!
+ */
+__inline u_int
+getptesw4m(pm, va) /* Assumes L3 mapping! */
+ register struct pmap *pm;
+ register vm_offset_t va;
+{
+ register struct regmap *rm;
+ register struct segmap *sm;
+
+ rm = &pm->pm_regmap[VA_VREG(va)];
+#ifdef DEBUG
+ if (rm == NULL)
+ panic("getptesw4m: no regmap entry");
+#endif
+ sm = &rm->rg_segmap[VA_VSEG(va)];
+#ifdef DEBUG
+ if (sm == NULL)
+ panic("getptesw4m: no segmap");
+#endif
+ return (sm->sg_pte[VA_SUN4M_VPG(va)]); /* return pte */
+}
+
+/*
+ * Set the page table entry for va to pte. Only affects software MMU page-
+ * tables (the in-core pagetables read by the MMU). Ignores TLB, and
+ * thus should _not_ be called if the pte translation could be in the TLB.
+ * In this case, use setpte4m().
+ */
+__inline void
+setptesw4m(pm, va, pte)
+ register struct pmap *pm;
+ register vm_offset_t va;
+ register int pte;
+{
+ register struct regmap *rm;
+ register struct segmap *sm;
+
+ rm = &pm->pm_regmap[VA_VREG(va)];
+
+#ifdef DEBUG
+ if (pm->pm_regmap == NULL || rm == NULL)
+ panic("setpte4m: no regmap entry");
+#endif
+ sm = &rm->rg_segmap[VA_VSEG(va)];
+
+#ifdef DEBUG
+ if (rm->rg_segmap == NULL || sm == NULL || sm->sg_pte == NULL)
+ panic("setpte4m: no segmap for va %p", (caddr_t)va);
+#endif
+ sm->sg_pte[VA_SUN4M_VPG(va)] = pte; /* set new pte */
+}
+
+/* Set the page table entry for va to pte. Flushes cache. */
+__inline void
+setpte4m(va, pte)
+ register vm_offset_t va;
+ register int pte;
+{
+ register struct pmap *pm;
+ register struct regmap *rm;
+ register struct segmap *sm;
+ register union ctxinfo *c;
+
+ if (vactype != VAC_NONE)
+ cache_flush_page(va);
+
+ /*
+ * Now walk tables to find pte. We use ctxinfo to locate the pmap
+ * from the current context
+ */
+#ifdef DEBUG
+ if (ctxbusyvector[getcontext()] == 0)
+ panic("setpte4m: no pmap for current context (%d)",
+ getcontext());
+#endif
+ c = &ctxinfo[getcontext()];
+ pm = c->c_pmap;
+
+ /* Note: inline version of setptesw4m() */
+#ifdef DEBUG
+ if (pm->pm_regmap == NULL)
+ panic("setpte4m: no regmap entry");
+#endif
+ rm = &pm->pm_regmap[VA_VREG(va)];
+ sm = &rm->rg_segmap[VA_VSEG(va)];
+
+#ifdef DEBUG
+ if (rm->rg_segmap == NULL || sm == NULL || sm->sg_pte == NULL)
+ panic("setpte4m: no segmap for va %p", (caddr_t)va);
+#endif
+ tlb_flush_page(va);
+ sm->sg_pte[VA_SUN4M_VPG(va)] = pte; /* set new pte */
+}
+#endif /* 4m only */
+
+/*----------------------------------------------------------------*/
+
+#if defined(MMU_3L)
+#define CTX_USABLE(pm,rp) (CPU_ISSUN4M \
+ ? ((pm)->pm_ctx != NULL ) \
+ : ((pm)->pm_ctx != NULL && \
+ (!mmu_3l || (rp)->rg_smeg != reginval)))
#else
-#define CTX_USABLE(pm,rp) ((pm)->pm_ctx)
+#define CTX_USABLE(pm,rp) ((pm)->pm_ctx != NULL )
#endif
-#define GAP_WIDEN(pm,vr) do { \
- if (vr + 1 == pm->pm_gap_start) \
- pm->pm_gap_start = vr; \
- if (vr == pm->pm_gap_end) \
- pm->pm_gap_end = vr + 1;\
+#define GAP_WIDEN(pm,vr) do if (CPU_ISSUN4OR4C) { \
+ if (vr + 1 == pm->pm_gap_start) \
+ pm->pm_gap_start = vr; \
+ if (vr == pm->pm_gap_end) \
+ pm->pm_gap_end = vr + 1; \
} while (0)
-#define GAP_SHRINK(pm,vr) do { \
+#define GAP_SHRINK(pm,vr) do if (CPU_ISSUN4OR4C) { \
register int x; \
x = pm->pm_gap_start + (pm->pm_gap_end - pm->pm_gap_start) / 2; \
if (vr > x) { \
@@ -362,6 +683,18 @@ static u_long segfixmask = 0xffffffff; /* all bits valid to start */
} \
} while (0)
+static void sortm __P((struct memarr *, int));
+void ctx_alloc __P((struct pmap *));
+void ctx_free __P((struct pmap *));
+void pv_flushcache __P((struct pvlist *));
+void kvm_iocache __P((caddr_t, int));
+#ifdef DEBUG
+void pm_check __P((char *, struct pmap *));
+void pm_check_k __P((char *, struct pmap *));
+void pm_check_u __P((char *, struct pmap *));
+#endif
+
+
/*
* Sort a memory array by address.
*/
@@ -477,7 +810,7 @@ pmap_next_page(paddr)
* The returned index does NOT need to start at zero.
*
*/
-u_long
+int
pmap_page_index(pa)
vm_offset_t pa;
{
@@ -487,7 +820,7 @@ pmap_page_index(pa)
#ifdef DIAGNOSTIC
if (pa < avail_start || pa >= avail_end)
- panic("pmap_page_index: pa=0x%x", pa);
+ panic("pmap_page_index: pa=0x%lx", pa);
#endif
for (idx = 0, mp = pmemarr, nmem = npmemarr; --nmem >= 0; mp++) {
@@ -515,7 +848,8 @@ pmap_pa_exists(pa)
}
/* update pv_flags given a valid pte */
-#define MR(pte) (((pte) >> PG_M_SHIFT) & (PV_MOD | PV_REF))
+#define MR4_4C(pte) (((pte) >> PG_M_SHIFT) & (PV_MOD | PV_REF))
+#define MR4M(pte) (((pte) >> PG_M_SHIFT4M) & (PV_MOD4M | PV_REF4M))
/*----------------------------------------------------------------*/
@@ -528,22 +862,33 @@ pmap_pa_exists(pa)
* description of *free* virtual memory. Rather than invert this, we
* resort to two magic constants from the PROM vector description file.
*/
+#if defined(SUN4) || defined(SUN4C)
void
-mmu_reservemon(nrp, nsp)
+mmu_reservemon4_4c(nrp, nsp)
register int *nrp, *nsp;
{
- register u_int va, eva;
- register int mmureg, mmuseg, i, nr, ns, vr, lastvr;
+ register u_int va = 0, eva = 0;
+ register int mmuseg, i, nr, ns, vr, lastvr;
+#ifdef MMU_3L
+ register int mmureg;
+#endif
register struct regmap *rp;
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ panic("mmu_reservemon called on Sun4M machine");
+ return;
+ }
+#endif
+
#if defined(SUN4)
- if (cputyp == CPU_SUN4) {
+ if (CPU_ISSUN4) {
prom_vstart = va = OLDMON_STARTVADDR;
prom_vend = eva = OLDMON_ENDVADDR;
}
#endif
#if defined(SUN4C)
- if (cputyp == CPU_SUN4C) {
+ if (CPU_ISSUN4C) {
prom_vstart = va = OPENPROM_STARTVADDR;
prom_vend = eva = OPENPROM_ENDVADDR;
}
@@ -592,12 +937,312 @@ mmu_reservemon(nrp, nsp)
/* PROM maps its memory user-accessible: fix it. */
for (i = NPTESG; --i >= 0; va += NBPG)
- setpte(va, getpte(va) | PG_S);
+ setpte4(va, getpte4(va) | PG_S);
}
*nsp = ns;
*nrp = nr;
return;
}
+#endif
+
+#if defined(SUN4M) /* Sun4M versions of above */
+
+/*
+ * Take the monitor's initial page table layout, convert it to 3rd-level pte's
+ * (it starts out as a L1 mapping), and install it along with a set of kernel
+ * mapping tables as the kernel's initial page table setup. Also create and
+ * enable a context table. I suppose we also want to block user-mode access
+ * to the new kernel/ROM mappings.
+ */
+
+/*
+ * mmu_reservemon4m(): Copies the existing (ROM) page tables to kernel space,
+ * converting any L1/L2 PTEs to L3 PTEs. Does *not* copy the L1 entry mapping
+ * the kernel at 0xf8000000 (KERNBASE) since we don't want to map 16M of
+ * physical memory for the kernel. Thus the kernel must be installed later!
+ * Also installs ROM mappings into the kernel pmap.
+ * NOTE: This also revokes all user-mode access to the mapped regions.
+ * NOTE ALSO: Must set up kernel pmap as all invalid before this is called.
+ */
+void
+mmu_reservemon4m(kpmap, kmemtop)
+ struct pmap *kpmap;
+ register caddr_t *kmemtop; /* Note: this is a *virtual* address! */
+{
+ unsigned int ctxtblptr;
+ int wierdviking = 0;
+ register int te;
+ register caddr_t tableptr;
+ unsigned int mmupcrsav;
+
+/*XXX-GCC!*/mmupcrsav = 0;
+
+ /*
+ * XXX: although the Sun4M can handle 36 bits of physical
+ * address space, we assume that all these page tables, etc
+ * are in the lower 4G (32-bits) of address space, i.e. out of I/O
+ * space. Eventually this should be changed to support the 36 bit
+ * physical addressing, in case some crazed ROM designer decides to
+ * stick the pagetables up there. In that case, we should use MMU
+ * transparent mode, (i.e. ASI 0x20 to 0x2f) to access
+ * physical memory.
+ */
+
+ ctxtblptr = (lda(SRMMU_CXTPTR,ASI_SRMMU) << SRMMU_PPNPASHIFT);
+
+ /* We're going to have to use MMU passthrough. If we're on a
+ * Viking MicroSparc without an mbus, we need to turn off traps
+ * and set the AC bit at 0x8000 in the MMU's control register. Ugh.
+ * XXX: Once we've done this, can we still access kernel vm?
+ */
+ if ((getpsr() & 0x40000000) && (!(lda(SRMMU_PCR,ASI_SRMMU) & 0x800))) {
+ wierdviking = 1;
+ sta(SRMMU_PCR, ASI_SRMMU, /* set MMU AC bit */
+ ((mmupcrsav = lda(SRMMU_PCR,ASI_SRMMU)) | SRMMU_PCR_AC));
+ }
+ if (ncontext < 1024) {
+ /* to keep supersparc happy, still align on 4K boundary */
+ ctx_phys_tbl = (int *)roundup((u_int) *kmemtop, 4096);
+ *kmemtop = (caddr_t)((u_int)ctx_phys_tbl + 4096);
+ qzero(ctx_phys_tbl, 4096);
+ } else {
+ ctx_phys_tbl = (int *)roundup((u_int) *kmemtop,
+ ncontext * sizeof(int));
+ *kmemtop = (caddr_t)((u_int)ctx_phys_tbl +
+ (ncontext * sizeof(int)));
+ qzero(ctx_phys_tbl, ncontext * sizeof(int));
+ }
+
+ te = lda(ctxtblptr, ASI_BYPASS);
+ switch (te & SRMMU_TETYPE) {
+ case SRMMU_TEINVALID:
+ ctx_phys_tbl[0] = SRMMU_TEINVALID;
+ panic("mmu_reservemon4m: no existing L0 mapping! (How are we running?");
+ break;
+ case SRMMU_TEPTE:
+#ifdef DEBUG
+ printf("mmu_reservemon4m: trying to remap 4G segment!\n");
+#endif
+ panic("mmu_reservemon4m: can't handle ROM 4G page size");
+ /* XXX: Should make this work, however stupid it is */
+ break;
+ case SRMMU_TEPTD:
+ tableptr = (caddr_t) roundup((u_int) *kmemtop,
+ SRMMU_L1SIZE * sizeof(long));
+ *kmemtop = tableptr + (SRMMU_L1SIZE * sizeof(long));
+ bzero(tableptr, *kmemtop - tableptr);
+ ctx_phys_tbl[0] = (VA2PA(tableptr) >> SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+ kpmap->pm_reg_ptps = (int *)tableptr;
+ kpmap->pm_reg_ptps_pa = VA2PA(tableptr);
+ mmu_setup4m_L1(te, tableptr, kpmap, kmemtop);
+ break;
+ default:
+ panic("mmu_reservemon4m: unknown pagetable entry type");
+ }
+
+ if (wierdviking == 1) {
+ sta(SRMMU_PCR, ASI_SRMMU, mmupcrsav);
+ }
+}
+
+void
+mmu_setup4m_L1(regtblptd, newtableptr, kpmap, kmemtop)
+ int regtblptd; /* PTD for region table to be remapped */
+ caddr_t newtableptr; /* Virtual ptr to new region table */
+ struct pmap *kpmap;
+ register caddr_t *kmemtop;
+{
+ register unsigned int regtblrover;
+ register int i;
+ unsigned int te;
+ caddr_t segtblptr;
+ register caddr_t pagtblptr;
+ struct regmap *thisregmap = NULL;
+ struct segmap *segmaps;
+ int j, k;
+
+ /* Here we scan the region table to copy any entries which appear.
+ * We are only concerned with regions in kernel space and above
+ * (i.e. regions 0xf8 to 0xff). We also ignore region 0xf8, since
+ * that is the 16MB L1 mapping that the ROM used to map the kernel
+ * in initially. Later, we will rebuild a new L3 mapping for the
+ * kernel and install it before switching to the new pagetables.
+ */
+ regtblrover = ((regtblptd & ~SRMMU_TETYPE) << SRMMU_PPNPASHIFT) +
+ (VA_VREG(KERNBASE)+1) * sizeof(long); /* kernel only */
+
+ for (i = VA_VREG(KERNBASE) + 1; i < SRMMU_L1SIZE;
+ i++, regtblrover += sizeof(long)) {
+ te = lda(regtblrover, ASI_BYPASS);
+ switch(te & SRMMU_TETYPE) {
+ case SRMMU_TEINVALID:
+ ((int *)newtableptr)[i] = SRMMU_TEINVALID;
+ break;
+ case SRMMU_TEPTE:
+#ifdef DEBUG
+ printf("mmu_reservemon4m: converting region 0x%x from L1->L3\n",i);
+#endif
+ /* We must build segment and page tables, then
+ * fill them in
+ */
+ thisregmap = &kpmap->pm_regmap[i];
+ bzero(thisregmap, sizeof(struct regmap));
+ segmaps = &kernel_segmap_store[(i-VA_VREG(KERNBASE))*NSEGRG];
+ segtblptr = (caddr_t) roundup((u_int) *kmemtop,
+ SRMMU_L2SIZE * sizeof(long));
+ *kmemtop = segtblptr + (SRMMU_L2SIZE * sizeof(long));
+ bzero(segtblptr, *kmemtop - segtblptr);
+ bzero(segmaps, NSEGRG * sizeof(struct segmap));
+ thisregmap->rg_segmap = segmaps;
+ thisregmap->rg_seg_ptps = (int *)segtblptr;
+ ((int *)newtableptr)[i] = (VA2PA(segtblptr) >>
+ SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+ for (j = 0; j < SRMMU_L2SIZE; j++) {
+ thisregmap->rg_nsegmap++;
+ pagtblptr = (caddr_t) roundup((u_int) *kmemtop,
+ SRMMU_L3SIZE * sizeof(int));
+ *kmemtop = segtblptr + (SRMMU_L3SIZE *
+ sizeof(long));
+ bzero(pagtblptr, *kmemtop - pagtblptr);
+ ((int *)segtblptr)[j] = (VA2PA(pagtblptr) >>
+ SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+ segmaps[j].sg_pte = (int *)pagtblptr;
+
+ for (k = 0; k < SRMMU_L3SIZE; k++) {
+ segmaps[j].sg_npte++;
+ ((int *)pagtblptr)[k] =
+ (te & SRMMU_L1PPNMASK) |
+ (j << SRMMU_L2PPNSHFT) |
+ (k << SRMMU_L3PPNSHFT) |
+ (te & SRMMU_PGBITSMSK) |
+ ((te & SRMMU_PROT_MASK) |
+ PPROT_U2S_OMASK) |
+ SRMMU_TEPTE;
+ }
+ }
+ break;
+ case SRMMU_TEPTD:
+ thisregmap = &kpmap->pm_regmap[i];
+ bzero(thisregmap, sizeof(struct regmap));
+ segtblptr = (caddr_t) roundup((u_int)*kmemtop,
+ SRMMU_L2SIZE * sizeof(long));
+ *kmemtop = segtblptr + (SRMMU_L2SIZE * sizeof(long));
+ segmaps = &kernel_segmap_store[(i-(KERNBASE >> RGSHIFT))*NSEGRG];
+ bzero(segtblptr, *kmemtop - segtblptr);
+ bzero(segmaps, NSEGRG * sizeof(struct segmap));
+ thisregmap->rg_segmap = segmaps;
+ thisregmap->rg_seg_ptps = (int *)segtblptr;
+ ((int *)newtableptr)[i] = (VA2PA(segtblptr) >>
+ SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+ mmu_setup4m_L2(te, segtblptr, thisregmap, kmemtop, segmaps);
+ break;
+ default:
+ panic("mmu_setup4m_L1: unknown pagetable entry type");
+ }
+ }
+}
+
+void
+mmu_setup4m_L2(segtblptd, newtableptr, pregmap, kmemtop, segmaps)
+ int segtblptd;
+ caddr_t newtableptr;
+ struct regmap *pregmap;
+ register caddr_t *kmemtop;
+ struct segmap *segmaps;
+{
+ register unsigned int segtblrover;
+ register int i, k;
+ unsigned int te;
+ register caddr_t pagtblptr;
+ struct segmap *thissegmap = NULL;
+
+ segtblrover = (segtblptd & ~SRMMU_TETYPE) << SRMMU_PPNPASHIFT;
+ for (i = 0; i < SRMMU_L2SIZE; i++, segtblrover += sizeof(long)) {
+ te = lda(segtblrover, ASI_BYPASS);
+ switch(te & SRMMU_TETYPE) {
+ case SRMMU_TEINVALID:
+ ((int *)newtableptr)[i] = SRMMU_TEINVALID;
+ break;
+ case SRMMU_TEPTE:
+#ifdef DEBUG
+ printf("mmu_reservemon4m: converting L2 entry at segment 0x%x to L3\n",i);
+#endif
+ pregmap->rg_nsegmap++;
+ /* We must build page tables and fill them in */
+ pagtblptr = (caddr_t) roundup((u_int) *kmemtop,
+ SRMMU_L3SIZE*sizeof(int));
+ *kmemtop = pagtblptr + (SRMMU_L3SIZE *
+ sizeof(int));
+ bzero(pagtblptr, *kmemtop - pagtblptr);
+ ((int *)newtableptr)[i] = (VA2PA(pagtblptr) >>
+ SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+ segmaps[i].sg_pte = (int *) pagtblptr;
+
+ for (k = 0; k < SRMMU_L3SIZE; k++) {
+ segmaps[i].sg_npte++;
+ ((int *)pagtblptr)[k] =
+ (te & SRMMU_L1PPNMASK) |
+ (te & SRMMU_L2PPNMASK) |
+ (k << SRMMU_L3PPNSHFT) |
+ (te & SRMMU_PGBITSMSK) |
+ ((te & SRMMU_PROT_MASK) |
+ PPROT_U2S_OMASK) |
+ SRMMU_TEPTE;
+ }
+ break;
+ case SRMMU_TEPTD:
+ pregmap->rg_nsegmap++;
+ thissegmap = &segmaps[i];
+ pagtblptr = (caddr_t) roundup((u_int) *kmemtop,
+ SRMMU_L3SIZE*sizeof(int));
+ *kmemtop = pagtblptr + (SRMMU_L3SIZE * sizeof(int));
+ bzero(pagtblptr, *kmemtop - pagtblptr);
+ ((int *)newtableptr)[i] = (VA2PA(pagtblptr) >>
+ SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+ thissegmap->sg_pte = (int *) pagtblptr;
+ thissegmap->sg_npte += mmu_setup4m_L3(te, pagtblptr);
+ break;
+ default:
+ panic("mmu_setup4m_L2: unknown pagetable entry type");
+ }
+ }
+}
+
+int
+mmu_setup4m_L3(pagtblptd, newtableptr)
+ register int pagtblptd;
+ register caddr_t newtableptr;
+{
+ register unsigned int pagtblrover;
+ register int i, n = 0;
+ register unsigned int te;
+
+ pagtblrover = (pagtblptd & ~SRMMU_TETYPE) << SRMMU_PPNPASHIFT;
+ for (i = 0; i < SRMMU_L3SIZE; i++, pagtblrover += sizeof(long)) {
+ te = lda(pagtblrover, ASI_BYPASS);
+ switch(te & SRMMU_TETYPE) {
+ case SRMMU_TEINVALID:
+ ((int *)newtableptr)[i] = SRMMU_TEINVALID;
+ break;
+ case SRMMU_TEPTE:
+ ((int *)newtableptr)[i] = te | PPROT_U2S_OMASK;
+ n++;
+ break;
+ case SRMMU_TEPTD:
+ panic("mmu_setup4m_L3: PTD found in L3 page table");
+ default:
+ panic("mmu_setup4m_L3: unknown pagetable entry type");
+ }
+ }
+ return n;
+}
+#endif /* defined SUN4M */
/*
* TODO: agree with the ROM on physical pages by taking them away
@@ -626,6 +1271,7 @@ void region_free __P((struct pmap *, u_int));
setcontext(new); \
}
+#if defined(SUN4) || defined(SUN4C) /* This is old sun MMU stuff */
/*
* Allocate an MMU entry (i.e., a PMEG).
* If necessary, steal one from someone else.
@@ -686,7 +1332,7 @@ me_alloc(mh, newpm, newvreg, newvseg)
panic("me_alloc: stealing from kernel");
#ifdef DEBUG
if (pmapdebug & (PDB_MMU_ALLOC | PDB_MMU_STEAL))
- printf("me_alloc: stealing pmeg %x from pmap %x\n",
+ printf("me_alloc: stealing pmeg %x from pmap %p\n",
me->me_cookie, pm);
#endif
/*
@@ -742,11 +1388,11 @@ me_alloc(mh, newpm, newvreg, newvseg)
*/
i = NPTESG;
do {
- tpte = getpte(va);
+ tpte = getpte4(va);
if ((tpte & (PG_V | PG_TYPE)) == (PG_V | PG_OBMEM)) {
- pa = ptoa(HWTOSW(tpte & PG_PFNUM));
+ pa = ptoa(tpte & PG_PFNUM);
if (managed(pa))
- pvhead(pa)->pv_flags |= MR(tpte);
+ pvhead(pa)->pv_flags |= MR4_4C(tpte);
}
*pte++ = tpte & ~(PG_U|PG_M);
va += NBPG;
@@ -799,7 +1445,7 @@ me_free(pm, pmeg)
#ifdef DEBUG
if (pmapdebug & PDB_MMU_ALLOC)
- printf("me_free: freeing pmeg %d from pmap %x\n",
+ printf("me_free: freeing pmeg %d from pmap %p\n",
me->me_cookie, pm);
if (me->me_cookie != pmeg)
panic("me_free: wrong mmuentry");
@@ -825,11 +1471,11 @@ if (getcontext() != 0) panic("me_free: ctx != 0");
}
i = NPTESG;
do {
- tpte = getpte(va);
+ tpte = getpte4(va);
if ((tpte & (PG_V | PG_TYPE)) == (PG_V | PG_OBMEM)) {
- pa = ptoa(HWTOSW(tpte & PG_PFNUM));
+ pa = ptoa(tpte & PG_PFNUM);
if (managed(pa))
- pvhead(pa)->pv_flags |= MR(tpte);
+ pvhead(pa)->pv_flags |= MR4_4C(tpte);
}
va += NBPG;
} while (--i > 0);
@@ -865,10 +1511,8 @@ region_alloc(mh, newpm, newvr)
{
register struct mmuentry *me;
register struct pmap *pm;
- register int i, va, pa;
int ctx;
struct regmap *rp;
- struct segmap *sp;
/* try free list first */
if ((me = region_freelist.tqh_first) != NULL) {
@@ -903,7 +1547,7 @@ region_alloc(mh, newpm, newvr)
panic("region_alloc: stealing from kernel");
#ifdef DEBUG
if (pmapdebug & (PDB_MMUREG_ALLOC | PDB_MMUREG_STEAL))
- printf("region_alloc: stealing smeg %x from pmap %x\n",
+ printf("region_alloc: stealing smeg %x from pmap %p\n",
me->me_cookie, pm);
#endif
/*
@@ -961,7 +1605,7 @@ region_free(pm, smeg)
#ifdef DEBUG
if (pmapdebug & PDB_MMUREG_ALLOC)
- printf("region_free: freeing smeg %x from pmap %x\n",
+ printf("region_free: freeing smeg %x from pmap %p\n",
me->me_cookie, pm);
if (me->me_cookie != smeg)
panic("region_free: wrong mmuentry");
@@ -1001,11 +1645,9 @@ region_free(pm, smeg)
int
mmu_pagein(pm, va, prot)
register struct pmap *pm;
- register int va;
- vm_prot_t prot;
+ register int va, prot;
{
register int *pte;
- register struct mmuentry *me;
register int vr, vs, pmeg, i, s, bits;
struct regmap *rp;
struct segmap *sp;
@@ -1051,7 +1693,7 @@ printf("mmu_pagein: kernel wants map at va %x, vr %d, vs %d\n", va, vr, vs);
/* return -1 if the fault is `hard', 0 if not */
if (sp->sg_pmeg != seginval)
- return (bits && (getpte(va) & bits) == bits ? -1 : 0);
+ return (bits && (getpte4(va) & bits) == bits ? -1 : 0);
/* reload segment: write PTEs into a new LRU entry */
va = VA_ROUNDDOWNTOSEG(va);
@@ -1060,12 +1702,62 @@ printf("mmu_pagein: kernel wants map at va %x, vr %d, vs %d\n", va, vr, vs);
setsegmap(va, pmeg);
i = NPTESG;
do {
- setpte(va, *pte++);
+ setpte4(va, *pte++);
va += NBPG;
} while (--i > 0);
splx(s);
return (1);
}
+#endif /* defined SUN4 or SUN4C */
+
+#if defined(DEBUG) && defined(SUN4M)
+/*
+ * `Page in' (load or inspect) an MMU entry; called on page faults.
+ * Returns -1 if the desired page was marked valid (in which case the
+ * fault must be a bus error or something), or 0 (segment loaded but
+ * PTE not valid, or segment not loaded at all).
+ *
+ * The SRMMU does not have the concept of `loading PMEGs into the MMU'.
+ * For now, we use it to debug certain sporadic and strange memory
+ * fault traps.
+ */
+int
+mmu_pagein4m(pm, va, prot)
+ register struct pmap *pm;
+ register int va, prot;
+{
+ register int pte;
+ register int bits;
+
+ pte = getpte4m(va);
+ if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
+ /* pte not found == not valid */
+ return 0;
+
+ /*
+ * If pte has "correct" protection (according to bits), then
+ * something bizarre has happened, so we return -1 to generate
+ * a fault. Otherwise, we return 0 and let the VM code reload
+ * the page.
+ * XXX: Does this actually work, or will it cause a loop?
+ */
+
+ if (prot != VM_PROT_NONE)
+ bits = ((prot & VM_PROT_WRITE) ? PPROT_RWX_RWX : PPROT_RX_RX);
+ else
+ bits = 0;
+ /* If we're in kernelland, mask out user RWX */
+/* if (getcontext() == 0)
+ bits |= PPROT_S;
+*/
+ if (bits && (pte & bits) == bits) {
+ printf("pagein4m(%s[%d]): OOPS: prot=%x, va=%x, pte=%x, bits=%x\n",
+ curproc->p_comm, curproc->p_pid, prot, va, pte, bits);
+ return -1;
+ }
+ return 0;
+}
+#endif
/*
* Allocate a context. If necessary, steal one from someone else.
@@ -1084,14 +1776,17 @@ ctx_alloc(pm)
register int gap_start, gap_end;
register unsigned long va;
+/*XXX-GCC!*/gap_start=gap_end=0;
#ifdef DEBUG
if (pm->pm_ctx)
panic("ctx_alloc pm_ctx");
if (pmapdebug & PDB_CTX_ALLOC)
- printf("ctx_alloc(%x)\n", pm);
+ printf("ctx_alloc(%p)\n", pm);
#endif
- gap_start = pm->pm_gap_start;
- gap_end = pm->pm_gap_end;
+ if (CPU_ISSUN4OR4C) {
+ gap_start = pm->pm_gap_start;
+ gap_end = pm->pm_gap_end;
+ }
s = splpmap();
if ((c = ctx_freelist) != NULL) {
@@ -1111,67 +1806,134 @@ ctx_alloc(pm)
if (c->c_pmap == NULL)
panic("ctx_alloc cu_pmap");
if (pmapdebug & (PDB_CTX_ALLOC | PDB_CTX_STEAL))
- printf("ctx_alloc: steal context %x from %x\n",
+ printf("ctx_alloc: steal context %d from %p\n",
cnum, c->c_pmap);
#endif
c->c_pmap->pm_ctx = NULL;
doflush = (vactype != VAC_NONE);
- if (gap_start < c->c_pmap->pm_gap_start)
- gap_start = c->c_pmap->pm_gap_start;
- if (gap_end > c->c_pmap->pm_gap_end)
- gap_end = c->c_pmap->pm_gap_end;
+ if (CPU_ISSUN4OR4C) {
+ if (gap_start < c->c_pmap->pm_gap_start)
+ gap_start = c->c_pmap->pm_gap_start;
+ if (gap_end > c->c_pmap->pm_gap_end)
+ gap_end = c->c_pmap->pm_gap_end;
+ }
}
- setcontext(cnum);
c->c_pmap = pm;
pm->pm_ctx = c;
pm->pm_ctxnum = cnum;
- splx(s);
- if (doflush)
- cache_flush_context();
- /*
- * Write pmap's region (3-level MMU) or segment table into the MMU.
- *
- * Only write those entries that actually map something in this
- * context by maintaining a pair of region numbers in between
- * which the pmap has no valid mappings.
- *
- * If a context was just allocated from the free list, trust that
- * all its pmeg numbers are `seginval'. We make sure this is the
- * case initially in pmap_bootstrap(). Otherwise, the context was
- * freed by calling ctx_free() in pmap_release(), which in turn is
- * supposedly called only when all mappings have been removed.
- *
- * On the other hand, if the context had to be stolen from another
- * pmap, we possibly shrink the gap to be the disjuction of the new
- * and the previous map.
- */
+ if (CPU_ISSUN4OR4C) {
+ /*
+ * Write pmap's region (3-level MMU) or segment table into
+ * the MMU.
+ *
+ * Only write those entries that actually map something in
+ * this context by maintaining a pair of region numbers in
+ * between which the pmap has no valid mappings.
+ *
+ * If a context was just allocated from the free list, trust
+ * that all its pmeg numbers are `seginval'. We make sure this
+ * is the case initially in pmap_bootstrap(). Otherwise, the
+ * context was freed by calling ctx_free() in pmap_release(),
+ * which in turn is supposedly called only when all mappings
+ * have been removed.
+ *
+ * On the other hand, if the context had to be stolen from
+ * another pmap, we possibly shrink the gap to be the
+ * disjuction of the new and the previous map.
+ */
+ setcontext(cnum);
+ splx(s);
+ if (doflush)
+ cache_flush_context();
- rp = pm->pm_regmap;
- for (va = 0, i = NUREG; --i >= 0; ) {
- if (VA_VREG(va) >= gap_start) {
- va = VRTOVA(gap_end);
- i -= gap_end - gap_start;
- rp += gap_end - gap_start;
- if (i < 0)
- break;
- gap_start = NUREG; /* mustn't re-enter this branch */
- }
+ rp = pm->pm_regmap;
+ for (va = 0, i = NUREG; --i >= 0; ) {
+ if (VA_VREG(va) >= gap_start) {
+ va = VRTOVA(gap_end);
+ i -= gap_end - gap_start;
+ rp += gap_end - gap_start;
+ if (i < 0)
+ break;
+ /* mustn't re-enter this branch */
+ gap_start = NUREG;
+ }
#ifdef MMU_3L
- if (mmu_3l) {
- setregmap(va, rp++->rg_smeg);
- va += NBPRG;
- } else
+ if (mmu_3l) {
+ setregmap(va, rp++->rg_smeg);
+ va += NBPRG;
+ } else
#endif
- {
- register int j;
- register struct segmap *sp = rp->rg_segmap;
- for (j = NSEGRG; --j >= 0; va += NBPSG)
- setsegmap(va, sp?sp++->sg_pmeg:seginval);
- rp++;
+ {
+ register int j;
+ register struct segmap *sp = rp->rg_segmap;
+ for (j = NSEGRG; --j >= 0; va += NBPSG)
+ setsegmap(va,
+ sp?sp++->sg_pmeg:seginval);
+ rp++;
+ }
}
+
+ } else if (CPU_ISSUN4M) {
+
+ /*
+ * Reload page and context tables to activate the page tables
+ * for this context.
+ *
+ * The gap stuff isn't really needed in the Sun4m architecture,
+ * since we don't have to worry about excessive mappings (all
+ * mappings exist since the page tables must be complete for
+ * the mmu to be happy).
+ *
+ * If a context was just allocated from the free list, trust
+ * that all of its mmu-edible page tables are zeroed out
+ * (except for those associated with the kernel). We make
+ * sure this is the case initially in pmap_bootstrap() and
+ * pmap_init() (?).
+ * Otherwise, the context was freed by calling ctx_free() in
+ * pmap_release(), which in turn is supposedly called only
+ * when all mappings have been removed.
+ *
+ * XXX: Do we have to flush cache after reloading ctx tbl?
+ */
+
+ /*
+ * We install kernel mappings into the pmap here, since when
+ * the kernel expands it only propagates the expansion to pmaps
+ * corresponding to valid contexts. Thus it is possible (and
+ * it has happened!) that a pmap is created just before
+ * the kernel expands, but the pmap gets a context *after*
+ * the kernel expands, thus missing getting mappings.
+ */
+ qcopy(&pmap_kernel()->pm_reg_ptps[VA_VREG(KERNBASE)],
+ &pm->pm_reg_ptps[VA_VREG(KERNBASE)],
+ NKREG * sizeof(int));
+ /*
+ * We must also install the regmap/segmap/etc stuff for
+ * kernel maps.
+ */
+ qcopy(&pmap_kernel()->pm_regmap[VA_VREG(KERNBASE)],
+ &pm->pm_regmap[VA_VREG(KERNBASE)],
+ NKREG * sizeof(struct regmap));
+
+ ctxbusyvector[cnum] = 1; /* mark context as busy */
+#ifdef DEBUG
+ if (pm->pm_reg_ptps_pa == 0)
+ panic("ctx_alloc: no region table in current pmap");
+#endif
+ /*setcontext(0); * paranoia? can we modify curr. ctx? */
+ ctx_phys_tbl[cnum] =
+ (pm->pm_reg_ptps_pa >> SRMMU_PPNPASHIFT) | SRMMU_TEPTD;
+
+ setcontext(cnum);
+ if (doflush)
+ cache_flush_context();
+#if defined(SUN4M)
+ tlb_flush_context(); /* remove any remnant garbage from tlb */
+#endif
+ splx(s);
}
}
@@ -1189,16 +1951,35 @@ ctx_free(pm)
panic("ctx_free");
pm->pm_ctx = NULL;
oldc = getcontext();
+
if (vactype != VAC_NONE) {
newc = pm->pm_ctxnum;
CHANGE_CONTEXTS(oldc, newc);
cache_flush_context();
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ tlb_flush_context();
+#endif
setcontext(0);
} else {
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ tlb_flush_context();
+#endif
CHANGE_CONTEXTS(oldc, 0);
}
c->c_nextfree = ctx_freelist;
ctx_freelist = c;
+
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ /* Map kernel back into unused context */
+ newc = pm->pm_ctxnum;
+ ctx_phys_tbl[newc] = ctx_phys_tbl[0];
+ if (newc)
+ ctxbusyvector[newc] = 0; /* mark as free */
+ }
+#endif
}
@@ -1221,15 +2002,18 @@ ctx_free(pm)
* It also copies ref and mod bits to the pvlist, on the theory that
* this might save work later. (XXX should test this theory)
*/
+
+#if defined(SUN4) || defined(SUN4C)
+
void
-pv_changepte(pv0, bis, bic)
+pv_changepte4_4c(pv0, bis, bic)
register struct pvlist *pv0;
register int bis, bic;
{
register int *pte;
register struct pvlist *pv;
register struct pmap *pm;
- register int va, vr, vs, i, flags;
+ register int va, vr, vs, flags;
int ctx, s;
struct regmap *rp;
struct segmap *sp;
@@ -1281,7 +2065,7 @@ if(pm==NULL)panic("pv_changepte 1");
continue;
setcontext(pm->pm_ctxnum);
/* XXX should flush only when necessary */
- tpte = getpte(va);
+ tpte = getpte4(va);
if (vactype != VAC_NONE && (tpte & PG_M))
cache_flush_page(va);
} else {
@@ -1293,13 +2077,12 @@ if(pm==NULL)panic("pv_changepte 1");
#endif
setsegmap(0, sp->sg_pmeg);
va = VA_VPG(va) << PGSHIFT;
- tpte = getpte(va);
+ tpte = getpte4(va);
}
if (tpte & PG_V)
- flags |= (tpte >> PG_M_SHIFT) &
- (PV_MOD|PV_REF);
+ flags |= (tpte >> PG_M_SHIFT) & (PV_MOD|PV_REF);
tpte = (tpte | bis) & ~bic;
- setpte(va, tpte);
+ setpte4(va, tpte);
if (pte != NULL) /* update software copy */
pte[VA_VPG(va)] = tpte;
}
@@ -1317,12 +2100,12 @@ if(pm==NULL)panic("pv_changepte 1");
* hence never need to adjust software copies.
*/
int
-pv_syncflags(pv0)
+pv_syncflags4_4c(pv0)
register struct pvlist *pv0;
{
register struct pvlist *pv;
register struct pmap *pm;
- register int tpte, va, vr, vs, pmeg, i, flags;
+ register int tpte, va, vr, vs, pmeg, flags;
int ctx, s;
struct regmap *rp;
struct segmap *sp;
@@ -1352,7 +2135,7 @@ pv_syncflags(pv0)
if (CTX_USABLE(pm,rp)) {
setcontext(pm->pm_ctxnum);
/* XXX should flush only when necessary */
- tpte = getpte(va);
+ tpte = getpte4(va);
if (vactype != VAC_NONE && (tpte & PG_M))
cache_flush_page(va);
} else {
@@ -1364,13 +2147,13 @@ pv_syncflags(pv0)
#endif
setsegmap(0, pmeg);
va = VA_VPG(va) << PGSHIFT;
- tpte = getpte(va);
+ tpte = getpte4(va);
}
if (tpte & (PG_M|PG_U) && tpte & PG_V) {
flags |= (tpte >> PG_M_SHIFT) &
(PV_MOD|PV_REF);
tpte &= ~(PG_M|PG_U);
- setpte(va, tpte);
+ setpte4(va, tpte);
}
}
pv0->pv_flags = flags;
@@ -1391,7 +2174,7 @@ pv_syncflags(pv0)
* in it to have PV_NC set, and we only remove one here.)
*/
/*static*/ void
-pv_unlink(pv, pm, va)
+pv_unlink4_4c(pv, pm, va)
register struct pvlist *pv;
register struct pmap *pm;
register vm_offset_t va;
@@ -1437,7 +2220,7 @@ pv_unlink(pv, pm, va)
if (BADALIAS(va, npv->pv_va))
return;
pv->pv_flags &= ~PV_NC;
- pv_changepte(pv, 0, PG_NC);
+ pv_changepte4_4c(pv, 0, PG_NC);
}
}
@@ -1447,7 +2230,7 @@ pv_unlink(pv, pm, va)
* be cached.
*/
/*static*/ int
-pv_link(pv, pm, va)
+pv_link4_4c(pv, pm, va)
register struct pvlist *pv;
register struct pmap *pm;
register vm_offset_t va;
@@ -1479,12 +2262,271 @@ pv_link(pv, pm, va)
if (BADALIAS(va, npv->pv_va)) {
#ifdef DEBUG
if (pmapdebug) printf(
- "pv_link: badalias: pid %d, %x<=>%x, pa %x\n",
+ "pv_link: badalias: pid %d, %lx<=>%x, pa %lx\n",
curproc?curproc->p_pid:-1, va, npv->pv_va,
vm_first_phys + (pv-pv_table)*NBPG);
#endif
pv->pv_flags |= PV_NC;
- pv_changepte(pv, ret = PG_NC, 0);
+ pv_changepte4_4c(pv, ret = PG_NC, 0);
+ break;
+ }
+ }
+ }
+ npv = (struct pvlist *)malloc(sizeof *npv, M_VMPVENT, M_WAITOK);
+ npv->pv_next = pv->pv_next;
+ npv->pv_pmap = pm;
+ npv->pv_va = va;
+ pv->pv_next = npv;
+ return (ret);
+}
+
+#endif /* sun4, sun4c code */
+
+#if defined(SUN4M) /* Sun4M versions of above */
+/*
+ * Walk the given pv list, and for each PTE, set or clear some bits
+ * (e.g., PG_W or PG_NC).
+ *
+ * As a special case, this never clears PG_W on `pager' pages.
+ * These, being kernel addresses, are always in hardware and have
+ * a context.
+ *
+ * This routine flushes the cache for any page whose PTE changes,
+ * as long as the process has a context; this is overly conservative.
+ * It also copies ref and mod bits to the pvlist, on the theory that
+ * this might save work later. (XXX should test this theory)
+ */
+void
+pv_changepte4m(pv0, bis, bic)
+ register struct pvlist *pv0;
+ register int bis, bic;
+{
+ register struct pvlist *pv;
+ register struct pmap *pm;
+ register int va, vr, flags;
+ int ctx, s;
+ struct regmap *rp;
+
+ write_user_windows(); /* paranoid? */
+
+ s = splpmap(); /* paranoid? */
+ if (pv0->pv_pmap == NULL) {
+ splx(s);
+ return;
+ }
+ ctx = getcontext();
+ flags = pv0->pv_flags;
+ for (pv = pv0; pv != NULL; pv = pv->pv_next) {
+ register int tpte;
+ pm = pv->pv_pmap;
+ if (pm == NULL)
+ panic("pv_changepte 1");
+ va = pv->pv_va;
+ vr = VA_VREG(va);
+ rp = &pm->pm_regmap[vr];
+ if (rp->rg_segmap == NULL)
+ panic("pv_changepte: no segments");
+
+ if (CTX_USABLE(pm,rp)) {
+ extern vm_offset_t pager_sva, pager_eva;
+
+ /*
+ * Bizarreness: we never clear PG_W on
+ * pager pages, nor set PG_C on DVMA pages.
+ */
+ if ((bic & PPROT_WRITE) &&
+ va >= pager_sva && va < pager_eva)
+ continue;
+ if ((bis & SRMMU_PG_C) &&
+ va >= DVMA_BASE && va < DVMA_END)
+ continue;
+ setcontext(pm->pm_ctxnum);
+ /* %%%: Do we need to always flush? */
+ tpte = getpte4m(va);
+ if (vactype != VAC_NONE && (tpte & SRMMU_PG_M))
+ cache_flush_page(va);
+ } else {
+ /* PTE that we want has no context. Use sw getpte*/
+ tpte = getptesw4m(pm, va);
+ }
+ if ((tpte & SRMMU_TETYPE) == SRMMU_TEPTE) /* i.e. if valid pte */
+ flags |= (tpte >> PG_M_SHIFT4M) & (PV_MOD4M|PV_REF4M|PV_C4M);
+
+ tpte = (tpte | bis) & ~bic;
+
+ if (CTX_USABLE(pm,rp))
+ setpte4m(va, tpte);
+ else
+ setptesw4m(pm, va, tpte);
+ }
+ pv0->pv_flags = flags;
+ setcontext(ctx);
+ splx(s);
+}
+
+/*
+ * Sync ref and mod bits in pvlist. If page has been ref'd or modified,
+ * update ref/mod bits in pvlist, and clear the hardware bits.
+ *
+ * Return the new flags.
+ */
+int
+pv_syncflags4m(pv0)
+ register struct pvlist *pv0;
+{
+ register struct pvlist *pv;
+ register struct pmap *pm;
+ register int tpte, va, vr, vs, flags;
+ int ctx, s;
+ struct regmap *rp;
+ struct segmap *sp;
+
+ write_user_windows(); /* paranoid? */
+
+ s = splpmap(); /* paranoid? */
+ if (pv0->pv_pmap == NULL) { /* paranoid */
+ splx(s);
+ return (0);
+ }
+ ctx = getcontext();
+ flags = pv0->pv_flags;
+ for (pv = pv0; pv != NULL; pv = pv->pv_next) {
+ pm = pv->pv_pmap;
+ va = pv->pv_va;
+ vr = VA_VREG(va);
+ vs = VA_VSEG(va);
+ rp = &pm->pm_regmap[vr];
+ if (rp->rg_segmap == NULL)
+ panic("pv_syncflags: no segments");
+ sp = &rp->rg_segmap[vs];
+
+ if (sp->sg_pte == NULL) /* invalid */
+ continue;
+
+ /*
+ * We need the PTE from memory as the TLB version will
+ * always have the SRMMU_PG_R bit on.
+ */
+ if (CTX_USABLE(pm,rp)) {
+ setcontext(pm->pm_ctxnum);
+ tlb_flush_page(va);
+ }
+ tpte = getptesw4m(pm, va);
+
+ if ((tpte & SRMMU_TETYPE) == SRMMU_TEPTE && /* if valid pte */
+ (tpte & (SRMMU_PG_M|SRMMU_PG_R))) { /* and mod/refd */
+ flags |= (tpte >> PG_M_SHIFT4M) &
+ (PV_MOD4M|PV_REF4M|PV_C4M);
+ tpte &= ~(SRMMU_PG_M | SRMMU_PG_R);
+ /* TLB has been invalidated, so just update memory */
+ setptesw4m(pm, va, tpte);
+ if (vactype != VAC_NONE &&
+ CTX_USABLE(pm,rp) && (tpte & SRMMU_PG_M))
+ cache_flush_page(va); /* XXX: do we need this?*/
+ }
+ }
+ pv0->pv_flags = flags;
+ setcontext(ctx);
+ splx(s);
+ return (flags);
+}
+
+void
+pv_unlink4m(pv, pm, va)
+ register struct pvlist *pv;
+ register struct pmap *pm;
+ register vm_offset_t va;
+{
+ register struct pvlist *npv;
+
+#ifdef DIAGNOSTIC
+ if (pv->pv_pmap == NULL)
+ panic("pv_unlink0");
+#endif
+ /*
+ * First entry is special (sigh).
+ */
+ npv = pv->pv_next;
+ if (pv->pv_pmap == pm && pv->pv_va == va) {
+ pmap_stats.ps_unlink_pvfirst++;
+ if (npv != NULL) {
+ pv->pv_next = npv->pv_next;
+ pv->pv_pmap = npv->pv_pmap;
+ pv->pv_va = npv->pv_va;
+ free(npv, M_VMPVENT);
+ } else
+ pv->pv_pmap = NULL;
+ } else {
+ register struct pvlist *prev;
+
+ for (prev = pv;; prev = npv, npv = npv->pv_next) {
+ pmap_stats.ps_unlink_pvsearch++;
+ if (npv == NULL)
+ panic("pv_unlink");
+ if (npv->pv_pmap == pm && npv->pv_va == va)
+ break;
+ }
+ prev->pv_next = npv->pv_next;
+ free(npv, M_VMPVENT);
+ }
+ if (!(pv->pv_flags & PV_C4M)) {
+ /*
+ * Not cached: check to see if we can fix that now.
+ */
+ va = pv->pv_va;
+ for (npv = pv->pv_next; npv != NULL; npv = npv->pv_next)
+ if (BADALIAS(va, npv->pv_va))
+ return;
+ pv->pv_flags |= PV_C4M;
+ pv_changepte4m(pv, SRMMU_PG_C, 0);
+ }
+}
+
+/*
+ * pv_link is the inverse of pv_unlink, and is used in pmap_enter.
+ * It returns SRMMU_PG_C if the (new) pvlist says that the address cannot
+ * be cached (i.e. its results must be (& ~)'d in.
+ */
+/*static*/ int
+pv_link4m(pv, pm, va)
+ register struct pvlist *pv;
+ register struct pmap *pm;
+ register vm_offset_t va;
+{
+ register struct pvlist *npv;
+ register int ret;
+
+ if (pv->pv_pmap == NULL) {
+ /* no pvlist entries yet */
+ pmap_stats.ps_enter_firstpv++;
+ pv->pv_next = NULL;
+ pv->pv_pmap = pm;
+ pv->pv_va = va;
+ pv->pv_flags |= PV_C4M;
+ return (0);
+ }
+ /*
+ * Before entering the new mapping, see if
+ * it will cause old mappings to become aliased
+ * and thus need to be `discached'.
+ */
+ ret = 0;
+ pmap_stats.ps_enter_secondpv++;
+ if (!(pv->pv_flags & PV_C4M)) {
+ /* already uncached, just stay that way */
+ ret = SRMMU_PG_C;
+ } else {
+ for (npv = pv; npv != NULL; npv = npv->pv_next) {
+ if (BADALIAS(va, npv->pv_va)) {
+#ifdef DEBUG
+ if (pmapdebug & PDB_CACHESTUFF) printf(
+ "pv_link: badalias: pid %d, %lx<=>%x, pa %lx\n",
+ curproc?curproc->p_pid:-1, va, npv->pv_va,
+ vm_first_phys + (pv-pv_table)*NBPG);
+#endif
+ pv->pv_flags &= ~PV_C4M;
+ pv_changepte4m(pv, 0, ret = SRMMU_PG_C);
+ /* cache_flush_page(va); XXX: needed? */
break;
}
}
@@ -1493,19 +2535,22 @@ pv_link(pv, pm, va)
npv->pv_next = pv->pv_next;
npv->pv_pmap = pm;
npv->pv_va = va;
+ npv->pv_flags |= (ret == SRMMU_PG_C ? 0 : PV_C4M);
pv->pv_next = npv;
return (ret);
}
+#endif
/*
* Walk the given list and flush the cache for each (MI) page that is
* potentially in the cache. Called only if vactype != VAC_NONE.
*/
+void
pv_flushcache(pv)
register struct pvlist *pv;
{
register struct pmap *pm;
- register int i, s, ctx;
+ register int s, ctx;
write_user_windows(); /* paranoia? */
@@ -1537,6 +2582,13 @@ pv_flushcache(pv)
int nptesg;
#endif
+#if defined(SUN4M)
+static void pmap_bootstrap4m __P((void));
+#endif
+#if defined(SUN4) || defined(SUN4C)
+static void pmap_bootstrap4_4c __P((int, int, int));
+#endif
+
/*
* Bootstrap the system enough to run with VM enabled.
*
@@ -1548,8 +2600,41 @@ void
pmap_bootstrap(nctx, nregion, nsegment)
int nsegment, nctx, nregion;
{
+
+ cnt.v_page_size = NBPG;
+ vm_set_page_size();
+
+#if defined(SUN4) && (defined(SUN4C) || defined(SUN4M))
+ /* In this case NPTESG is not a #define */
+ nptesg = (NBPSG >> pgshift);
+#endif
+
+ ncontext = nctx;
+
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ pmap_bootstrap4m();
+ return;
+ }
+#endif
+#if defined(SUN4) || defined(SUN4C)
+ if (CPU_ISSUN4OR4C) {
+ pmap_bootstrap4_4c(nctx, nregion, nsegment);
+ return;
+ }
+#endif
+}
+
+#if defined(SUN4) || defined(SUN4C)
+void
+pmap_bootstrap4_4c(nctx, nregion, nsegment)
+ int nsegment, nctx, nregion;
+{
register union ctxinfo *ci;
- register struct mmuentry *mmuseg, *mmureg;
+ register struct mmuentry *mmuseg;
+#ifdef MMU_3L
+ register struct mmuentry *mmureg;
+#endif
struct regmap *rp;
register int i, j;
register int npte, zseg, vr, vs;
@@ -1563,7 +2648,6 @@ pmap_bootstrap(nctx, nregion, nsegment)
extern char *esym;
char *theend = end;
#endif
- extern caddr_t reserve_dumppages(caddr_t);
switch (cputyp) {
case CPU_SUN4C:
@@ -1579,11 +2663,6 @@ pmap_bootstrap(nctx, nregion, nsegment)
cnt.v_page_size = NBPG;
vm_set_page_size();
-#if defined(SUN4) && defined(SUN4C)
- /* In this case NPTESG is not a #define */
- nptesg = (NBPSG >> pgshift);
-#endif
-
#if defined(SUN4)
/*
* set up the segfixmask to mask off invalid bits
@@ -1598,7 +2677,21 @@ pmap_bootstrap(nctx, nregion, nsegment)
#endif
#endif
- ncontext = nctx;
+#if defined(SUN4M) /* We're in a dual-arch kernel. Setup 4/4c fn. ptrs */
+ pmap_clear_modify_p = pmap_clear_modify4_4c;
+ pmap_clear_reference_p = pmap_clear_reference4_4c;
+ pmap_copy_page_p = pmap_copy_page4_4c;
+ pmap_enter_p = pmap_enter4_4c;
+ pmap_extract_p = pmap_extract4_4c;
+ pmap_is_modified_p = pmap_is_modified4_4c;
+ pmap_is_referenced_p = pmap_is_referenced4_4c;
+ pmap_page_protect_p = pmap_page_protect4_4c;
+ pmap_protect_p = pmap_protect4_4c;
+ pmap_zero_page_p = pmap_zero_page4_4c;
+ pmap_changeprot_p = pmap_changeprot4_4c;
+ pmap_rmk_p = pmap_rmk4_4c;
+ pmap_rmu_p = pmap_rmu4_4c;
+#endif /* defined SUN4M */
/*
* Last segment is the `invalid' one (one PMEG of pte's with !pg_v).
@@ -1640,7 +2733,7 @@ pmap_bootstrap(nctx, nregion, nsegment)
* (otherwise L1-A crashes the machine!).
*/
- mmu_reservemon(&nregion, &nsegment);
+ mmu_reservemon4_4c(&nregion, &nsegment);
#ifdef MMU_3L
/* Reserve one region for temporary mappings */
@@ -1828,7 +2921,7 @@ pmap_bootstrap(nctx, nregion, nsegment)
* the final segment.
*/
for (p += npte << PGSHIFT; npte < NPTESG; npte++, p += NBPG)
- setpte(p, 0);
+ setpte4(p, 0);
#ifdef MMU_3L
if (mmu_3l) {
@@ -1889,9 +2982,521 @@ pmap_bootstrap(nctx, nregion, nsegment)
#endif
for (p = (caddr_t)trapbase; p < etext; p += NBPG)
- setpte(p, getpte(p) & mask);
+ setpte4(p, getpte4(p) & mask);
+ }
+}
+#endif
+
+#if defined(SUN4M) /* Sun4M version of pmap_bootstrap */
+/*
+ * Bootstrap the system enough to run with VM enabled on a Sun4M machine.
+ *
+ * Switches from ROM to kernel page tables, and sets up initial mappings.
+ */
+static void
+pmap_bootstrap4m(void)
+{
+ register int i, j;
+ caddr_t p, p2;
+ register caddr_t q;
+ register union ctxinfo *ci;
+ register struct memarr *mp;
+ struct regmap *rmapp = NULL;
+ struct segmap *smapp = NULL;
+ register int reg, seg;
+#if 0
+ int nkreg, nkseg, nkpag, kernsize, newpgs;
+#endif
+ caddr_t kphyssegtbl, kphyspagtbl = NULL;
+ int deadfill, deadspace;
+ extern char end[];
+ extern char etext[];
+#ifdef DDB
+ extern char *esym;
+ char *theend = end;
+#endif
+ extern caddr_t reserve_dumppages(caddr_t);
+
+#if defined(SUN4) || defined(SUN4C) /* setup 4M fn. ptrs for dual-arch kernel */
+ pmap_clear_modify_p = pmap_clear_modify4m;
+ pmap_clear_reference_p = pmap_clear_reference4m;
+ pmap_copy_page_p = pmap_copy_page4m;
+ pmap_enter_p = pmap_enter4m;
+ pmap_extract_p = pmap_extract4m;
+ pmap_is_modified_p = pmap_is_modified4m;
+ pmap_is_referenced_p = pmap_is_referenced4m;
+ pmap_page_protect_p = pmap_page_protect4m;
+ pmap_protect_p = pmap_protect4m;
+ pmap_zero_page_p = pmap_zero_page4m;
+ pmap_changeprot_p = pmap_changeprot4m;
+ pmap_rmk_p = pmap_rmk4m;
+ pmap_rmu_p = pmap_rmu4m;
+#endif /* defined Sun4/Sun4c */
+
+ /*
+ * Intialize the kernel pmap.
+ */
+ /* kernel_pmap_store.pm_ctxnum = 0; */
+ simple_lock_init(kernel_pmap_store.pm_lock);
+ kernel_pmap_store.pm_refcount = 1;
+ /* Set up pm_regmap for kernel to point NUREG *below* the beginning
+ * of kernel regmap storage. Since the kernel only uses regions
+ * above NUREG, we save storage space and can index kernel and
+ * user regions in the same way
+ */
+ kernel_pmap_store.pm_regmap = &kernel_regmap_store[-NUREG];
+ kernel_pmap_store.pm_reg_ptps = NULL;
+ kernel_pmap_store.pm_reg_ptps_pa = 0;
+ bzero(kernel_regmap_store, NKREG * sizeof(struct regmap));
+ bzero(kernel_segmap_store, NKREG * NSEGRG * sizeof(struct segmap));
+ for (i = NKREG; --i >= 0;) {
+ kernel_regmap_store[i].rg_segmap =
+ &kernel_segmap_store[i * NSEGRG];
+ kernel_regmap_store[i].rg_seg_ptps = NULL;
+ for (j = NSEGRG; --j >= 0;)
+ kernel_segmap_store[i * NSEGRG + j].sg_pte = NULL;
+ }
+
+ p = end; /* p points to top of kernel mem */
+#ifdef DDB
+ if (esym != 0)
+ theend = p = esym;
+#endif
+
+ /*
+ * Preserve the monitor ROM's reserved VM region, so that
+ * we can use L1-A or the monitor's debugger.
+ */
+
+ mmu_reservemon4m(&kernel_pmap_store, &p);
+
+ pmap_kernel()->pm_ctx = ctxinfo = ci = (union ctxinfo *)p;
+ p += ncontext * sizeof *ci;
+ bzero((caddr_t)ctxinfo, (u_int)p - (u_int)ctxinfo);
+ ctxbusyvector = p;
+ p += ncontext;
+ bzero(ctxbusyvector, ncontext);
+ ctxbusyvector[0] = 1; /* context 0 is always in use */
+
+ /*
+ * reserve memory for I/O pagetables. This takes 64k of memory
+ * since we want to have 64M of dvma space (this actually depends
+ * on the definition of DVMA4M_BASE...we may drop it back to 32M)
+ * but since the table must be aligned, we might end up using
+ * as much as 128K. (note 1024 = NBPG / sizeof(iopte_t))
+ *
+ * We optimize with some space saving song and dance to
+ * squeeze other pagetables in the dead space.
+ */
+#ifdef DEBUG
+ if ((0 - DVMA4M_BASE) % (16*1024*1024))
+ panic("pmap_bootstrap4m: invalid DVMA4M_BASE of 0x%x",DVMA4M_BASE);
+#endif
+
+ deadfill = 0;
+ p = (caddr_t) roundup((u_int) p, max(SRMMU_L1SIZE * sizeof(long),
+ max(SRMMU_L2SIZE * sizeof(long),
+ SRMMU_L3SIZE * sizeof(long))));
+
+ deadspace = (int) (((caddr_t)roundup((u_int)p,
+ (0 - DVMA4M_BASE) / 1024)) - p);
+
+ if (deadspace >= SRMMU_L3SIZE * sizeof(long) * NKREG * NSEGRG) {
+ p = (caddr_t) roundup((u_int)p, SRMMU_L3SIZE * sizeof(long));
+ kernel_pagtable_store = (u_int *)p;
+ p += ((SRMMU_L3SIZE * sizeof(long)) * NKREG) * NSEGRG;
+ bzero(kernel_pagtable_store,
+ p - (caddr_t) kernel_pagtable_store);
+ deadfill |= 4;
+ deadspace -= (int)(p - (caddr_t) kernel_pagtable_store);
+ }
+ if (deadspace >= SRMMU_L2SIZE * sizeof(long) * NKREG) {
+ p = (caddr_t) roundup((u_int)p, SRMMU_L2SIZE * sizeof(long));
+ kernel_segtable_store = (u_int *)p;
+ p += (SRMMU_L2SIZE * sizeof(long)) * NKREG;
+ bzero(kernel_segtable_store,
+ p - (caddr_t) kernel_segtable_store);
+ deadfill |= 2;
+ deadspace -= (int)(p - (caddr_t) kernel_segtable_store);
+ }
+ if (deadspace >= SRMMU_L1SIZE * sizeof(long)) {
+ p = (caddr_t) roundup((u_int)p, SRMMU_L1SIZE * sizeof(long));
+ kernel_regtable_store = (u_int *)p;
+ p += SRMMU_L1SIZE * sizeof(long);
+ bzero(kernel_regtable_store,
+ p - (caddr_t) kernel_regtable_store);
+ deadfill |= 1;
+ deadspace -= (int)(p - (caddr_t) kernel_regtable_store);
+ }
+ if (deadspace < 0)
+ printf("pmap_bootstrap4m: botch in memory-saver\n");
+
+ p = (caddr_t) roundup((u_int)p, (0 - DVMA4M_BASE) / 1024);
+ kernel_iopte_table = (u_int *)p;
+ kernel_iopte_table_pa = VA2PA((caddr_t)kernel_iopte_table);
+ p += (0 - DVMA4M_BASE) / 1024;
+ bzero(kernel_iopte_table, p - (caddr_t) kernel_iopte_table);
+
+ /*
+ * reserve memory for segment and page tables needed to map the entire
+ * kernel (from regions 0xf8 -> 0xff). This takes 130k of space, but
+ * unfortunately is necessary since pmap_enk *must* be able to enter
+ * a kernel mapping without resorting to malloc, or else the
+ * possibility of deadlock arises (pmap_enk4m is called to enter a
+ * mapping; it needs to malloc a page table; malloc then calls
+ * pmap_enk4m to enter the new malloc'd page; pmap_enk4m needs to
+ * malloc a page table to enter _that_ mapping; malloc deadlocks since
+ * it is already allocating that object).
+ *
+ * We only do this if it wasn't done above...
+ */
+ if (!(deadfill & 2)) {
+ p = (caddr_t) roundup((u_int)p, SRMMU_L2SIZE * sizeof(long));
+ kernel_segtable_store = (u_int *)p;
+ p += (SRMMU_L2SIZE * sizeof(long)) * NKREG;
+ bzero(kernel_segtable_store,
+ p - (caddr_t) kernel_segtable_store);
+ }
+ if (!(deadfill & 4)) {
+ p = (caddr_t) roundup((u_int)p, SRMMU_L3SIZE * sizeof(long));
+ kernel_pagtable_store = (u_int *)p;
+ p += ((SRMMU_L3SIZE * sizeof(long)) * NKREG) * NSEGRG;
+ bzero(kernel_pagtable_store,
+ p - (caddr_t) kernel_pagtable_store);
+ }
+ if (!(deadfill & 1)) {
+ p = (caddr_t) roundup((u_int)p, SRMMU_L1SIZE * sizeof(long));
+ kernel_regtable_store = (u_int *)p;
+ p += SRMMU_L1SIZE * sizeof(long);
+ bzero(kernel_regtable_store,
+ p - (caddr_t) kernel_regtable_store);
+ }
+
+#if 0
+ /* At this point, "p" is the highest location of kernel memory that
+ * we need to lock in/map initially. We now need to calculate the
+ * size of this kernel image and allocate memory for its page tables,
+ * which we won't set up until the end of this function. After this
+ * point, it is NOT POSSIBLE to allocate kernel physical memory
+ * by bumping up p!!!
+ */
+ p = (caddr_t) roundup((u_int)p,SRMMU_L1SIZE * sizeof(long));
+ kernsize = (u_int)p - KERNBASE;
+
+ /* We keep adding pages until the number of added pages is sufficient
+ * to hold the map for both the kernel and the new pages. This
+ * converges since it takes at most about 1152 bytes to map one page.
+ */
+ newpgs = 0;
+ do {
+ newpgs++;
+ nkreg = (kernsize + (newpgs * NBPG) + NBPRG - 1) / NBPRG;
+ nkseg = (kernsize + (newpgs * NBPG) + NBPSG - 1) / NBPSG;
+ nkpag = (kernsize + NBPG - 1) / NBPG + newpgs;
+ } while (((SRMMU_L1SIZE + (nkreg * SRMMU_L2SIZE) +
+ (nkseg * SRMMU_L3SIZE) + (nkpag)) * sizeof(long)) >
+ newpgs * NBPG);
+
+ kernsize += newpgs * NBPG;
+ p2 = p; /* Page tables go from p2 to p. */
+ p += newpgs * NBPG; /* p is now the _real_ top of kernel mem. */
+#endif
+
+ /*
+ * Set up the `constants' for the call to vm_init()
+ * in main(). All pages beginning at p (rounded up to
+ * the next whole page) and continuing through the number
+ * of available pages are free, but they start at a higher
+ * virtual address. This gives us two mappable MD pages
+ * for pmap_zero_page and pmap_copy_page, and one MI page
+ * for /dev/mem, all with no associated physical memory.
+ */
+ p = (caddr_t)(((u_int)p + NBPG - 1) & ~PGOFSET);
+ avail_start = (int)p - KERNBASE;
+ /*
+ * Grab physical memory list, so pmap_next_page() can do its bit.
+ */
+ npmemarr = makememarr(pmemarr, MA_SIZE, MEMARR_AVAILPHYS);
+ sortm(pmemarr, npmemarr);
+ if (pmemarr[0].addr != 0) {
+ printf("pmap_bootstrap: no kernel memory?!\n");
+ callrom();
+ }
+ avail_end = pmemarr[npmemarr-1].addr + pmemarr[npmemarr-1].len;
+ avail_next = avail_start;
+ for (physmem = 0, mp = pmemarr, j = npmemarr; --j >= 0; mp++)
+ physmem += btoc(mp->len);
+
+ i = (int)p;
+ vpage[0] = p, p += NBPG;
+ vpage[1] = p, p += NBPG;
+ vmmap = p, p += NBPG;
+ p = reserve_dumppages(p);
+
+ /*
+ * Allocate virtual memory for pv_table[], which will be mapped
+ * sparsely in pmap_init().
+ */
+ pv_table = (struct pvlist *)p;
+ p += round_page(sizeof(struct pvlist) * atop(avail_end - avail_start));
+
+ virtual_avail = (vm_offset_t)p;
+ virtual_end = VM_MAX_KERNEL_ADDRESS;
+
+ p = (caddr_t)i; /* retract to first free phys */
+
+ /* Set up the ctxinfo structures (freelist of contexts)
+ */
+ ci->c_pmap = pmap_kernel();
+ ctx_freelist = ci + 1;
+ for (i = 1; i < ncontext; i++) {
+ ci++;
+ ci->c_nextfree = ci + 1;
+ }
+ ci->c_nextfree = NULL;
+ ctx_kick = 0;
+ ctx_kickdir = -1;
+
+ /* Now map the kernel into our new set of page tables, then
+ * (finally) switch over to our running page tables.
+ * We map from KERNBASE to p into context 0's page tables (and
+ * the kernel pmap).
+ */
+#ifdef DEBUG /* Sanity checks */
+ if ((u_int)p % NBPG != 0)
+ panic("pmap_bootstrap4m: p misaligned?!?");
+ if (KERNBASE % NBPRG != 0)
+ panic("pmap_bootstrap4m: KERNBASE not region-aligned");
+#endif
+ if (pmap_kernel()->pm_reg_ptps == NULL) {
+#ifdef DEBUG
+ printf("pmap_bootstrap4m: no kernel regiontable; creating.\n");
+#endif
+ pmap_kernel()->pm_reg_ptps = (int *) kernel_regtable_store;
+ pmap_kernel()->pm_reg_ptps_pa =
+ VA2PA((caddr_t)pmap_kernel()->pm_reg_ptps);
+ p2 = (caddr_t) pmap_kernel()->pm_reg_ptps +
+ (SRMMU_L1SIZE * sizeof(int));
+ bzero(pmap_kernel()->pm_reg_ptps, SRMMU_L1SIZE * sizeof(long));
+ }
+ reg = -1;
+ seg = -1;
+ for (q = (caddr_t) KERNBASE; q < p; q += NBPG) {
+ if ((VA_VSEG(q) % NSEGRG == 0) && VA_VREG(q) != reg) {
+ /* entering new region; install & build segtbl
+ * XXX: WE TRASH ANY EXISTING MAPPINGS IN THE KERNEL
+ * REGION. SHOULD BE FIXED!
+ */
+ reg = VA_VREG(q);
+ rmapp = &(pmap_kernel()->pm_regmap[reg]);
+ kphyssegtbl = (caddr_t)
+ &kernel_segtable_store[(reg - VA_VREG(KERNBASE)) *
+ SRMMU_L2SIZE];
+ bzero(kphyssegtbl, SRMMU_L2SIZE * sizeof(long));
+
+ ((int *)pmap_kernel()->pm_reg_ptps)[VA_VREG(q)] =
+ (VA2PA(kphyssegtbl) >> SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+
+ rmapp->rg_seg_ptps = (int *)kphyssegtbl;
+
+ if (rmapp->rg_segmap == NULL)
+ rmapp->rg_segmap = &kernel_segmap_store[(reg -
+ VA_VREG(KERNBASE)) * NSEGRG];
+ }
+ if (((VA_VPG(q) % NPTESG) == 0) && VA_VSEG(q) != seg) {
+ rmapp->rg_nsegmap++;
+ /* Entering new segment. XXX: trashes existing maps */
+ seg = VA_VSEG(q);
+ smapp = &(rmapp->rg_segmap[seg]);
+ kphyspagtbl = (caddr_t)
+ &kernel_pagtable_store[(((reg-VA_VREG(KERNBASE))*
+ NSEGRG) + seg)*SRMMU_L3SIZE];
+ bzero(kphyspagtbl, SRMMU_L3SIZE * sizeof(long));
+
+ rmapp->rg_seg_ptps[VA_VSEG(q)] =
+ (VA2PA(kphyspagtbl) >> SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+ smapp->sg_pte = (int *) kphyspagtbl;
+ }
+ /* Now install entry for current page. Cache and write-protect
+ * kernel text.
+ */
+ smapp->sg_npte++;
+ if (q == (caddr_t) KERNBASE) {
+ /* Must map in message buffer in low page. */
+ ((int *)kphyspagtbl)[VA_VPG(q)] = PPROT_N_RWX |
+ SRMMU_PG_C | SRMMU_TEPTE;
+ continue;
+ }
+ else if (q < (caddr_t) (KERNBASE+0x4000)) {
+ /* Special case: retain interrupt register mapping */
+ ((int *)kphyspagtbl)[VA_VPG(q)] =
+ getpte4m((vm_offset_t)q);
+ }
+ if (q >= (caddr_t) trapbase && q < etext)
+ ((int *)kphyspagtbl)[VA_VPG(q)] =
+ (VA2PA(q) >> SRMMU_PPNPASHIFT) |
+ PPROT_N_RX | SRMMU_PG_C | SRMMU_TEPTE;
+ else
+ ((int *)kphyspagtbl)[VA_VPG(q)] =
+ (VA2PA(q) >> SRMMU_PPNPASHIFT) |
+ PPROT_N_RWX | SRMMU_PG_C | SRMMU_TEPTE;
+ }
+
+ /*
+ * We must also create a segment table for region 0xfe and any
+ * needed page tables necessary to map the special (important)
+ * devices that get mapped at the beginning of this I/O segment.
+ * This is necessary since we have to map the interrupt registers
+ * at the start of region 0xfe in bootstrap().
+ *
+ * Since we've statically allocated space to map the entire kernel,
+ * we might as well pre-wire the mappings to save time in pmap_enter.
+ * This also gets around nasty problems with caching of L1/L2 ptp's.
+ *
+ * XXX WHY DO WE HAVE THIS CACHING PROBLEM WITH L1/L2 PTPS????? %%%
+ */
+ for (reg = VA_VREG(KERNBASE); reg < NKREG+VA_VREG(KERNBASE); reg++) {
+ rmapp = &(pmap_kernel()->pm_regmap[reg]);
+
+ if (((int *)pmap_kernel()->pm_reg_ptps)[reg] == NULL) {
+ kphyssegtbl = (caddr_t)
+ &kernel_segtable_store[(reg - VA_VREG(KERNBASE)) *
+ SRMMU_L2SIZE];
+ bzero(kphyssegtbl, SRMMU_L2SIZE * sizeof(long));
+ ((int *)pmap_kernel()->pm_reg_ptps)[reg] =
+ (VA2PA(kphyssegtbl) >> SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+
+ rmapp->rg_seg_ptps = (int *)kphyssegtbl;
+
+ if (rmapp->rg_segmap == NULL)
+ rmapp->rg_segmap = &kernel_segmap_store
+ [(reg - VA_VREG(KERNBASE)) * NSEGRG];
+ }
+ for (seg = 0; seg < NSEGRG; seg++) {
+ if (rmapp->rg_seg_ptps[seg] == NULL) {
+ rmapp->rg_nsegmap++;
+
+ smapp = &(rmapp->rg_segmap[seg]);
+ kphyspagtbl = (caddr_t)
+ &kernel_pagtable_store[(((reg-
+ VA_VREG(KERNBASE))*
+ NSEGRG) + seg)*
+ SRMMU_L3SIZE];
+ bzero(kphyspagtbl,
+ SRMMU_L3SIZE * sizeof(long));
+
+ rmapp->rg_seg_ptps[seg] =
+ (VA2PA(kphyspagtbl) >> SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD;
+ smapp->sg_pte = (int *) kphyspagtbl;
+ }
+ }
+ }
+
+ /*
+ * We also install the kernel mapping into all other contexts by
+ * copying the context 0 L1 PTP from ctx_phys_tbl[0] into the
+ * remainder of the context table (i.e. we share the kernel page-
+ * tables). Each user pmap automatically gets the kernel mapped
+ * into it when it is created, but we do this extra step early on
+ * in case some twit decides to switch to a context with no user
+ * pmap associated with it.
+ */
+ for (i = 1; i < ncontext; i++)
+ ctx_phys_tbl[i] = ctx_phys_tbl[0];
+
+ /*
+ * Now switch to kernel pagetables (finally!)
+ */
+#ifdef DEBUG
+ printf("pmap_bootstrap: installing kernel page tables...");
+#endif
+ setcontext(0); /* paranoia? %%%: Make 0x3 a define! below */
+
+ /* Enable MMU tablewalk caching, flush TLB */
+
+ i = lda(SRMMU_PCR, ASI_SRMMU);
+ switch(mmumod) {
+/* case SUN4M_MMU_MS: */ /* These have the same model # as SS */
+ case SUN4M_MMU_SS:
+ if ((cpumod & 0xf0) == (SUN4M_SS & 0xf0))
+ sta(SRMMU_PCR, ASI_SRMMU, (i | SRMMU_PCR_TC));
+ else /* microsparc */
+ printf("(if this doesn't work, "
+ "fix pmap_bootstrap4m in pmap.c)");
+ break;
+ case SUN4M_MMU_HS:
+ printf("(if this doesn't work, fix pmap_bootstrap4m in pmap.c)");
+ sta(SRMMU_PCR, ASI_SRMMU, (i | SRMMU_PCR_C) & ~SRMMU_PCR_CE);
+ /* above: CHECKFIX %%% below: add microsparc*/
+ break;
+ case SUN4M_MMU_MS1:
+ printf("(if this doesn't work, fix pmap_bootstrap4m in pmap.c)");
+ break;
+ default:
+ panic("Unimplemented MMU architecture %d",mmumod);
+ }
+
+ tlb_flush_all();
+
+ sta(SRMMU_CXTPTR, ASI_SRMMU,
+ (VA2PA((caddr_t)ctx_phys_tbl) >> SRMMU_PPNPASHIFT) & ~0x3);
+
+ tlb_flush_all();
+
+#ifdef DEBUG
+ printf("done.\n");
+#endif
+
+ /*
+ * On SuperSPARC machines without a MXCC, we *cannot* cache the
+ * page tables.
+ * XXX: this needs to be cleaned up with the cpu_softc stuff...
+ */
+ if (mmumod == SUN4M_MMU_SS &&
+ (lda(SRMMU_PCR, ASI_SRMMU) & SRMMU_PCR_MB)) {
+
+ int bytes, numpages;
+ cant_cache_pagetables = 1;
+
+#define DO_THE_MATH(math) \
+ bytes = (math); \
+ numpages = (bytes >> PGSHIFT) + (bytes % NBPG ? 1 : 0);
+
+ DO_THE_MATH(SRMMU_L3SIZE * sizeof(long) * NKREG * NSEGRG);
+#ifdef DEBUG
+ printf("pmap_bootstrap4m: uncaching %d PT pages at 0x%lx\n",
+ numpages, (long)kernel_pagtable_store);
+#endif
+ kvm_uncache((caddr_t)kernel_pagtable_store, numpages);
+
+ DO_THE_MATH(SRMMU_L2SIZE * sizeof(long) * NKREG);
+#ifdef DEBUG
+ printf("pmap_bootstrap4m: uncaching %d ST pages at 0x%lx\n",
+ numpages, (long)kernel_segtable_store);
+#endif
+ kvm_uncache((caddr_t)kernel_segtable_store, numpages);
+
+ DO_THE_MATH(SRMMU_L1SIZE * sizeof(long));
+#ifdef DEBUG
+ printf("pmap_bootstrap4m: uncaching %d RT pages at 0x%lx\n",
+ numpages, (long)kernel_regtable_store);
+#endif
+ kvm_uncache((caddr_t)kernel_regtable_store, numpages);
+
+#undef DO_THE_MATH
}
+
+#ifdef DEBUG
+ printf("\n"); /* Might as well make it pretty... */
+#endif
+
+ /* All done! */
}
+#endif /* defined sun4m */
void
pmap_init()
@@ -1900,7 +3505,7 @@ pmap_init()
int pass1, nmem;
register struct memarr *mp;
vm_offset_t sva, va, eva;
- vm_offset_t pa;
+ vm_offset_t pa = 0;
if (PAGE_SIZE != NBPG)
panic("pmap_init: CLSIZE!=1");
@@ -1932,17 +3537,23 @@ pass2:
len = sizeof(struct pvlist) * atop(len);
if (addr < avail_start || addr >= avail_end)
- panic("pmap_init: unmanaged address: 0x%x", addr);
+ panic("pmap_init: unmanaged address: 0x%lx", addr);
va = (vm_offset_t)&pv_table[atop(addr - avail_start)];
sva = trunc_page(va);
+
if (sva < eva) {
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(SUN4M)
+ /*
+ * crowded chunks are normal on SS20s; don't clutter
+ * screen with messages
+ */
printf("note: crowded chunk at 0x%x\n", mp->addr);
#endif
sva += PAGE_SIZE;
if (sva < eva)
- panic("pmap_init: sva(%x) < eva(%x)", sva, eva);
+ panic("pmap_init: sva(%lx) < eva(%lx)",
+ sva, eva);
}
eva = round_page(va + len);
if (pass1) {
@@ -2005,7 +3616,7 @@ pmap_create(size)
pm = (struct pmap *)malloc(sizeof *pm, M_VMPMAP, M_WAITOK);
#ifdef DEBUG
if (pmapdebug & PDB_CREATE)
- printf("pmap_create: created %x\n", pm);
+ printf("pmap_create: created %p\n", pm);
#endif
bzero((caddr_t)pm, sizeof *pm);
pmap_pinit(pm);
@@ -2020,30 +3631,60 @@ void
pmap_pinit(pm)
register struct pmap *pm;
{
- register int i, size;
+ register int size;
void *urp;
#ifdef DEBUG
if (pmapdebug & PDB_CREATE)
- printf("pmap_pinit(%x)\n", pm);
+ printf("pmap_pinit(%p)\n", pm);
#endif
size = NUREG * sizeof(struct regmap);
+
pm->pm_regstore = urp = malloc(size, M_VMPMAP, M_WAITOK);
- bzero((caddr_t)urp, size);
+ qzero((caddr_t)urp, size);
/* pm->pm_ctx = NULL; */
simple_lock_init(&pm->pm_lock);
pm->pm_refcount = 1;
-#ifdef MMU_3L
- TAILQ_INIT(&pm->pm_reglist);
-#endif
- TAILQ_INIT(&pm->pm_seglist);
pm->pm_regmap = urp;
+
+ if (CPU_ISSUN4OR4C) {
+ TAILQ_INIT(&pm->pm_seglist);
#ifdef MMU_3L
- if (mmu_3l)
- for (i = NUREG; --i >= 0;)
+ TAILQ_INIT(&pm->pm_reglist);
+ if (mmu_3l)
+ for (i = NUREG; --i >= 0;)
pm->pm_regmap[i].rg_smeg = reginval;
#endif
+ }
+#if defined(SUN4M)
+ else {
+ /*
+ * We must allocate and initialize hardware-readable (MMU)
+ * pagetables. We must also map the kernel regions into this
+ * pmap's pagetables, so that we can access the kernel from
+ * user mode!
+ *
+ * Note: pm->pm_regmap's have been zeroed already, so we don't
+ * need to explicitly mark them as invalid (a null
+ * rg_seg_ptps pointer indicates invalid for the 4m)
+ */
+ urp = malloc(SRMMU_L1SIZE * sizeof(int), M_VMPMAP, M_WAITOK);
+ if (cant_cache_pagetables)
+ kvm_uncache(urp,
+ ((SRMMU_L1SIZE*sizeof(int))+NBPG-1)/NBPG);
+
+#ifdef DEBUG
+ if ((u_int) urp % (SRMMU_L1SIZE * sizeof(int)))
+ panic("pmap_pinit: malloc() not giving aligned memory");
+#endif
+ pm->pm_reg_ptps = urp;
+ pm->pm_reg_ptps_pa = VA2PA(urp);
+ qzero(urp, SRMMU_L1SIZE * sizeof(int));
+
+ }
+#endif
+
pm->pm_gap_end = VA_VREG(VM_MAXUSER_ADDRESS);
return;
@@ -2063,7 +3704,7 @@ pmap_destroy(pm)
return;
#ifdef DEBUG
if (pmapdebug & PDB_DESTROY)
- printf("pmap_destroy(%x)\n", pm);
+ printf("pmap_destroy(%p)\n", pm);
#endif
simple_lock(&pm->pm_lock);
count = --pm->pm_refcount;
@@ -2087,22 +3728,27 @@ pmap_release(pm)
#ifdef DEBUG
if (pmapdebug & PDB_DESTROY)
- printf("pmap_release(%x)\n", pm);
+ printf("pmap_release(%p)\n", pm);
#endif
+
+ if (CPU_ISSUN4OR4C) {
#ifdef MMU_3L
- if (pm->pm_reglist.tqh_first)
- panic("pmap_release: region list not empty");
+ if (pm->pm_reglist.tqh_first)
+ panic("pmap_release: region list not empty");
#endif
- if (pm->pm_seglist.tqh_first)
- panic("pmap_release: segment list not empty");
- if ((c = pm->pm_ctx) != NULL) {
- if (pm->pm_ctxnum == 0)
- panic("pmap_release: releasing kernel");
- ctx_free(pm);
+ if (pm->pm_seglist.tqh_first)
+ panic("pmap_release: segment list not empty");
+
+ if ((c = pm->pm_ctx) != NULL) {
+ if (pm->pm_ctxnum == 0)
+ panic("pmap_release: releasing kernel");
+ ctx_free(pm);
+ }
}
splx(s);
+
#ifdef DEBUG
-{
+if (pmapdebug) {
int vs, vr;
for (vr = 0; vr < NUREG; vr++) {
struct regmap *rp = &pm->pm_regmap[vr];
@@ -2129,6 +3775,17 @@ pmap_release(pm)
#endif
if (pm->pm_regstore)
free(pm->pm_regstore, M_VMPMAP);
+
+ if (CPU_ISSUN4M) {
+ if ((c = pm->pm_ctx) != NULL) {
+ if (pm->pm_ctxnum == 0)
+ panic("pmap_release: releasing kernel");
+ ctx_free(pm);
+ }
+ free(pm->pm_reg_ptps, M_VMPMAP);
+ pm->pm_reg_ptps = NULL;
+ pm->pm_reg_ptps_pa = 0;
+ }
}
/*
@@ -2146,11 +3803,6 @@ pmap_reference(pm)
}
}
-static void pmap_rmk __P((struct pmap *, vm_offset_t, vm_offset_t,
- int, int));
-static void pmap_rmu __P((struct pmap *, vm_offset_t, vm_offset_t,
- int, int));
-
/*
* Remove the given range of mapping entries.
* The starting and ending addresses are already rounded to pages.
@@ -2171,7 +3823,7 @@ pmap_remove(pm, va, endva)
#ifdef DEBUG
if (pmapdebug & PDB_REMOVE)
- printf("pmap_remove(%x, %x, %x)\n", pm, va, endva);
+ printf("pmap_remove(%p, %lx, %lx)\n", pm, va, endva);
#endif
if (pm == pmap_kernel()) {
@@ -2225,9 +3877,11 @@ pmap_remove(pm, va, endva)
* These are egregiously complicated routines.
*/
+#if defined(SUN4) || defined(SUN4C)
+
/* remove from kernel */
-static void
-pmap_rmk(pm, va, endva, vr, vs)
+/*static*/ void
+pmap_rmk4_4c(pm, va, endva, vr, vs)
register struct pmap *pm;
register vm_offset_t va, endva;
register int vr, vs;
@@ -2274,24 +3928,24 @@ pmap_rmk(pm, va, endva, vr, vs)
perpage = (vactype != VAC_NONE);
}
while (va < endva) {
- tpte = getpte(va);
+ tpte = getpte4(va);
if ((tpte & PG_V) == 0) {
- va += PAGE_SIZE;
+ va += NBPG;
continue;
}
if ((tpte & PG_TYPE) == PG_OBMEM) {
/* if cacheable, flush page as needed */
if (perpage && (tpte & PG_NC) == 0)
cache_flush_page(va);
- i = ptoa(HWTOSW(tpte & PG_PFNUM));
+ i = ptoa(tpte & PG_PFNUM);
if (managed(i)) {
pv = pvhead(i);
- pv->pv_flags |= MR(tpte);
- pv_unlink(pv, pm, va);
+ pv->pv_flags |= MR4_4C(tpte);
+ pv_unlink4_4c(pv, pm, va);
}
}
nleft--;
- setpte(va, 0);
+ setpte4(va, 0);
va += NBPG;
}
@@ -2326,6 +3980,105 @@ pmap_rmk(pm, va, endva, vr, vs)
}
}
+#endif /* sun4, sun4c */
+
+#if defined(SUN4M) /* 4M version of pmap_rmk */
+/* remove from kernel (4m)*/
+/*static*/ void
+pmap_rmk4m(pm, va, endva, vr, vs)
+ register struct pmap *pm;
+ register vm_offset_t va, endva;
+ register int vr, vs;
+{
+ register int i, tpte, perpage, npg;
+ register struct pvlist *pv;
+ register int nleft;
+ struct regmap *rp;
+ struct segmap *sp;
+
+ rp = &pm->pm_regmap[vr];
+ sp = &rp->rg_segmap[vs];
+
+ if (rp->rg_nsegmap == 0)
+ return;
+
+#ifdef DEBUG
+ if (rp->rg_segmap == NULL)
+ panic("pmap_rmk: no segments");
+#endif
+
+ if ((nleft = sp->sg_npte) == 0)
+ return;
+
+#ifdef DEBUG
+ if (sp->sg_pte == NULL || rp->rg_seg_ptps == NULL)
+ panic("pmap_rmk: segment/region does not exist");
+ if (pm->pm_ctx == NULL)
+ panic("pmap_rmk: lost context");
+#endif
+
+ setcontext(0);
+ /* decide how to flush cache */
+ npg = (endva - va) >> PGSHIFT;
+ if (npg > PMAP_RMK_MAGIC) {
+ /* flush the whole segment */
+ perpage = 0;
+ if (vactype != VAC_NONE)
+ cache_flush_segment(vr, vs);
+ } else {
+ /* flush each page individually; some never need flushing */
+ perpage = (vactype != VAC_NONE);
+ }
+ while (va < endva) {
+ tpte = getpte4m(va);
+ if ((tpte & SRMMU_TETYPE) != SRMMU_TEPTE) {
+ va += NBPG;
+ continue;
+ }
+ if ((tpte & SRMMU_PGTYPE) == PG_SUN4M_OBMEM) {
+ /* if cacheable, flush page as needed */
+ if (perpage && (tpte & SRMMU_PG_C))
+ cache_flush_page(va);
+ i = ptoa((tpte & SRMMU_PPNMASK) >> SRMMU_PPNSHIFT);
+ if (managed(i)) {
+ pv = pvhead(i);
+ pv->pv_flags |= MR4M(tpte);
+ pv_unlink4m(pv, pm, va);
+ }
+ }
+ nleft--;
+ setpte4m(va, SRMMU_TEINVALID);
+ va += NBPG;
+ }
+
+ /*
+ * If the segment is all gone, remove it from everyone and
+ * flush the TLB.
+ */
+ if ((sp->sg_npte = nleft) == 0) {
+ va = VSTOVA(vr,vs); /* retract */
+
+ tlb_flush_segment(vr, vs); /* Paranoia? */
+
+ /*
+ * We need to free the segment table. The problem is that
+ * we can't free the initial (bootstrap) mapping, so
+ * we have to explicitly check for this case (ugh).
+ */
+ if (va < virtual_avail) {
+#ifdef DEBUG
+ printf("pmap_rmk4m: attempt to free base kernel alloc\n");
+#endif
+ /* sp->sg_pte = NULL; */
+ sp->sg_npte = 0;
+ return;
+ }
+ /* no need to free the table; it is statically allocated */
+ qzero(sp->sg_pte, SRMMU_L3SIZE * sizeof(long));
+ }
+ /* if we're done with a region, leave it wired */
+}
+#endif /* sun4m */
/*
* Just like pmap_rmk_magic, but we have a different threshold.
* Note that this may well deserve further tuning work.
@@ -2336,9 +4089,11 @@ pmap_rmk(pm, va, endva, vr, vs)
#define PMAP_RMU_MAGIC 4 /* if > magic, use cache_flush_segment */
#endif
+#if defined(SUN4) || defined(SUN4C)
+
/* remove from user */
-static void
-pmap_rmu(pm, va, endva, vr, vs)
+/*static*/ void
+pmap_rmu4_4c(pm, va, endva, vr, vs)
register struct pmap *pm;
register vm_offset_t va, endva;
register int vr, vs;
@@ -2371,16 +4126,16 @@ pmap_rmu(pm, va, endva, vr, vs)
/*
* PTEs are not in MMU. Just invalidate software copies.
*/
- for (; va < endva; pte++, va += PAGE_SIZE) {
+ for (; va < endva; pte++, va += NBPG) {
tpte = *pte;
if ((tpte & PG_V) == 0) {
/* nothing to remove (braindead VM layer) */
continue;
}
if ((tpte & PG_TYPE) == PG_OBMEM) {
- i = ptoa(HWTOSW(tpte & PG_PFNUM));
+ i = ptoa(tpte & PG_PFNUM);
if (managed(i))
- pv_unlink(pvhead(i), pm, va);
+ pv_unlink4_4c(pvhead(i), pm, va);
}
nleft--;
*pte = 0;
@@ -2433,23 +4188,23 @@ pmap_rmu(pm, va, endva, vr, vs)
pteva = VA_VPG(va) << PGSHIFT;
perpage = 0;
}
- for (; va < endva; pteva += PAGE_SIZE, va += PAGE_SIZE) {
- tpte = getpte(pteva);
+ for (; va < endva; pteva += NBPG, va += NBPG) {
+ tpte = getpte4(pteva);
if ((tpte & PG_V) == 0)
continue;
if ((tpte & PG_TYPE) == PG_OBMEM) {
/* if cacheable, flush page as needed */
if (perpage && (tpte & PG_NC) == 0)
cache_flush_page(va);
- i = ptoa(HWTOSW(tpte & PG_PFNUM));
+ i = ptoa(tpte & PG_PFNUM);
if (managed(i)) {
pv = pvhead(i);
- pv->pv_flags |= MR(tpte);
- pv_unlink(pv, pm, va);
+ pv->pv_flags |= MR4_4C(tpte);
+ pv_unlink4_4c(pv, pm, va);
}
}
nleft--;
- setpte(pteva, 0);
+ setpte4(pteva, 0);
#define PMAP_PTESYNC
#ifdef PMAP_PTESYNC
pte0[VA_VPG(pteva)] = 0;
@@ -2498,6 +4253,109 @@ if (pm->pm_ctx == NULL) {
}
}
+#endif /* sun4,4c */
+
+#if defined(SUN4M) /* 4M version of pmap_rmu */
+/* remove from user */
+/*static*/ void
+pmap_rmu4m(pm, va, endva, vr, vs)
+ register struct pmap *pm;
+ register vm_offset_t va, endva;
+ register int vr, vs;
+{
+ register int *pte0, i, tpte, perpage, npg;
+ register struct pvlist *pv;
+ register int nleft;
+ struct regmap *rp;
+ struct segmap *sp;
+
+ rp = &pm->pm_regmap[vr];
+ if (rp->rg_nsegmap == 0)
+ return;
+ if (rp->rg_segmap == NULL)
+ panic("pmap_rmu: no segments");
+
+ sp = &rp->rg_segmap[vs];
+ if ((nleft = sp->sg_npte) == 0)
+ return;
+ if (sp->sg_pte == NULL)
+ panic("pmap_rmu: no pages");
+
+ pte0 = sp->sg_pte;
+
+ /*
+ * Invalidate PTE in MMU pagetables. Flush cache if necessary.
+ */
+ if (CTX_USABLE(pm,rp)) {
+ /* process has a context, must flush cache */
+ setcontext(pm->pm_ctxnum);
+ if (vactype != VAC_NONE) {
+ npg = (endva - va) >> PGSHIFT;
+ if (npg > PMAP_RMU_MAGIC) {
+ perpage = 0; /* flush the whole segment */
+ cache_flush_segment(vr, vs);
+ } else
+ perpage = 1;
+ } else
+ perpage = 0;
+ } else {
+ /* no context; cache flush unnecessary */
+ perpage = 0;
+ }
+ for (; va < endva; va += NBPG) {
+ /* Note: we use sw pagetables here since pages have been
+ * flushed already. This avoids over-zealous cache flushing.
+ */
+ if (CTX_USABLE(pm,rp)) { /* %%% XXX: Performance hit? */
+ tpte = getpte4m(va); /* should we just flush seg? */
+ tlb_flush_page(va);
+ } else
+ tpte = getptesw4m(pm, va);
+ if ((tpte & SRMMU_TETYPE) != SRMMU_TEPTE)
+ continue;
+ if ((tpte & SRMMU_PGTYPE) == PG_SUN4M_OBMEM) {
+ /* if cacheable, flush page as needed */
+ if (perpage && (tpte & SRMMU_PG_C))
+ cache_flush_page(va);
+ i = ptoa((tpte & SRMMU_PPNMASK) >> SRMMU_PPNSHIFT);
+ if (managed(i)) {
+ pv = pvhead(i);
+ pv->pv_flags |= MR4M(tpte);
+ pv_unlink4m(pv, pm, va);
+ }
+ }
+ nleft--;
+ setptesw4m(pm, va, SRMMU_TEINVALID); /* Update pagetables */
+ }
+
+ /*
+ * If the segment is all gone, and the context is loaded, give
+ * the segment back.
+ */
+ if ((sp->sg_npte = nleft) == 0 /* ??? && pm->pm_ctx != NULL*/) {
+#ifdef DEBUG
+ if (pm->pm_ctx == NULL) {
+ printf("pmap_rmu: no context here...");
+ }
+#endif
+ va = VSTOVA(vr,vs); /* retract */
+
+ tlb_flush_segment(vr, vs); /* Paranoia? */
+ rp->rg_seg_ptps[vs] = SRMMU_TEINVALID;
+ free(pte0, M_VMPMAP);
+ sp->sg_pte = NULL;
+
+ if (--rp->rg_nsegmap == 0) {
+ free(rp->rg_segmap, M_VMPMAP);
+ rp->rg_segmap = NULL;
+ free(rp->rg_seg_ptps, M_VMPMAP);
+ pm->pm_reg_ptps[vr] = SRMMU_TEINVALID;
+ GAP_WIDEN(pm,vr);
+ }
+ }
+}
+#endif /* sun4m */
+
/*
* Lower (make more strict) the protection on the specified
* physical page.
@@ -2506,24 +4364,26 @@ if (pm->pm_ctx == NULL) {
* (in which case we do the dirty work here), or it is going from
* to read-only (in which case pv_changepte does the trick).
*/
+
+#if defined(SUN4) || defined(SUN4C)
void
-pmap_page_protect(pa, prot)
+pmap_page_protect4_4c(pa, prot)
vm_offset_t pa;
vm_prot_t prot;
{
register struct pvlist *pv, *pv0, *npv;
register struct pmap *pm;
register int va, vr, vs, pteva, tpte;
- register int flags, nleft, i, s, ctx, doflush;
+ register int flags, nleft, i, s, ctx;
struct regmap *rp;
struct segmap *sp;
#ifdef DEBUG
if (!pmap_pa_exists(pa))
- panic("pmap_page_protect: no such address: %x", pa);
+ panic("pmap_page_protect: no such address: %lx", pa);
if ((pmapdebug & PDB_CHANGEPROT) ||
(pmapdebug & PDB_REMOVE && prot == VM_PROT_NONE))
- printf("pmap_page_protect(%x, %x)\n", pa, prot);
+ printf("pmap_page_protect(%lx, %x)\n", pa, prot);
#endif
/*
* Skip unmanaged pages, or operations that do not take
@@ -2534,7 +4394,7 @@ pmap_page_protect(pa, prot)
return;
write_user_windows(); /* paranoia */
if (prot & VM_PROT_READ) {
- pv_changepte(pvhead(pa), 0, PG_W);
+ pv_changepte4_4c(pvhead(pa), 0, PG_W);
return;
}
@@ -2607,13 +4467,13 @@ pmap_page_protect(pa, prot)
pteva = VA_VPG(va) << PGSHIFT;
}
- tpte = getpte(pteva);
+ tpte = getpte4(pteva);
if ((tpte & PG_V) == 0)
panic("pmap_page_protect !PG_V");
- flags |= MR(tpte);
+ flags |= MR4_4C(tpte);
if (nleft) {
- setpte(pteva, 0);
+ setpte4(pteva, 0);
#ifdef PMAP_PTESYNC
if (sp->sg_pte != NULL)
sp->sg_pte[VA_VPG(pteva)] = 0;
@@ -2692,12 +4552,12 @@ pmap_page_protect(pa, prot)
* fairly easy.
*/
void
-pmap_protect(pm, sva, eva, prot)
+pmap_protect4_4c(pm, sva, eva, prot)
register struct pmap *pm;
vm_offset_t sva, eva;
vm_prot_t prot;
{
- register int va, nva, vr, vs, pteva;
+ register int va, nva, vr, vs;
register int s, ctx;
struct regmap *rp;
struct segmap *sp;
@@ -2758,14 +4618,14 @@ if (nva == 0) panic("pmap_protect: last segment"); /* cannot happen */
*/
setcontext(pm->pm_ctxnum);
for (; va < nva; va += NBPG) {
- tpte = getpte(va);
+ tpte = getpte4(va);
pmap_stats.ps_npg_prot_all++;
if ((tpte & (PG_W|PG_TYPE)) ==
(PG_W|PG_OBMEM)) {
pmap_stats.ps_npg_prot_actual++;
if (vactype != VAC_NONE)
cache_flush_page(va);
- setpte(va, tpte & ~PG_W);
+ setpte4(va, tpte & ~PG_W);
}
}
} else {
@@ -2784,7 +4644,7 @@ if (nva == 0) panic("pmap_protect: last segment"); /* cannot happen */
setsegmap(0, sp->sg_pmeg);
pteva = VA_VPG(va) << PGSHIFT;
for (; va < nva; pteva += NBPG, va += NBPG)
- setpte(pteva, getpte(pteva) & ~PG_W);
+ setpte4(pteva, getpte4(pteva) & ~PG_W);
}
}
}
@@ -2799,24 +4659,25 @@ if (nva == 0) panic("pmap_protect: last segment"); /* cannot happen */
* is changing.
*/
void
-pmap_changeprot(pm, va, prot, wired)
+pmap_changeprot4_4c(pm, va, prot, wired)
register struct pmap *pm;
register vm_offset_t va;
vm_prot_t prot;
int wired;
{
- register int vr, vs, tpte, newprot, ctx, i, s;
+ register int vr, vs, tpte, newprot, ctx, s;
struct regmap *rp;
struct segmap *sp;
#ifdef DEBUG
if (pmapdebug & PDB_CHANGEPROT)
- printf("pmap_changeprot(%x, %x, %x, %x)\n",
+ printf("pmap_changeprot(%p, %lx, %x, %x)\n",
pm, va, prot, wired);
#endif
write_user_windows(); /* paranoia */
+ va &= ~(NBPG-1);
if (pm == pmap_kernel())
newprot = prot & VM_PROT_WRITE ? PG_S|PG_W : PG_S;
else
@@ -2856,18 +4717,12 @@ pmap_changeprot(pm, va, prot, wired)
if (CTX_USABLE(pm,rp)) {
/* use current context; flush writeback cache */
setcontext(pm->pm_ctxnum);
- tpte = getpte(va);
+ tpte = getpte4(va);
if ((tpte & PG_PROT) == newprot) {
setcontext(ctx);
goto useless;
}
-
- /*
- * the latter check deals with a writethrough cache
- * problem on the 4/300
- */
- if ((vactype==VAC_WRITEBACK ||
- (vactype==VAC_WRITETHROUGH && cputyp==CPU_SUN4)) &&
+ if (vactype == VAC_WRITEBACK &&
(tpte & (PG_U|PG_NC|PG_TYPE)) == (PG_U|PG_OBMEM))
cache_flush_page((int)va);
} else {
@@ -2879,16 +4734,304 @@ pmap_changeprot(pm, va, prot, wired)
#endif
setsegmap(0, sp->sg_pmeg);
va = VA_VPG(va) << PGSHIFT;
- tpte = getpte(va);
+ tpte = getpte4(va);
if ((tpte & PG_PROT) == newprot) {
setcontext(ctx);
goto useless;
}
}
tpte = (tpte & ~PG_PROT) | newprot;
- setpte(va, tpte);
+ setpte4(va, tpte);
+ setcontext(ctx);
+ }
+ splx(s);
+ return;
+
+useless:
+ /* only wiring changed, and we ignore wiring */
+ pmap_stats.ps_useless_changeprots++;
+ splx(s);
+}
+
+#endif /* sun4, 4c */
+
+#if defined(SUN4M) /* 4M version of protection routines above */
+/*
+ * Lower (make more strict) the protection on the specified
+ * physical page.
+ *
+ * There are only two cases: either the protection is going to 0
+ * (in which case we do the dirty work here), or it is going
+ * to read-only (in which case pv_changepte does the trick).
+ */
+void
+pmap_page_protect4m(pa, prot)
+ vm_offset_t pa;
+ vm_prot_t prot;
+{
+ register struct pvlist *pv, *pv0, *npv;
+ register struct pmap *pm;
+ register int va, vr, vs, tpte;
+ register int flags, nleft, s, ctx;
+ struct regmap *rp;
+ struct segmap *sp;
+
+#ifdef DEBUG
+ if (!pmap_pa_exists(pa))
+ panic("pmap_page_protect: no such address: 0x%lx", pa);
+ if ((pmapdebug & PDB_CHANGEPROT) ||
+ (pmapdebug & PDB_REMOVE && prot == VM_PROT_NONE))
+ printf("pmap_page_protect(%lx, %x)\n", pa, prot);
+#endif
+ /*
+ * Skip unmanaged pages, or operations that do not take
+ * away write permission.
+ */
+ if (!managed(pa) || prot & VM_PROT_WRITE)
+ return;
+ write_user_windows(); /* paranoia */
+ if (prot & VM_PROT_READ) {
+ pv_changepte4m(pvhead(pa), 0, PPROT_WRITE);
+ return;
+ }
+
+ /*
+ * Remove all access to all people talking to this page.
+ * Walk down PV list, removing all mappings.
+ * The logic is much like that for pmap_remove,
+ * but we know we are removing exactly one page.
+ */
+ pv = pvhead(pa);
+ s = splpmap();
+ if ((pm = pv->pv_pmap) == NULL) {
+ splx(s);
+ return;
+ }
+ ctx = getcontext();
+ pv0 = pv;
+ flags = pv->pv_flags /*| PV_C4M*/; /* %%%: ???? */
+ for (;; pm = pv->pv_pmap) {
+ va = pv->pv_va;
+ vr = VA_VREG(va);
+ vs = VA_VSEG(va);
+ rp = &pm->pm_regmap[vr];
+ if (rp->rg_nsegmap == 0)
+ panic("pmap_remove_all: empty vreg");
+ sp = &rp->rg_segmap[vs];
+ if ((nleft = sp->sg_npte) == 0)
+ panic("pmap_remove_all: empty vseg");
+ nleft--;
+ sp->sg_npte = nleft;
+
+ /* Invalidate PTE in MMU pagetables. Flush cache if necessary */
+ if (CTX_USABLE(pm,rp)) { /* Must flush */
+ setcontext(pm->pm_ctxnum);
+ tpte = getpte4m(va);
+ if (vactype != VAC_NONE)
+ cache_flush_page(va);
+ tlb_flush_page(va);
+ } else
+ tpte = getptesw4m(pm, va);
+
+ if ((tpte & SRMMU_TETYPE) != SRMMU_TEPTE)
+ panic("pmap_page_protect !PG_V");
+ flags |= MR4M(tpte);
+
+ if (nleft)
+ setptesw4m(pm, va, SRMMU_TEINVALID);
+ else {
+ if (pm == pmap_kernel()) {
+ tlb_flush_segment(vr, vs); /* Paranoid? */
+ if (va < virtual_avail) {
+#ifdef DEBUG
+ printf("pmap_rmk4m: attempt to free "
+ "base kernel allocation\n");
+#endif
+ goto nextpv;
+ }
+ /* no need to free the table; it is static */
+ qzero(sp->sg_pte, SRMMU_L3SIZE * sizeof(int));
+
+ /* if we're done with a region, leave it */
+
+ } else { /* User mode mapping */
+ if (CTX_USABLE(pm,rp))
+ tlb_flush_segment(vr, vs);
+ rp->rg_seg_ptps[vs] = SRMMU_TEINVALID;
+ free(sp->sg_pte, M_VMPMAP);
+ sp->sg_pte = NULL;
+
+ if (--rp->rg_nsegmap == 0) {
+ free(rp->rg_segmap, M_VMPMAP);
+ rp->rg_segmap = NULL;
+ free(rp->rg_seg_ptps, M_VMPMAP);
+ pm->pm_reg_ptps[vr] = SRMMU_TEINVALID;
+ GAP_WIDEN(pm,vr);
+ }
+ }
+ }
+ nextpv:
+ npv = pv->pv_next;
+ if (pv != pv0)
+ free(pv, M_VMPVENT);
+ if ((pv = npv) == NULL)
+ break;
+ }
+ pv0->pv_pmap = NULL;
+ pv0->pv_next = NULL; /* ? */
+ pv0->pv_flags = flags;
+ setcontext(ctx);
+ splx(s);
+}
+
+/*
+ * Lower (make more strict) the protection on the specified
+ * range of this pmap.
+ *
+ * There are only two cases: either the protection is going to 0
+ * (in which case we call pmap_remove to do the dirty work), or
+ * it is going from read/write to read-only. The latter is
+ * fairly easy.
+ */
+void
+pmap_protect4m(pm, sva, eva, prot)
+ register struct pmap *pm;
+ vm_offset_t sva, eva;
+ vm_prot_t prot;
+{
+ register int va, nva, vr, vs;
+ register int s, ctx;
+ struct regmap *rp;
+ struct segmap *sp;
+
+ if (pm == NULL || prot & VM_PROT_WRITE)
+ return;
+
+ if ((prot & VM_PROT_READ) == 0) {
+ pmap_remove(pm, sva, eva);
+ return;
+ }
+
+ write_user_windows();
+ ctx = getcontext();
+ s = splpmap();
+ simple_lock(&pm->pm_lock);
+
+ for (va = sva; va < eva;) {
+ vr = VA_VREG(va);
+ vs = VA_VSEG(va);
+ rp = &pm->pm_regmap[vr];
+ nva = VSTOVA(vr,vs + 1);
+ if (nva == 0) /* XXX */
+ panic("pmap_protect: last segment"); /* cannot happen(why?)*/
+ if (nva > eva)
+ nva = eva;
+ if (rp->rg_nsegmap == 0) {
+ va = nva;
+ continue;
+ }
+#ifdef DEBUG
+ if (rp->rg_segmap == NULL)
+ panic("pmap_protect: no segments");
+#endif
+ sp = &rp->rg_segmap[vs];
+ if (sp->sg_npte == 0) {
+ va = nva;
+ continue;
+ }
+#ifdef DEBUG
+ if (sp->sg_pte == NULL)
+ panic("pmap_protect: no pages");
+#endif
+ /* in MMU: take away write bits from MMU PTEs */
+ if (CTX_USABLE(pm,rp)) {
+ /*
+ * Flush cache so that any existing cache
+ * tags are updated. This is really only
+ * needed for PTEs that lose PG_W.
+ */
+ setcontext(pm->pm_ctxnum);
+ for (; va < nva; va += NBPG) {
+ register int tpte = getpte4m(va);
+ pmap_stats.ps_npg_prot_all++;
+ if ((tpte & (PPROT_WRITE|SRMMU_PGTYPE)) ==
+ (PPROT_WRITE|PG_SUN4M_OBMEM)) {
+ pmap_stats.ps_npg_prot_actual++;
+ if (vactype != VAC_NONE)
+ cache_flush_page(va);
+ setpte4m(va, tpte & ~PPROT_WRITE);
+ }
+ }
+ } else {
+ /*
+ * No context, hence not cached;
+ * just update PTEs.
+ */
+ setcontext(0);
+ for (; va < nva; va += NBPG) {
+ register int tpte = getptesw4m(pm, va);
+ pmap_stats.ps_npg_prot_all++;
+ if ((tpte & (PPROT_WRITE)))
+ pmap_stats.ps_npg_prot_actual++;
+ setptesw4m(pm, va, tpte & ~PPROT_WRITE);
+ }
+ }
+ }
+ simple_unlock(&pm->pm_lock);
+ splx(s);
+ setcontext(ctx);
+}
+
+/*
+ * Change the protection and/or wired status of the given (MI) virtual page.
+ * XXX: should have separate function (or flag) telling whether only wiring
+ * is changing.
+ */
+void
+pmap_changeprot4m(pm, va, prot, wired)
+ register struct pmap *pm;
+ register vm_offset_t va;
+ vm_prot_t prot;
+ int wired;
+{
+ register int tpte, newprot, ctx, s;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_CHANGEPROT)
+ printf("pmap_changeprot(%p, %lx, %x, %x)\n",
+ pm, va, prot, wired);
+#endif
+
+ write_user_windows(); /* paranoia */
+
+ va &= ~(NBPG-1);
+ if (pm == pmap_kernel())
+ newprot = prot & VM_PROT_WRITE ? PPROT_N_RWX : PPROT_N_RX;
+ else
+ newprot = prot & VM_PROT_WRITE ? PPROT_RWX_RWX : PPROT_RX_RX;
+
+ pmap_stats.ps_changeprots++;
+
+ s = splpmap(); /* conservative */
+ ctx = getcontext();
+ if (pm->pm_ctx) {
+ setcontext(pm->pm_ctxnum);
+ tpte = getpte4m(va);
+ if (vactype == VAC_WRITEBACK &&
+ (tpte & SRMMU_PGTYPE) == PG_SUN4M_OBMEM)
+ cache_flush_page(va); /* XXX: paranoia? */
+ } else {
+ tpte = getptesw4m(pm, va);
+ }
+ if ((tpte & SRMMU_PROT_MASK) == newprot) {
setcontext(ctx);
+ goto useless;
}
+ if (pm->pm_ctx)
+ setpte4m(va, (tpte & ~SRMMU_PROT_MASK) | newprot);
+ else
+ setptesw4m(pm, va, (tpte & ~SRMMU_PROT_MASK) | newprot);
+ setcontext(ctx);
splx(s);
return;
@@ -2897,6 +5040,7 @@ useless:
pmap_stats.ps_useless_changeprots++;
splx(s);
}
+#endif /* 4m */
/*
* Insert (MI) physical page pa at virtual address va in the given pmap.
@@ -2910,8 +5054,11 @@ useless:
* changing protections and/or wiring on an existing mapping.
* XXX should have different entry points for changing!
*/
+
+#if defined(SUN4) || defined(SUN4C)
+
void
-pmap_enter(pm, va, pa, prot, wired)
+pmap_enter4_4c(pm, va, pa, prot, wired)
register struct pmap *pm;
vm_offset_t va, pa;
vm_prot_t prot;
@@ -2925,7 +5072,7 @@ pmap_enter(pm, va, pa, prot, wired)
if (VA_INHOLE(va)) {
#ifdef DEBUG
- printf("pmap_enter: pm %x, va %x, pa %x: in MMU hole\n",
+ printf("pmap_enter: pm %p, va %lx, pa %lx: in MMU hole\n",
pm, va, pa);
#endif
return;
@@ -2933,7 +5080,7 @@ pmap_enter(pm, va, pa, prot, wired)
#ifdef DEBUG
if (pmapdebug & PDB_ENTER)
- printf("pmap_enter(%x, %x, %x, %x, %x)\n",
+ printf("pmap_enter(%p, %lx, %lx, %x, %x)\n",
pm, va, pa, prot, wired);
#endif
@@ -2947,27 +5094,27 @@ pmap_enter(pm, va, pa, prot, wired)
if ((pteproto & PG_TYPE) == PG_OBMEM && managed(pa)) {
#ifdef DIAGNOSTIC
if (!pmap_pa_exists(pa))
- panic("pmap_enter: no such address: %x", pa);
+ panic("pmap_enter: no such address: %lx", pa);
#endif
- pteproto |= SWTOHW(atop(pa));
pv = pvhead(pa);
} else {
- pteproto |= atop(pa) & PG_PFNUM;
pv = NULL;
}
+ pteproto |= atop(pa) & PG_PFNUM;
if (prot & VM_PROT_WRITE)
pteproto |= PG_W;
ctx = getcontext();
if (pm == pmap_kernel())
- pmap_enk(pm, va, prot, wired, pv, pteproto | PG_S);
+ pmap_enk4_4c(pm, va, prot, wired, pv, pteproto | PG_S);
else
- pmap_enu(pm, va, prot, wired, pv, pteproto);
+ pmap_enu4_4c(pm, va, prot, wired, pv, pteproto);
setcontext(ctx);
}
/* enter new (or change existing) kernel mapping */
-pmap_enk(pm, va, prot, wired, pv, pteproto)
+void
+pmap_enk4_4c(pm, va, prot, wired, pv, pteproto)
register struct pmap *pm;
vm_offset_t va;
vm_prot_t prot;
@@ -3003,7 +5150,7 @@ pmap_enk(pm, va, prot, wired, pv, pteproto)
};
}
#endif
- if (sp->sg_pmeg != seginval && (tpte = getpte(va)) & PG_V) {
+ if (sp->sg_pmeg != seginval && (tpte = getpte4(va)) & PG_V) {
register int addr;
/* old mapping exists, and is of the same pa type */
@@ -3017,7 +5164,7 @@ pmap_enk(pm, va, prot, wired, pv, pteproto)
if ((tpte & PG_TYPE) == PG_OBMEM) {
#ifdef DEBUG
-printf("pmap_enk: changing existing va=>pa entry: va %x, pteproto %x\n",
+printf("pmap_enk: changing existing va=>pa entry: va %lx, pteproto %x\n",
va, pteproto);
#endif
/*
@@ -3025,9 +5172,9 @@ printf("pmap_enk: changing existing va=>pa entry: va %x, pteproto %x\n",
* If old pa was managed, remove from pvlist.
* If old page was cached, flush cache.
*/
- addr = ptoa(HWTOSW(tpte & PG_PFNUM));
+ addr = ptoa(tpte & PG_PFNUM);
if (managed(addr))
- pv_unlink(pvhead(addr), pm, va);
+ pv_unlink4_4c(pvhead(addr), pm, va);
if ((tpte & PG_NC) == 0) {
setcontext(0); /* ??? */
if (vactype != VAC_NONE)
@@ -3045,7 +5192,7 @@ printf("pmap_enk: changing existing va=>pa entry: va %x, pteproto %x\n",
* unique (hence will never cause a second call to malloc).
*/
if (pv != NULL)
- pteproto |= pv_link(pv, pm, va);
+ pteproto |= pv_link4_4c(pv, pm, va);
if (sp->sg_pmeg == seginval) {
register int tva;
@@ -3080,18 +5227,19 @@ printf("pmap_enk: changing existing va=>pa entry: va %x, pteproto %x\n",
tva = VA_ROUNDDOWNTOSEG(va);
i = NPTESG;
do {
- setpte(tva, 0);
+ setpte4(tva, 0);
tva += NBPG;
} while (--i > 0);
}
/* ptes kept in hardware only */
- setpte(va, pteproto);
+ setpte4(va, pteproto);
splx(s);
}
/* enter new (or change existing) user mapping */
-pmap_enu(pm, va, prot, wired, pv, pteproto)
+void
+pmap_enu4_4c(pm, va, prot, wired, pv, pteproto)
register struct pmap *pm;
vm_offset_t va;
vm_prot_t prot;
@@ -3140,7 +5288,7 @@ printf("pmap_enter: segment filled during sleep\n"); /* can this happen? */
free(sp, M_VMPMAP);
goto rretry;
}
- bzero((caddr_t)sp, size);
+ qzero((caddr_t)sp, size);
rp->rg_segmap = sp;
rp->rg_nsegmap = 0;
for (i = NSEGRG; --i >= 0;)
@@ -3164,7 +5312,7 @@ printf("pmap_enter: pte filled during sleep\n"); /* can this happen? */
if (sp->sg_pmeg != seginval)
panic("pmap_enter: new ptes, but not seginval");
#endif
- bzero((caddr_t)pte, size);
+ qzero((caddr_t)pte, size);
sp->sg_pte = pte;
sp->sg_npte = 1;
rp->rg_nsegmap++;
@@ -3178,7 +5326,7 @@ printf("pmap_enter: pte filled during sleep\n"); /* can this happen? */
/* hardware pte */
if (CTX_USABLE(pm,rp)) {
setcontext(pm->pm_ctxnum);
- tpte = getpte(va);
+ tpte = getpte4(va);
doflush = 1;
} else {
setcontext(0);
@@ -3188,7 +5336,7 @@ printf("pmap_enter: pte filled during sleep\n"); /* can this happen? */
setregmap(0, tregion);
#endif
setsegmap(0, pmeg);
- tpte = getpte(VA_VPG(va) << PGSHIFT);
+ tpte = getpte4(VA_VPG(va) << PGSHIFT);
}
}
if (tpte & PG_V) {
@@ -3200,7 +5348,7 @@ printf("pmap_enter: pte filled during sleep\n"); /* can this happen? */
/* just changing prot and/or wiring */
splx(s);
/* caller should call this directly: */
- pmap_changeprot(pm, va, prot, wired);
+ pmap_changeprot4_4c(pm, va, prot, wired);
if (wired)
pm->pm_stats.wired_count++;
else
@@ -3215,9 +5363,9 @@ printf("pmap_enter: pte filled during sleep\n"); /* can this happen? */
/*printf("%s[%d]: pmap_enu: changing existing va(%x)=>pa entry\n",
curproc->p_comm, curproc->p_pid, va);*/
if ((tpte & PG_TYPE) == PG_OBMEM) {
- addr = ptoa(HWTOSW(tpte & PG_PFNUM));
+ addr = ptoa(tpte & PG_PFNUM);
if (managed(addr))
- pv_unlink(pvhead(addr), pm, va);
+ pv_unlink4_4c(pvhead(addr), pm, va);
if (vactype != VAC_NONE &&
doflush && (tpte & PG_NC) == 0)
cache_flush_page((int)va);
@@ -3235,7 +5383,7 @@ curproc->p_comm, curproc->p_pid, va);*/
}
if (pv != NULL)
- pteproto |= pv_link(pv, pm, va);
+ pteproto |= pv_link4_4c(pv, pm, va);
/*
* Update hardware & software PTEs.
@@ -3254,7 +5402,7 @@ curproc->p_comm, curproc->p_pid, va);*/
setsegmap(0, pmeg);
va = VA_VPG(va) << PGSHIFT;
}
- setpte(va, pteproto);
+ setpte4(va, pteproto);
}
/* update software copy */
pte += VA_VPG(va);
@@ -3263,6 +5411,330 @@ curproc->p_comm, curproc->p_pid, va);*/
splx(s);
}
+#endif /*sun4,4c*/
+
+#if defined(SUN4M) /* Sun4M versions of enter routines */
+/*
+ * Insert (MI) physical page pa at virtual address va in the given pmap.
+ * NB: the pa parameter includes type bits PMAP_OBIO, PMAP_NC as necessary.
+ *
+ * If pa is not in the `managed' range it will not be `bank mapped'.
+ * This works during bootstrap only because the first 4MB happens to
+ * map one-to-one.
+ *
+ * There may already be something else there, or we might just be
+ * changing protections and/or wiring on an existing mapping.
+ * XXX should have different entry points for changing!
+ */
+
+void
+pmap_enter4m(pm, va, pa, prot, wired)
+ register struct pmap *pm;
+ vm_offset_t va, pa;
+ vm_prot_t prot;
+ int wired;
+{
+ register struct pvlist *pv;
+ register int pteproto, ctx;
+
+ if (pm == NULL)
+ return;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("pmap_enter(%p, %lx, %lx, %x, %x)\n",
+ pm, va, pa, prot, wired);
+#endif
+
+ /* Initialise pteproto with cache bit */
+ pteproto = (pa & PMAP_NC) == 0 ? SRMMU_PG_C : 0;
+
+ if (pa & PMAP_TYPE4M) { /* this page goes in an iospace */
+ if (cpumod == SUN4M_MS)
+ panic("pmap_enter4m: attempt to use 36-bit iospace on"
+ " MicroSPARC");
+ pteproto |= (pa & PMAP_TYPE4M) << PMAP_PTESHFT4M;
+ }
+
+ /* Make sure we get a pte with appropriate perms! */
+ pteproto |= SRMMU_TEPTE | PPROT_RX_RX;
+
+ pa &= ~PMAP_TNC;
+ /*
+ * Set up prototype for new PTE. Cannot set PG_NC from PV_NC yet
+ * since the pvlist no-cache bit might change as a result of the
+ * new mapping.
+ */
+ if ((pteproto & SRMMU_PGTYPE) == PG_SUN4M_OBMEM && managed(pa)) {
+#ifdef DIAGNOSTIC
+ if (!pmap_pa_exists(pa))
+ panic("pmap_enter: no such address: %lx", pa);
+#endif
+ pv = pvhead(pa);
+ } else {
+ pv = NULL;
+ }
+ pteproto |= (atop(pa) << SRMMU_PPNSHIFT);
+
+ if (prot & VM_PROT_WRITE)
+ pteproto |= PPROT_WRITE;
+
+ ctx = getcontext();
+
+ if (pm == pmap_kernel())
+ pmap_enk4m(pm, va, prot, wired, pv, pteproto | PPROT_S);
+ else
+ pmap_enu4m(pm, va, prot, wired, pv, pteproto);
+
+ setcontext(ctx);
+}
+
+/* enter new (or change existing) kernel mapping */
+void
+pmap_enk4m(pm, va, prot, wired, pv, pteproto)
+ register struct pmap *pm;
+ vm_offset_t va;
+ vm_prot_t prot;
+ int wired;
+ register struct pvlist *pv;
+ register int pteproto;
+{
+ register int vr, vs, tpte, s;
+ struct regmap *rp;
+ struct segmap *sp;
+
+#ifdef DEBUG
+ if (va < KERNBASE)
+ panic("pmap_enk4m: can't enter va 0x%lx below KERNBASE",va);
+#endif
+ vr = VA_VREG(va);
+ vs = VA_VSEG(va);
+ rp = &pm->pm_regmap[vr];
+ sp = &rp->rg_segmap[vs];
+
+ s = splpmap(); /* XXX way too conservative */
+
+ if (rp->rg_seg_ptps == NULL) /* enter new region */
+ panic("pmap_enk4m: missing kernel region table for va %lx",va);
+
+ if (((tpte = getpte4m(va)) & SRMMU_TETYPE) == SRMMU_TEPTE) {
+ register int addr;
+
+ /* old mapping exists, and is of the same pa type */
+
+ if ((tpte & SRMMU_PPNMASK) == (pteproto & SRMMU_PPNMASK)) {
+ /* just changing protection and/or wiring */
+ splx(s);
+ pmap_changeprot(pm, va, prot, wired);
+ return;
+ }
+
+ if ((tpte & SRMMU_PGTYPE) == PG_SUN4M_OBMEM) {
+#ifdef DEBUG
+printf("pmap_enk4m: changing existing va=>pa entry: va %lx, pteproto %x, "
+ "oldpte %x\n", va, pteproto, tpte);
+#endif
+ /*
+ * Switcheroo: changing pa for this va.
+ * If old pa was managed, remove from pvlist.
+ * If old page was cached, flush cache.
+ */
+ addr = ptoa((tpte & SRMMU_PPNMASK) >> SRMMU_PPNSHIFT);
+ if (managed(addr))
+ pv_unlink4m(pvhead(addr), pm, va);
+ if (tpte & SRMMU_PG_C) {
+ setcontext(0); /* ??? */
+ if (vactype != VAC_NONE)
+ cache_flush_page((int)va);
+ }
+ }
+ } else {
+ /* adding new entry */
+ sp->sg_npte++;
+ }
+
+ /*
+ * If the new mapping is for a managed PA, enter into pvlist.
+ * Note that the mapping for a malloc page will always be
+ * unique (hence will never cause a second call to malloc).
+ */
+ if (pv != NULL)
+ pteproto &= ~(pv_link4m(pv, pm, va));
+
+ if (sp->sg_pte == NULL) /* If no existing pagetable */
+ panic("pmap_enk4m: missing segment table for va 0x%lx",va);
+
+ /* ptes kept in hardware only */
+ setpte4m(va, pteproto);
+
+ splx(s);
+}
+
+/* enter new (or change existing) user mapping */
+void
+pmap_enu4m(pm, va, prot, wired, pv, pteproto)
+ register struct pmap *pm;
+ vm_offset_t va;
+ vm_prot_t prot;
+ int wired;
+ register struct pvlist *pv;
+ register int pteproto;
+{
+ register int vr, vs, *pte, tpte, s, doflush;
+ struct regmap *rp;
+ struct segmap *sp;
+
+ write_user_windows(); /* XXX conservative */
+ vr = VA_VREG(va);
+ vs = VA_VSEG(va);
+ rp = &pm->pm_regmap[vr];
+ s = splpmap(); /* XXX conservative */
+
+#ifdef DEBUG
+ if (pm->pm_gap_end < pm->pm_gap_start) {
+ printf("pmap_enu: gap_start %x, gap_end %x",
+ pm->pm_gap_start, pm->pm_gap_end);
+ panic("pmap_enu: gap botch");
+ }
+#endif
+
+rretry:
+ if (rp->rg_segmap == NULL) {
+ /* definitely a new mapping */
+ register int size = NSEGRG * sizeof (struct segmap);
+
+ sp = (struct segmap *)malloc((u_long)size, M_VMPMAP, M_WAITOK);
+ if (rp->rg_segmap != NULL) {
+#ifdef DEBUG
+printf("pmap_enu4m: segment filled during sleep\n"); /* can this happen? */
+#endif
+ free(sp, M_VMPMAP);
+ goto rretry;
+ }
+ qzero((caddr_t)sp, size);
+ rp->rg_segmap = sp;
+ rp->rg_nsegmap = 0;
+ rp->rg_seg_ptps = NULL;
+ }
+rgretry:
+ if (rp->rg_seg_ptps == NULL) {
+ /* Need a segment table */
+ register int size;
+ register caddr_t tblp;
+ size = SRMMU_L2SIZE * sizeof(long);
+ tblp = malloc(size, M_VMPMAP, M_WAITOK);
+ if (rp->rg_seg_ptps != NULL) {
+#ifdef DEBUG
+printf("pmap_enu4m: bizarre segment table fill during sleep\n");
+#endif
+ free(tblp,M_VMPMAP);
+ goto rgretry;
+ }
+ if (cant_cache_pagetables)
+ kvm_uncache(tblp, (size+NBPG-1)/NBPG);
+
+ rp->rg_seg_ptps = (int *)tblp;
+ qzero(tblp, size);
+ pm->pm_reg_ptps[vr] =
+ (VA2PA(tblp) >> SRMMU_PPNPASHIFT) | SRMMU_TEPTD;
+ }
+
+ sp = &rp->rg_segmap[vs];
+
+sretry:
+ if ((pte = sp->sg_pte) == NULL) {
+ /* definitely a new mapping */
+ register int size = SRMMU_L3SIZE * sizeof(*pte);
+
+ pte = (int *)malloc((u_long)size, M_VMPMAP, M_WAITOK);
+ if (sp->sg_pte != NULL) {
+printf("pmap_enter: pte filled during sleep\n"); /* can this happen? */
+ free(pte, M_VMPMAP);
+ goto sretry;
+ }
+ if (cant_cache_pagetables)
+ kvm_uncache((caddr_t)pte, (size+NBPG-1)/NBPG);
+
+ qzero((caddr_t)pte, size);
+ sp->sg_pte = pte;
+ sp->sg_npte = 1;
+ rp->rg_nsegmap++;
+ rp->rg_seg_ptps[vs] =
+ (VA2PA((caddr_t)pte) >> SRMMU_PPNPASHIFT) | SRMMU_TEPTD;
+ } else {
+ /* might be a change: fetch old pte */
+ doflush = 0;
+
+ if (CTX_USABLE(pm,rp)) {
+ setcontext(pm->pm_ctxnum);
+ tpte = getpte4m(va);
+ doflush = 1;
+ } else {
+ tpte = getptesw4m(pm, va);
+ }
+ if ((tpte & SRMMU_TETYPE) == SRMMU_TEPTE) {
+ register int addr;
+
+ /* old mapping exists, and is of the same pa type */
+ if ((tpte & SRMMU_PPNMASK) ==
+ (pteproto & SRMMU_PPNMASK)) {
+ /* just changing prot and/or wiring */
+ splx(s);
+ /* caller should call this directly: */
+ pmap_changeprot4m(pm, va, prot, wired);
+ if (wired)
+ pm->pm_stats.wired_count++;
+ else
+ pm->pm_stats.wired_count--;
+ return;
+ }
+ /*
+ * Switcheroo: changing pa for this va.
+ * If old pa was managed, remove from pvlist.
+ * If old page was cached, flush cache.
+ */
+#ifdef DEBUG
+if (pmapdebug & PDB_ENTER)
+printf("%s[%d]: pmap_enu: changing existing va(%x)=>pa(pte=%x) entry\n",
+curproc->p_comm, curproc->p_pid, (int)va, (int)pte);
+#endif
+ if ((tpte & SRMMU_PGTYPE) == PG_SUN4M_OBMEM) {
+ addr = ptoa( (tpte & SRMMU_PPNMASK) >>
+ SRMMU_PPNSHIFT);
+ if (managed(addr))
+ pv_unlink4m(pvhead(addr), pm, va);
+ if (vactype != VAC_NONE &&
+ doflush && (tpte & SRMMU_PG_C))
+ cache_flush_page((int)va);
+ }
+ } else {
+ /* adding new entry */
+ sp->sg_npte++;
+
+ /*
+ * Increment counters
+ */
+ if (wired)
+ pm->pm_stats.wired_count++;
+ }
+ }
+ if (pv != NULL)
+ pteproto &= ~(pv_link4m(pv, pm, va));
+
+ /*
+ * Update hardware & software PTEs.
+ */
+ if (CTX_USABLE(pm,rp)) {
+ setcontext(pm->pm_ctxnum);
+ setpte4m(va, pteproto);
+ } else
+ setptesw4m(pm, va, pteproto);
+ /* XXX: restore previous context here? */
+
+ splx(s);
+}
+#endif /* sun4m */
+
/*
* Change the wiring attribute for a map/virtual-address pair.
*/
@@ -3282,8 +5754,10 @@ pmap_change_wiring(pm, va, wired)
* with the given map/virtual_address pair.
* GRR, the vm code knows; we should not have to do this!
*/
+
+#if defined(SUN4) || defined(SUN4C)
vm_offset_t
-pmap_extract(pm, va)
+pmap_extract4_4c(pm, va)
register struct pmap *pm;
vm_offset_t va;
{
@@ -3309,16 +5783,16 @@ pmap_extract(pm, va)
register int ctx = getcontext();
if (CTX_USABLE(pm,rp)) {
- setcontext(pm->pm_ctxnum);
- tpte = getpte(va);
+ CHANGE_CONTEXTS(ctx, pm->pm_ctxnum);
+ tpte = getpte4(va);
} else {
- setcontext(0);
+ CHANGE_CONTEXTS(ctx, 0);
#ifdef MMU_3L
if (mmu_3l)
setregmap(0, tregion);
#endif
setsegmap(0, sp->sg_pmeg);
- tpte = getpte(VA_VPG(va) << PGSHIFT);
+ tpte = getpte4(VA_VPG(va) << PGSHIFT);
}
setcontext(ctx);
} else {
@@ -3335,9 +5809,48 @@ pmap_extract(pm, va)
return (0);
}
tpte &= PG_PFNUM;
- tpte = HWTOSW(tpte);
+ tpte = tpte;
return ((tpte << PGSHIFT) | (va & PGOFSET));
}
+#endif /*4,4c*/
+
+#if defined(SUN4M) /* 4m version of pmap_extract */
+/*
+ * Extract the physical page address associated
+ * with the given map/virtual_address pair.
+ * GRR, the vm code knows; we should not have to do this!
+ */
+vm_offset_t
+pmap_extract4m(pm, va)
+ register struct pmap *pm;
+ vm_offset_t va;
+{
+ register int tpte, ctx;
+
+ if (pm == NULL) {
+ printf("pmap_extract: null pmap\n");
+ return (0);
+ }
+
+ if (pm->pm_ctx) {
+ ctx = getcontext();
+ CHANGE_CONTEXTS(ctx, pm->pm_ctxnum);
+ tpte = getpte4m(va);
+#ifdef DEBUG
+ if ((tpte & SRMMU_TETYPE) != SRMMU_TEPTE) {
+ printf("pmap_extract: invalid pte of type %d\n",
+ tpte & SRMMU_TETYPE);
+ return (0);
+ }
+#endif
+ setcontext(ctx);
+ } else
+ tpte = getptesw4m(pm, va);
+
+
+ return (ptoa((tpte & SRMMU_PPNMASK) >> SRMMU_PPNSHIFT) | VA_OFF(va));
+}
+#endif /* sun4m */
/*
* Copy the range specified by src_addr/len
@@ -3354,6 +5867,24 @@ pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
vm_size_t len;
vm_offset_t src_addr;
{
+#if 0
+ if (CPU_ISSUN4M) {
+ register int i, pte;
+ for (i = 0; i < len/NBPG; i++) {
+ pte = getptesw4m(src_pmap, src_addr);
+ pmap_enter(dst_pmap, dst_addr,
+ ptoa((pte & SRMMU_PPNMASK) >>
+ SRMMU_PPNSHIFT) |
+ VA_OFF(src_addr),
+ (pte & PPROT_WRITE)
+ ? VM_PROT_WRITE| VM_PROT_READ
+ : VM_PROT_READ,
+ 0);
+ src_addr += NBPG;
+ dst_addr += NBPG;
+ }
+ }
+#endif
}
/*
@@ -3364,6 +5895,10 @@ pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
void
pmap_update()
{
+#if defined(SUN4M)
+ if (CPU_ISSUN4M)
+ tlb_flush_all(); /* %%%: Extreme Paranoia? */
+#endif
}
/*
@@ -3381,18 +5916,20 @@ pmap_collect(pm)
{
}
+#if defined(SUN4) || defined(SUN4C)
+
/*
* Clear the modify bit for the given physical page.
*/
void
-pmap_clear_modify(pa)
+pmap_clear_modify4_4c(pa)
register vm_offset_t pa;
{
register struct pvlist *pv;
if ((pa & (PMAP_TNC & ~PMAP_NC)) == 0 && managed(pa)) {
pv = pvhead(pa);
- (void) pv_syncflags(pv);
+ (void) pv_syncflags4_4c(pv);
pv->pv_flags &= ~PV_MOD;
}
}
@@ -3401,14 +5938,14 @@ pmap_clear_modify(pa)
* Tell whether the given physical page has been modified.
*/
int
-pmap_is_modified(pa)
+pmap_is_modified4_4c(pa)
register vm_offset_t pa;
{
register struct pvlist *pv;
if ((pa & (PMAP_TNC & ~PMAP_NC)) == 0 && managed(pa)) {
pv = pvhead(pa);
- if (pv->pv_flags & PV_MOD || pv_syncflags(pv) & PV_MOD)
+ if (pv->pv_flags & PV_MOD || pv_syncflags4_4c(pv) & PV_MOD)
return (1);
}
return (0);
@@ -3418,14 +5955,14 @@ pmap_is_modified(pa)
* Clear the reference bit for the given physical page.
*/
void
-pmap_clear_reference(pa)
+pmap_clear_reference4_4c(pa)
vm_offset_t pa;
{
register struct pvlist *pv;
if ((pa & (PMAP_TNC & ~PMAP_NC)) == 0 && managed(pa)) {
pv = pvhead(pa);
- (void) pv_syncflags(pv);
+ (void) pv_syncflags4_4c(pv);
pv->pv_flags &= ~PV_REF;
}
}
@@ -3434,18 +5971,97 @@ pmap_clear_reference(pa)
* Tell whether the given physical page has been referenced.
*/
int
-pmap_is_referenced(pa)
+pmap_is_referenced4_4c(pa)
vm_offset_t pa;
{
register struct pvlist *pv;
if ((pa & (PMAP_TNC & ~PMAP_NC)) == 0 && managed(pa)) {
pv = pvhead(pa);
- if (pv->pv_flags & PV_REF || pv_syncflags(pv) & PV_REF)
+ if (pv->pv_flags & PV_REF || pv_syncflags4_4c(pv) & PV_REF)
return (1);
}
return (0);
}
+#endif /*4,4c*/
+
+#if defined(SUN4M)
+
+/*
+ * 4m versions of bit test/set routines
+ *
+ * Note that the 4m-specific routines should eventually service these
+ * requests from their page tables, and the whole pvlist bit mess should
+ * be dropped for the 4m (unless this causes a performance hit from
+ * tracing down pagetables/regmap/segmaps).
+ */
+
+/*
+ * Clear the modify bit for the given physical page.
+ */
+void
+pmap_clear_modify4m(pa) /* XXX %%%: Should service from swpagetbl for 4m */
+ register vm_offset_t pa;
+{
+ register struct pvlist *pv;
+
+ if ((pa & (PMAP_TNC & ~PMAP_NC)) == 0 && managed(pa)) {
+ pv = pvhead(pa);
+ (void) pv_syncflags4m(pv);
+ pv->pv_flags &= ~PV_MOD4M;
+ }
+}
+
+/*
+ * Tell whether the given physical page has been modified.
+ */
+int
+pmap_is_modified4m(pa) /* Test performance with SUN4M && SUN4/4C. XXX */
+ register vm_offset_t pa;
+{
+ register struct pvlist *pv;
+
+ if ((pa & (PMAP_TNC & ~PMAP_NC)) == 0 && managed(pa)) {
+ pv = pvhead(pa);
+ if (pv->pv_flags & PV_MOD4M || pv_syncflags4m(pv) & PV_MOD4M)
+ return(1);
+ }
+ return (0);
+}
+
+/*
+ * Clear the reference bit for the given physical page.
+ */
+void
+pmap_clear_reference4m(pa)
+ vm_offset_t pa;
+{
+ register struct pvlist *pv;
+
+ if ((pa & (PMAP_TNC & ~PMAP_NC)) == 0 && managed(pa)) {
+ pv = pvhead(pa);
+ (void) pv_syncflags4m(pv);
+ pv->pv_flags &= ~PV_REF4M;
+ }
+}
+
+/*
+ * Tell whether the given physical page has been referenced.
+ */
+int
+pmap_is_referenced4m(pa)
+ vm_offset_t pa;
+{
+ register struct pvlist *pv;
+
+ if ((pa & (PMAP_TNC & ~PMAP_NC)) == 0 && managed(pa)) {
+ pv = pvhead(pa);
+ if (pv->pv_flags & PV_REF4M || pv_syncflags4m(pv) & PV_REF4M)
+ return(1);
+ }
+ return (0);
+}
+#endif /* 4m */
/*
* Make the specified pages (by pmap, offset) pageable (or not) as requested.
@@ -3472,8 +6088,11 @@ pmap_pageable(pm, start, end, pageable)
* We avoid stomping on the cache.
* XXX might be faster to use destination's context and allow cache to fill?
*/
+
+#if defined(SUN4) || defined(SUN4C)
+
void
-pmap_zero_page(pa)
+pmap_zero_page4_4c(pa)
register vm_offset_t pa;
{
register caddr_t va;
@@ -3487,14 +6106,13 @@ pmap_zero_page(pa)
*/
if (vactype != VAC_NONE)
pv_flushcache(pvhead(pa));
- pte = PG_V | PG_S | PG_W | PG_NC | SWTOHW(atop(pa));
- } else
- pte = PG_V | PG_S | PG_W | PG_NC | (atop(pa) & PG_PFNUM);
+ }
+ pte = PG_V | PG_S | PG_W | PG_NC | (atop(pa) & PG_PFNUM);
va = vpage[0];
- setpte(va, pte);
+ setpte4(va, pte);
qzero(va, NBPG);
- setpte(va, 0);
+ setpte4(va, 0);
}
/*
@@ -3507,7 +6125,7 @@ pmap_zero_page(pa)
* the processor.
*/
void
-pmap_copy_page(src, dst)
+pmap_copy_page4_4c(src, dst)
vm_offset_t src, dst;
{
register caddr_t sva, dva;
@@ -3516,28 +6134,101 @@ pmap_copy_page(src, dst)
if (managed(src)) {
if (vactype == VAC_WRITEBACK)
pv_flushcache(pvhead(src));
- spte = PG_V | PG_S | SWTOHW(atop(src));
- } else
- spte = PG_V | PG_S | (atop(src) & PG_PFNUM);
+ }
+ spte = PG_V | PG_S | (atop(src) & PG_PFNUM);
if (managed(dst)) {
/* similar `might not be necessary' comment applies */
if (vactype != VAC_NONE)
pv_flushcache(pvhead(dst));
- dpte = PG_V | PG_S | PG_W | PG_NC | SWTOHW(atop(dst));
- } else
- dpte = PG_V | PG_S | PG_W | PG_NC | (atop(dst) & PG_PFNUM);
+ }
+ dpte = PG_V | PG_S | PG_W | PG_NC | (atop(dst) & PG_PFNUM);
sva = vpage[0];
dva = vpage[1];
- setpte(sva, spte);
- setpte(dva, dpte);
+ setpte4(sva, spte);
+ setpte4(dva, dpte);
qcopy(sva, dva, NBPG); /* loads cache, so we must ... */
if (vactype != VAC_NONE)
cache_flush_page((int)sva);
- setpte(sva, 0);
- setpte(dva, 0);
+ setpte4(sva, 0);
+ setpte4(dva, 0);
}
+#endif /* 4, 4c */
+
+#if defined(SUN4M) /* Sun4M version of copy/zero routines */
+/*
+ * Fill the given MI physical page with zero bytes.
+ *
+ * We avoid stomping on the cache.
+ * XXX might be faster to use destination's context and allow cache to fill?
+ */
+void
+pmap_zero_page4m(pa)
+ register vm_offset_t pa;
+{
+ register caddr_t va;
+ register int pte;
+
+ if (((pa & (PMAP_TNC & ~PMAP_NC)) == 0) && managed(pa)) {
+ /*
+ * The following might not be necessary since the page
+ * is being cleared because it is about to be allocated,
+ * i.e., is in use by no one.
+ */
+ if (vactype != VAC_NONE)
+ pv_flushcache(pvhead(pa));
+ }
+ pte = ~SRMMU_PG_C & (SRMMU_TEPTE | PPROT_S | PPROT_WRITE |
+ (atop(pa) << SRMMU_PPNSHIFT));
+ va = vpage[0];
+ setpte4m((vm_offset_t) va, pte);
+ qzero(va, NBPG);
+ setpte4m((vm_offset_t) va, SRMMU_TEINVALID);
+}
+
+/*
+ * Copy the given MI physical source page to its destination.
+ *
+ * We avoid stomping on the cache as above (with same `XXX' note).
+ * We must first flush any write-back cache for the source page.
+ * We go ahead and stomp on the kernel's virtual cache for the
+ * source page, since the cache can read memory MUCH faster than
+ * the processor.
+ */
+void
+pmap_copy_page4m(src, dst)
+ vm_offset_t src, dst;
+{
+ register caddr_t sva, dva;
+ register int spte, dpte;
+
+ if (managed(src)) {
+ if (vactype == VAC_WRITEBACK)
+ pv_flushcache(pvhead(src));
+ }
+ spte = SRMMU_TEPTE | SRMMU_PG_C | PPROT_S |
+ (atop(src) << SRMMU_PPNSHIFT);
+
+ if (managed(dst)) {
+ /* similar `might not be necessary' comment applies */
+ if (vactype != VAC_NONE)
+ pv_flushcache(pvhead(dst));
+ }
+ dpte = ~SRMMU_PG_C & (SRMMU_TEPTE | PPROT_S | PPROT_WRITE |
+ (atop(dst) << SRMMU_PPNSHIFT));
+
+ sva = vpage[0];
+ dva = vpage[1];
+ setpte4m((vm_offset_t) sva, spte);
+ setpte4m((vm_offset_t) dva, dpte);
+ qcopy(sva, dva, NBPG); /* loads cache, so we must ... */
+ if (vactype != VAC_NONE)
+ cache_flush_page((int)sva);
+ setpte4m((vm_offset_t) sva, SRMMU_TEINVALID);
+ setpte4m((vm_offset_t) dva, SRMMU_TEINVALID);
+}
+#endif /* Sun4M */
/*
* Turn a cdevsw d_mmap value into a byte address for pmap_enter.
@@ -3558,20 +6249,36 @@ pmap_phys_address(x)
* We just assert PG_NC for each PTE; the addresses must reside
* in locked kernel space. A cache flush is also done.
*/
+void
kvm_uncache(va, npages)
register caddr_t va;
register int npages;
{
register int pte;
-
- for (; --npages >= 0; va += NBPG) {
- pte = getpte(va);
- if ((pte & PG_V) == 0)
- panic("kvm_uncache !pg_v");
- pte |= PG_NC;
- setpte(va, pte);
- if (vactype != VAC_NONE && (pte & PG_TYPE) == PG_OBMEM)
- cache_flush_page((int)va);
+ if (CPU_ISSUN4M) {
+#if defined(SUN4M)
+ for (; --npages >= 0; va += NBPG) {
+ pte = getpte4m((vm_offset_t) va);
+ if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
+ panic("kvm_uncache: table entry not pte");
+ pte &= ~SRMMU_PG_C;
+ setpte4m((vm_offset_t) va, pte);
+ if (vactype != VAC_NONE && (pte & PG_TYPE) == PG_OBMEM)
+ cache_flush_page((int)va);
+ }
+#endif
+ } else {
+#if defined(SUN4) || defined(SUN4C)
+ for (; --npages >= 0; va += NBPG) {
+ pte = getpte4(va);
+ if ((pte & PG_V) == 0)
+ panic("kvm_uncache !pg_v");
+ pte |= PG_NC;
+ setpte4(va, pte);
+ if (vactype != VAC_NONE && (pte & PG_TYPE) == PG_OBMEM)
+ cache_flush_page((int)va);
+ }
+#endif
}
}
@@ -3581,19 +6288,25 @@ kvm_uncache(va, npages)
* We just assert PG_NC for each PTE; the addresses must reside
* in locked kernel space. A cache flush is also done.
*/
+void
kvm_iocache(va, npages)
register caddr_t va;
register int npages;
{
- register int pte;
+#ifdef SUN4M
+ if (CPU_ISSUN4M) /* %%%: Implement! */
+ panic("kvm_iocache: 4m iocache not implemented");
+#endif
+#if defined(SUN4) || defined(SUN4C)
for (; --npages >= 0; va += NBPG) {
- pte = getpte(va);
+ register int pte = getpte4(va);
if ((pte & PG_V) == 0)
panic("kvm_iocache !pg_v");
pte |= PG_IOC;
- setpte(va, pte);
+ setpte4(va, pte);
}
+#endif
}
int
@@ -3619,62 +6332,52 @@ pmap_count_ptes(pm)
}
/*
- * Find first virtual address >= va that doesn't cause
- * a cache alias on physical address pa.
+ * Find first virtual address >= *va that is
+ * least likely to cause cache aliases.
+ * (This will just seg-align mappings.)
*/
-vm_offset_t
-pmap_prefer(pa, va)
- register vm_offset_t pa;
- register vm_offset_t va;
+void
+pmap_prefer(foff, vap)
+ register vm_offset_t foff;
+ register vm_offset_t *vap;
{
- register struct pvlist *pv;
- register long m, d;
+ register vm_offset_t va = *vap;
+ register long d, m;
+
+ if (VA_INHOLE(va))
+ va = MMU_HOLE_END;
m = CACHE_ALIAS_DIST;
if (m == 0) /* m=0 => no cache aliasing */
- return (va);
-
- if (pa == (vm_offset_t)-1) {
- /*
- * Do not consider physical address. Just return
- * a cache aligned address.
- */
- if (VA_INHOLE(va))
- va = MMU_HOLE_END;
-
- /* XXX - knowledge about `exec' formats; can we get by without? */
- va -= USRTEXT;
- va = (va + m - 1) & ~(m - 1);
- return (va + USRTEXT);
- }
-
- if ((pa & (PMAP_TNC & ~PMAP_NC)) || !managed(pa))
- return va;
-
- pv = pvhead(pa);
- if (pv->pv_pmap == NULL) {
- /* Unusable, tell caller to try another one */
- return (vm_offset_t)-1;
- }
-
- d = (long)(pv->pv_va & (m - 1)) - (long)(va & (m - 1));
- if (d < 0)
- va += m;
- va += d;
+ return;
- return va;
+ d = foff - va;
+ d &= (m - 1);
+ *vap = va + d;
}
+void
pmap_redzone()
{
- setpte(KERNBASE, 0);
+#if defined(SUN4M)
+ if (CPU_ISSUN4M) {
+ setpte4m(KERNBASE, 0);
+ return;
+ }
+#endif
+#if defined(SUN4) || defined(SUN4C)
+ if (CPU_ISSUN4OR4C) {
+ setpte4(KERNBASE, 0);
+ return;
+ }
+#endif
}
#ifdef DEBUG
/*
* Check consistency of a pmap (time consuming!).
*/
-int
+void
pm_check(s, pm)
char *s;
struct pmap *pm;
@@ -3685,7 +6388,7 @@ pm_check(s, pm)
pm_check_u(s, pm);
}
-int
+void
pm_check_u(s, pm)
char *s;
struct pmap *pm;
@@ -3694,6 +6397,24 @@ pm_check_u(s, pm)
struct segmap *sp;
int n, vs, vr, j, m, *pte;
+ if (pm->pm_regmap == NULL)
+ panic("%s: CHK(pmap %p): no region mapping", s, pm);
+
+#if defined(SUN4M)
+ if (CPU_ISSUN4M &&
+ (pm->pm_reg_ptps == NULL ||
+ pm->pm_reg_ptps_pa != VA2PA((caddr_t)pm->pm_reg_ptps)))
+ panic("%s: CHK(pmap %p): no SRMMU region table or bad pa: tblva=%p, tblpa=0x%x",
+ s, pm, pm->pm_reg_ptps, pm->pm_reg_ptps_pa);
+
+ if (CPU_ISSUN4M && pm->pm_ctx != NULL &&
+ (ctx_phys_tbl[pm->pm_ctxnum] != ((VA2PA((caddr_t)pm->pm_reg_ptps)
+ >> SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD)))
+ panic("%s: CHK(pmap %p): SRMMU region table at %x not installed "
+ "for context %d", s, pm, pm->pm_reg_ptps_pa, pm->pm_ctxnum);
+#endif
+
for (vr = 0; vr < NUREG; vr++) {
rp = &pm->pm_regmap[vr];
if (rp->rg_nsegmap == 0)
@@ -3701,24 +6422,44 @@ pm_check_u(s, pm)
if (rp->rg_segmap == NULL)
panic("%s: CHK(vr %d): nsegmap = %d; sp==NULL",
s, vr, rp->rg_nsegmap);
+#if defined(SUN4M)
+ if (CPU_ISSUN4M && rp->rg_seg_ptps == NULL)
+ panic("%s: CHK(vr %d): nsegmap=%d; no SRMMU segment table",
+ s, vr, rp->rg_nsegmap);
+ if (CPU_ISSUN4M &&
+ pm->pm_reg_ptps[vr] != ((VA2PA((caddr_t)rp->rg_seg_ptps) >>
+ SRMMU_PPNPASHIFT) | SRMMU_TEPTD))
+ panic("%s: CHK(vr %d): SRMMU segtbl not installed",s,vr);
+#endif
if ((unsigned int)rp < KERNBASE)
- panic("%s: rp=%x", s, rp);
+ panic("%s: rp=%p", s, rp);
n = 0;
for (vs = 0; vs < NSEGRG; vs++) {
sp = &rp->rg_segmap[vs];
if ((unsigned int)sp < KERNBASE)
- panic("%s: sp=%x", s, sp);
+ panic("%s: sp=%p", s, sp);
if (sp->sg_npte != 0) {
n++;
if (sp->sg_pte == NULL)
panic("%s: CHK(vr %d, vs %d): npte=%d, "
"pte=NULL", s, vr, vs, sp->sg_npte);
-
+#if defined(SUN4M)
+ if (CPU_ISSUN4M &&
+ rp->rg_seg_ptps[vs] !=
+ ((VA2PA((caddr_t)sp->sg_pte)
+ >> SRMMU_PPNPASHIFT) |
+ SRMMU_TEPTD))
+ panic("%s: CHK(vr %d, vs %d): SRMMU page "
+ "table not installed correctly",s,vr,
+ vs);
+#endif
pte=sp->sg_pte;
m = 0;
for (j=0; j<NPTESG; j++,pte++)
- if (*pte & PG_V)
- m++;
+ if ((CPU_ISSUN4M
+ ?((*pte & SRMMU_TETYPE) == SRMMU_TEPTE)
+ :(*pte & PG_V)))
+ m++;
if (m != sp->sg_npte)
/*if (pmapdebug & 0x10000)*/
printf("%s: user CHK(vr %d, vs %d): "
@@ -3731,18 +6472,33 @@ pm_check_u(s, pm)
"# of pte's: %d, should be %d",
s, vr, rp->rg_nsegmap, n);
}
- return 0;
+ return;
}
-int
-pm_check_k(s, pm)
+void
+pm_check_k(s, pm) /* Note: not as extensive as pm_check_u. */
char *s;
struct pmap *pm;
{
struct regmap *rp;
- struct segmap *sp;
int vr, vs, n;
+ if (pm->pm_regmap == NULL)
+ panic("%s: CHK(pmap %p): no region mapping", s, pm);
+
+#if defined(SUN4M)
+ if (CPU_ISSUN4M &&
+ (pm->pm_reg_ptps == NULL ||
+ pm->pm_reg_ptps_pa != VA2PA((caddr_t)pm->pm_reg_ptps)))
+ panic("%s: CHK(pmap %p): no SRMMU region table or bad pa: tblva=%p, tblpa=%x",
+ s, pm, pm->pm_reg_ptps, pm->pm_reg_ptps_pa);
+
+ if (CPU_ISSUN4M &&
+ (ctx_phys_tbl[0] != ((VA2PA((caddr_t)pm->pm_reg_ptps) >>
+ SRMMU_PPNPASHIFT) | SRMMU_TEPTD)))
+ panic("%s: CHK(pmap %p): SRMMU region table at %x not installed "
+ "for context %d", s, pm, pm->pm_reg_ptps_pa, 0);
+#endif
for (vr = NUREG; vr < NUREG+NKREG; vr++) {
rp = &pm->pm_regmap[vr];
if (rp->rg_segmap == NULL)
@@ -3750,6 +6506,15 @@ pm_check_k(s, pm)
s, vr, rp->rg_nsegmap);
if (rp->rg_nsegmap == 0)
continue;
+#if defined(SUN4M)
+ if (CPU_ISSUN4M && rp->rg_seg_ptps == NULL)
+ panic("%s: CHK(vr %d): nsegmap=%d; no SRMMU segment table",
+ s, vr, rp->rg_nsegmap);
+ if (CPU_ISSUN4M &&
+ pm->pm_reg_ptps[vr] != ((VA2PA((caddr_t)rp->rg_seg_ptps) >>
+ SRMMU_PPNPASHIFT) | SRMMU_TEPTD))
+ panic("%s: CHK(vr %d): SRMMU segtbl not installed",s,vr);
+#endif
n = 0;
for (vs = 0; vs < NSEGRG; vs++) {
if (rp->rg_segmap[vs].sg_npte)
@@ -3760,7 +6525,7 @@ pm_check_k(s, pm)
"# of pte's: %d, should be %d\n",
s, vr, rp->rg_nsegmap, n);
}
- return 0;
+ return;
}
#endif
@@ -3772,30 +6537,40 @@ pm_check_k(s, pm)
int
pmap_dumpsize()
{
- return btoc(((seginval + 1) * NPTESG * sizeof(int)) +
- sizeof(seginval) +
- sizeof(pmemarr) +
- sizeof(kernel_segmap_store));
+ if (CPU_ISSUN4M) /* No need to dump on 4m; its in-core. */
+ return (0);
+
+ if (CPU_ISSUN4OR4C)
+ return btoc(((seginval + 1) * NPTESG * sizeof(int)) +
+ sizeof(seginval) +
+ sizeof(pmemarr) +
+ sizeof(kernel_segmap_store));
+ return 0;
}
/*
* Write the mmu contents to the dump device.
* This gets appended to the end of a crash dump since
- * there is no in-core copy of kernel memory mappings.
+ * there is no in-core copy of kernel memory mappings on a 4/4c machine.
*/
int
pmap_dumpmmu(dump, blkno)
register daddr_t blkno;
register int (*dump) __P((dev_t, daddr_t, caddr_t, size_t));
{
+#if defined(SUN4C) || defined(SUN4)
register int pmeg;
- register int addr; /* unused kernel virtual address */
register int i;
register int *pte, *ptend;
- register int error;
+ register int error = 0;
register int *kp;
int buffer[dbtob(1) / sizeof(int)];
+#endif
+
+ if (CPU_ISSUN4M) /* No need to dump on 4m; its in-core. */
+ return (0);
+#if defined(SUN4C) || defined(SUN4)
/*
* dump page table entries
*
@@ -3805,6 +6580,7 @@ pmap_dumpmmu(dump, blkno)
* in the MMU. This fixed segment number is used in the virtual
* address argument to getpte().
*/
+
setcontext(0);
/*
@@ -3818,12 +6594,12 @@ pmap_dumpmmu(dump, blkno)
setsegmap(va, pmeg);
i = NPTESG;
do {
- *pte++ = getpte(va);
+ *pte++ = getpte4(va);
if (pte >= ptend) {
/*
* Note that we'll dump the last block
* the last time through the loops because
- * all the PMEGs occupy 32KB which is
+ * all the PMEGs occupy 32KB which is
* a multiple of the block size.
*/
error = (*dump)(dumpdev, blkno,
@@ -3865,4 +6641,180 @@ pmap_dumpmmu(dump, blkno)
error = (*dump)(dumpdev, blkno++, (caddr_t)buffer, dbtob(1));
return (error);
+#endif
+}
+
+#ifdef EXTREME_DEBUG
+
+static void test_region __P((int, int, int));
+
+void
+debug_pagetables()
+{
+ register int i;
+ register int *regtbl;
+ register int te;
+
+ printf("\nncontext=%d. ",ncontext);
+ printf("Context table is at va 0x%x. Level 0 PTP: 0x%x\n",
+ ctx_phys_tbl, ctx_phys_tbl[0]);
+ printf("Context 0 region table is at va 0x%x, pa 0x%x. Contents:\n",
+ pmap_kernel()->pm_reg_ptps, pmap_kernel()->pm_reg_ptps_pa);
+
+ regtbl = pmap_kernel()->pm_reg_ptps;
+
+ printf("PROM vector is at 0x%x\n",promvec);
+ printf("PROM reboot routine is at 0x%x\n",promvec->pv_reboot);
+ printf("PROM abort routine is at 0x%x\n",promvec->pv_abort);
+ printf("PROM halt routine is at 0x%x\n",promvec->pv_halt);
+
+ printf("Testing region 0xfe: ");
+ test_region(0xfe,0,16*1024*1024);
+ printf("Testing region 0xff: ");
+ test_region(0xff,0,16*1024*1024);
+ printf("Testing kernel region 0xf8: ");
+ test_region(0xf8, 4096, avail_start);
+ cngetc();
+
+ for (i = 0; i < SRMMU_L1SIZE; i++) {
+ te = regtbl[i];
+ if ((te & SRMMU_TETYPE) == SRMMU_TEINVALID)
+ continue;
+ printf("Region 0x%x: PTE=0x%x <%s> L2PA=0x%x kernL2VA=0x%x\n",
+ i, te, ((te & SRMMU_TETYPE) == SRMMU_TEPTE ? "pte" :
+ ((te & SRMMU_TETYPE) == SRMMU_TEPTD ? "ptd" :
+ ((te & SRMMU_TETYPE) == SRMMU_TEINVALID ?
+ "invalid" : "reserved"))),
+ (te & ~0x3) << SRMMU_PPNPASHIFT,
+ pmap_kernel()->pm_regmap[i].rg_seg_ptps);
+ }
+ printf("Press q to halt...\n");
+ if (cngetc()=='q')
+ callrom();
+}
+
+static u_int
+VA2PAsw(ctx, addr, pte)
+ register int ctx;
+ register caddr_t addr;
+ int *pte;
+{
+ register int *curtbl;
+ register int curpte;
+
+#ifdef EXTREME_EXTREME_DEBUG
+ printf("Looking up addr 0x%x in context 0x%x\n",addr,ctx);
+#endif
+ /* L0 */
+ *pte = curpte = ctx_phys_tbl[ctx];
+#ifdef EXTREME_EXTREME_DEBUG
+ printf("Got L0 pte 0x%x\n",pte);
+#endif
+ if ((curpte & SRMMU_TETYPE) == SRMMU_TEPTE) {
+ return (((curpte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT) |
+ ((u_int)addr & 0xffffffff));
+ }
+ if ((curpte & SRMMU_TETYPE) != SRMMU_TEPTD) {
+ printf("Bad context table entry 0x%x for context 0x%x\n",
+ curpte, ctx);
+ return 0;
+ }
+ /* L1 */
+ curtbl = ((curpte & ~0x3) << 4) | (0xf8 << RGSHIFT); /* correct for krn*/
+ *pte = curpte = curtbl[VA_VREG(addr)];
+#ifdef EXTREME_EXTREME_DEBUG
+ printf("L1 table at 0x%x.\nGot L1 pte 0x%x\n",curtbl,curpte);
+#endif
+ if ((curpte & SRMMU_TETYPE) == SRMMU_TEPTE)
+ return (((curpte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT) |
+ ((u_int)addr & 0xffffff));
+ if ((curpte & SRMMU_TETYPE) != SRMMU_TEPTD) {
+ printf("Bad region table entry 0x%x for region 0x%x\n",
+ curpte, VA_VREG(addr));
+ return 0;
+ }
+ /* L2 */
+ curtbl = ((curpte & ~0x3) << 4) | (0xf8 << RGSHIFT); /* correct for krn*/
+ *pte = curpte = curtbl[VA_VSEG(addr)];
+#ifdef EXTREME_EXTREME_DEBUG
+ printf("L2 table at 0x%x.\nGot L2 pte 0x%x\n",curtbl,curpte);
+#endif
+ if ((curpte & SRMMU_TETYPE) == SRMMU_TEPTE)
+ return (((curpte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT) |
+ ((u_int)addr & 0x3ffff));
+ if ((curpte & SRMMU_TETYPE) != SRMMU_TEPTD) {
+ printf("Bad segment table entry 0x%x for reg 0x%x, seg 0x%x\n",
+ curpte, VA_VREG(addr), VA_VSEG(addr));
+ return 0;
+ }
+ /* L3 */
+ curtbl = ((curpte & ~0x3) << 4) | (0xf8 << RGSHIFT); /* correct for krn*/
+ *pte = curpte = curtbl[VA_VPG(addr)];
+#ifdef EXTREME_EXTREME_DEBUG
+ printf("L3 table at 0x%x.\nGot L3 pte 0x%x\n",curtbl,curpte);
+#endif
+ if ((curpte & SRMMU_TETYPE) == SRMMU_TEPTE)
+ return (((curpte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT) |
+ ((u_int)addr & 0xfff));
+ else {
+ printf("Bad L3 pte 0x%x for reg 0x%x, seg 0x%x, pg 0x%x\n",
+ curpte, VA_VREG(addr), VA_VSEG(addr), VA_VPG(addr));
+ return 0;
+ }
+ printf("Bizarreness with address 0x%x!\n",addr);
+}
+
+void test_region(reg, start, stop)
+ register int reg;
+ register int start, stop;
+{
+ register int i;
+ register int addr;
+ register int pte;
+ int ptesw;
+/* int cnt=0;
+*/
+
+ for (i = start; i < stop; i+= NBPG) {
+ addr = (reg << RGSHIFT) | i;
+ pte=lda(((u_int)(addr)) | ASI_SRMMUFP_LN, ASI_SRMMUFP);
+ if (pte) {
+/* printf("Valid address 0x%x\n",addr);
+ if (++cnt == 20) {
+ cngetc();
+ cnt=0;
+ }
+*/
+ if (VA2PA(addr) != VA2PAsw(0,addr,&ptesw)) {
+ printf("Mismatch at address 0x%x.\n",addr);
+ if (cngetc()=='q') break;
+ }
+ if (reg == 0xf8) /* kernel permissions are different */
+ continue;
+ if ((pte&SRMMU_PROT_MASK)!=(ptesw&SRMMU_PROT_MASK)) {
+ printf("Mismatched protections at address "
+ "0x%x; pte=0x%x, ptesw=0x%x\n",
+ addr,pte,ptesw);
+ if (cngetc()=='q') break;
+ }
+ }
+ }
+ printf("done.\n");
+}
+
+
+void print_fe_map(void)
+{
+ u_int i, pte;
+
+ printf("map of region 0xfe:\n");
+ for (i = 0xfe000000; i < 0xff000000; i+=4096) {
+ if (((pte = getpte4m(i)) & SRMMU_TETYPE) != SRMMU_TEPTE)
+ continue;
+ printf("0x%x -> 0x%x%x (pte %x)\n", i, pte >> 28,
+ (pte & ~0xff) << 4, pte);
+ }
+ printf("done\n");
}
+
+#endif
diff --git a/sys/arch/sparc/sparc/process_machdep.c b/sys/arch/sparc/sparc/process_machdep.c
index 0f20e1858e2..3ea7669ede6 100644
--- a/sys/arch/sparc/sparc/process_machdep.c
+++ b/sys/arch/sparc/sparc/process_machdep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: process_machdep.c,v 1.5 1994/11/20 20:54:37 deraadt Exp $ */
+/* $NetBSD: process_machdep.c,v 1.6 1996/03/14 21:09:26 christos Exp $ */
/*
* Copyright (c) 1993 The Regents of the University of California.
@@ -97,6 +97,7 @@ process_write_regs(p, regs)
int
process_sstep(p, sstep)
struct proc *p;
+ int sstep;
{
if (sstep)
return EINVAL;
diff --git a/sys/arch/sparc/sparc/svr4_machdep.c b/sys/arch/sparc/sparc/svr4_machdep.c
index 5a572604c7b..a16e126ab1c 100644
--- a/sys/arch/sparc/sparc/svr4_machdep.c
+++ b/sys/arch/sparc/sparc/svr4_machdep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: svr4_machdep.c,v 1.13 1996/01/07 19:47:27 christos Exp $ */
+/* $NetBSD: svr4_machdep.c,v 1.17.4.1 1996/06/11 01:46:42 jtc Exp $ */
/*
* Copyright (c) 1994 Christos Zoulas
@@ -74,7 +74,7 @@ svr4_printcontext(fun, uc)
svr4_greg_t *r = uc->uc_mcontext.greg;
struct svr4_sigaltstack *s = &uc->uc_stack;
- printf("%s at %x\n", fun, uc);
+ printf("%s at %p\n", fun, uc);
printf("Regs: ");
printf("PSR = %x ", r[SVR4_SPARC_PSR]);
@@ -98,12 +98,10 @@ svr4_printcontext(fun, uc)
printf("O7 = %x ", r[SVR4_SPARC_O7]);
printf("\n");
- printf("Signal Stack: sp %x, size %d, flags %x\n",
+ printf("Signal Stack: sp %p, size %d, flags %x\n",
s->ss_sp, s->ss_size, s->ss_flags);
- printf("Signal mask: %x\n", uc->uc_sigmask);
-
- printf("Flags: %x\n", uc->uc_flags);
+ printf("Flags: %lx\n", uc->uc_flags);
}
#endif
@@ -114,15 +112,21 @@ svr4_getcontext(p, uc, mask, oonstack)
int mask, oonstack;
{
struct trapframe *tf = (struct trapframe *)p->p_md.md_tf;
- struct sigacts *psp = p->p_sigacts;
svr4_greg_t *r = uc->uc_mcontext.greg;
struct svr4_sigaltstack *s = &uc->uc_stack;
- struct sigaltstack *sf = &psp->ps_sigstk;
+#ifdef FPU_CONTEXT
+ svr4_fregset_t *f = &uc->uc_mcontext.freg;
+ struct fpstate *fps = p->p_md.md_fpstate;
+#endif
+
+ write_user_windows();
+ if (rwindow_save(p))
+ sigexit(p, SIGILL);
bzero(uc, sizeof(struct svr4_ucontext));
/*
- * Set the general purpose registers
+ * Get the general purpose registers
*/
r[SVR4_SPARC_PSR] = tf->tf_psr;
r[SVR4_SPARC_PC] = tf->tf_pc;
@@ -144,20 +148,50 @@ svr4_getcontext(p, uc, mask, oonstack)
r[SVR4_SPARC_O6] = tf->tf_out[6];
r[SVR4_SPARC_O7] = tf->tf_out[7];
+#ifdef FPU_CONTEXT
/*
- * Set the signal stack
+ * Get the floating point registers
*/
- bsd_to_svr4_sigaltstack(sf, s);
+ bcopy(fps->fs_regs, f->fpu_regs, sizeof(fps->fs_regs));
+ f->fp_nqsize = sizeof(struct fp_qentry);
+ f->fp_nqel = fps->fs_qsize;
+ f->fp_fsr = fps->fs_fsr;
+ if (f->fp_q != NULL) {
+ size_t sz = f->fp_nqel * f->fp_nqsize;
+ if (sz > sizeof(fps->fs_queue)) {
+#ifdef DIAGNOSTIC
+ printf("getcontext: fp_queue too large\n");
+#endif
+ return;
+ }
+ if (copyout(fps->fs_queue, f->fp_q, sz) != 0) {
+#ifdef DIAGNOSTIC
+ printf("getcontext: copy of fp_queue failed %d\n",
+ error);
+#endif
+ return;
+ }
+ }
+ f->fp_busy = 0; /* XXX: How do we determine that? */
+#endif
/*
- * Set the signal mask
+ * Set the signal stack to something reasonable
+ */
+ /* XXX: Don't really know what to do with this */
+ s->ss_sp = (char *) ((r[SVR4_SPARC_SP] & ~0xfff) - 8192);
+ s->ss_size = 8192;
+ s->ss_flags = 0;
+
+ /*
+ * Get the signal mask
*/
bsd_to_svr4_sigset(&mask, &uc->uc_sigmask);
/*
- * Set the flags
+ * Get the flags
*/
- uc->uc_flags = SVR4_UC_ALL;
+ uc->uc_flags = SVR4_UC_CPU|SVR4_UC_SIGMASK|SVR4_UC_STACK;
#ifdef DEBUG_SVR4
svr4_printcontext("getcontext", uc);
@@ -181,21 +215,20 @@ svr4_setcontext(p, uc)
struct proc *p;
struct svr4_ucontext *uc;
{
- struct sigcontext *scp, context;
struct sigacts *psp = p->p_sigacts;
register struct trapframe *tf;
svr4_greg_t *r = uc->uc_mcontext.greg;
struct svr4_sigaltstack *s = &uc->uc_stack;
struct sigaltstack *sf = &psp->ps_sigstk;
int mask;
+#ifdef FPU_CONTEXT
+ svr4_fregset_t *f = &uc->uc_mcontext.freg;
+ struct fpstate *fps = p->p_md.md_fpstate;
+#endif
#ifdef DEBUG_SVR4
svr4_printcontext("setcontext", uc);
#endif
- /*
- * XXX:
- * Should we check the value of flags to determine what to restore?
- */
write_user_windows();
if (rwindow_save(p))
@@ -203,7 +236,7 @@ svr4_setcontext(p, uc)
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
- printf("svr4_setcontext: %s[%d], svr4_ucontext %x\n",
+ printf("svr4_setcontext: %s[%d], svr4_ucontext %p\n",
p->p_comm, p->p_pid, uc);
#endif
@@ -212,50 +245,86 @@ svr4_setcontext(p, uc)
/*
* Restore register context.
*/
- /*
- * Only the icc bits in the psr are used, so it need not be
- * verified. pc and npc must be multiples of 4. This is all
- * that is required; if it holds, just do it.
- */
- if (((r[SVR4_SPARC_PC] | r[SVR4_SPARC_nPC]) & 3) != 0) {
- printf("pc or npc are not multiples of 4!\n");
- return EINVAL;
+ if (uc->uc_flags & SVR4_UC_CPU) {
+ /*
+ * Only the icc bits in the psr are used, so it need not be
+ * verified. pc and npc must be multiples of 4. This is all
+ * that is required; if it holds, just do it.
+ */
+ if (((r[SVR4_SPARC_PC] | r[SVR4_SPARC_nPC]) & 3) != 0) {
+ printf("pc or npc are not multiples of 4!\n");
+ return EINVAL;
+ }
+
+ /* take only psr ICC field */
+ tf->tf_psr = (tf->tf_psr & ~PSR_ICC) |
+ (r[SVR4_SPARC_PSR] & PSR_ICC);
+ tf->tf_pc = r[SVR4_SPARC_PC];
+ tf->tf_npc = r[SVR4_SPARC_nPC];
+ tf->tf_y = r[SVR4_SPARC_Y];
+
+ /* Restore everything */
+ tf->tf_global[1] = r[SVR4_SPARC_G1];
+ tf->tf_global[2] = r[SVR4_SPARC_G2];
+ tf->tf_global[3] = r[SVR4_SPARC_G3];
+ tf->tf_global[4] = r[SVR4_SPARC_G4];
+ tf->tf_global[5] = r[SVR4_SPARC_G5];
+ tf->tf_global[6] = r[SVR4_SPARC_G6];
+ tf->tf_global[7] = r[SVR4_SPARC_G7];
+
+ tf->tf_out[0] = r[SVR4_SPARC_O0];
+ tf->tf_out[1] = r[SVR4_SPARC_O1];
+ tf->tf_out[2] = r[SVR4_SPARC_O2];
+ tf->tf_out[3] = r[SVR4_SPARC_O3];
+ tf->tf_out[4] = r[SVR4_SPARC_O4];
+ tf->tf_out[5] = r[SVR4_SPARC_O5];
+ tf->tf_out[6] = r[SVR4_SPARC_O6];
+ tf->tf_out[7] = r[SVR4_SPARC_O7];
}
- /* take only psr ICC field */
- tf->tf_psr = (tf->tf_psr & ~PSR_ICC) | (r[SVR4_SPARC_PSR] & PSR_ICC);
- tf->tf_pc = r[SVR4_SPARC_PC];
- tf->tf_npc = r[SVR4_SPARC_nPC];
- tf->tf_y = r[SVR4_SPARC_Y];
-
- /* Restore everything */
- tf->tf_global[1] = r[SVR4_SPARC_G1];
- tf->tf_global[2] = r[SVR4_SPARC_G2];
- tf->tf_global[3] = r[SVR4_SPARC_G3];
- tf->tf_global[4] = r[SVR4_SPARC_G4];
- tf->tf_global[5] = r[SVR4_SPARC_G5];
- tf->tf_global[6] = r[SVR4_SPARC_G6];
- tf->tf_global[7] = r[SVR4_SPARC_G7];
-
- tf->tf_out[0] = r[SVR4_SPARC_O0];
- tf->tf_out[1] = r[SVR4_SPARC_O1];
- tf->tf_out[2] = r[SVR4_SPARC_O2];
- tf->tf_out[3] = r[SVR4_SPARC_O3];
- tf->tf_out[4] = r[SVR4_SPARC_O4];
- tf->tf_out[5] = r[SVR4_SPARC_O5];
- tf->tf_out[6] = r[SVR4_SPARC_O6];
- tf->tf_out[7] = r[SVR4_SPARC_O7];
- /*
- * restore signal stack
- */
- svr4_to_bsd_sigaltstack(s, sf);
+#ifdef FPU_CONTEXT
+ if (uc->uc_flags & SVR4_UC_FPU) {
+ /*
+ * Set the floating point registers
+ */
+ int error;
+ size_t sz = f->fp_nqel * f->fp_nqsize;
+ if (sz > sizeof(fps->fs_queue)) {
+#ifdef DIAGNOSTIC
+ printf("setcontext: fp_queue too large\n");
+#endif
+ return EINVAL;
+ }
+ bcopy(f->fpu_regs, fps->fs_regs, sizeof(fps->fs_regs));
+ fps->fs_qsize = f->fp_nqel;
+ fps->fs_fsr = f->fp_fsr;
+ if (f->fp_q != NULL) {
+ if ((error = copyin(f->fp_q, fps->fs_queue,
+ f->fp_nqel * f->fp_nqsize)) != 0) {
+#ifdef DIAGNOSTIC
+ printf("setcontext: copy of fp_queue failed\n");
+#endif
+ return error;
+ }
+ }
+ }
+#endif
- /*
- * restore signal mask
- */
- svr4_to_bsd_sigset(&uc->uc_sigmask, &mask);
- p->p_sigmask = mask & ~sigcantmask;
+ if (uc->uc_flags & SVR4_UC_STACK) {
+ /*
+ * restore signal stack
+ */
+ svr4_to_bsd_sigaltstack(s, sf);
+ }
+
+ if (uc->uc_flags & SVR4_UC_SIGMASK) {
+ /*
+ * restore signal mask
+ */
+ svr4_to_bsd_sigset(&uc->uc_sigmask, &mask);
+ p->p_sigmask = mask & ~sigcantmask;
+ }
return EJUSTRETURN;
}
@@ -280,6 +349,10 @@ svr4_getsiginfo(si, sig, code, addr)
si->si_trap = code;
switch (code) {
+ case T_RESET:
+ si->si_code = 0;
+ break;
+
case T_TEXTFAULT:
si->si_code = SVR4_BUS_ADRALN;
break;
@@ -372,7 +445,7 @@ svr4_getsiginfo(si, sig, code, addr)
default:
si->si_code = 0;
#ifdef DIAGNOSTIC
- printf("sig %d code %d\n", sig, code);
+ printf("sig %d code %ld\n", sig, code);
panic("svr4_getsiginfo");
#endif
break;
@@ -399,7 +472,6 @@ svr4_sendsig(catcher, sig, mask, code)
struct svr4_sigframe *fp, frame;
struct sigacts *psp = p->p_sigacts;
int oonstack, oldsp, newsp, addr;
- svr4_greg_t* r = frame.sf_uc.uc_mcontext.greg;
extern char svr4_sigcode[], svr4_esigcode[];
@@ -424,7 +496,7 @@ svr4_sendsig(catcher, sig, mask, code)
*/
fp = (struct svr4_sigframe *) ((int) (fp - 1) & ~7);
- /*
+ /*
* Build the argument list for the signal handler.
*/
svr4_getsiginfo(&frame.sf_si, sig, code, (caddr_t) tf->tf_pc);
@@ -502,15 +574,30 @@ svr4_trap(type, p)
break;
case T_SVR4_GETHRTIME:
- uprintf("T_SVR4_GETHRTIME\n");
- break;
-
+ /*
+ * this list like gethrtime(3). To implement this
+ * correctly we need a timer that does not get affected
+ * adjtime(), or settimeofday(). For now we use
+ * microtime, and convert to nanoseconds...
+ */
+ /*FALLTHROUGH*/
case T_SVR4_GETHRVTIME:
- uprintf("T_SVR4_GETHRVTIME\n");
+ /*
+ * This is like gethrvtime(3). Since we don't have lwp
+ * we massage microtime() output
+ */
+ {
+ struct timeval tv;
+
+ microtime(&tv);
+ tf->tf_out[0] = tv.tv_sec;
+ tf->tf_out[1] = tv.tv_usec * 1000;
+ }
break;
case T_SVR4_GETHRESTIME:
{
+ /* I assume this is like gettimeofday(3) */
struct timeval tv;
microtime(&tv);
diff --git a/sys/arch/sparc/sparc/swapgeneric.c b/sys/arch/sparc/sparc/swapgeneric.c
index c2518a0bdf4..493b04bc198 100644
--- a/sys/arch/sparc/sparc/swapgeneric.c
+++ b/sys/arch/sparc/sparc/swapgeneric.c
@@ -1,4 +1,4 @@
-/* $NetBSD: swapgeneric.c,v 1.7 1995/02/16 21:42:52 pk Exp $ */
+/* $NetBSD: swapgeneric.c,v 1.8 1996/03/14 21:09:32 christos Exp $ */
/*-
* Copyright (c) 1994
@@ -42,7 +42,7 @@
#include <sys/param.h>
#include <sys/conf.h>
-int (*mountroot)() = NULL; /* tells autoconf.c that we are "generic" */
+int (*mountroot) __P((void *)) = NULL; /* tells autoconf.c that we are "generic" */
dev_t rootdev = NODEV;
dev_t dumpdev = NODEV;
diff --git a/sys/arch/sparc/sparc/sys_machdep.c b/sys/arch/sparc/sparc/sys_machdep.c
index 28f00072d14..e83270eaf3b 100644
--- a/sys/arch/sparc/sparc/sys_machdep.c
+++ b/sys/arch/sparc/sparc/sys_machdep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_machdep.c,v 1.6 1995/10/07 06:26:10 mycroft Exp $ */
+/* $NetBSD: sys_machdep.c,v 1.7 1996/03/14 21:09:33 christos Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -62,6 +62,7 @@
#ifdef TRACE
int nvualarm;
+int
vtrace(p, uap, retval)
struct proc *p;
register struct vtrace_args /* {
@@ -103,6 +104,7 @@ vtrace(p, uap, retval)
return (0);
}
+void
vdoualarm(arg)
int arg;
{
@@ -114,6 +116,7 @@ vdoualarm(arg)
}
#endif
+int
sys_sysarch(p, v, retval)
struct proc *p;
void *v;
diff --git a/sys/arch/sparc/sparc/timerreg.h b/sys/arch/sparc/sparc/timerreg.h
index ae90cd8c237..26bc2a57ca3 100644
--- a/sys/arch/sparc/sparc/timerreg.h
+++ b/sys/arch/sparc/sparc/timerreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: timerreg.h,v 1.2 1994/11/20 20:54:41 deraadt Exp $ */
+/* $NetBSD: timerreg.h,v 1.5 1996/05/02 18:17:33 pk Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -66,18 +66,53 @@
* 1, 2, 3, 1, 2, 3, ...
*
* and if we want to divide by N we must set the limit register to N+1.
+ *
+ * Sun-4m counters/timer registers are similar, with these exceptions:
+ *
+ * - the limit and counter registers have changed positions..
+ * - both limit and counter registers are 22 bits wide, but
+ * they count in 500ns increments (bit 9 being the least
+ * significant bit).
+ *
+ * Note that we still use the `sun4c' masks and shifts to compute
+ * the bit pattern, given the tick period in microseconds, resulting
+ * in a limit value that is 1 too high. This means that (with HZ=100)
+ * the clock will err on the slow side by 500ns/10ms (or 0.00005 %).
+ * We dont bother.
+ *
+ */
+#ifndef _LOCORE
+struct timer_4 {
+ volatile int t_counter; /* counter reg */
+ volatile int t_limit; /* limit reg */
+};
+
+struct timerreg_4 {
+ struct timer_4 t_c10; /* counter that interrupts at ipl 10 */
+ struct timer_4 t_c14; /* counter that interrupts at ipl 14 */
+};
+
+struct timer_4m { /* counter that interrupts at ipl 10 */
+ volatile int t_limit; /* limit register */
+ volatile int t_counter; /* counter register */
+ volatile int t_limit_nr; /* limit reg, non-resetting */
+ volatile int t_reserved;
+ volatile int t_cfg; /* a configuration register */
+/*
+ * Note: The SparcClassic manual only defines this one bit
+ * I suspect there are more in multi-processor machines.
*/
-#ifndef LOCORE
-struct timer {
- int t_counter; /* counter reg */
- int t_limit; /* limit reg */
+#define TMR_CFG_USER 1
};
-struct timerreg {
- struct timer t_c10; /* counter that interrupts at ipl 10 */
- struct timer t_c14; /* counter that interrupts at ipl 14 */
+struct counter_4m { /* counter that interrupts at ipl 14 */
+ volatile int t_limit; /* limit register */
+ volatile int t_counter; /* counter register */
+ volatile int t_limit_nr; /* limit reg, non-resetting */
+ volatile int t_ss; /* Start/Stop register */
+#define TMR_USER_RUN 1
};
-#endif
+#endif /* _LOCORE */
#define TMR_LIMIT 0x80000000 /* counter reached its limit */
#define TMR_SHIFT 10 /* shift to obtain microseconds */
@@ -86,5 +121,5 @@ struct timerreg {
/* Compute a limit that causes the timer to fire every n microseconds. */
#define tmr_ustolim(n) (((n) + 1) << TMR_SHIFT)
-#include <sparc/sparc/vaddrs.h>
-#define TIMERREG ((volatile struct timerreg *)TIMERREG_VA)
+/*efine TMR_SHIFT4M 9 -* shift to obtain microseconds */
+/*efine tmr_ustolim(n) (((2*(n)) + 1) << TMR_SHIFT4M)*/
diff --git a/sys/arch/sparc/sparc/trap.c b/sys/arch/sparc/sparc/trap.c
index 2925b0adea2..e44f163ccb8 100644
--- a/sys/arch/sparc/sparc/trap.c
+++ b/sys/arch/sparc/sparc/trap.c
@@ -1,6 +1,8 @@
-/* $NetBSD: trap.c,v 1.33 1995/07/04 22:57:35 christos Exp $ */
+/* $NetBSD: trap.c,v 1.42.4.2 1996/07/03 00:06:40 jtc Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -12,6 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
+ * This product includes software developed by Harvard University.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,6 +28,7 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
+ * This product includes software developed by Harvard University.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -59,18 +63,35 @@
#include <sys/ktrace.h>
#endif
+#include <vm/vm.h>
#include <vm/vm_kern.h>
+#include <sparc/sparc/asm.h>
#include <machine/cpu.h>
#include <machine/ctlreg.h>
-#include <machine/frame.h>
#include <machine/trap.h>
+#include <machine/instr.h>
+#include <machine/pmap.h>
+
+#ifdef DDB
+#include <machine/db_machdep.h>
+#else
+#include <machine/frame.h>
+#endif
+#ifdef COMPAT_SVR4
+#include <machine/svr4_machdep.h>
+#endif
+
+#include <sparc/fpu/fpu_extern.h>
+#include <sparc/sparc/memreg.h>
#define offsetof(s, f) ((int)&((s *)0)->f)
extern int cold;
+#ifdef DEBUG
int rwindow_debug = 0;
+#endif
/*
* Initial FPU state is all registers == all 1s, everything else == all 0s.
@@ -162,12 +183,22 @@ const char *trap_type[] = {
#define N_TRAP_TYPES (sizeof trap_type / sizeof *trap_type)
+static __inline void userret __P((struct proc *, int, u_quad_t));
+void trap __P((unsigned, int, int, struct trapframe *));
+static __inline void share_fpu __P((struct proc *, struct trapframe *));
+void mem_access_fault __P((unsigned, int, u_int, int, int, struct trapframe *));
+void mem_access_fault4m __P((unsigned, u_int, u_int, u_int, u_int, struct trapframe *));
+void syscall __P((register_t, struct trapframe *, register_t));
+
/*
* Define the code needed before returning to user mode, for
* trap, mem_access_fault, and syscall.
*/
-static inline void
-userret(struct proc *p, int pc, u_quad_t oticks)
+static __inline void
+userret(p, pc, oticks)
+ struct proc *p;
+ int pc;
+ u_quad_t oticks;
{
int sig;
@@ -215,7 +246,10 @@ userret(struct proc *p, int pc, u_quad_t oticks)
* the ktrsysret() in syscall(). Actually, it is likely that the
* ktrsysret should occur before the call to userret.
*/
-static inline void share_fpu(struct proc *p, struct trapframe *tf) {
+static __inline void share_fpu(p, tf)
+ struct proc *p;
+ struct trapframe *tf;
+{
if ((tf->tf_psr & PSR_EF) != 0 && fpproc != p)
tf->tf_psr &= ~PSR_EF;
}
@@ -224,6 +258,7 @@ static inline void share_fpu(struct proc *p, struct trapframe *tf) {
* Called from locore.s trap handling, for non-MMU-related traps.
* (MMU-related traps go through mem_access_fault, below.)
*/
+void
trap(type, psr, pc, tf)
register unsigned type;
register int psr, pc;
@@ -252,6 +287,17 @@ trap(type, psr, pc, tf)
}
}
#endif
+#ifdef DIAGNOSTIC
+ /*
+ * Currently, we allow DIAGNOSTIC kernel code to
+ * flush the windows to record stack traces.
+ */
+ if (type == T_FLUSHWIN) {
+ write_all_windows();
+ ADVANCE;
+ return;
+ }
+#endif
/*
* Storing %fsr in cpu_attach will cause this trap
* even though the fpu has been enabled, if and only
@@ -272,14 +318,21 @@ trap(type, psr, pc, tf)
switch (type) {
default:
+#if defined(SUN4M)
+ if (type == 0x29)
+ /* Mysterious trap 29.. for now print&signal process */
+ goto badtrap;
+#endif
if (type < 0x80) {
dopanic:
printf("trap type 0x%x: pc=%x npc=%x psr=%b\n",
- type, pc, tf->tf_npc, psr, PSR_BITS);
+ type, pc, tf->tf_npc, psr, PSR_BITS);
panic(type < N_TRAP_TYPES ? trap_type[type] : T);
/* NOTREACHED */
}
+#if defined(COMPAT_SVR4) || defined(SUN4M)
badtrap:
+#endif
/* the following message is gratuitous */
/* ... but leave it in until we find anything */
printf("%s[%d]: unimplemented software trap 0x%x\n",
@@ -367,19 +420,17 @@ badtrap:
* nsaved to -1. If we decide to deliver a signal on
* our way out, we will clear nsaved.
*/
-#ifdef DIAGNOSTIC
if (pcb->pcb_uw || pcb->pcb_nsaved)
panic("trap T_RWRET 1");
+#ifdef DEBUG
if (rwindow_debug)
printf("%s[%d]: rwindow: pcb<-stack: %x\n",
- p->p_comm, p->p_pid, tf->tf_out[6]);
-#endif /* DIAGNOSTIC */
+ p->p_comm, p->p_pid, tf->tf_out[6]);
+#endif
if (read_rw(tf->tf_out[6], &pcb->pcb_rw[0]))
sigexit(p, SIGILL);
-#ifdef DIAGNOSTIC
if (pcb->pcb_nsaved)
panic("trap T_RWRET 2");
-#endif /* DIAGNOSTIC */
pcb->pcb_nsaved = -1; /* mark success */
break;
@@ -393,25 +444,23 @@ badtrap:
* in the pcb. The restore's window may still be in
* the cpu; we need to force it out to the stack.
*/
-#ifdef DIAGNOSTIC
+#ifdef DEBUG
if (rwindow_debug)
printf("%s[%d]: rwindow: T_WINUF 0: pcb<-stack: %x\n",
- p->p_comm, p->p_pid, tf->tf_out[6]);
-#endif /* DIAGNOSTIC */
+ p->p_comm, p->p_pid, tf->tf_out[6]);
+#endif
write_user_windows();
if (rwindow_save(p) || read_rw(tf->tf_out[6], &pcb->pcb_rw[0]))
sigexit(p, SIGILL);
-#ifdef DIAGNOSTIC
+#ifdef DEBUG
if (rwindow_debug)
printf("%s[%d]: rwindow: T_WINUF 1: pcb<-stack: %x\n",
- p->p_comm, p->p_pid, pcb->pcb_rw[0].rw_in[6]);
-#endif /* DIAGNOSTIC */
+ p->p_comm, p->p_pid, pcb->pcb_rw[0].rw_in[6]);
+#endif
if (read_rw(pcb->pcb_rw[0].rw_in[6], &pcb->pcb_rw[1]))
sigexit(p, SIGILL);
-#ifdef DIAGNOSTIC
if (pcb->pcb_nsaved)
panic("trap T_WINUF");
-#endif /* DIAGNOSTIC */
pcb->pcb_nsaved = -1; /* mark success */
break;
@@ -518,24 +567,24 @@ rwindow_save(p)
}
if (i == 0)
return (0);
-#ifdef DIAGNOSTIC
- if(rwindow_debug)
+#ifdef DEBUG
+ if (rwindow_debug)
printf("%s[%d]: rwindow: pcb->stack:", p->p_comm, p->p_pid);
-#endif /* DIAGNOSTIC */
+#endif
do {
-#ifdef DIAGNOSTIC
- if(rwindow_debug)
+#ifdef DEBUG
+ if (rwindow_debug)
printf(" %x", rw[1].rw_in[6]);
-#endif /* DIAGNOSTIC */
+#endif
if (copyout((caddr_t)rw, (caddr_t)rw[1].rw_in[6],
sizeof *rw))
return (-1);
rw++;
} while (--i > 0);
-#ifdef DIAGNOSTIC
- if(rwindow_debug)
+#ifdef DEBUG
+ if (rwindow_debug)
printf("\n");
-#endif /* DIAGNOSTIC */
+#endif
pcb->pcb_nsaved = 0;
return (0);
}
@@ -545,6 +594,7 @@ rwindow_save(p)
* and then erasing any pcb tracks. Otherwise we might try to write
* the registers into the new process after the exec.
*/
+void
kill_user_windows(p)
struct proc *p;
{
@@ -564,6 +614,7 @@ kill_user_windows(p)
* more than one `cause'. But we do not care what the cause, here;
* we just want to page in the page and try again.
*/
+void
mem_access_fault(type, ser, v, pc, psr, tf)
register unsigned type;
register int ser;
@@ -571,12 +622,13 @@ mem_access_fault(type, ser, v, pc, psr, tf)
register int pc, psr;
register struct trapframe *tf;
{
+#if defined(SUN4) || defined(SUN4C)
register struct proc *p;
register struct vmspace *vm;
register vm_offset_t va;
register int rv;
vm_prot_t ftype;
- int onfault, mmucode;
+ int onfault;
u_quad_t sticks;
cnt.v_trap++;
@@ -598,28 +650,13 @@ mem_access_fault(type, ser, v, pc, psr, tf)
if (VA_INHOLE(v))
goto fault;
ftype = ser & SER_WRITE ? VM_PROT_READ|VM_PROT_WRITE : VM_PROT_READ;
- if(ftype == VM_PROT_READ && (ser & SER_PROT) && type != T_TEXTFAULT) {
- /* If this is an ldstub or swap instruction
- * then we are about to fault in a loop forever
- * as only the read part of the fault will be
- * reported by the mmu.
- */
- int error, insn;
-
- error = copyin((caddr_t) pc, &insn, sizeof(int));
- if(!error) {
- insn = (insn >> 16); /* high word */
- insn &= 0xc168;
- if(insn == 0xc068)
- ftype |= VM_PROT_WRITE;
- }
- }
va = trunc_page(v);
if (psr & PSR_PS) {
extern char Lfsbail[];
if (type == T_TEXTFAULT) {
(void) splhigh();
- printf("text fault: pc=%x ser=%b\n", pc, ser, SER_BITS);
+ printf("text fault: pc=%x ser=%b\n", pc,
+ ser, SER_BITS);
panic("kernel fault");
/* NOTREACHED */
}
@@ -651,7 +688,8 @@ mem_access_fault(type, ser, v, pc, psr, tf)
* that got bumped out via LRU replacement.
*/
vm = p->p_vmspace;
- rv = mmu_pagein(&vm->vm_pmap, va, ftype);
+ rv = mmu_pagein(&vm->vm_pmap, va,
+ ser & SER_WRITE ? VM_PROT_WRITE : VM_PROT_READ);
if (rv < 0)
goto fault;
if (rv > 0)
@@ -697,7 +735,7 @@ kfault:
if (!onfault) {
(void) splhigh();
printf("data fault: pc=%x addr=%x ser=%b\n",
- pc, v, ser, SER_BITS);
+ pc, v, ser, SER_BITS);
panic("kernel fault");
/* NOTREACHED */
}
@@ -712,7 +750,280 @@ out:
userret(p, pc, sticks);
share_fpu(p, tf);
}
+#endif /* Sun4/Sun4C */
+}
+
+#if defined(SUN4M) /* 4m version of mem_access_fault() follows */
+
+static int tfaultaddr = (int) 0xdeadbeef;
+
+#ifdef DEBUG
+int dfdebug = 0;
+#endif
+
+void
+mem_access_fault4m(type, sfsr, sfva, afsr, afva, tf)
+ register unsigned type;
+ register u_int sfsr;
+ register u_int sfva;
+ register u_int afsr;
+ register u_int afva;
+ register struct trapframe *tf;
+{
+ register int pc, psr;
+ register struct proc *p;
+ register struct vmspace *vm;
+ register vm_offset_t va;
+ register int rv;
+ vm_prot_t ftype;
+ int onfault;
+ u_quad_t sticks;
+#if DEBUG
+static int lastdouble;
+#endif
+
+ cnt.v_trap++;
+ if ((p = curproc) == NULL) /* safety check */
+ p = &proc0;
+ sticks = p->p_sticks;
+
+ pc = tf->tf_pc; /* These are needed below */
+ psr = tf->tf_psr;
+
+ /*
+ * Our first priority is handling serious faults, such as
+ * parity errors or async faults that might have come through here.
+ * If afsr & AFSR_AFO != 0, then we're on a HyperSPARC and we
+ * got an async fault. We pass it on to memerr4m. Similarly, if
+ * the trap was T_STOREBUFFAULT, we pass it on to memerr4m.
+ * If we have a data fault, but SFSR_FAV is not set in the sfsr,
+ * then things are really bizarre, and we treat it as a hard
+ * error and pass it on to memerr4m. See pg. 9-35 in the SuperSPARC
+ * user's guide for more info, and for a possible solution which we
+ * don't implement here.
+ */
+ if ((afsr & AFSR_AFO) != 0 || type == T_STOREBUFFAULT ||
+ (type == T_DATAFAULT && !(sfsr & SFSR_FAV))) {
+ memerr4m(type, sfsr, sfva, afsr, afva, tf);
+ /*
+ * If we get here, exit the trap handler and wait for the
+ * trap to reoccur
+ */
+ goto out;
+ }
+
+ /*
+ * Figure out what to pass the VM code. We cannot ignore the sfva
+ * register on text faults, since this might be a trap on an
+ * alternate-ASI access to code space. However, if we're on a
+ * supersparc, we can't help using PC, since we don't get a VA in
+ * sfva.
+ * Kernel faults are somewhat different: text faults are always
+ * illegal, and data faults are extra complex. User faults must
+ * set p->p_md.md_tf, in case we decide to deliver a signal. Check
+ * for illegal virtual addresses early since those can induce more
+ * faults.
+ * All translation faults are illegal, and result in a SIGSEGV
+ * being delivered to the running process (or a kernel panic, for
+ * a kernel fault). We check the translation first to make sure
+ * it is not spurious.
+ * Also, note that in the case where we have an overwritten
+ * text fault (OW==1, AT==2,3), we attempt to service the
+ * second (overwriting) fault, then restart the instruction
+ * (which is from the first fault) and allow the first trap
+ * to reappear. XXX is this right? It will probably change...
+ */
+ if ((sfsr & SFSR_FT) == SFSR_FT_NONE)
+ goto out; /* No fault. Why were we called? */
+
+ /*
+ * This next section is a mess since some chips use sfva, and others
+ * don't on text faults. We want to use sfva where possible, since
+ * we _could_ be dealing with an ASI 0x8,0x9 data access to text space,
+ * which would trap as a text fault, at least on a HyperSPARC. Ugh.
+ * XXX: Find out about MicroSPARCs.
+ */
+
+ if (type == T_TEXTFAULT && mmumod == SUN4M_MMU_SS &&
+ (cpumod & 0xf0) == (SUN4M_SS) && (sfsr & SFSR_FAV)) {
+ sfva = pc; /* can't trust fav on supersparc/text fault */
+ } else if (type == T_TEXTFAULT && mmumod != SUN4M_MMU_HS) {
+ sfva = pc;
+ } else if (!(sfsr & SFSR_FAV)) {
+#ifdef DEBUG
+ if (type != T_TEXTFAULT)
+ printf("mem_access_fault: got fault without valid SFVA\n");
+ if (mmumod == SUN4M_MMU_HS)
+ printf("mem_access_fault: got fault without valid SFVA on "
+ "HyperSPARC!\n");
+#endif
+ if (type == T_TEXTFAULT)
+ sfva = pc;
+ else
+ goto fault;
+ }
+
+ if ((sfsr & SFSR_FT) == SFSR_FT_TRANSERR) {
+ /* Translation errors are always fatal, as they indicate
+ * a corrupt translation (page) table heirarchy.
+ */
+ if (tfaultaddr == sfva) /* Prevent infinite loops w/a static */
+ goto fault;
+ tfaultaddr = sfva;
+ if ((lda((sfva & 0xFFFFF000) | ASI_SRMMUFP_LN, ASI_SRMMUFP) &
+ SRMMU_TETYPE) != SRMMU_TEPTE)
+ goto fault; /* Translation bad */
+ else goto out; /* Translation OK, retry operation */
+ }
+
+ va = trunc_page(sfva);
+
+#ifdef DEBUG
+ if (lastdouble) {
+ printf("stacked tfault @ %x (pc %x); sfsr %x", sfva, pc, sfsr);
+ lastdouble = 0;
+ if (curproc == NULL)
+ printf("NULL proc\n");
+ else
+ printf("pid %d(%s); sigmask %x, sigcatch %x\n",
+ curproc->p_pid, curproc->p_comm,
+ curproc->p_sigmask, curproc->p_sigcatch);
+ }
+#endif
+ if (((sfsr & SFSR_AT_TEXT) || type == T_TEXTFAULT) &&
+ !(sfsr & SFSR_AT_STORE) && (sfsr & SFSR_OW)) {
+ if (psr & PSR_PS) /* never allow in kernel */
+ goto kfault;
+ /*
+ * Double text fault. The evil "case 5" from the HS manual...
+ * Attempt to handle early fault. Ignores ASI 8,9 issue...may
+ * do a useless VM read.
+ * XXX: Is this really necessary?
+ */
+#ifdef DEBUG
+ if (dfdebug) {
+ lastdouble = 1;
+ printf("mem_access_fault: double text fault @ %x (pc %x); sfsr %x",
+ sfva, pc, sfsr);
+ if (curproc == NULL)
+ printf("NULL proc\n");
+ else
+ printf(" pid %d(%s); sigmask %x, sigcatch %x\n",
+ curproc->p_pid, curproc->p_comm,
+ curproc->p_sigmask, curproc->p_sigcatch);
+ }
+#endif
+ if (mmumod == SUN4M_MMU_HS) { /* On HS, we have va for both */
+ if (vm_fault(kernel_map, trunc_page(pc),
+ VM_PROT_READ, 0) != KERN_SUCCESS)
+#ifdef DEBUG
+ printf("mem_access_fault: "
+ "can't pagein 1st text fault.\n")
+#endif
+ ;
+ }
+ }
+
+ /* Now munch on protections... */
+
+ ftype = sfsr & SFSR_AT_STORE ? VM_PROT_READ|VM_PROT_WRITE:VM_PROT_READ;
+ if (psr & PSR_PS) {
+ extern char Lfsbail[];
+ if (sfsr & SFSR_AT_TEXT || type == T_TEXTFAULT) {
+ (void) splhigh();
+ printf("text fault: pc=%x sfsr=%b sfva=%x\n", pc,
+ sfsr, SFSR_BITS, sfva);
+ panic("kernel fault");
+ /* NOTREACHED */
+ }
+ /*
+ * If this was an access that we shouldn't try to page in,
+ * resume at the fault handler without any action.
+ */
+ if (p->p_addr && p->p_addr->u_pcb.pcb_onfault == Lfsbail)
+ goto kfault;
+
+ /*
+ * During autoconfiguration, faults are never OK unless
+ * pcb_onfault is set. Once running normally we must allow
+ * exec() to cause copy-on-write faults to kernel addresses.
+ */
+ if (cold)
+ goto kfault;
+ if (va >= KERNBASE) {
+ if (vm_fault(kernel_map, va, ftype, 0) == KERN_SUCCESS)
+ return;
+ goto kfault;
+ }
+ } else
+ p->p_md.md_tf = tf;
+
+ vm = p->p_vmspace;
+#ifdef DEBUG
+ /*
+ * mmu_pagein returns -1 if the page is already valid, in which
+ * case we have a hard fault.. now why would *that* happen?
+ * But it happens sporadically, and vm_fault() seems to clear it..
+ */
+ rv = mmu_pagein4m(&vm->vm_pmap, va,
+ sfsr & SFSR_AT_STORE ? VM_PROT_WRITE : VM_PROT_READ);
+ if (rv < 0)
+ printf(" sfsr=%x(FT=%x,AT=%x,LVL=%x), sfva=%x, pc=%x, psr=%x\n",
+ sfsr, (sfsr >> 2) & 7, (sfsr >> 5) & 7, (sfsr >> 8) & 3,
+ sfva, pc, psr);
+ if (rv > 0)
+ panic("mmu_pagein4m returns %d", rv);
+#endif
+
+ /* alas! must call the horrible vm code */
+ rv = vm_fault(&vm->vm_map, (vm_offset_t)va, ftype, FALSE);
+
+ /*
+ * If this was a stack access we keep track of the maximum
+ * accessed stack size. Also, if vm_fault gets a protection
+ * failure it is due to accessing the stack region outside
+ * the current limit and we need to reflect that as an access
+ * error.
+ */
+ if ((caddr_t)va >= vm->vm_maxsaddr) {
+ if (rv == KERN_SUCCESS) {
+ unsigned nss = clrnd(btoc(USRSTACK - va));
+ if (nss > vm->vm_ssize)
+ vm->vm_ssize = nss;
+ } else if (rv == KERN_PROTECTION_FAILURE)
+ rv = KERN_INVALID_ADDRESS;
+ }
+ if (rv != KERN_SUCCESS) {
+ /*
+ * Pagein failed. If doing copyin/out, return to onfault
+ * address. Any other page fault in kernel, die; if user
+ * fault, deliver SIGSEGV.
+ */
+fault:
+ if (psr & PSR_PS) {
+kfault:
+ onfault = p->p_addr ?
+ (int)p->p_addr->u_pcb.pcb_onfault : 0;
+ if (!onfault) {
+ (void) splhigh();
+ printf("data fault: pc=%x addr=%x sfsr=%b\n",
+ pc, sfva, sfsr, SFSR_BITS);
+ panic("kernel fault");
+ /* NOTREACHED */
+ }
+ tf->tf_pc = onfault;
+ tf->tf_npc = onfault + 4;
+ return;
+ }
+ trapsignal(p, SIGSEGV, (u_int)sfva);
+ }
+out:
+ if ((psr & PSR_PS) == 0) {
+ userret(p, pc, sticks);
+ share_fpu(p, tf);
+ }
}
+#endif
/*
* System calls. `pc' is just a copy of tf->tf_pc.
@@ -722,9 +1033,11 @@ out:
* `save' effect of each trap). They are, however, the %o registers of the
* thing that made the system call, and are named that way here.
*/
+void
syscall(code, tf, pc)
- register_t code, pc;
+ register_t code;
register struct trapframe *tf;
+ register_t pc;
{
register int i, nsys, *ap, nap;
register struct sysent *callp;
@@ -735,7 +1048,9 @@ syscall(code, tf, pc)
} args;
register_t rval[2];
u_quad_t sticks;
+#ifdef DIAGNOSTIC
extern struct pcb *cpcb;
+#endif
cnt.v_syscall++;
p = curproc;
@@ -783,7 +1098,7 @@ syscall(code, tf, pc)
break;
}
- if (code < 0 || code >= nsys)
+ if (code < 0 || code >= nsys)
callp += p->p_emul->e_nosys;
else {
callp += code;
@@ -814,18 +1129,7 @@ syscall(code, tf, pc)
rval[1] = tf->tf_out[1];
error = (*callp->sy_call)(p, &args, rval);
if (error == 0) {
- /*
- * If fork succeeded and we are the child, our stack
- * has moved and the pointer tf is no longer valid,
- * and p is wrong. Compute the new trapframe pointer.
- * (The trap frame invariably resides at the
- * tippity-top of the u. area.)
- */
- p = curproc;
- tf = (struct trapframe *)
- ((caddr_t)p->p_addr + USPACE - sizeof(*tf));
-/* this is done earlier: */
-/* p->p_md.md_tf = tf; */
+ /* Note: fork() does not return here in the child */
tf->tf_out[0] = rval[0];
tf->tf_out[1] = rval[1];
if (new) {
@@ -862,3 +1166,22 @@ bad:
#endif
share_fpu(p, tf);
}
+
+/*
+ * Process the tail end of a fork() for the child.
+ */
+void
+child_return(p)
+ struct proc *p;
+{
+
+ /*
+ * Return values in the frame set by cpu_fork().
+ */
+ userret(p, p->p_md.md_tf->tf_pc, 0);
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p->p_tracep,
+ (p->p_flag & P_PPWAIT) ? SYS_vfork : SYS_fork, 0, 0);
+#endif
+}
diff --git a/sys/arch/sparc/sparc/vaddrs.h b/sys/arch/sparc/sparc/vaddrs.h
index e6d02bf0c95..48cad5f52e8 100644
--- a/sys/arch/sparc/sparc/vaddrs.h
+++ b/sys/arch/sparc/sparc/vaddrs.h
@@ -1,6 +1,8 @@
-/* $NetBSD: vaddrs.h,v 1.5 1994/12/06 08:34:14 deraadt Exp $ */
+/* $NetBSD: vaddrs.h,v 1.7 1996/05/16 15:57:28 abrown Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -25,6 +27,7 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
+ * This product includes software developed by Harvard University.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -59,24 +62,57 @@
* the Zilog ZSCC serial port chips to be mapped at fixed VAs to make
* microtime() and the zs hardware interrupt handlers faster.
*
+ * [sun4/sun4c:]
* Ideally, we should map the interrupt enable register here as well,
* but that would require allocating pmegs in locore.s, so instead we
- * use one of the two `wasted' pages at KERNBASE+2*NBPG (see locore.s).
+ * use one of the two `wasted' pages at KERNBASE+_MAXNBPG (see locore.s).
*/
#ifndef IODEV_0
#define IODEV_0 0xfe000000 /* must match VM_MAX_KERNEL_ADDRESS */
+#define _MAXNBPG 8192 /* fixed VAs, independent of actual NBPG */
+#define _MAXNCPU 4 /* fixed VA allocation allows 4 CPUs */
+
+/* [4m:] interrupt and counter registers take (1 + NCPU) pages. */
+
#define TIMERREG_VA (IODEV_0)
-#define ZS0_VA (IODEV_0 + 1*NBPG)
-#define ZS1_VA (IODEV_0 + 2*NBPG)
-#define AUXREG_VA (IODEV_0 + 3*NBPG)
-#define TMPMAP_VA (IODEV_0 + 4*NBPG)
-#define MSGBUF_VA (IODEV_0 + 5*NBPG)
-#define IODEV_BASE (IODEV_0 + 6*NBPG)
+#define COUNTERREG_VA ( TIMERREG_VA + _MAXNBPG*_MAXNCPU) /* [4m] */
+#define ZS0_VA (COUNTERREG_VA + _MAXNBPG)
+#define ZS1_VA ( ZS0_VA + _MAXNBPG)
+#define AUXREG_VA ( ZS1_VA + _MAXNBPG)
+#define TMPMAP_VA ( AUXREG_VA + _MAXNBPG)
+#define MSGBUF_VA ( TMPMAP_VA + _MAXNBPG)
+#define PI_INTR_VA ( MSGBUF_VA + _MAXNBPG) /* [4m] */
+#define SI_INTR_VA ( PI_INTR_VA + _MAXNBPG*_MAXNCPU) /* [4m] */
+#define IODEV_BASE ( SI_INTR_VA + _MAXNBPG)
#define IODEV_END 0xff000000 /* 16 MB of iospace */
#define DVMA_BASE 0xfff00000
#define DVMA_END 0xfffc0000
+/*
+ * The next constant defines the amount of reserved DVMA space on the
+ * Sun4m. The amount of space *must* be a multiple of 16MB, and thus
+ * (((u_int)0) - DVMA4M_BASE) must be divisible by 16*1024*1024!
+ * Note that pagetables must be allocated at a cost of 1k per MB of DVMA
+ * space, plus severe alignment restrictions. So don't make DVMA4M_BASE too
+ * low (max space = 2G).
+ *
+ * Since DVMA space overlaps with normal kernel address space (notably
+ * the device mappings and the PROM), we don't want to put any DVMA
+ * mappings where any of this useful stuff is (i.e. if we dvma_malloc
+ * a buffer, we want to still have a SRMMU mapping to it, and we can't
+ * have that if its on top of kernel code). Thus the last two
+ * constants define the actual DVMA addresses used. These can be anything
+ * as long as they are within the bounds setup by the first 2 constants.
+ * This is especially important on MP systems with cache coherency: to
+ * avoid consistency problems, DVMA addresses must map to the same place
+ * in both processor and IOMMU space.
+ */
+#define DVMA4M_BASE 0xfc000000 /* can change subject to above rule */
+#define DVMA4M_TOP 0xffffffff /* do not modify */
+#define DVMA4M_START 0xfd000000 /* 16M of DVMA */
+#define DVMA4M_END 0xfe000000 /* XXX is this enough? */
+
#endif /* IODEV_0 */
diff --git a/sys/arch/sparc/sparc/vm_machdep.c b/sys/arch/sparc/sparc/vm_machdep.c
index a4c3c9fa4c5..0a0bc838935 100644
--- a/sys/arch/sparc/sparc/vm_machdep.c
+++ b/sys/arch/sparc/sparc/vm_machdep.c
@@ -1,6 +1,8 @@
-/* $NetBSD: vm_machdep.c,v 1.18 1995/12/11 12:44:39 pk Exp $ */
+/* $NetBSD: vm_machdep.c,v 1.27.4.1 1996/08/02 21:35:20 jtc Exp $ */
/*
+ * Copyright (c) 1996
+ * The President and Fellows of Harvard College. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -12,6 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
+ * This product includes software developed by Harvard University.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,6 +26,7 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
+ * This product includes software developed by Harvard University.
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
@@ -53,21 +57,24 @@
#include <sys/buf.h>
#include <sys/exec.h>
#include <sys/vnode.h>
+#include <sys/map.h>
#include <vm/vm.h>
#include <vm/vm_kern.h>
#include <machine/cpu.h>
#include <machine/frame.h>
+#include <machine/trap.h>
#include <sparc/sparc/cache.h>
/*
* Move pages from one kernel virtual address to another.
*/
+void
pagemove(from, to, size)
register caddr_t from, to;
- int size;
+ size_t size;
{
register vm_offset_t pa;
@@ -108,6 +115,7 @@ dvma_malloc(len, kaddr, flags)
vm_offset_t kva;
vm_offset_t dva;
+ len = round_page(len);
kva = (vm_offset_t)malloc(len, M_DEVBUF, flags);
if (kva == NULL)
return (NULL);
@@ -129,7 +137,7 @@ dvma_free(dva, len, kaddr)
{
vm_offset_t kva = *(vm_offset_t *)kaddr;
- dvma_mapout((vm_offset_t)dva, kva, len);
+ dvma_mapout((vm_offset_t)dva, kva, round_page(len));
free((void *)kva, M_DEVBUF);
}
@@ -147,13 +155,19 @@ dvma_mapin(map, va, len, canwait)
register int npf, s;
register vm_offset_t pa;
long off, pn;
+#if defined(SUN4M)
+ extern int has_iocache;
+#endif
off = (int)va & PGOFSET;
va -= off;
len = round_page(len + off);
npf = btoc(len);
- kvm_uncache((caddr_t)va, len >> PGSHIFT);
+#if defined(SUN4M)
+ if (!has_iocache)
+ kvm_uncache((caddr_t)va, len >> PGSHIFT);
+#endif
s = splimp();
for (;;) {
@@ -179,25 +193,25 @@ dvma_mapin(map, va, len, canwait)
panic("dvma_mapin: null page frame");
pa = trunc_page(pa);
-#if defined(SUN4M) && 0
+#if defined(SUN4M)
if (cputyp == CPU_SUN4M) {
iommu_enter(tva, pa);
} else
#endif
{
- /*
+ /*
* pmap_enter distributes this mapping to all
* contexts... maybe we should avoid this extra work
- */
+ */
#ifdef notyet
#if defined(SUN4)
if (have_iocache)
pa |= PG_IOC;
#endif
#endif
- pmap_enter(pmap_kernel(), tva,
+ pmap_enter(pmap_kernel(), tva,
pa | PMAP_NC,
- VM_PROT_READ|VM_PROT_WRITE, 1);
+ VM_PROT_READ|VM_PROT_WRITE, 1);
}
tva += PAGE_SIZE;
@@ -209,7 +223,7 @@ dvma_mapin(map, va, len, canwait)
/*
* Remove double map of `va' in DVMA space at `kva'.
*/
-int
+void
dvma_mapout(kva, va, len)
vm_offset_t kva, va;
int len;
@@ -220,12 +234,12 @@ dvma_mapout(kva, va, len)
kva -= off;
len = round_page(len + off);
-#if defined(SUN4M) && 0
+#if defined(SUN4M)
if (cputyp == CPU_SUN4M)
iommu_remove(kva, len);
else
#endif
- pmap_remove(pmap_kernel(), kva, kva + len);
+ pmap_remove(pmap_kernel(), kva, kva + len);
s = splimp();
rmfree(dvmamap, btoc(len), vtorc(kva));
@@ -239,8 +253,11 @@ dvma_mapout(kva, va, len)
/*
* Map an IO request into kernel virtual address space.
*/
-vmapbuf(bp)
+/*ARGSUSED*/
+void
+vmapbuf(bp, sz)
register struct buf *bp;
+ vm_size_t sz;
{
register vm_offset_t addr, kva, pa;
register vm_size_t size, off;
@@ -281,8 +298,11 @@ vmapbuf(bp)
/*
* Free the io map addresses associated with this IO operation.
*/
-vunmapbuf(bp)
+/*ARGSUSED*/
+void
+vunmapbuf(bp, sz)
register struct buf *bp;
+ vm_size_t sz;
{
register vm_offset_t kva = (vm_offset_t)bp->b_data;
register vm_size_t size, off;
@@ -308,39 +328,34 @@ vunmapbuf(bp)
/*
* Finish a fork operation, with process p2 nearly set up.
- * Copy and update the kernel stack and pcb, making the child
- * ready to run, and marking it so that it can return differently
- * than the parent. Returns 1 in the child process, 0 in the parent.
+ * Copy and update the pcb, making the child ready to run, and marking
+ * it so that it can return differently than the parent.
*
* This function relies on the fact that the pcb is
* the first element in struct user.
*/
+void
cpu_fork(p1, p2)
register struct proc *p1, *p2;
{
register struct pcb *opcb = &p1->p_addr->u_pcb;
register struct pcb *npcb = &p2->p_addr->u_pcb;
- register u_int sp, topframe, off, ssize;
+ register struct trapframe *tf2;
+ register struct rwindow *rp;
/*
- * Save all the registers to p1's stack or, in the case of
+ * Save all user registers to p1's stack or, in the case of
* user registers and invalid stack pointers, to opcb.
- * snapshot() also sets the given pcb's pcb_sp and pcb_psr
- * to the current %sp and %psr, and sets pcb_pc to a stub
- * which returns 1. We then copy the whole pcb to p2;
- * when switch() selects p2 to run, it will run at the stub,
- * rather than at the copying code below, and cpu_fork
- * will return 1.
- *
- * Note that the order `*npcb = *opcb, snapshot(npcb)' is wrong,
- * as user registers might then wind up only in opcb.
- * We could call save_user_windows first,
- * but that would only save 3 stores anyway.
+ * We then copy the whole pcb to p2; when switch() selects p2
+ * to run, it will run at the `proc_trampoline' stub, rather
+ * than returning at the copying code below.
*
* If process p1 has an FPU state, we must copy it. If it is
* the FPU user, we must save the FPU state first.
*/
- snapshot(opcb);
+
+ write_user_windows();
+ opcb->pcb_psr = getpsr();
bcopy((caddr_t)opcb, (caddr_t)npcb, sizeof(struct pcb));
if (p1->p_md.md_fpstate) {
if (p1 == fpproc)
@@ -353,30 +368,81 @@ cpu_fork(p1, p2)
p2->p_md.md_fpstate = NULL;
/*
- * Copy the active part of the kernel stack,
- * then adjust each kernel sp -- the frame pointer
- * in the top frame is a user sp -- in the child's copy,
- * including the initial one in the child's pcb.
+ * Setup (kernel) stack frame that will by-pass the child
+ * out of the kernel. (The trap frame invariably resides at
+ * the tippity-top of the u. area.)
*/
- sp = npcb->pcb_sp; /* points to old kernel stack */
- ssize = (u_int)opcb + USPACE - sp;
- if (ssize >= USPACE - sizeof(struct pcb))
- panic("cpu_fork 1");
- off = (u_int)npcb - (u_int)opcb;
- qcopy((caddr_t)sp, (caddr_t)sp + off, ssize);
- sp += off;
- npcb->pcb_sp = sp;
- topframe = (u_int)npcb + TOPFRAMEOFF;
- while (sp < topframe)
- sp = ((struct rwindow *)sp)->rw_in[6] += off;
- if (sp != topframe)
- panic("cpu_fork 2");
+ tf2 = p2->p_md.md_tf = (struct trapframe *)
+ ((int)npcb + USPACE - sizeof(*tf2));
+
+ /* Copy parent's trapframe */
+ *tf2 = *(struct trapframe *)((int)opcb + USPACE - sizeof(*tf2));
+
+ /* Duplicate efforts of syscall(), but slightly differently */
+ if (tf2->tf_global[1] & SYSCALL_G2RFLAG) {
+ /* jmp %g2 (or %g7, deprecated) on success */
+ tf2->tf_npc = tf2->tf_global[2];
+ } else {
+ /*
+ * old system call convention: clear C on success
+ * note: proc_trampoline() sets a fresh psr when
+ * returning to user mode.
+ */
+ /*tf2->tf_psr &= ~PSR_C; -* success */
+ }
+
+ /* Set return values in child mode */
+ tf2->tf_out[0] = 0;
+ tf2->tf_out[1] = 1;
+
+ /* Construct kernel frame to return to in cpu_switch() */
+ rp = (struct rwindow *)((u_int)npcb + TOPFRAMEOFF);
+ rp->rw_local[0] = (int)child_return; /* Function to call */
+ rp->rw_local[1] = (int)p2; /* and its argument */
+
+ npcb->pcb_pc = (int)proc_trampoline - 8;
+ npcb->pcb_sp = (int)rp;
+ npcb->pcb_psr &= ~PSR_CWP; /* Run in window #0 */
+ npcb->pcb_wim = 1; /* Fence at window #1 */
+
+}
+
+/*
+ * cpu_set_kpc:
+ *
+ * Arrange for in-kernel execution of a process to continue at the
+ * named pc, as if the code at that address were called as a function
+ * with the current process's process pointer as an argument.
+ *
+ * Note that it's assumed that when the named process returns,
+ * we immediately return to user mode.
+ *
+ * (Note that cpu_fork(), above, uses an open-coded version of this.)
+ */
+void
+cpu_set_kpc(p, pc)
+ struct proc *p;
+ void (*pc) __P((struct proc *));
+{
+ struct pcb *pcb;
+ struct rwindow *rp;
+
+ pcb = &p->p_addr->u_pcb;
+
+ rp = (struct rwindow *)((u_int)pcb + TOPFRAMEOFF);
+ rp->rw_local[0] = (int)pc; /* Function to call */
+ rp->rw_local[1] = (int)p; /* and its argument */
+
/*
- * This might be unnecessary, but it may be possible for the child
- * to run in ptrace or sendsig before it returns from fork.
+ * Frob PCB:
+ * - arrange to return to proc_trampoline() from cpu_switch()
+ * - point it at the stack frame constructed above
+ * - make it run in a clear set of register windows
*/
- p2->p_md.md_tf = (struct trapframe *)((int)p1->p_md.md_tf + off);
- return (0);
+ pcb->pcb_pc = (int)proc_trampoline - 8;
+ pcb->pcb_sp = (int)rp;
+ pcb->pcb_psr &= ~PSR_CWP; /* Run in window #0 */
+ pcb->pcb_wim = 1; /* Fence at window #1 */
}
/*
@@ -416,7 +482,6 @@ cpu_coredump(p, vp, cred, chdr)
struct core *chdr;
{
int error;
- register struct user *up = p->p_addr;
struct md_coredump md_core;
struct coreseg cseg;
diff --git a/sys/arch/sparc/stand/Makefile.inc b/sys/arch/sparc/stand/Makefile.inc
index a083047b0d1..5a960d5b0cb 100644
--- a/sys/arch/sparc/stand/Makefile.inc
+++ b/sys/arch/sparc/stand/Makefile.inc
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.inc,v 1.4 1995/10/09 23:25:55 pk Exp $
+# $NetBSD: Makefile.inc,v 1.5 1996/02/01 22:33:01 mycroft Exp $
.if !defined(__stand_makefile_inc)
__stand_makefile_inc=1
@@ -22,7 +22,7 @@ DEFS+= -DSTANDALONE -DRELOC=${RELOC} -DSUN4 -DSUN4C -DSUN_BOOTPARAMS
CFLAGS+= -O2 ${INCLUDES} ${DEFS}
srt0.o: srt0.S
- ${CC} ${CFLAGS} -DLOCORE -c ${.IMPSRC}
+ ${CC} ${CFLAGS} -D_LOCORE -c ${.IMPSRC}
cleandir:
rm -rf lib machine
diff --git a/sys/arch/sparc/stand/binstall.sh b/sys/arch/sparc/stand/binstall.sh
index 552a18ef41c..1b2db4158af 100644
--- a/sys/arch/sparc/stand/binstall.sh
+++ b/sys/arch/sparc/stand/binstall.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# $NetBSD: binstall.sh,v 1.1.2.1 1995/10/13 19:55:03 pk Exp $
+# $NetBSD: binstall.sh,v 1.3 1996/04/07 20:00:12 thorpej Exp $
#
vecho () {
@@ -59,7 +59,7 @@ fi
WHAT=$1
DEST=$2
-if [ "`sysctl -n hw.model | cut -b1-5`" = "SUN/4" ]; then
+if [ "`sysctl -n hw.model | cut -b1-5`" = "SUN-4" ]; then
KARCH=sun4
else
KARCH=sun4c
@@ -106,7 +106,7 @@ case $WHAT in
;;
"net")
- TARGET=$DEST/boot.sparc.openbsd.$KARCH
+ TARGET=$DEST/boot.sparc.netbsd.$KARCH
vecho Target: $TARGET
$DOIT dd if=${MDEC}/boot of=$TARGET skip=$SKIP bs=32
;;
diff --git a/sys/arch/sparc/stand/boot.c b/sys/arch/sparc/stand/boot.c
index 7a696f208e7..5b423db0ad2 100644
--- a/sys/arch/sparc/stand/boot.c
+++ b/sys/arch/sparc/stand/boot.c
@@ -39,7 +39,6 @@
#include <sys/reboot.h>
#include <a.out.h>
#include <stand.h>
-#include <paths.h>
#include "promdev.h"
@@ -51,6 +50,7 @@ int netif_debug;
/*
* Boot device is derived from ROM provided information.
*/
+#define DEFAULT_KERNEL "netbsd"
extern char *version;
unsigned long esym;
@@ -69,11 +69,11 @@ main()
prom_init();
- printf(">> OpenBSD BOOT [%s]\n", version);
+ printf(">> NetBSD BOOT [%s]\n", version);
file = prom_bootfile;
if (file == 0 || *file == 0)
- file = _PATH_UNIX;
+ file = DEFAULT_KERNEL;
for (;;) {
if (prom_boothow & RB_ASKNAME) {
diff --git a/sys/arch/sparc/stand/bootxx/Makefile b/sys/arch/sparc/stand/bootxx/Makefile
index 7769be5223b..fb0900ac655 100644
--- a/sys/arch/sparc/stand/bootxx/Makefile
+++ b/sys/arch/sparc/stand/bootxx/Makefile
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.4.2.1 1995/10/13 19:55:36 pk Exp $
+# $NetBSD: Makefile,v 1.5 1995/10/10 20:07:54 pk Exp $
R= ..
.PATH: ${.CURDIR}/${R}
diff --git a/sys/arch/sparc/stand/installboot.c b/sys/arch/sparc/stand/installboot.c
index e92313f5c69..79dd8964036 100644
--- a/sys/arch/sparc/stand/installboot.c
+++ b/sys/arch/sparc/stand/installboot.c
@@ -1,4 +1,4 @@
-/* $NetBSD$ */
+/* $NetBSD: installboot.c,v 1.11 1995/11/08 09:09:20 pk Exp $ */
/*
* Copyright (c) 1994 Paul Kranenburg
diff --git a/sys/arch/sparc/stand/net.c b/sys/arch/sparc/stand/net.c
index f70c1834793..e67b22ac6f4 100644
--- a/sys/arch/sparc/stand/net.c
+++ b/sys/arch/sparc/stand/net.c
@@ -1,4 +1,4 @@
-/* $NetBSD: net.c,v 1.2 1995/09/18 21:31:46 pk Exp $ */
+/* $NetBSD: net.c,v 1.3 1996/05/04 19:36:01 pk Exp $ */
/*
* Copyright (c) 1995 Gordon W. Ross
@@ -153,5 +153,7 @@ net_mountroot()
printf("root addr=%s path=%s\n", inet_ntoa(rootip), rootpath);
/* Get the NFS file handle (mount). */
- return nfs_mount(netdev_sock, rootip, rootpath);
+ if (nfs_mount(netdev_sock, rootip, rootpath) != 0)
+ return (errno);
+ return 0;
}
diff --git a/sys/arch/sparc/stand/promdev.c b/sys/arch/sparc/stand/promdev.c
index 1404ce4f20d..94ab155eff0 100644
--- a/sys/arch/sparc/stand/promdev.c
+++ b/sys/arch/sparc/stand/promdev.c
@@ -1,4 +1,4 @@
-/* $NetBSD: promdev.c,v 1.14.2.1 1995/10/13 19:53:55 pk Exp $ */
+/* $NetBSD: promdev.c,v 1.16 1995/11/14 15:04:01 pk Exp $ */
/*
* Copyright (c) 1993 Paul Kranenburg
diff --git a/sys/arch/sparc/stand/srt0.S b/sys/arch/sparc/stand/srt0.S
index b31e322a86d..e5248292b84 100644
--- a/sys/arch/sparc/stand/srt0.S
+++ b/sys/arch/sparc/stand/srt0.S
@@ -1,4 +1,4 @@
-/* $NetBSD: srt0.S,v 1.5 1995/12/13 23:35:18 pk Exp $ */
+/* $NetBSD: srt0.S,v 1.5.4.2 1996/07/17 01:51:46 jtc Exp $ */
/*
* Copyright (c) 1994 Paul Kranenburg
@@ -102,13 +102,16 @@ start:
call _bzero
sub %o1, %o0, %o1
+#if 0
/*
- * Enable interrupts.
+ * Enable interrupts above level 11. This enables "L1-A", but
+ * avoids spurious interrupt bites from most other devices
*/
rd %psr, %o0
andn %o0, PSR_PIL, %o0
- wr %g0, %o0, %psr
+ wr %o0, 0xb00, %psr ! (11 << 8)
nop; nop; nop
+#endif
/*
* Set CPU type that we are running on.
diff --git a/sys/arch/sparc/stand/version.c b/sys/arch/sparc/stand/version.c
index f288f3059da..1217ce7aba7 100644
--- a/sys/arch/sparc/stand/version.c
+++ b/sys/arch/sparc/stand/version.c
@@ -38,4 +38,4 @@
* 1.4 add oldmon support and network support.
*/
-char *version = "$Revision: 1.1 $";
+char *version = "$Revision: 1.2 $";