diff options
Diffstat (limited to 'sys/arch')
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 $"; |