diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-03-28 20:44:24 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-03-28 20:44:24 +0000 |
commit | 6ea0ed8392999d052b79785548a577d7e55b7184 (patch) | |
tree | b4c5fb05563150bb09cc3d203971a18a2b5277bc | |
parent | b71835f84a40d614f56816274c2400a719e82600 (diff) |
Work in progress support for the SGI Indigo, Indigo 2 and Indy systems
(IP20, IP22, IP24) in 64-bit mode, adapated from NetBSD. Currently limited
to headless operation, input and video drivers will get ported soon.
Should work on all R4000, R4440 and R5000 based systems. L2 cache on R5000SC
Indy not supported yet (coming soon), R4600 not supported yet either (coming
soon as well).
Tested to boot multiuser on: Indigo2 R4000SC, Indy R4000PC, Indy R4000SC,
Indy R5000SC, Indigo2 R4400SC. There are still glitches in the Ethernet driver
which are being looked at.
Expansion support is limited to the GIO E++ board; GIO boards with PCI-GIO
bridges not ported yet due to the lack of hardware, and this kind of driver
does not port blindly.
Most of this work comes from NetBSD, polishing and integration work, as well
as putting as many ``R4x00 in 64-bit mode'' erratas as necessary, by yours
truly.
More work is coming, as well as trying to get some easy way to boot install
kernels (as older PROM can only boot ECOFF binaries, which won't do for the
kernel).
78 files changed, 14975 insertions, 233 deletions
diff --git a/etc/etc.sgi/MAKEDEV.md b/etc/etc.sgi/MAKEDEV.md index 561a9b8abeb..cae1e4d51e2 100644 --- a/etc/etc.sgi/MAKEDEV.md +++ b/etc/etc.sgi/MAKEDEV.md @@ -1,6 +1,6 @@ define(MACHINE,sgi)dnl vers(__file__, - {-$OpenBSD: MAKEDEV.md,v 1.35 2011/10/22 19:31:23 miod Exp $-}, + {-$OpenBSD: MAKEDEV.md,v 1.36 2012/03/28 20:44:23 miod Exp $-}, etc.MACHINE)dnl dnl dnl Copyright (c) 2001-2006 Todd T. Fries <todd@OpenBSD.org> @@ -26,6 +26,15 @@ dnl OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF dnl ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. dnl dnl +__devitem(zs, tty[a-b]*, Zilog 8530 serial port,zs)dnl +_mkdev(zs, {-tty[a-b]-}, {-u=${i#tty*} + case $u in + a) n=0 ;; + b) n=1 ;; + *) echo unknown tty device $i ;; + esac + M tty$u c major_zs_c $n 660 dialer uucp + M cua$u c major_zs_c Add($n, 128) 660 dialer uucp-})dnl _TITLE(make) _DEV(all) _DEV(ramd) @@ -42,6 +51,7 @@ _DEV(ch, 36) _DEV(st, 10, 10) _TITLE(term) _DEV(com, 17) +_DEV(zs, 19) _TITLE(pty) _DEV(ptm, 52) _DEV(pty, 5) @@ -94,8 +104,6 @@ target(all, ch, 0)dnl target(all, nnpfs, 0)dnl target(all, vscsi, 0)dnl target(all, diskmap)dnl -dnl twrget(all, flo, fd, 0, 0B, 0C, 0D, 0E, 0F, 0G, 0H)dnl -dnl twrget(all, flo, fd, 1, 1B, 1C, 1D, 1E, 1F, 1G, 1H)dnl target(all, pty, 0, 1, 2)dnl target(all, bpf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)dnl target(all, bio)dnl @@ -104,6 +112,7 @@ target(all, rd, 0)dnl target(all, cd, 0, 1)dnl target(all, sd, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)dnl target(all, vnd, 0, 1, 2, 3)dnl +twrget(all, zs, tty, a, b)dnl twrget(wscons, wscons, ttyD, cfg, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b)dnl twrget(wscons, wscons, ttyE, cfg, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b)dnl twrget(wscons, wscons, ttyF, cfg, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b)dnl diff --git a/share/man/man4/man4.sgi/Makefile b/share/man/man4/man4.sgi/Makefile index 7a76d44f6a2..64d1c715513 100644 --- a/share/man/man4/man4.sgi/Makefile +++ b/share/man/man4/man4.sgi/Makefile @@ -1,10 +1,14 @@ -# $OpenBSD: Makefile,v 1.20 2010/03/08 01:47:00 deraadt Exp $ +# $OpenBSD: Makefile,v 1.21 2012/03/28 20:44:23 miod Exp $ -MAN= dsrtc.4 gbe.4 iec.4 impact.4 intro.4 ioc.4 iockbc.4 iof.4 \ +MAN= dpclock.4 dsclock.4 dsrtc.4 gbe.4 gio.4 hpc.4 iec.4 imc.4 \ + impact.4 intro.4 ioc.4 iockbc.4 iof.4 \ macebus.4 mavb.4 mec.4 mkbc.4 odyssey.4 \ - owmac.4 owserial.4 power.4 xbow.4 xbridge.4 xheart.4 + owmac.4 owserial.4 power.4 \ + sq.4 wdsc.4 xbow.4 xbridge.4 xheart.4 zs.4 MLINKS= macebus.4 macepcibr.4 \ - xbridge.4 xbpci.4 + xbridge.4 xbpci.4 \ + zs.4 zstty.4 +# zs.4 zskbd.4 zs.4 zsms.4 MANSUBDIR=sgi diff --git a/share/man/man4/man4.sgi/dpclock.4 b/share/man/man4/man4.sgi/dpclock.4 new file mode 100644 index 00000000000..86b32fadcc3 --- /dev/null +++ b/share/man/man4/man4.sgi/dpclock.4 @@ -0,0 +1,46 @@ +.\" $OpenBSD: dpclock.4,v 1.5 2012/03/28 20:44:23 miod Exp $ +.\" $NetBSD: dpclock.4,v 1.5 2008/04/30 13:10:56 martin Exp $ +.\" +.\" Copyright (c) 2004 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This document is derived from work contributed to The NetBSD Foundation +.\" by Steve Rumble. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd $Mdocdate: March 28 2012 $ +.Dt DPCLOCK 4 sgi +.Os +.Sh NAME +.Nm dpclock +.Nd DS8573A realtime clock +.Sh SYNOPSIS +.Cd "dpclock* at hpc0" +.Sh DESCRIPTION +The +.Nm +driver provides support for the DP8573A realtime clock. +This device appears on SGI Indigo machines. +.Sh SEE ALSO +.Xr hpc 4 , +.Xr intro 4 diff --git a/share/man/man4/man4.sgi/dsclock.4 b/share/man/man4/man4.sgi/dsclock.4 new file mode 100644 index 00000000000..fe1f7b4e5b0 --- /dev/null +++ b/share/man/man4/man4.sgi/dsclock.4 @@ -0,0 +1,46 @@ +.\" $OpenBSD: dsclock.4,v 1.5 2012/03/28 20:44:23 miod Exp $ +.\" $NetBSD: dsclock.4,v 1.4 2008/04/30 13:10:56 martin Exp $ +.\" +.\" Copyright (c) 2004 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This document is derived from work contributed to The NetBSD Foundation +.\" by Steve Rumble. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd $Mdocdate: March 28 2012 $ +.Dt DSCLOCK 4 sgi +.Os +.Sh NAME +.Nm dsclock +.Nd DS1286 realtime clock +.Sh SYNOPSIS +.Cd "dsclock* at hpc0" +.Sh DESCRIPTION +The +.Nm +driver provides support for the DS1286 realtime clock. +This device appears on SGI Indy and Indigo2 machines. +.Sh SEE ALSO +.Xr hpc 4 , +.Xr intro 4 diff --git a/share/man/man4/man4.sgi/gio.4 b/share/man/man4/man4.sgi/gio.4 new file mode 100644 index 00000000000..07e2249f965 --- /dev/null +++ b/share/man/man4/man4.sgi/gio.4 @@ -0,0 +1,82 @@ +.\" $OpenBSD: gio.4,v 1.4 2012/03/28 20:44:23 miod Exp $ +.\" $NetBSD: gio.4,v 1.20 2008/04/30 13:10:56 martin Exp $ +.\" +.\" Copyright (c) 2002 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This document is derived from work contributed to The NetBSD Foundation +.\" by Antti Kantee. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd $Mdocdate: March 28 2012 $ +.Dt GIO 4 sgi +.Os +.Sh NAME +.Nd Graphics I/O GIO bus +.Sh SYNOPSIS +.Cd "gio0 at imc0" +.Sh DESCRIPTION +The +.Nm +bus is a bus for connecting high-speed peripherals to the main memory and +CPU. +The devices themselves are typically (but not necessarily) connected to the +.Xr hpc 4 +peripheral controller, and memory and CPU are accessed through the +.Xr imc 4 +system controller. +The +.Nm +bus is found on the Indigo, Indy, Challenge S, +Challenge M, and Indigo2 machines and exists in three incarnations: +GIO32, GIO32-bis, and GIO64. +.Sh SEE ALSO +.\" .Xr giopci 4 , +.\" .Xr grtwo 4 , +.Xr hpc 4 , +.Xr imc 4 , +.Xr intro 4 +.\" .Xr light 4 , +.\" .Xr newport 4 +.Sh CAVEATS +Challenge S systems may use only one +.Nm +DMA-capable expansion card, despite having two slots. +Cards based on the +.Xr hpc 4 +controller, such as the GIO32 scsi and E++ Ethernet adapters, must be +placed in slot 1 (closest to the side of the case). +All other cards must be placed in slot 0 (adjacent to the memory banks). +.Pp +Indigo2 and Challenge M systems contain either three or four GIO64 connectors, +depending on the model. +However, in both cases only two electrically distinct slots are present. +Therefore, distinct expansion cards may not share physical connectors +associated with the same slot. +On the other hand, this apparently redundant slot connectors allows +multiple board assemblies to draw more power from the bus, and also +helps mixing +.Nm +and EISA boards in the same chassis. +In all systems, the upper two GIO64 connectors are GIO slot 1, while +the lower connectors (either one or two of them) are GIO slot 0. diff --git a/share/man/man4/man4.sgi/hpc.4 b/share/man/man4/man4.sgi/hpc.4 new file mode 100644 index 00000000000..c996ce17f38 --- /dev/null +++ b/share/man/man4/man4.sgi/hpc.4 @@ -0,0 +1,91 @@ +.\" $OpenBSD: hpc.4,v 1.4 2012/03/28 20:44:23 miod Exp $ +.\" $NetBSD: hpc.4,v 1.12 2008/04/30 13:10:56 martin Exp $ +.\" +.\" Copyright (c) 2002 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This document is derived from work contributed to The NetBSD Foundation +.\" by Antti Kantee. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd $Mdocdate: March 28 2012 $ +.Dt HPC 4 sgi +.Os +.Sh NAME +.Nm hpc +.Nd SGI High performance Peripheral Controller +.Sh SYNOPSIS +.Cd "hpc0 at gio0 addr 0x1fb80000" +.Cd "hpc1 at gio0 addr 0x1fb00000" +.Cd "hpc2 at gio0 addr 0x1fb98000" +.\" .Cd "hpc3 at gio0 addr 0x1fb90000" +.Sh DESCRIPTION +.Nm +interfaces the peripherals connected to it to the +.Xr gio 4 +bus. +.Nm +is found on the Indigo, Indy, Challenge S, Challenge M, +and Indigo2 machines. +.Pp +There are three different numerical revisions of the +.Nm +controller. +Revisions 1 and 1.5 exist on Indigo machines, +as well as GIO32bis expansion cards such as the E++ SEEQ-based +Ethernet adapter. +Revision 1.5 supports bi-endian operation. +Revision 3 exists on Indy, Challenge S, Indigo2, and Challenge M systems. +It is possible to have an on-board HPC3 as well as HPC1.5-based +GIO32bis adapters in the Indy and Challenge S systems. +Additionally, the Challenge S may have a secondary HPC3 if the IOPLUS +(a.k.a. ''mezzanine'') board is installed. +.Sh LIST OF DEVICES +The devices currently supported are: +.Pp +.Bl -tag -width 10n -offset 3n -compact +.It Xr dsclock 4 +DS1286 realtime clock +.It Xr dpclock 4 +DP8573A realtime clock +.\" .It Xr haltwo 4 +.\" HAL2 audio controller +.It Xr sq 4 +Seeq 8003/80C03 Ethernet controller +.It Xr wdsc 4 +WD33c93 SCSI controller +.It Xr zs 4 +Zilog Z8530 UART +.El +.Sh SEE ALSO +.Xr gio 4 , +.Xr imc 4 , +.Xr intro 4 +.Sh BUGS +.Nm +Revisions 1 and 1.5 support DMA buffer pointers of only 28 bits +and may therefore only address 256 megabytes of memory. +The R4k Indigo and Indy are the only systems that support sufficient +memory to illustrate this drawback. +A software workaround is not currently implemented. +Revision 3, with 32 bit pointers, does not have this limitation. diff --git a/share/man/man4/man4.sgi/imc.4 b/share/man/man4/man4.sgi/imc.4 new file mode 100644 index 00000000000..abc53e562bb --- /dev/null +++ b/share/man/man4/man4.sgi/imc.4 @@ -0,0 +1,51 @@ +.\" $OpenBSD: imc.4,v 1.4 2012/03/28 20:44:23 miod Exp $ +.\" $NetBSD: imc.4,v 1.8 2008/04/30 13:10:56 martin Exp $ +.\" +.\" Copyright (c) 2002 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This document is derived from work contributed to The NetBSD Foundation +.\" by Antti Kantee. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd $Mdocdate: March 28 2012 $ +.Dt IMC 4 sgi +.Os +.Sh NAME +.Nm imc +.Nd Indy Memory Controller and system controller +.Sh SYNOPSIS +.Cd "imc0 at mainbus0" +.Sh DESCRIPTION +The Indy Memory Controller is responsible for acting as an interface from +the +.Xr gio 4 +bus to the main memory and CPU. +The +.Nm +is found in the Indigo R4k, Indy, Challenge S, Challenge M, and Indigo2 +machines. +.Sh SEE ALSO +.Xr gio 4 , +.\" .Xr int 4 , +.Xr intro 4 diff --git a/share/man/man4/man4.sgi/intro.4 b/share/man/man4/man4.sgi/intro.4 index 6ba0ae866d8..19076f477ba 100644 --- a/share/man/man4/man4.sgi/intro.4 +++ b/share/man/man4/man4.sgi/intro.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: intro.4,v 1.23 2011/09/03 22:59:07 jmc Exp $ +.\" $OpenBSD: intro.4,v 1.24 2012/03/28 20:44:23 miod Exp $ .\" .\" Copyright (c) 2009 Miodrag Vallat. .\" @@ -38,7 +38,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: September 3 2011 $ +.Dd $Mdocdate: March 28 2012 $ .Dt INTRO 4 sgi .Os .Sh NAME @@ -98,7 +98,14 @@ A list of the supported devices is given below. The following systems are supported: .Bl -column "Hardware" "Family" "Kernel" "Model" -offset 3n .It Sy Hardware Ta Sy Family Ta Sy Kernel Ta Sy Model +.It Li IP20 Ta IP20 Ta IP22 Ta "Indigo (R4k)" +.It Li IP22 Ta IP22 Ta IP22 Ta "Indigo2 (R4k)" +.It Li IP24 Ta IP22 Ta IP22 Ta "Indy" +.\" not yet +.\" .It Li IP26 Ta IP22 Ta IP26 Ta "Indigo2 (R8000)" .It Li IP27 Ta IP27 Ta IP27 Ta "Origin 2x00, Onyx 2" +.\" not yet +.\" .It Li IP28 Ta IP22 Ta IP28 Ta "Indigo2 (R10000)" .It Li IP29 Ta IP27 Ta IP27 Ta "Origin 200" .It Li IP30 Ta IP30 Ta IP30 Ta "Octane, Octane 2 (Speedracer)" .It Li IP31 Ta IP27 Ta IP27 Ta "Origin 200/2x00, Onyx 2 (250+\ MHz)" @@ -145,6 +152,8 @@ man page. The following buses and controllers list these devices: .Pp .Bl -tag -width "cardbus(4)XX" -offset 3n -compact +.It Xr gio 4 +Graphics I/O GIO bus .It Xr pci 4 introduction to PCI bus support .It Xr usb 4 diff --git a/share/man/man4/man4.sgi/sq.4 b/share/man/man4/man4.sgi/sq.4 new file mode 100644 index 00000000000..8763a117558 --- /dev/null +++ b/share/man/man4/man4.sgi/sq.4 @@ -0,0 +1,58 @@ +.\" $OpenBSD: sq.4,v 1.1 2012/03/28 20:44:23 miod Exp $ +.\" $NetBSD: sq.4,v 1.5 2008/04/30 13:10:56 martin Exp $ +.\" +.\" Copyright (c) 2004 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This document is derived from work contributed to The NetBSD Foundation +.\" by Steve Rumble. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd $Mdocdate: March 28 2012 $ +.Dt SQ 4 sgi +.Os +.Sh NAME +.Nm sq +.Nd Seeq 8003/80C03 Ethernet controller +.Sh SYNOPSIS +.Cd "sq* at hpc?" +.Sh DESCRIPTION +The +.Nm +interface provides support for the SEEQ 8003 and 80c03 (aka SGI EDLC) +Ethernet controller. +DMA is provided by +.Xr hpc 4 . +.Pp +The +.Nm +is found in the Indigo, Indy, Challenge S, Challenge M and +Indigo2 machines, as well as the SGI E++ GIO32bis Ethernet adapter. +.Sh SEE ALSO +.Xr arp 4 , +.Xr hpc 4 , +.\" .Xr ifmedia 4 , +.Xr intro 4 , +.Xr netintro 4 , +.Xr hostname.if 5 , +.Xr ifconfig 8 diff --git a/share/man/man4/man4.sgi/wdsc.4 b/share/man/man4/man4.sgi/wdsc.4 new file mode 100644 index 00000000000..d96b03f488d --- /dev/null +++ b/share/man/man4/man4.sgi/wdsc.4 @@ -0,0 +1,69 @@ +.\" $OpenBSD: wdsc.4,v 1.5 2012/03/28 20:44:23 miod Exp $ +.\" $NetBSD: wdsc.4,v 1.10 2009/03/09 19:24:30 joerg Exp $ +.\" +.\" Copyright (c) 1999 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Steve C. Woodford. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd $Mdocdate: March 28 2012 $ +.Dt WDSC 4 sgi +.Os +.Sh NAME +.Nm wdsc +.Nd WD33c93 SCSI controller +.Sh SYNOPSIS +.Cd "wdsc* at hpc?" +.Sh DESCRIPTION +The +.Nm +driver provides support for the Western Digital WD33c93 and WD33c93B SCSI +controllers. +.Pp +In addition to sending the required SCSI commands to +target devices on the SCSI bus, the +.Nm +driver deals with DMA, device interrupts, sync/async negotiation, +and target disconnects/reconnects. +.Sh DEVICE FLAGS +.Bl -tag -width "Bits XX-XX" -compact +.It Bits 0-7 +Disable disconnect/reselect for the corresponding target +.It Bits 8-15 +Disable synchronous negotiation for target "[bit - 8]" +.It Bits 16-23 +Disable tagged queuing for target "[bit - 16]" +.El +.Pp +The +.Nm +device flags may be OR'd together to enable any combination of +the features listed above. +Tape devices should be allowed to disconnect for the SCSI bus to operate +acceptably. +.Sh SEE ALSO +.Xr hpc 4 , +.Xr intro 4 , +.Xr scsibus 4 diff --git a/share/man/man4/man4.sgi/zs.4 b/share/man/man4/man4.sgi/zs.4 new file mode 100644 index 00000000000..480d4afbe1f --- /dev/null +++ b/share/man/man4/man4.sgi/zs.4 @@ -0,0 +1,101 @@ +.\" $OpenBSD: zs.4,v 1.1 2012/03/28 20:44:23 miod Exp $ +.\" $NetBSD: zstty.4,v 1.14 2011/06/07 20:22:56 wiz Exp $ +.\" +.\" Copyright (c) 1997 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Gordon W. Ross. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd $Mdocdate: March 28 2012 $ +.Dt ZS 4 sgi +.Os +.Sh NAME +.Nm zs , +.Nm zstty +.Nd Zilog 8530 (ZSCC) Serial Communications Controller +.Sh SYNOPSIS +.Cd "zs* at hpc0" +.Cd "zstty* at zs? channel ?" +.Sh DESCRIPTION +The +.Nm +driver provides TTY support for Zilog 8530 Dual UART chips. +One of the interfaces is hardwired for use by the keyboard and mouse +attached to the workstation console. +.\" The +.\" .Nm zskbd +.\" devices connect keyboard devices to the generic keyboard driver +.\" .Nm wskbd . +.\" The +.\" .Nm zsms +.\" devices connect mice to the generic mouse driver +.\" .Xr wsmouse 4 . +.\" The remaining additional +The +.Nm zstty +interfaces provide RS-423 +and RS-232 serial ports for general purpose use. +.Pp +The +.Nm +driver supports all of the standard +.Xr tty 4 +ioctl calls. +The status of the DTR, RTS, CTS, and DCD signals can be queried with +TIOCMGET command, but, due to limitations in the hardware, +only the DTR and RTS signals can be modified with TIOCMSET, TIOCMBIC, +and TIOCMBIS +.Xr ioctl 2 +commands. +.Pp +Input and output for each line may set to any baud rate in the +range 50 to 38400 (and higher on some machines). +.Sh FILES +.Bl -tag -width Pa -compact +.It Pa /dev/ttya +.It Pa /dev/ttyb +.El +.Sh DIAGNOSTICS +.Bl -tag -width indent +.It zs0*: fifo overflow +.br +The on-chip +.Dq FIFO +has overflowed and incoming data has been lost. +This generally means the machine is not responding to +interrupts from the ZS chip fast enough, which can be +remedied only by using a lower baud rate. +.It zs0*: ring overflow +.br +The software input +.Qq ring +has overflowed. +This usually means input flow-control is not configured correctly +.Pq i.e. incorrect cable wiring . +.El +.Sh SEE ALSO +.Xr hpc 4 , +.Xr intro 4 , +.Xr tty 4 diff --git a/sys/arch/mips64/conf/files.mips64 b/sys/arch/mips64/conf/files.mips64 index def002b4c53..9383b21aadd 100644 --- a/sys/arch/mips64/conf/files.mips64 +++ b/sys/arch/mips64/conf/files.mips64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.mips64,v 1.17 2010/10/24 15:40:03 miod Exp $ +# $OpenBSD: files.mips64,v 1.18 2012/03/28 20:44:23 miod Exp $ file arch/mips64/mips64/arcbios.c arcbios file arch/mips64/mips64/clock.c @@ -15,6 +15,7 @@ file arch/mips64/mips64/trap.c file arch/mips64/mips64/vm_machdep.c file arch/mips64/mips64/cache_loongson2.S cpu_loongson2 +file arch/mips64/mips64/cache_r4k.c cpu_r4000 file arch/mips64/mips64/cache_r5k.S cpu_r5000 | cpu_rm7000 file arch/mips64/mips64/cache_r10k.S cpu_r10000 file arch/mips64/mips64/cache_octeon.c cpu_octeon diff --git a/sys/arch/mips64/include/arcbios.h b/sys/arch/mips64/include/arcbios.h index 51e6f00b014..112bbaf2f2c 100644 --- a/sys/arch/mips64/include/arcbios.h +++ b/sys/arch/mips64/include/arcbios.h @@ -1,4 +1,4 @@ -/* $OpenBSD: arcbios.h,v 1.18 2011/06/05 20:58:46 miod Exp $ */ +/* $OpenBSD: arcbios.h,v 1.19 2012/03/28 20:44:23 miod Exp $ */ /*- * Copyright (c) 1996 M. Warner Losh. All rights reserved. * @@ -419,6 +419,7 @@ typedef struct arc_param_blk_64 #define ARCBIOS_PAGE_SIZE 4096 extern int bios_is_32bit; +extern int bios_consrate; extern char bios_enaddr[20]; extern char bios_console[30]; extern char bios_graphics[6]; diff --git a/sys/arch/mips64/include/cpu.h b/sys/arch/mips64/include/cpu.h index 5a079b54e11..59b0760382b 100644 --- a/sys/arch/mips64/include/cpu.h +++ b/sys/arch/mips64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.77 2012/03/25 13:52:52 miod Exp $ */ +/* $OpenBSD: cpu.h,v 1.78 2012/03/28 20:44:23 miod Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -560,6 +560,7 @@ uint32_t cp0_get_config_2(void); uint32_t cp0_get_config_3(void); uint32_t cp0_get_prid(void); void cp0_set_compare(u_int); +void cp0_set_config(uint32_t); u_int cp1_get_prid(void); void tlb_set_page_mask(uint32_t); void tlb_set_pid(int); @@ -580,6 +581,8 @@ void save_fpu(void); int fpe_branch_emulate(struct proc *, struct trap_frame *, uint32_t, vaddr_t); +int guarded_read_1(paddr_t, uint8_t *); +int guarded_read_2(paddr_t, uint16_t *); int guarded_read_4(paddr_t, uint32_t *); int guarded_write_4(paddr_t, uint32_t); diff --git a/sys/arch/mips64/mips64/arcbios.c b/sys/arch/mips64/mips64/arcbios.c index e0704b8a504..dac9405f891 100644 --- a/sys/arch/mips64/mips64/arcbios.c +++ b/sys/arch/mips64/mips64/arcbios.c @@ -1,4 +1,4 @@ -/* $OpenBSD: arcbios.c,v 1.31 2012/03/24 20:11:28 miod Exp $ */ +/* $OpenBSD: arcbios.c,v 1.32 2012/03/28 20:44:23 miod Exp $ */ /*- * Copyright (c) 1996 M. Warner Losh. All rights reserved. * Copyright (c) 1996-2004 Opsycon AB. All rights reserved. @@ -50,6 +50,7 @@ int bios_is_32bit; */ char bios_enaddr[20] = "ff:ff:ff:ff:ff:ff"; +int bios_consrate; /* Serial console speed. */ char bios_console[30]; /* Primary console. */ char bios_graphics[6]; /* Graphics state. */ char bios_keyboard[6]; /* Keyboard layout. */ diff --git a/sys/arch/mips64/mips64/cache_r4k.c b/sys/arch/mips64/mips64/cache_r4k.c new file mode 100644 index 00000000000..5d8aec81215 --- /dev/null +++ b/sys/arch/mips64/mips64/cache_r4k.c @@ -0,0 +1,323 @@ +/* $OpenBSD: cache_r4k.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> + +#include <mips64/cache.h> +#include <machine/cpu.h> + +#define IndexInvalidate_I 0x00 +#define IndexWBInvalidate_D 0x01 +#define IndexWBInvalidate_S 0x03 + +#define HitInvalidate_D 0x11 +#define HitInvalidate_S 0x13 + +#define HitWBInvalidate_D 0x15 +#define HitWBInvalidate_S 0x17 + +#define cache(op,addr) \ + __asm__ __volatile__ ("cache %0, 0(%1)" :: "i"(op), "r"(addr) : "memory") +#define sync() \ + __asm__ __volatile__ ("sync" ::: "memory"); + +void +Mips4k_ConfigCache(struct cpu_info *ci) +{ + uint32_t cfg; + + cfg = cp0_get_config(); + + if (cfg & (1 << 5)) /* IB */ + ci->ci_l1instcacheline = 32; + else + ci->ci_l1instcacheline = 16; + ci->ci_l1instcachesize = (1 << 12) << ((cfg >> 9) & 0x07); /* IC */ + + if (cfg & (1 << 4)) /* DB */ + ci->ci_l1datacacheline = 32; + else + ci->ci_l1datacacheline = 16; + ci->ci_l1datacachesize = (1 << 12) << ((cfg >> 6) & 0x07); /* DC */ + + /* R4000 and R4400 L1 caches are direct */ + ci->ci_cacheways = 1; + ci->ci_l1instcacheset = ci->ci_l1instcachesize; + ci->ci_l1datacacheset = ci->ci_l1datacachesize; + + CpuCacheAliasMask = (ci->ci_l1instcachesize | ci->ci_l1datacachesize) & + ~PAGE_MASK; + + if ((cfg & (1 << 17)) == 0) { /* SC */ + /* + * We expect the setup code to have set up ci->ci_l2size for + * us. Unfortunately we aren't allowed to panic() there, + * because the console is not available. + */ + + /* fixed 32KB aliasing to avoid VCE */ + CpuCacheAliasMask |= ((1 << 15) - 1) & ~PAGE_MASK; + } else { + ci->ci_cacheconfiguration = 0; + ci->ci_l2size = 0; + } + ci->ci_l3size = 0; + + if (CpuCacheAliasMask != 0) + CpuCacheAliasMask |= PAGE_MASK; + + if ((cfg & 7) != CCA_CACHED) { + void (*fn)(uint32_t); + vaddr_t va; + paddr_t pa; + + va = (vaddr_t)&cp0_set_config; + if (IS_XKPHYS(va)) { + pa = XKPHYS_TO_PHYS(va); + va = PHYS_TO_XKPHYS(pa, CCA_NC); + } else { + pa = CKSEG0_TO_PHYS(va); + va = PHYS_TO_CKSEG1(pa); + } + fn = (void (*)(uint32_t))va; + + cfg = (cfg & ~7) | CCA_CACHED; + (*fn)(cfg); + } +} + +/* + * Writeback and invalidate all caches. + */ +void +Mips4k_SyncCache(struct cpu_info *ci) +{ + vaddr_t sva, eva; + uint64_t line; + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l1instcachesize; + line = ci->ci_l1instcacheline; + while (sva != eva) { + cache(IndexInvalidate_I, sva); + sva += line; + } + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l1datacachesize; + line = ci->ci_l1datacacheline; + while (sva != eva) { + cache(IndexWBInvalidate_D, sva); + sva += line; + } + + if (ci->ci_l2size != 0) { + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + eva = sva + ci->ci_l2size; + line = ci->ci_cacheconfiguration; /* L2 line size */ + while (sva != eva) { + cache(IndexWBInvalidate_S, sva); + sva += line; + } + } + + sync(); +} + +/* + * Invalidate I$ for the given range. + */ +void +Mips4k_InvalidateICache(struct cpu_info *ci, uint64_t _va, size_t _sz) +{ + vaddr_t va, sva, eva; + vsize_t sz; + uint64_t line; + + line = ci->ci_l1instcacheline; + /* extend the range to integral cache lines */ + if (line == 16) { + va = _va & ~(16UL - 1); + sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - _va; + } else { + va = _va & ~(32UL - 1); + sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - _va; + } + + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + /* keep only the index bits */ + sva += va & ((1UL << 15) - 1); + eva = sva + sz; + while (sva != eva) { + cache(IndexInvalidate_I, sva); + sva += line; + } + + sync(); +} + +/* + * Writeback D$ for the given page. + */ +void +Mips4k_SyncDCachePage(struct cpu_info *ci, uint64_t va) +{ + vaddr_t sva, eva; + uint64_t line; + + line = ci->ci_l1datacacheline; + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + /* keep only the index bits */ + sva += va & ((1UL << 15) - 1); + eva = sva + PAGE_SIZE; + while (sva != eva) { + cache(IndexWBInvalidate_D, sva); + sva += line; + } + + if (ci->ci_l2size != 0) { + line = ci->ci_cacheconfiguration; /* L2 line size */ + sva = PHYS_TO_XKPHYS(0, CCA_CACHED); + /* keep only the index bits */ + sva += va & ((1UL << 22) - 1); /* largest L2 is 4MB */ + eva = sva + PAGE_SIZE; + while (sva != eva) { + cache(IndexWBInvalidate_S, sva); + sva += line; + } + } + + sync(); +} + +/* + * Writeback D$ for the given range. Range is expected to be currently + * mapped, allowing the use of `Hit' operations. This is less aggressive + * than using `Index' operations. + */ +void +Mips4k_HitSyncDCache(struct cpu_info *ci, uint64_t _va, size_t _sz) +{ + vaddr_t va, sva, eva; + vsize_t sz; + uint64_t line; + + line = ci->ci_l1datacacheline; + /* extend the range to integral cache lines */ + if (line == 16) { + va = _va & ~(16UL - 1); + sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - va; + } else { + va = _va & ~(32UL - 1); + sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - va; + } + + sva = va; + eva = sva + sz; + while (sva != eva) { + cache(HitWBInvalidate_D, sva); + sva += line; + } + + if (ci->ci_l2size != 0) { + line = ci->ci_cacheconfiguration; /* L2 line size */ + /* extend the range to integral cache lines */ + va = _va & ~(line - 1); + sz = ((_va + _sz + line - 1) & ~(line - 1)) - va; + + sva = va; + eva = sva + sz; + while (sva != eva) { + cache(HitWBInvalidate_S, sva); + sva += line; + } + } + + sync(); +} + +/* + * Invalidate D$ for the given range. Range is expected to be currently + * mapped, allowing the use of `Hit' operations. This is less aggressive + * than using `Index' operations. + */ +void +Mips4k_HitInvalidateDCache(struct cpu_info *ci, uint64_t _va, size_t _sz) +{ + vaddr_t va, sva, eva; + vsize_t sz; + uint64_t line; + + line = ci->ci_l1datacacheline; + /* extend the range to integral cache lines */ + if (line == 16) { + va = _va & ~(16UL - 1); + sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - _va; + } else { + va = _va & ~(32UL - 1); + sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - _va; + } + + sva = va; + eva = sva + sz; + while (sva != eva) { + cache(HitInvalidate_D, sva); + sva += line; + } + + if (ci->ci_l2size != 0) { + line = ci->ci_cacheconfiguration; /* L2 line size */ + /* extend the range to integral cache lines */ + va = _va & ~(line - 1); + sz = ((_va + _sz + line - 1) & ~(line - 1)) - va; + + sva = va; + eva = sva + sz; + while (sva != eva) { + cache(HitInvalidate_S, sva); + sva += line; + } + } + + sync(); +} + +/* + * Backend for bus_dmamap_sync(). Enforce coherency of the given range + * by performing the necessary cache writeback and/or invalidate + * operations. + */ +void +Mips4k_IOSyncDCache(struct cpu_info *ci, uint64_t va, size_t sz, int how) +{ + switch (how) { + case CACHE_SYNC_R: + if (((va | sz) & (ci->ci_l1datacacheline - 1)) == 0) { + Mips4k_HitInvalidateDCache(ci, va, sz); + break; + } + /* FALLTHROUGH */ + case CACHE_SYNC_X: + Mips4k_HitSyncDCache(ci, va, sz); + break; + case CACHE_SYNC_W: + Mips4k_HitSyncDCache(ci, va, sz); + break; + } +} diff --git a/sys/arch/mips64/mips64/cp0access.S b/sys/arch/mips64/mips64/cp0access.S index 32866dce285..7bb04346f0c 100644 --- a/sys/arch/mips64/mips64/cp0access.S +++ b/sys/arch/mips64/mips64/cp0access.S @@ -1,4 +1,4 @@ -/* $OpenBSD: cp0access.S,v 1.14 2010/09/11 11:29:50 syuu Exp $ */ +/* $OpenBSD: cp0access.S,v 1.15 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -154,6 +154,13 @@ LEAF(cp0_get_config, 0) nop END(cp0_get_config) +/* WARNING! Needs to be invoked from uncached address. */ +LEAF(cp0_set_config, 0) + mtc0 a0, COP_0_CONFIG + j ra + nop +END(cp0_set_config) + LEAF(cp0_get_prid, 0) mfc0 v0, COP_0_PRID j ra diff --git a/sys/arch/mips64/mips64/cpu.c b/sys/arch/mips64/mips64/cpu.c index 37240e67095..2a85adba26e 100644 --- a/sys/arch/mips64/mips64/cpu.c +++ b/sys/arch/mips64/mips64/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.39 2011/04/10 17:16:51 miod Exp $ */ +/* $OpenBSD: cpu.c,v 1.40 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 1997-2004 Opsycon AB (www.opsycon.se) @@ -112,14 +112,18 @@ cpuattach(struct device *parent, struct device *dev, void *aux) printf(": "); displayver = 1; + fptype = (ch->c1prid >> 8) & 0xff; vers_maj = (ch->c0prid >> 4) & 0x0f; vers_min = ch->c0prid & 0x0f; switch (ch->type) { case MIPS_R4000: - if (ci->ci_l1instcachesize == 16384) - printf("MIPS R4400 CPU"); - else + if (vers_maj < 4) printf("MIPS R4000 CPU"); + else { + vers_maj -= 3; + printf("MIPS R4400 CPU"); + } + fptype = MIPS_R4000; break; case MIPS_R5000: printf("MIPS R5000 CPU"); @@ -184,6 +188,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux) break; case MIPS_OCTEON: printf("Cavium OCTEON CPU"); + fptype = MIPS_SOFT; break; default: printf("Unknown CPU type (0x%x)", ch->type); @@ -194,13 +199,8 @@ cpuattach(struct device *parent, struct device *dev, void *aux) printf(" %d MHz, ", ch->clock / 1000000); displayver = 1; - if (ch->type == MIPS_OCTEON) - fptype = MIPS_SOFT; - else { - fptype = (ch->c1prid >> 8) & 0xff; - vers_maj = (ch->c1prid >> 4) & 0x0f; - vers_min = ch->c1prid & 0x0f; - } + vers_maj = (ch->c1prid >> 4) & 0x0f; + vers_min = ch->c1prid & 0x0f; switch (fptype) { case MIPS_SOFT: printf("Software FP emulation"); @@ -267,7 +267,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux) printf("4 way"); break; default: - printf("1 way"); + printf("direct"); break; } @@ -293,8 +293,10 @@ cpuattach(struct device *parent, struct device *dev, void *aux) printf("\n"); #ifdef DEBUG - printf("cpu%d: Setsize %d:%d\n", cpuno, + printf("cpu%d: L1 set size %d:%d\n", cpuno, ci->ci_l1instcacheset, ci->ci_l1datacacheset); + printf("cpu%d: L1 line size %d:%d\n", cpuno, + ci->ci_l1instcacheline, ci->ci_l1datacacheline); printf("cpu%d: Alias mask %p\n", cpuno, CpuCacheAliasMask); printf("cpu%d: Config Register %08x\n", cpuno, cp0_get_config()); printf("cpu%d: Cache configuration %x\n", diff --git a/sys/arch/mips64/mips64/exception.S b/sys/arch/mips64/mips64/exception.S index a02a560136b..2626cf95a77 100644 --- a/sys/arch/mips64/mips64/exception.S +++ b/sys/arch/mips64/mips64/exception.S @@ -1,4 +1,4 @@ -/* $OpenBSD: exception.S,v 1.32 2010/12/28 18:40:28 miod Exp $ */ +/* $OpenBSD: exception.S,v 1.33 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -129,6 +129,11 @@ u_exception_table: * to the vector area and must thus be PIC and less than 128 * bytes long to fit. Only k0 and k1 may be used at this time. */ + .globl cache_err +cache_err: +#ifdef CPU_R4000 + nop +#endif .globl exception exception: .set noat diff --git a/sys/arch/mips64/mips64/lcore_access.S b/sys/arch/mips64/mips64/lcore_access.S index 4975d28094e..c48b44ef6fa 100644 --- a/sys/arch/mips64/mips64/lcore_access.S +++ b/sys/arch/mips64/mips64/lcore_access.S @@ -1,4 +1,4 @@ -/* $OpenBSD: lcore_access.S,v 1.19 2010/01/31 19:39:04 miod Exp $ */ +/* $OpenBSD: lcore_access.S,v 1.20 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -286,10 +286,42 @@ _kcopyerr: /* * Guarded ``memory'' access routines + * int guarded_read_1(paddr_t address, uint8_t *dest); + * int guarded_read_2(paddr_t address, uint16_t *dest); * int guarded_read_4(paddr_t address, uint32_t *dest); * int guarded_write_4(paddr_t address, uint32_t src); */ +LEAF(guarded_read_1, 0) + GET_CPU_INFO(t1, t0) + PTR_L t3, CI_CURPROCPADDR(t1) + li v0, KT_GUARDERR + lw v1, PCB_ONFAULT(t3) + sw v0, PCB_ONFAULT(t3) + + lb v0, 0(a0) + sb v0, 0(a1) + + sw v1, PCB_ONFAULT(t3) + j ra + move v0, zero +END(guarded_read_1) + +LEAF(guarded_read_2, 0) + GET_CPU_INFO(t1, t0) + PTR_L t3, CI_CURPROCPADDR(t1) + li v0, KT_GUARDERR + lw v1, PCB_ONFAULT(t3) + sw v0, PCB_ONFAULT(t3) + + lh v0, 0(a0) + sh v0, 0(a1) + + sw v1, PCB_ONFAULT(t3) + j ra + move v0, zero +END(guarded_read_2) + LEAF(guarded_read_4, 0) GET_CPU_INFO(t1, t0) PTR_L t3, CI_CURPROCPADDR(t1) diff --git a/sys/arch/mips64/mips64/tlbhandler.S b/sys/arch/mips64/mips64/tlbhandler.S index d96e343d765..d78fe8cebc6 100644 --- a/sys/arch/mips64/mips64/tlbhandler.S +++ b/sys/arch/mips64/mips64/tlbhandler.S @@ -1,4 +1,4 @@ -/* $OpenBSD: tlbhandler.S,v 1.32 2010/09/12 12:05:37 syuu Exp $ */ +/* $OpenBSD: tlbhandler.S,v 1.33 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 1995-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -54,6 +54,22 @@ */ .set noat +#ifdef CPU_R4000 + .globl xtlb_miss_err_r4k + .ent xtlb_miss_err_r4k, 0 +xtlb_miss_err_r4k: + /* + * R4000 errata: TLB miss exception may be invoked with BadVAddr + * being incorrect. + */ + tlbp + mfc0 k1, COP_0_TLB_INDEX + bltz k1, xtlb_miss # missing! + nop + eret + nop + .end xtlb_miss_err_r4k +#endif /* CPU_R4000 */ #if defined(CPU_R5000) || defined(CPU_RM7000) .globl xtlb_miss_err_r5k .ent xtlb_miss_err_r5k, 0 diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c index d906010b49a..73aa524bcf7 100644 --- a/sys/arch/mips64/mips64/trap.c +++ b/sys/arch/mips64/mips64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.77 2011/11/16 20:50:19 deraadt Exp $ */ +/* $OpenBSD: trap.c,v 1.78 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -763,6 +763,36 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr } goto err; +#ifdef CPU_R4000 + case T_VCEI: + case T_VCEI+T_USER: + { + vaddr_t va = trapframe->badvaddr & + ~((vaddr_t)ci->ci_l1instcacheline - 1); +#ifdef DEBUG + printf("VCEI trap, badvaddr %p\n", trapframe->badvaddr); +#endif + /* HitWBInvalidate_S */ + __asm__ __volatile__ ("cache 0x17, 0(%0)" :: "r"(va)); + /* HitInvalidate_I */ + __asm__ __volatile__ ("cache 0x10, 0(%0)" :: "r"(va)); + } + return; + case T_VCED: + case T_VCED+T_USER: + { + vaddr_t va = trapframe->badvaddr & + ~((vaddr_t)ci->ci_l1datacacheline - 1); +#ifdef DEBUG + printf("VCED trap, badvaddr %p\n", trapframe->badvaddr); +#endif + /* HitWBInvalidate_S */ + __asm__ __volatile__ ("cache 0x17, 0(%0)" :: "r"(va)); + /* HitInvalidate_D */ + __asm__ __volatile__ ("cache 0x11, 0(%0)" :: "r"(va)); + } + return; +#endif /* CPU_R4000 */ default: err: disableintr(); diff --git a/sys/arch/sgi/compile/.cvsignore b/sys/arch/sgi/compile/.cvsignore index 8a0ebe82e75..db6b8d0fedd 100644 --- a/sys/arch/sgi/compile/.cvsignore +++ b/sys/arch/sgi/compile/.cvsignore @@ -1,7 +1,10 @@ +GENERIC-IP22 GENERIC-IP27 +GENERIC-IP27.MP GENERIC-IP30 GENERIC-IP30.MP GENERIC-IP32 +RAMDISK-IP22 RAMDISK-IP27 RAMDISK-IP30 RAMDISK-IP32 diff --git a/sys/arch/sgi/conf/GENERIC-IP22 b/sys/arch/sgi/conf/GENERIC-IP22 new file mode 100644 index 00000000000..c062b6c4cb4 --- /dev/null +++ b/sys/arch/sgi/conf/GENERIC-IP22 @@ -0,0 +1,85 @@ +# $OpenBSD: GENERIC-IP22,v 1.1 2012/03/28 20:44:23 miod Exp $ +# +# THIS KERNEL IS FOR INDIGO (IP20), INDY (IP22) AND INDIGO2 (IP24) SYSTEMS ONLY. +# +# For further information on compiling OpenBSD kernels, see the config(8) +# man page. +# +# For further information on hardware support for this architecture, see +# the intro(4) man page. For further information about kernel options +# for this architecture, see the options(4) man page. For an explanation +# of each device driver in this file see the section 4 man page for the +# device. + +machine sgi mips64 +include "../../../conf/GENERIC" +maxusers 32 # Estimated number of users + +# Make options +makeoption LINK_ADDRESS="0xffffffff88100000" +# Force use of 16KB pages. The R5000 Indy, which has the infamous XKPHYS +# coherency bug wrt ll/sc instructions, can not have more than 256MB of +# physical memory, all of it fitting within CKSEG0. +option PAGE_SHIFT="14" + +#option WSDISPLAY_COMPAT_RAWKBD # Provide raw scancodes; needed for X11 + +# Define what targets to support +option TGT_INDIGO # R4x00 Indigo (IP20) +option TGT_INDIGO2 # Indigo2 (IP22/IP26/IP28) +option TGT_INDY # Indy (IP24) +option ARCBIOS # mandatory +option CPU_R4000 # R4000/R4400 support (IP20/IP22/IP24) +#option CPU_R4600 # R4600 support (IP22/IP24) +option CPU_R5000 # R5000 support (IP24) + +config bsd swap generic + +# +# Definition of system +# +mainbus0 at root +cpu* at mainbus0 +clock0 at mainbus0 + +int0 at mainbus0 # Interrupt Controller +imc0 at mainbus0 # Memory Controller +gio0 at imc0 +#eisa0 at imc0 + +hpc0 at gio? addr 0x1fb80000 +hpc1 at gio? addr 0x1fb00000 +hpc2 at gio? addr 0x1f980000 + +dpclock0 at hpc0 # IP20 +dsclock0 at hpc0 # IP22/24 +sq* at hpc? # On-board Ethernet or E++ adapter +wdsc* at hpc? # On-board SCSI or GIO32 SCSI adapter +#haltwo* at hpc? # Indy/Indigo2 Audio +#panel* at hpc? # Indy front panel buttons +#pckbc* at hpc? # Indy/Indigo2 keyboard and mouse + +zs* at hpc? +zstty* at zs? # Serial ports + +#newport* at gio? # Indy Newport graphics +#wsdisplay* at newport? + +#grtwo* at gio? # Express (GR2) graphics +#wsdisplay* at grtwo? + +#light* at gio? # Light/Starter/Entry (LG1/LG2) graphics +#wsdisplay* at light? + +scsibus* at scsi? +sd* at scsibus? +st* at scsibus? +cd* at scsibus? +ch* at scsibus? +safte* at scsibus? +ses* at scsibus? +uk* at scsibus? + +pseudo-device crypto 1 +#pseudo-device hotplug 1 # devices hot plugging +#pseudo-device wsmux 2 # Mouse and keyboard multiplexor diff --git a/sys/arch/sgi/conf/RAMDISK-IP22 b/sys/arch/sgi/conf/RAMDISK-IP22 new file mode 100644 index 00000000000..91e2e00f390 --- /dev/null +++ b/sys/arch/sgi/conf/RAMDISK-IP22 @@ -0,0 +1,95 @@ +# $OpenBSD: RAMDISK-IP22,v 1.1 2012/03/28 20:44:23 miod Exp $ +# +# THIS KERNEL IS FOR INDIGO (IP20), INDY (IP22) AND INDIGO2 (IP24) SYSTEMS ONLY. + +machine sgi mips64 + +maxusers 4 +option TIMEZONE=0 # minutes west of GMT (for) +option DST=0 # use daylight savings rules + +# Make options +makeoption LINK_ADDRESS="0xffffffff88100000" +# Force use of 16KB pages. The R5000 Indy, which has the infamous XKPHYS +# coherency bug wrt ll/sc instructions, can not have more than 256MB of +# physical memory, all of it fitting within CKSEG0. +option PAGE_SHIFT="14" + +option DDB + +# Filesystem options +option CD9660 # ISO 9660 + Rock Ridge file system +option FIFO # POSIX fifo support (in all filesystems) +option FFS # fast filesystem +#option MSDOSFS # Ability to read write MS-Dos filesystem +option NFSCLIENT # Sun NFS-compatible filesystem (client) + +# Networking options +option INET # IP + ICMP + TCP + UDP +option INET6 # IPv6 (needs INET) + +# RAMDISK stuff +option MINIROOTSIZE=10240 +option RAMDISK_HOOKS + +# Define what targets to support +option TGT_INDIGO # R4x00 Indigo (IP20) +option TGT_INDIGO2 # Indigo2 (IP22/IP26/IP28) +option TGT_INDY # Indy (IP24) +option ARCBIOS # mandatory +option CPU_R4000 # R4000/R4400 support (IP20/IP22/IP24) +#option CPU_R4600 # R4600 support (IP22/IP24) +option CPU_R5000 # R5000 support (IP24) + +# Specify storage configuration using ramdisk +config bsd root on rd0a swap on rd0b + +# +# Definition of system +# +mainbus0 at root +cpu* at mainbus0 +clock0 at mainbus0 + +int0 at mainbus0 # Interrupt Controller +imc0 at mainbus0 # Memory Controller +gio0 at imc0 +#eisa0 at imc0 + +hpc0 at gio? addr 0x1fb80000 +hpc1 at gio? addr 0x1fb00000 +hpc2 at gio? addr 0x1f980000 + +dpclock0 at hpc0 # IP20 +dsclock0 at hpc0 # IP22/24 +sq* at hpc? # On-board Ethernet or E++ adapter +wdsc* at hpc? # On-board SCSI or GIO32 SCSI adapter +#pckbc* at hpc? # Indy/Indigo2 keyboard and mouse + +zs* at hpc? +zstty* at zs? # Serial ports + +#newport* at gio? # Indy Newport graphics +#wsdisplay* at newport? + +#grtwo* at gio? # Express (GR2) graphics +#wsdisplay* at grtwo? + +#light* at gio? # Light/Starter/Entry (LG1/LG2) graphics +#wsdisplay* at light? + +scsibus* at scsi? +sd* at scsibus? +st* at scsibus? +cd* at scsibus? +#ch* at scsibus? +#uk* at scsibus? + +#### PSEUDO Devices +pseudo-device loop 1 # network loopback +pseudo-device bpfilter 1 # packet filter ports + +pseudo-device rd 1 # Ram disk. +pseudo-device bio 1 # ioctl multiplexing device + +option BOOT_CONFIG # add support for boot -c diff --git a/sys/arch/sgi/conf/files.sgi b/sys/arch/sgi/conf/files.sgi index 83953010ed9..a13ff36f3c7 100644 --- a/sys/arch/sgi/conf/files.sgi +++ b/sys/arch/sgi/conf/files.sgi @@ -1,4 +1,4 @@ -# $OpenBSD: files.sgi,v 1.46 2011/11/15 22:27:53 deraadt Exp $ +# $OpenBSD: files.sgi,v 1.47 2012/03/28 20:44:23 miod Exp $ # # maxpartitions must be first item in files.${ARCH} # @@ -14,6 +14,8 @@ file arch/sgi/sgi/bus_dma.c file arch/sgi/sgi/conf.c file arch/sgi/sgi/disksubr.c disk file arch/sgi/sgi/lock_machdep.c multiprocessor +file arch/sgi/sgi/ip22_machdep.c tgt_indigo | tgt_indigo2 | + tgt_indy file arch/sgi/sgi/ip27_machdep.c tgt_origin file arch/sgi/sgi/ip30_machdep.c tgt_octane file arch/sgi/sgi/ip30_nmi.S tgt_octane & ddb @@ -56,6 +58,21 @@ device clock attach clock at mainbus # +# IP20/22/24 specific devices +# +define giobus {} +device imc: giobus, eisabus +attach imc at mainbus +file arch/sgi/localbus/imc.c imc + +device int +attach int at mainbus +file arch/sgi/localbus/int.c int + +include "arch/sgi/gio/files.gio" +include "arch/sgi/hpc/files.hpc" + +# # O2 MACE localbus autoconfiguration devices # define macebus {[base = -1]} @@ -87,6 +104,13 @@ major {cd = 3} include "dev/i2o/files.i2o" # +# EISA Bus support +# + +include "dev/eisa/files.eisa" +file arch/sgi/sgi/eisa_machdep.c eisa + +# # PCI Bus support # @@ -132,9 +156,9 @@ file arch/sgi/dev/iockbc.c iockbc | # DS1687 Time-Of-Day calendar device device dsrtc -attach dsrtc at macebus with dsrtc_macebus attach dsrtc at ioc with dsrtc_ioc attach dsrtc at iof with dsrtc_iof +attach dsrtc at macebus with dsrtc_macebus file arch/sgi/dev/dsrtc.c dsrtc # GBE framebuffer @@ -207,4 +231,3 @@ file arch/sgi/dev/owmem_subr.c owmac | owserial # IP35 SPD memory information attach spdmem at mainbus with spdmem_mainbus file arch/sgi/dev/spdmem_mainbus.c spdmem_mainbus - diff --git a/sys/arch/sgi/dev/dsrtc.c b/sys/arch/sgi/dev/dsrtc.c index 7132df8e5fd..8991abfe0bf 100644 --- a/sys/arch/sgi/dev/dsrtc.c +++ b/sys/arch/sgi/dev/dsrtc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dsrtc.c,v 1.11 2009/11/07 14:49:01 miod Exp $ */ +/* $OpenBSD: dsrtc.c,v 1.12 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -122,7 +122,7 @@ dsrtc_attach_ioc(struct device *parent, struct device *self, void *aux) bus_space_handle_t ih, ih2; /* - * The IOC3 RTC is either a Dallas (now Maxim) DS1386 or compatible + * The IOC3 RTC is either a Dallas (now Maxim) DS1397 or compatible * (likely a more recent DS1687), or a DS1747 or compatible * (itself being a Mostek MK48T35 clone). * diff --git a/sys/arch/sgi/gio/Makefile b/sys/arch/sgi/gio/Makefile new file mode 100644 index 00000000000..130e520dcfb --- /dev/null +++ b/sys/arch/sgi/gio/Makefile @@ -0,0 +1,8 @@ +# $OpenBSD: Makefile,v 1.1 2012/03/28 20:44:23 miod Exp $ +# $NetBSD: Makefile.giodevs,v 1.5 2008/10/19 22:05:21 apb Exp $ + +AWK= awk + +giodevs.h giodevs_data.h: giodevs devlist2h.awk + /bin/rm -f giodevs.h giodevs_data.h + ${AWK} -f devlist2h.awk giodevs diff --git a/sys/arch/sgi/gio/devlist2h.awk b/sys/arch/sgi/gio/devlist2h.awk new file mode 100644 index 00000000000..361a2eb2a25 --- /dev/null +++ b/sys/arch/sgi/gio/devlist2h.awk @@ -0,0 +1,152 @@ +#! /usr/bin/awk -f +# $OpenBSD: devlist2h.awk,v 1.1 2012/03/28 20:44:23 miod Exp $ +# $NetBSD: devlist2h.awk,v 1.5 2008/05/02 18:11:05 martin Exp $ +# +# Copyright (c) 1998 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Christos Zoulas. +# +# 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. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# +# Copyright (c) 1995, 1996 Christopher G. Demetriou +# 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 Christopher G. Demetriou. +# This product includes software developed by Christos Zoulas +# 4. The name of the author(s) 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. +# +function collectline(_f, _line) { + _oparen = 0 + _line = "" + while (_f <= NF) { + if ($_f == "#") { + _line = _line "(" + _oparen = 1 + _f++ + continue + } + if (_oparen) { + _line = _line $_f + if (_f < NF) + _line = _line " " + _f++ + continue + } + _line = _line $_f + if (_f < NF) + _line = _line " " + _f++ + } + if (_oparen) + _line = _line ")" + return _line +} +BEGIN { + nproducts = nvendors = blanklines = 0 + dfile="giodevs_data.h" + hfile="giodevs.h" + line="" +} +NR == 1 { + VERSION = $0 + gsub("\\$", "", VERSION) + + printf("/*\n") > hfile + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \ + > hfile + printf(" *\n") > hfile + printf(" * generated from:\n") > hfile + printf(" *\t%s\n", VERSION) > hfile + printf(" */\n\n") > hfile + + printf("/*\n") > dfile + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \ + > dfile + printf(" *\n") > dfile + printf(" * generated from:\n") > dfile + printf(" *\t%s\n", VERSION) > dfile + printf(" */\n\n") > dfile + + next +} +NF > 0 && $1 == "product" { + nproducts++ + + products[nproducts, 1] = $2; + products[nproducts, 2] = $3 + products[nproducts, 3] = collectline(4, line) + + next +} +{ + if ($0 == "") + blanklines++ + if (blanklines < 2) + print $0 > dfile +} +END { + # print out the match tables + + printf("\n") > dfile + + printf("struct gio_knowndev {\n") > dfile + printf("\tint productid;\n") > dfile + printf("\tconst char *product;\n") > dfile + printf("};\n") > dfile + printf("\nstruct gio_knowndev gio_knowndevs[] = {\n") > dfile + + printf("\n") > hfile + for (i = 1; i <= nproducts; i++) { + printf("#define %s\t%s\t/* %s */\n", products[i, 1], products[i,2], products[i, 3]) > hfile + + printf("\t{ %s, \"%s\" },\n", + products[i, 2], products[i, 3]) > dfile + } + printf("\t{ 0, NULL }\n") > dfile + printf("};\n") > dfile + close(dfile) + close(hfile) +} diff --git a/sys/arch/sgi/gio/files.gio b/sys/arch/sgi/gio/files.gio new file mode 100644 index 00000000000..fe393862625 --- /dev/null +++ b/sys/arch/sgi/gio/files.gio @@ -0,0 +1,31 @@ +# $OpenBSD: files.gio,v 1.1 2012/03/28 20:44:23 miod Exp $ +# $NetBSD: files.gio,v 1.11 2009/02/12 06:33:57 rumble Exp $ + +device gio {[slot = -1], [addr = -1]} +attach gio at giobus + +file arch/sgi/gio/gio.c gio needs-flag + +device hpc {[offset = -1]}: smc93cx6 +attach hpc at gio +file arch/sgi/hpc/hpc.c hpc + +# XL graphics +device newport: wsemuldisplaydev, rasops8 +attach newport at gio +file arch/sgi/gio/newport.c newport needs-flag + +# GR2 graphics +device grtwo: wsemuldisplaydev +attach grtwo at gio +file arch/sgi/gio/grtwo.c grtwo needs-flag + +# LG1/LG2 graphics +device light: wsemuldisplaydev +attach light at gio +file arch/sgi/gio/light.c light needs-flag + +# PCI cards glued to the GIO bus +device giopci: pcibus +attach giopci at gio +file arch/sgi/gio/pci_gio.c giopci diff --git a/sys/arch/sgi/gio/gio.c b/sys/arch/sgi/gio/gio.c new file mode 100644 index 00000000000..b201adab5b9 --- /dev/null +++ b/sys/arch/sgi/gio/gio.c @@ -0,0 +1,518 @@ +/* $OpenBSD: gio.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: gio.c,v 1.32 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2000 Soren S. Jorvang + * 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 for the + * NetBSD Project. See http://www.NetBSD.org/ for + * information about NetBSD. + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <mips64/archtype.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> + +#include <sgi/gio/gioreg.h> +#include <sgi/gio/giovar.h> +#include <sgi/gio/giodevs_data.h> + +#include <sgi/localbus/imcvar.h> +#include <sgi/localbus/intvar.h> +#include <sgi/sgi/ip22.h> + +int gio_match(struct device *, void *, void *); +void gio_attach(struct device *, struct device *, void *); +int gio_print(void *, const char *); +int gio_print_fb(void *, const char *); +int gio_search(struct device *, void *, void *); +int gio_submatch(struct device *, void *, void *); +uint32_t gio_id(paddr_t, int); + +struct gio_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_dma_tag_t sc_dmat; +}; + +const struct cfattach gio_ca = { + sizeof(struct gio_softc), gio_match, gio_attach +}; + +struct cfdriver gio_cd = { + NULL, "gio", DV_DULL +}; + +struct gio_probe { + uint32_t slot; + uint64_t base; + uint32_t mach_type; + uint32_t mach_subtype; +}; + +/* + * Expansion Slot Base Addresses + * + * IP12, IP20 and IP24 have two GIO connectors: GIO_SLOT_EXP0 and + * GIO_SLOT_EXP1. + * + * On IP24 these slots exist on the graphics board or the IOPLUS + * "mezzanine" on Indy and Challenge S, respectively. The IOPLUS or + * graphics board connects to the mainboard via a single GIO64 connector. + * + * IP22 has either three or four physical connectors, but only two + * electrically distinct slots: GIO_SLOT_GFX and GIO_SLOT_EXP0. + * + * It should also be noted that DMA is (mostly) not supported in Challenge S's + * GIO_SLOT_EXP1. See gio(4) for the story. + */ +static const struct gio_probe slot_bases[] = { + { GIO_SLOT_GFX, 0x1f000000, SGI_IP22, IP22_INDIGO2 }, + + { GIO_SLOT_EXP0, 0x1f400000, SGI_IP20, -1 }, + { GIO_SLOT_EXP0, 0x1f400000, SGI_IP22, -1 }, + + { GIO_SLOT_EXP1, 0x1f600000, SGI_IP20, -1 }, + { GIO_SLOT_EXP1, 0x1f600000, SGI_IP22, IP22_INDY }, + + { 0, 0, 0, 0 } +}; + +/* + * Graphic Board Base Addresses + * + * Graphics boards are not treated like expansion slot cards. Their base + * addresses do not necessarily correspond to GIO slot addresses and they + * do not contain product identification words. + */ +static const struct gio_probe gfx_bases[] = { + /* grtwo, and newport on IP22 */ + { -1, 0x1f000000, SGI_IP20, -1 }, + { -1, 0x1f000000, SGI_IP22, -1 }, + + /* light */ + { -1, 0x1f3f0000, SGI_IP20, -1 }, + + /* light (dual headed) */ + { -1, 0x1f3f8000, SGI_IP20, -1 }, + + /* grtwo, and newport on IP22 */ + { -1, 0x1f400000, SGI_IP20, -1 }, + { -1, 0x1f400000, SGI_IP22, -1 }, + + /* grtwo */ + { -1, 0x1f600000, SGI_IP20, -1 }, + { -1, 0x1f600000, SGI_IP22, -1 }, + + /* newport */ + { -1, 0x1f800000, SGI_IP22, IP22_INDIGO2 }, + + /* newport */ + { -1, 0x1fc00000, SGI_IP22, IP22_INDIGO2 }, + + { 0, 0, 0, 0 } +}; + +/* maximum number of graphics boards possible (arbitrarily large estimate) */ +#define MAXGFX (nitems(gfx_bases) - 1) + +int +gio_match(struct device *parent, void *match, void *aux) +{ + struct imc_attach_args *iaa = aux; + + if (strcmp(iaa->iaa_name, gio_cd.cd_name) != 0) + return 0; + + return 1; +} + +void +gio_attach(struct device *parent, struct device *self, void *aux) +{ + struct gio_softc *sc = (struct gio_softc *)self; + struct imc_attach_args *iaa = (struct imc_attach_args *)aux; + struct gio_attach_args ga; + uint32_t gfx[MAXGFX]; + uint i, j, ngfx; + + printf("\n"); + + sc->sc_iot = iaa->iaa_st; + sc->sc_dmat = iaa->iaa_dmat; + + ngfx = 0; + memset(gfx, 0, sizeof(gfx)); + + /* + * Try and attach graphics devices first. + * Unfortunately, they - not being GIO devices after all - do not + * contain a Product Identification Word, nor have a slot number. + * + * Record addresses to which graphics devices attach so that + * we do not confuse them with expansion slots, should the + * addresses coincide. + * + * Unfortunately graphics devices for which we have no configured + * driver, which address matches a regular slot number, will show + * up as rogue devices attached to real slots. + * + * If only the ARCBios component tree would be so kind as to give + * us the address of the frame buffer components... + */ + for (i = 0; gfx_bases[i].base != 0; i++) { + /* skip slots that don't apply to us */ + if (gfx_bases[i].mach_type != sys_config.system_type) + continue; + + if (gfx_bases[i].mach_subtype != -1 && + gfx_bases[i].mach_subtype != sys_config.system_subtype) + continue; + + ga.ga_slot = -1; + ga.ga_addr = gfx_bases[i].base; + ga.ga_iot = sc->sc_iot; + ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC); + ga.ga_dmat = sc->sc_dmat; + ga.ga_product = -1; + + if (gio_id(ga.ga_ioh, 1) == 0) + continue; + + if (config_found_sm(self, &ga, gio_print_fb, gio_submatch)) { + gfx[ngfx++] = gfx_bases[i].base; + } + } + + /* + * Now attach any GIO expansion cards. + * + * Be sure to skip any addresses to which a graphics device has + * already been attached. + */ + for (i = 0; slot_bases[i].base != 0; i++) { + int skip = 0; + + /* skip slots that don't apply to us */ + if (slot_bases[i].mach_type != sys_config.system_type) + continue; + + if (slot_bases[i].mach_subtype != -1 && + slot_bases[i].mach_subtype != sys_config.system_subtype) + continue; + + for (j = 0; j < ngfx; j++) { + if (slot_bases[i].base == gfx[j]) { + skip = 1; + break; + } + } + if (skip) + continue; + + ga.ga_slot = slot_bases[i].slot; + ga.ga_addr = slot_bases[i].base; + ga.ga_iot = sc->sc_iot; + ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC); + ga.ga_dmat = sc->sc_dmat; + + if (gio_id(ga.ga_ioh, 0) == 0) + continue; + + ga.ga_product = bus_space_read_4(ga.ga_iot, ga.ga_ioh, 0); + + config_found_sm(self, &ga, gio_print, gio_submatch); + } + + config_search(gio_search, self, aux); +} + +/* + * Try and figure out whether there is a device at the given slot address. + */ +uint32_t +gio_id(paddr_t pa, int maybe_gfx) +{ + uint32_t id32; + uint16_t id16 = 0; + uint8_t id8 = 0; + + if (guarded_read_4(pa, &id32) != 0) + return 0; + + id16 = id32 ^ 0xffff; + (void)guarded_read_2(pa | 2, &id16); + id8 = id16 ^ 0xff; + (void)guarded_read_1(pa | 3, &id8); + + /* + * If there is a real GIO device at this address (as opposed to + * a graphics card), then the low-order 8 bits of each read need + * to be consistent... + */ + if (id8 == (id16 & 0xff) && id8 == (id32 & 0xff)) { + if (GIO_PRODUCT_32BIT_ID(id8)) { + if (id16 == (id32 & 0xffff)) + return id32; + } else { + if (id8 != 0) + return id32; + } + } + + if (maybe_gfx) + return 1; + + return 0; +} + +int +gio_print(void *aux, const char *pnp) +{ + struct gio_attach_args *ga = aux; + const char *descr; + int product, revision; + uint i; + + product = GIO_PRODUCT_PRODUCTID(ga->ga_product); + if (GIO_PRODUCT_32BIT_ID(ga->ga_product)) + revision = GIO_PRODUCT_REVISION(ga->ga_product); + else + revision = 0; + + descr = "unknown GIO card"; + for (i = 0; gio_knowndevs[i].productid != 0; i++) { + if (gio_knowndevs[i].productid == product) { + descr = gio_knowndevs[i].product; + break; + } + } + + if (pnp != NULL) { + printf("%s", descr); + if (ga->ga_product != -1) + printf(" (product 0x%02x revision 0x%02x)", + product, revision); + printf(" at %s", pnp); + } + + if (ga->ga_slot != -1) + printf(" slot %d", ga->ga_slot); + printf(" addr 0x%lx", ga->ga_addr); + + return UNCONF; +} + +int +gio_print_fb(void *aux, const char *pnp) +{ +#if 0 /* once we can know for sure there really is a frame buffer here */ + if (pnp != NULL) + printf("framebuffer at %s", pnp); + + if (ga->ga_addr != (uint64_t)-1) + printf(" addr 0x%lx", ga->ga_addr); + + return UNCONF; +#else + return QUIET; +#endif +} + +int +gio_search(struct device *parent, void *vcf, void *aux) +{ + struct gio_softc *sc = (struct gio_softc *)parent; + struct cfdata *cf = (struct cfdata *)vcf; + struct gio_attach_args ga; + + /* Handled by direct configuration, so skip here */ + if (cf->cf_loc[1 /*GIOCF_ADDR*/] == -1) + return 0; + + ga.ga_product = -1; + ga.ga_slot = cf->cf_loc[0 /*GIOCF_SLOT*/]; + ga.ga_addr = (uint64_t)cf->cf_loc[1 /*GIOCF_ADDR*/]; + ga.ga_iot = sc->sc_iot; + ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC); + ga.ga_dmat = sc->sc_dmat; + + if ((*cf->cf_attach->ca_match)(parent, cf, &ga) == 0) + return 0; + + config_attach(parent, cf, &ga, gio_print); + + return 1; +} + +int +gio_submatch(struct device *parent, void *vcf, void *aux) +{ + struct cfdata *cf = (struct cfdata *)vcf; + struct gio_attach_args *ga = (struct gio_attach_args *)aux; + + if (cf->cf_loc[0 /*GIOCF_SLOT*/] != -1 && + cf->cf_loc[0 /*GIOCF_SLOT*/] != ga->ga_slot) + return 0; + + if (cf->cf_loc[1 /*GIOCF_ADDR*/] != -1 && + (uint64_t)cf->cf_loc[1 /*GIOCF_ADDR*/] != ga->ga_addr) + return 0; + + return (*cf->cf_attach->ca_match)(parent, cf, aux); +} + +#if 0 /* XXX involve wscons_machdep somehow */ +int +gio_cnattach(void) +{ + extern struct machine_bus_dma_tag imc_bus_dma_tag; /* XXX */ + extern bus_space_t imcbus_tag; /* XXX */ + struct gio_attach_args ga; + uint32_t dummy; + int i; + + for (i = 0; gfx_bases[i].base != 0; i++) { + /* skip bases that don't apply to us */ + if (gfx_bases[i].mach_type != sys_config.system_type) + continue; + + if (gfx_bases[i].mach_subtype != -1 && + gfx_bases[i].mach_subtype != sys_config.system_subtype) + continue; + + ga.ga_slot = -1; + ga.ga_addr = gfx_bases[i].base; + ga.ga_iot = &imcbus_tag; /* XXX */ + ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC); + ga.ga_dmat = &imc_bus_dma_tag; /* XXX */ + ga.ga_product = -1; + + if (gio_id(ga.ga_ioh, 1) == 0) + continue; + +#if NGRTWO > 0 + if (grtwo_cnattach(&ga) == 0) + return 0; +#endif + +#if NLIGHT > 0 + if (light_cnattach(&ga) == 0) + return 0; +#endif + +#if NNEWPORT > 0 + if (newport_cnattach(&ga) == 0) + return 0; +#endif + + } + + return ENXIO; +} +#endif + +/* + * Devices living in the expansion slots must enable or disable some + * GIO arbiter settings. This is accomplished via imc(4) registers. + */ +int +gio_arb_config(int slot, uint32_t flags) +{ + if (flags == 0) + return (EINVAL); + + if (flags & ~(GIO_ARB_RT | GIO_ARB_LB | GIO_ARB_MST | GIO_ARB_SLV | + GIO_ARB_PIPE | GIO_ARB_NOPIPE | GIO_ARB_32BIT | GIO_ARB_64BIT | + GIO_ARB_HPC2_32BIT | GIO_ARB_HPC2_64BIT)) + return (EINVAL); + + if (((flags & GIO_ARB_RT) && (flags & GIO_ARB_LB)) || + ((flags & GIO_ARB_MST) && (flags & GIO_ARB_SLV)) || + ((flags & GIO_ARB_PIPE) && (flags & GIO_ARB_NOPIPE)) || + ((flags & GIO_ARB_32BIT) && (flags & GIO_ARB_64BIT)) || + ((flags & GIO_ARB_HPC2_32BIT) && (flags & GIO_ARB_HPC2_64BIT))) + return (EINVAL); + + return (imc_gio64_arb_config(slot, flags)); +} + +/* + * Establish an interrupt handler for the specified slot. + * + * Indy and Challenge S have an interrupt per GIO slot. Indigo and Indigo2 + * share a single interrupt, however. + */ +void * +gio_intr_establish(int slot, int level, int (*func)(void *), void *arg, + const char *what) +{ + int intr; + + switch (sys_config.system_type) { + case SGI_IP20: + if (slot == GIO_SLOT_GFX) + return NULL; + intr = 6; + break; + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + if (sys_config.system_subtype == IP22_INDIGO2) { + if (slot == GIO_SLOT_EXP1) + return NULL; + intr = 6; + } else { + if (slot == GIO_SLOT_GFX) + return NULL; + intr = (slot == GIO_SLOT_EXP0) ? 22 : 23; + } + break; + default: + return NULL; + } + + return int2_intr_establish(intr, level, func, arg, what); +} + +const char * +gio_product_string(int prid) +{ + int i; + + for (i = 0; gio_knowndevs[i].product != NULL; i++) + if (gio_knowndevs[i].productid == prid) + return (gio_knowndevs[i].product); + + return (NULL); +} diff --git a/sys/arch/sgi/gio/giodevs b/sys/arch/sgi/gio/giodevs new file mode 100644 index 00000000000..8189affed20 --- /dev/null +++ b/sys/arch/sgi/gio/giodevs @@ -0,0 +1,21 @@ +$OpenBSD: giodevs,v 1.1 2012/03/28 20:44:23 miod Exp $ +/* $NetBSD: giodevs,v 1.8 2007/02/19 04:46:33 rumble Exp $ */ + +product XPI 0x01 XPI low cost FDDI +product GTR 0x02 GTR TokenRing +product ISDN 0x04 Synchronous ISDN +product CANON 0x06 Canon Interface +product JPEG_D 0x08 JPEG (Double Wide) +product JPEG_S 0x09 JPEG (Single Wide) +product XPI_M0 0x0a XPI mez. FDDI device 0 +product XPI_M1 0x0b XPI mez. FDDI device 1 +product EP 0x0e E-Plex 8-port Ethernet +product IVAS 0x30 Lyon Lamb IVAS +product PHOBOS_G160 0x35 Phobos G160 10/100 Ethernet +product PHOBOS_G130 0x36 Phobos G130 10/100 Ethernet +product PHOBOS_G100 0x37 Phobos G100 100baseTX Fast Ethernet +product SETENG_GFE 0x38 Set Engineering GFE 10/100 Ethernet +product ATM 0x85 ATM board +product SCSI 0x87 16 bit SCSI Card +product SMPTE 0x8c SMPTE 259M Video +product BABBLE 0x8d Babblefish Compression diff --git a/sys/arch/sgi/gio/gioreg.h b/sys/arch/sgi/gio/gioreg.h new file mode 100644 index 00000000000..a5bf76444e3 --- /dev/null +++ b/sys/arch/sgi/gio/gioreg.h @@ -0,0 +1,68 @@ +/* $OpenBSD: gioreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: gioreg.h,v 1.4 2006/08/31 00:01:10 rumble Exp $ */ + +/* + * Copyright (c) 2003 Ilpo Ruotsalainen + * 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. 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. + * + * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>> + */ + +/* + * The GIO Product Identification Word is the first word (1 or 4 bytes) + * in each GIO device's address space. It is the same format for GIO32, + * GIO32-bis, and GIO64 devices. The macros below extract the following + * fields: + * + * Bits: + * 0-6 Product ID Code + * 7 Product Identification Word size (0: 8 bits, 1: 32 bits) + * 8-15 Product Revision + * 16 GIO Interface Size (0: 32, 1: 64; NB: GIO64 devices may be 32) + * 17 Rom Present (1: present) + * 18-31 Manufacturer-specific Code + * + * The upper three bytes containing the Product Revision, GIO Interface + * Size, Rom Presence indicator, and Manufacturer-specific Code are only + * valid if bit 7 is set in the Product ID Word. If it is not set, all + * values default to 0. + * + * If the Rom Present bit is set, the three words after the Product ID are + * reserved for three ROM registers: + * Board Serial Number Register (base_address + 0x4) + * ROM Index Register (base_address + 0x8) + * ROM Read Register (base_address + 0xc) + * + * The ROM Index Register is initialised by the CPU to 0 and incremented by + * 4 on each read from the ROM Read Register. The Board Serial Number + * Register contains a manufacturer-specific serial number. + */ + +#define GIO_PRODUCT_32BIT_ID(x) ((x) & 0x80) +#define GIO_PRODUCT_PRODUCTID(x) ((x) & 0x7f) +#define GIO_PRODUCT_REVISION(x) (((x) >> 8) & 0xff) +#define GIO_PRODUCT_IS_64BIT(x) (!!((x) & 0x8000)) +#define GIO_PRODUCT_HAS_ROM(x) (!!((x) & 0x10000)) +#define GIO_PRODUCT_MANUCODE(x) ((x) >> 18) diff --git a/sys/arch/sgi/gio/giovar.h b/sys/arch/sgi/gio/giovar.h new file mode 100644 index 00000000000..6c35c7561da --- /dev/null +++ b/sys/arch/sgi/gio/giovar.h @@ -0,0 +1,75 @@ +/* $OpenBSD: giovar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: giovar.h,v 1.10 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2000 Soren S. Jorvang + * 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 for the + * NetBSD Project. See http://www.NetBSD.org/ for + * information about NetBSD. + * 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. + */ + +/* + * GIO 32/32-bis/64 bus + */ + +struct gio_attach_args { + bus_space_tag_t ga_iot; + bus_space_handle_t ga_ioh; + bus_dma_tag_t ga_dmat; + + int ga_slot; /* not valid if graphics */ + u_int64_t ga_addr; + + u_int32_t ga_product; /* not valid if graphics */ +}; + + +#define GIO_SLOT_GFX 0 +#define GIO_SLOT_EXP0 1 +#define GIO_SLOT_EXP1 2 + +#define GIO_ARB_RT 0x001 /* real-time device */ +#define GIO_ARB_LB 0x002 /* long-burst device */ + +#define GIO_ARB_MST 0x004 /* bus master enable */ +#define GIO_ARB_SLV 0x008 /* slave */ + +#define GIO_ARB_PIPE 0x010 /* pipelining enable */ +#define GIO_ARB_NOPIPE 0x020 /* pipelining disable */ + +#define GIO_ARB_32BIT 0x040 /* 32-bit transfers */ +#define GIO_ARB_64BIT 0x080 /* 64-bit transfers */ + +#define GIO_ARB_HPC2_32BIT 0x100 /* 32-bit secondary HPC (ignores slot)*/ +#define GIO_ARB_HPC2_64BIT 0x200 /* 64-bit secondary HPC (ignores slot)*/ + +int gio_cnattach(void); +int gio_arb_config(int, uint32_t); +void *gio_intr_establish(int, int, int (*)(void *), void *, + const char *); +const char *gio_product_string(int); diff --git a/sys/arch/sgi/hpc/dpclock.c b/sys/arch/sgi/hpc/dpclock.c new file mode 100644 index 00000000000..600c3ede567 --- /dev/null +++ b/sys/arch/sgi/hpc/dpclock.c @@ -0,0 +1,312 @@ +/* $OpenBSD: dpclock.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: dpclock.c,v 1.3 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 2001 Erik Reid + * Copyright (c) 2001 Rafal K. Boni + * Copyright (c) 2001 Christopher Sekiya + * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Portions of this code are derived from software contributed to The + * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + * + * 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. 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) 1988 University of Utah. + * Copyright (c) 1982, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * 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. 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. + * + * from: Utah $Hdr: clock.c 1.18 91/01/21$ + * + * @(#)clock.c 8.2 (Berkeley) 1/12/94 + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> + +#include <mips64/archtype.h> +#include <mips64/dev/clockvar.h> + +#include <dev/ic/dp8573areg.h> +#include <sgi/hpc/hpcvar.h> + +#define IRIX_BASE_YEAR 1940 + +struct dpclock_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +int dpclock_match(struct device *, void *, void *); +void dpclock_attach(struct device *, struct device *, void *); + +struct cfdriver dpclock_cd = { + NULL, "dpclock", DV_DULL +}; + +const struct cfattach dpclock_ca = { + sizeof(struct dpclock_softc), dpclock_match, dpclock_attach +}; + +#define dpclock_read(sc,r) \ + bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3) +#define dpclock_write(sc,r,v) \ + bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3, (v)) + +static inline int frombcd(int); +static inline int tobcd(int); +static inline int leapyear(int year); + +static inline int +frombcd(int x) +{ + return (x >> 4) * 10 + (x & 0xf); +} +static inline int +tobcd(int x) +{ + return (x / 10 * 16) + (x % 10); +} +/* + * This inline avoids some unnecessary modulo operations + * as compared with the usual macro: + * ( ((year % 4) == 0 && + * (year % 100) != 0) || + * ((year % 400) == 0) ) + * It is otherwise equivalent. + * (borrowed from kern/clock_subr.c) + */ +static inline int +leapyear(int year) +{ + int rv = 0; + + if ((year & 3) == 0) { + rv = 1; + if ((year % 100) == 0) { + rv = 0; + if ((year % 400) == 0) + rv = 1; + } + } + return (rv); +} + +void dpclock_gettime(void *, time_t, struct tod_time *); +void dpclock_settime(void *, struct tod_time *); + +int +dpclock_match(struct device *parent, void *vcf, void *aux) +{ + struct hpc_attach_args *haa = aux; + + if (strcmp(haa->ha_name, dpclock_cd.cd_name) != 0) + return 0; + + return 1; +} + +void +dpclock_attach(struct device *parent, struct device *self, void *aux) +{ + struct dpclock_softc *sc = (void *)self; + struct hpc_attach_args *haa = aux; + uint8_t st, r; + + sc->sc_iot = haa->ha_st; + if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff, + 4 * DP8573A_NREG, &sc->sc_ioh) != 0) { + printf(": can't map registers\n"); + return; + } + + st = dpclock_read(sc, DP8573A_STATUS); + dpclock_write(sc, DP8573A_STATUS, st | DP8573A_STATUS_REGSEL); + r = dpclock_read(sc, DP8573A_RT_MODE); + if ((r & DP8573A_RT_MODE_CLKSS) == 0) { + printf(": clock stopped"); + dpclock_write(sc, DP8573A_RT_MODE, r | DP8573A_RT_MODE_CLKSS); + dpclock_write(sc, DP8573A_INT0_CTL, 0); + dpclock_write(sc, DP8573A_INT1_CTL, DP8573A_INT1_CTL_PWRINT); + } + dpclock_write(sc, DP8573A_STATUS, st & ~DP8573A_STATUS_REGSEL); + r = dpclock_read(sc, DP8573A_PFLAG); + if (r & DP8573A_PFLAG_TESTMODE) { + dpclock_write(sc, DP8573A_RAM_1F, 0); + dpclock_write(sc, DP8573A_PFLAG, r & ~DP8573A_PFLAG_TESTMODE); + } + + printf("\n"); + + sys_tod.tod_get = dpclock_gettime; + sys_tod.tod_set = dpclock_settime; + sys_tod.tod_cookie = self; +} + +/* + * Get the time of day, based on the clock's value and/or the base value. + */ +void +dpclock_gettime(void *cookie, time_t base, struct tod_time *ct) +{ + struct dpclock_softc *sc = (void *)cookie; + uint i; + uint8_t regs[DP8573A_NREG]; + + i = dpclock_read(sc, DP8573A_TIMESAVE_CTL); + dpclock_write(sc, DP8573A_TIMESAVE_CTL, i | DP8573A_TIMESAVE_CTL_EN); + dpclock_write(sc, DP8573A_TIMESAVE_CTL, i); + + for (i = 0; i < DP8573A_NREG; i++) + regs[i] = dpclock_read(sc, i); + + ct->sec = frombcd(regs[DP8573A_SAVE_SEC]); + ct->min = frombcd(regs[DP8573A_SAVE_MIN]); + + if (regs[DP8573A_RT_MODE] & DP8573A_RT_MODE_1224) { + ct->hour = frombcd(regs[DP8573A_SAVE_HOUR] & + DP8573A_HOUR_12HR_MASK) + + ((regs[DP8573A_SAVE_HOUR] & DP8573A_RT_MODE_1224) ? 0 : 12); + + /* + * In AM/PM mode, hour range is 01-12, so adding in 12 hours + * for PM gives us 01-24, whereas we want 00-23, so map hour + * 24 to hour 0. + */ + if (ct->hour == 24) + ct->hour = 0; + } else { + ct->hour = frombcd(regs[DP8573A_SAVE_HOUR] & + DP8573A_HOUR_24HR_MASK); + } + + ct->day = frombcd(regs[DP8573A_SAVE_DOM]); + ct->mon = frombcd(regs[DP8573A_SAVE_MONTH]); + ct->year = frombcd(regs[DP8573A_YEAR]) + (IRIX_BASE_YEAR - 1900); +} + +/* + * Reset the TODR based on the time value. + */ +void +dpclock_settime(void *cookie, struct tod_time *ct) +{ + struct dpclock_softc *sc = (void *)cookie; + uint i; + uint st, r, delta; + uint8_t regs[DP8573A_NREG]; + + r = dpclock_read(sc, DP8573A_TIMESAVE_CTL); + dpclock_write(sc, DP8573A_TIMESAVE_CTL, r | DP8573A_TIMESAVE_CTL_EN); + dpclock_write(sc, DP8573A_TIMESAVE_CTL, r); + + for (i = 0; i < DP8573A_NREG; i++) + regs[i] = dpclock_read(sc, i); + + regs[DP8573A_SUBSECOND] = 0; + regs[DP8573A_SECOND] = tobcd(ct->sec); + regs[DP8573A_MINUTE] = tobcd(ct->min); + regs[DP8573A_HOUR] = tobcd(ct->hour) & DP8573A_HOUR_24HR_MASK; + regs[DP8573A_DOW] = tobcd(ct->dow); + regs[DP8573A_DOM] = tobcd(ct->day); + regs[DP8573A_MONTH] = tobcd(ct->mon); + regs[DP8573A_YEAR] = tobcd(ct->year - (IRIX_BASE_YEAR - 1900)); + + st = dpclock_read(sc, DP8573A_STATUS); + dpclock_write(sc, DP8573A_STATUS, st | DP8573A_STATUS_REGSEL); + r = dpclock_read(sc, DP8573A_RT_MODE); + dpclock_write(sc, DP8573A_RT_MODE, r & ~DP8573A_RT_MODE_CLKSS); + + for (i = 0; i < 10; i++) + dpclock_write(sc, DP8573A_COUNTERS + i, + regs[DP8573A_COUNTERS + i]); + + /* + * We now need to set the leap year counter to the correct value. + * Unfortunately it is only two bits wide, while eight years can + * happen between two leap years. Skirting this is left as an + * exercise to the reader with an Indigo in working condition + * by year 2100. + */ + delta = 0; + while (delta < 3 && !leapyear(ct->year - delta)) + delta++; + + r &= ~(DP8573A_RT_MODE_LYLSB | DP8573A_RT_MODE_LYMSB); + dpclock_write(sc, DP8573A_RT_MODE, r | delta | DP8573A_RT_MODE_CLKSS); + + dpclock_write(sc, DP8573A_STATUS, st & ~DP8573A_STATUS_REGSEL); +} diff --git a/sys/arch/sgi/hpc/dsclock.c b/sys/arch/sgi/hpc/dsclock.c new file mode 100644 index 00000000000..396d68ec9d9 --- /dev/null +++ b/sys/arch/sgi/hpc/dsclock.c @@ -0,0 +1,192 @@ +/* $OpenBSD: dsclock.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: dsclock.c,v 1.5 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2001 Rafal K. Boni + * Copyright (c) 2001 Christopher Sekiya + * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Portions of this code are derived from software contributed to The + * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + * + * 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. 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. + */ + + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> + +#include <mips64/archtype.h> +#include <mips64/dev/clockvar.h> + +#include <dev/ic/ds1286reg.h> +#include <sgi/hpc/hpcvar.h> + +#define IRIX_BASE_YEAR 1940 + +struct dsclock_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +int dsclock_match(struct device *, void *, void *); +void dsclock_attach(struct device *, struct device *, void *); + +struct cfdriver dsclock_cd = { + NULL, "dsclock", DV_DULL +}; + +const struct cfattach dsclock_ca = { + sizeof(struct dsclock_softc), dsclock_match, dsclock_attach +}; + +#define ds1286_read(sc,r) \ + bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3) +#define ds1286_write(sc,r,v) \ + bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3, (v)) + +static inline int frombcd(int); +static inline int tobcd(int); + +static inline int +frombcd(int x) +{ + return (x >> 4) * 10 + (x & 0xf); +} +static inline int +tobcd(int x) +{ + return (x / 10 * 16) + (x % 10); +} + +void dsclock_gettime(void *, time_t, struct tod_time *); +void dsclock_settime(void *, struct tod_time *); + +int +dsclock_match(struct device *parent, void *vcf, void *aux) +{ + struct hpc_attach_args *haa = aux; + + if (strcmp(haa->ha_name, dsclock_cd.cd_name) != 0) + return 0; + + return 1; +} + +void +dsclock_attach(struct device *parent, struct device *self, void *aux) +{ + struct dsclock_softc *sc = (void *)self; + struct hpc_attach_args *haa = aux; + + sc->sc_iot = haa->ha_st; + if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff, + 4 * 8192, &sc->sc_ioh) != 0) { + printf(": can't map registers\n"); + return; + } + + printf("\n"); + + sys_tod.tod_get = dsclock_gettime; + sys_tod.tod_set = dsclock_settime; + sys_tod.tod_cookie = self; +} + +/* + * Get the time of day, based on the clock's value and/or the base value. + */ +void +dsclock_gettime(void *cookie, time_t base, struct tod_time *ct) +{ + struct dsclock_softc *sc = (void *)cookie; + ds1286_todregs regs; + int s; + + s = splhigh(); + DS1286_GETTOD(sc, ®s) + splx(s); + + ct->sec = frombcd(regs[DS1286_SEC]); + ct->min = frombcd(regs[DS1286_MIN]); + + if (regs[DS1286_HOUR] & DS1286_HOUR_12MODE) { + ct->hour = frombcd(regs[DS1286_HOUR] & DS1286_HOUR_12HR_MASK) + + ((regs[DS1286_HOUR] & DS1286_HOUR_12HR_PM) ? 12 : 0); + + /* + * In AM/PM mode, hour range is 01-12, so adding in 12 hours + * for PM gives us 01-24, whereas we want 00-23, so map hour + * 24 to hour 0. + */ + if (ct->hour == 24) + ct->hour = 0; + } else { + ct->hour = frombcd(regs[DS1286_HOUR] & DS1286_HOUR_24HR_MASK); + } + + ct->day = frombcd(regs[DS1286_DOM]); + ct->mon = frombcd(regs[DS1286_MONTH] & DS1286_MONTH_MASK); + ct->year = frombcd(regs[DS1286_YEAR]) + (IRIX_BASE_YEAR - 1900); +} + +/* + * Reset the TODR based on the time value. + */ +void +dsclock_settime(void *cookie, struct tod_time *ct) +{ + struct dsclock_softc *sc = (void *)cookie; + ds1286_todregs regs; + int s; + + s = splhigh(); + DS1286_GETTOD(sc, ®s); + splx(s); + + regs[DS1286_SUBSEC] = 0; + regs[DS1286_SEC] = tobcd(ct->sec); + regs[DS1286_MIN] = tobcd(ct->min); + regs[DS1286_HOUR] = tobcd(ct->hour) & DS1286_HOUR_24HR_MASK; + regs[DS1286_DOW] = tobcd(ct->dow); + regs[DS1286_DOM] = tobcd(ct->day); + + /* Leave wave-generator bits as set originally */ + regs[DS1286_MONTH] &= ~DS1286_MONTH_MASK; + regs[DS1286_MONTH] |= tobcd(ct->mon) & DS1286_MONTH_MASK; + + regs[DS1286_YEAR] = tobcd(ct->year - (IRIX_BASE_YEAR - 1900)); + + s = splhigh(); + DS1286_PUTTOD(sc, ®s); + splx(s); +} diff --git a/sys/arch/sgi/hpc/files.hpc b/sys/arch/sgi/hpc/files.hpc new file mode 100644 index 00000000000..4463f066a45 --- /dev/null +++ b/sys/arch/sgi/hpc/files.hpc @@ -0,0 +1,56 @@ +# $OpenBSD: files.hpc,v 1.1 2012/03/28 20:44:23 miod Exp $ +# $NetBSD: files.hpc,v 1.14 2009/05/14 01:10:19 macallan Exp $ + +# IP20 RTC +device dpclock +attach dpclock at hpc +file arch/sgi/hpc/dpclock.c dpclock + +# IP22/24 RTC +device dsclock +attach dsclock at hpc +file arch/sgi/hpc/dsclock.c dsclock + +device sq: ether, ifnet +attach sq at hpc +file arch/sgi/hpc/if_sq.c sq + +define hpcdma +file arch/sgi/hpc/hpcdma.c hpcdma + +device wdsc: wd33c93, scsi, hpcdma +attach wdsc at hpc +file arch/sgi/hpc/wdsc.c wdsc + +device haltwo: audio, auconv, mulaw +attach haltwo at hpc +file arch/sgi/hpc/haltwo.c haltwo + +device zs {[channel = -1]} +attach zs at hpc with zs_hpc +file arch/sgi/hpc/zs.c zs needs-flag +file arch/sgi/hpc/z8530sc.c zs + +device zstty: tty +attach zstty at zs +file arch/sgi/hpc/z8530tty.c zstty needs-flag + +device zskbd: wskbddev +attach zskbd at zs +file arch/sgi/hpc/zs_kbd.c zskbd needs-flag +file arch/sgi/dev/wskbdmap_sgi.c zskbd + +device zsms: wsmousedev +attach zsms at zs +file arch/sgi/hpc/zs_ms.c zsms + +attach pckbc at hpc with pckbc_hpc +file arch/sgi/hpc/pckbc_hpc.c pckbc_hpc + +#device pione +#attach pione at hpc +#file arch/sgi/hpc/pione.c pione + +device panel +attach panel at hpc +file arch/sgi/hpc/panel.c panel diff --git a/sys/arch/sgi/hpc/hpc.c b/sys/arch/sgi/hpc/hpc.c new file mode 100644 index 00000000000..ca2c31c06ed --- /dev/null +++ b/sys/arch/sgi/hpc/hpc.c @@ -0,0 +1,822 @@ +/* $OpenBSD: hpc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: hpc.c,v 1.66 2011/07/01 18:53:46 dyoung Exp $ */ +/* $NetBSD: ioc.c,v 1.9 2011/07/01 18:53:47 dyoung Exp $ */ + +/* + * Copyright (c) 2003 Christopher Sekiya + * 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 for the + * NetBSD Project. See http://www.NetBSD.org/ for + * information about NetBSD. + * 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) 2000 Soren S. Jorvang + * Copyright (c) 2001 Rafal K. Boni + * Copyright (c) 2001 Jason R. Thorpe + * 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 for the + * NetBSD Project. See http://www.NetBSD.org/ for + * information about NetBSD. + * 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. + */ + +/* + * Combined driver for the HPC (High performance Peripheral Controller) + * and IOC2 (I/O Controller) chips. + * + * It would theoretically be better to attach an IOC driver to HPC on + * IOC systems (IP22/24/26/28), and attach the few onboard devices + * which attach directly to HPC on IP20, to IOC. But since IOC depends + * too much on HPC, the complexity this would introduce is not worth + * the hassle. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/timeout.h> + +#include <mips64/archtype.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cpu.h> + +#include <sgi/gio/gioreg.h> +#include <sgi/gio/giovar.h> + +#include <sgi/hpc/hpcvar.h> +#include <sgi/hpc/hpcreg.h> +#include <sgi/hpc/iocreg.h> +#include <sgi/sgi/ip22.h> + +#include <dev/ic/smc93cx6var.h> + +struct hpc_device { + const char *hd_name; + bus_addr_t hd_base; + bus_addr_t hd_devoff; + bus_addr_t hd_dmaoff; + int hd_irq; + int hd_sysmask; +}; + +static const struct hpc_device hpc1_devices[] = { + /* probe order is important for IP20 zs */ + + { "zs", /* Indigo serial 0/1 duart 1 */ + HPC_BASE_ADDRESS_0, + 0x0d10, 0, + 5, + HPCDEV_IP20 }, + + { "zs", /* Indigo kbd/ms duart 0 */ + HPC_BASE_ADDRESS_0, + 0x0d00, 0, + 5, + HPCDEV_IP20 }, + + { "sq", /* Indigo onboard ethernet */ + HPC_BASE_ADDRESS_0, + HPC1_ENET_DEVREGS, HPC1_ENET_REGS, + 3, + HPCDEV_IP20 }, + + { "sq", /* E++ GIO adapter slot 0 (Indigo) */ + HPC_BASE_ADDRESS_1, + HPC1_ENET_DEVREGS, HPC1_ENET_REGS, + 6, + HPCDEV_IP20 }, + + { "sq", /* E++ GIO adapter slot 0 (Indy) */ + HPC_BASE_ADDRESS_1, + HPC1_ENET_DEVREGS, HPC1_ENET_REGS, + 16 + 6, + HPCDEV_IP24 }, + + { "sq", /* E++ GIO adapter slot 1 (Indigo) */ + HPC_BASE_ADDRESS_2, + HPC1_ENET_DEVREGS, HPC1_ENET_REGS, + 6, + HPCDEV_IP20 }, + + { "sq", /* E++ GIO adapter slot 1 (Indy/Challenge S) */ + HPC_BASE_ADDRESS_2, + HPC1_ENET_DEVREGS, HPC1_ENET_REGS, + 16 + 7, + HPCDEV_IP24 }, + + { "wdsc", /* Indigo onboard SCSI */ + HPC_BASE_ADDRESS_0, + HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS, + 2, + HPCDEV_IP20 }, + + { "wdsc", /* GIO32 SCSI adapter slot 0 (Indigo) */ + HPC_BASE_ADDRESS_1, + HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS, + 6, + HPCDEV_IP20 }, + + { "wdsc", /* GIO32 SCSI adapter slot 0 (Indy) */ + HPC_BASE_ADDRESS_1, + HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS, + 16 + 6, + HPCDEV_IP24 }, + + { "wdsc", /* GIO32 SCSI adapter slot 1 (Indigo) */ + HPC_BASE_ADDRESS_2, + HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS, + 6, + HPCDEV_IP20 }, + + { "wdsc", /* GIO32 SCSI adapter slot 1 (Indy/Challenge S) */ + HPC_BASE_ADDRESS_2, + HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS, + 16 + 7, + HPCDEV_IP24 }, + + { NULL, + 0, + 0, 0, + 0, + 0 + } +}; + +static const struct hpc_device hpc3_devices[] = { + { "zs", /* serial 0/1 duart 0 */ + HPC_BASE_ADDRESS_0, + /* XXX Magic numbers */ + HPC3_PBUS_CH6_DEVREGS + IOC_SERIAL_REGS, 0, + 24 + 5, + HPCDEV_IP22 | HPCDEV_IP24 }, + + { "pckbc", /* Indigo2/Indy ps2 keyboard/mouse controller */ + HPC_BASE_ADDRESS_0, + HPC3_PBUS_CH6_DEVREGS + IOC_KB_REGS, 0, + 24 + 4, + HPCDEV_IP22 | HPCDEV_IP24 }, + + { "sq", /* Indigo2/Indy/Challenge S/Challenge M onboard enet */ + HPC_BASE_ADDRESS_0, + HPC3_ENET_DEVREGS, HPC3_ENET_REGS, + 3, + HPCDEV_IP22 | HPCDEV_IP24 }, + + { "sq", /* Challenge S IOPLUS secondary ethernet */ + HPC_BASE_ADDRESS_1, + HPC3_ENET_DEVREGS, HPC3_ENET_REGS, + 0, + HPCDEV_IP24 }, + + { "wdsc", /* Indigo2/Indy/Challenge S/Challenge M onboard SCSI */ + HPC_BASE_ADDRESS_0, + HPC3_SCSI0_DEVREGS, HPC3_SCSI0_REGS, + 1, + HPCDEV_IP22 | HPCDEV_IP24 }, + + { "wdsc", /* Indigo2/Challenge M secondary onboard SCSI */ + HPC_BASE_ADDRESS_0, + HPC3_SCSI1_DEVREGS, HPC3_SCSI1_REGS, + 2, + HPCDEV_IP22 }, + + { "haltwo", /* Indigo2/Indy onboard audio */ + HPC_BASE_ADDRESS_0, + HPC3_PBUS_CH0_DEVREGS, HPC3_PBUS_DMAREGS, + 8 + 4, /* really the HPC DMA complete interrupt */ + HPCDEV_IP22 | HPCDEV_IP24 }, + + { "pione", /* Indigo2/Indy/Challenge S/Challenge M onboard pport */ + HPC_BASE_ADDRESS_0, + HPC3_PBUS_CH6_DEVREGS + IOC_PLP_REGS, 0, + 5, + HPCDEV_IP22 | HPCDEV_IP24 }, + + { "panel", /* Indy front panel */ + HPC_BASE_ADDRESS_0, + HPC3_PBUS_CH6_DEVREGS + IOC_PANEL, 0, + 9, + HPCDEV_IP24 }, + + { NULL, + 0, + 0, 0, + 0, + 0 + } +}; + +struct hpc_softc { + struct device sc_dev; + + bus_addr_t sc_base; + + bus_space_tag_t sc_ct; + bus_space_handle_t sc_ch; + bus_dma_tag_t sc_dmat; + + struct timeout sc_blink_tmo; +}; + +static struct hpc_values hpc1_values = { + .revision = 1, + .scsi0_regs = HPC1_SCSI0_REGS, + .scsi0_regs_size = HPC1_SCSI0_REGS_SIZE, + .scsi0_cbp = HPC1_SCSI0_CBP, + .scsi0_ndbp = HPC1_SCSI0_NDBP, + .scsi0_bc = HPC1_SCSI0_BC, + .scsi0_ctl = HPC1_SCSI0_CTL, + .scsi0_gio = HPC1_SCSI0_GIO, + .scsi0_dev = HPC1_SCSI0_DEV, + .scsi0_dmacfg = HPC1_SCSI0_DMACFG, + .scsi0_piocfg = HPC1_SCSI0_PIOCFG, + .scsi1_regs = 0, + .scsi1_regs_size = 0, + .scsi1_cbp = 0, + .scsi1_ndbp = 0, + .scsi1_bc = 0, + .scsi1_ctl = 0, + .scsi1_gio = 0, + .scsi1_dev = 0, + .scsi1_dmacfg = 0, + .scsi1_piocfg = 0, + .enet_regs = HPC1_ENET_REGS, + .enet_regs_size = HPC1_ENET_REGS_SIZE, + .enet_intdelay = HPC1_ENET_INTDELAY, + .enet_intdelayval = HPC1_ENET_INTDELAY_OFF, + .enetr_cbp = HPC1_ENETR_CBP, + .enetr_ndbp = HPC1_ENETR_NDBP, + .enetr_bc = HPC1_ENETR_BC, + .enetr_ctl = HPC1_ENETR_CTL, + .enetr_ctl_active = HPC1_ENETR_CTL_ACTIVE, + .enetr_reset = HPC1_ENETR_RESET, + .enetr_dmacfg = 0, + .enetr_piocfg = 0, + .enetx_cbp = HPC1_ENETX_CBP, + .enetx_ndbp = HPC1_ENETX_NDBP, + .enetx_bc = HPC1_ENETX_BC, + .enetx_ctl = HPC1_ENETX_CTL, + .enetx_ctl_active = HPC1_ENETX_CTL_ACTIVE, + .enetx_dev = 0, + .enetr_fifo = HPC1_ENETR_FIFO, + .enetr_fifo_size = HPC1_ENETR_FIFO_SIZE, + .enetx_fifo = HPC1_ENETX_FIFO, + .enetx_fifo_size = HPC1_ENETX_FIFO_SIZE, + .enet_dma_boundary = 4096, + .enet_devregs = HPC1_ENET_DEVREGS, + .enet_devregs_size = HPC1_ENET_DEVREGS_SIZE, + .pbus_fifo = 0, + .pbus_fifo_size = 0, + .pbus_bbram = 0, +#define MAX_SCSI_XFER (roundup(MAXPHYS, PAGE_SIZE)) + .scsi_dma_segs = (MAX_SCSI_XFER / 4096), + .scsi_dma_segs_size = 4096, + .scsi_dma_datain_cmd = (HPC1_SCSI_DMACTL_ACTIVE | HPC1_SCSI_DMACTL_DIR), + .scsi_dma_dataout_cmd = HPC1_SCSI_DMACTL_ACTIVE, + .scsi_dmactl_flush = HPC1_SCSI_DMACTL_FLUSH, + .scsi_dmactl_active = HPC1_SCSI_DMACTL_ACTIVE, + .scsi_dmactl_reset = HPC1_SCSI_DMACTL_RESET +}; + +static struct hpc_values hpc3_values = { + .revision = 3, + .scsi0_regs = HPC3_SCSI0_REGS, + .scsi0_regs_size = HPC3_SCSI0_REGS_SIZE, + .scsi0_cbp = HPC3_SCSI0_CBP, + .scsi0_ndbp = HPC3_SCSI0_NDBP, + .scsi0_bc = HPC3_SCSI0_BC, + .scsi0_ctl = HPC3_SCSI0_CTL, + .scsi0_gio = HPC3_SCSI0_GIO, + .scsi0_dev = HPC3_SCSI0_DEV, + .scsi0_dmacfg = HPC3_SCSI0_DMACFG, + .scsi0_piocfg = HPC3_SCSI0_PIOCFG, + .scsi1_regs = HPC3_SCSI1_REGS, + .scsi1_regs_size = HPC3_SCSI1_REGS_SIZE, + .scsi1_cbp = HPC3_SCSI1_CBP, + .scsi1_ndbp = HPC3_SCSI1_NDBP, + .scsi1_bc = HPC3_SCSI1_BC, + .scsi1_ctl = HPC3_SCSI1_CTL, + .scsi1_gio = HPC3_SCSI1_GIO, + .scsi1_dev = HPC3_SCSI1_DEV, + .scsi1_dmacfg = HPC3_SCSI1_DMACFG, + .scsi1_piocfg = HPC3_SCSI1_PIOCFG, + .enet_regs = HPC3_ENET_REGS, + .enet_regs_size = HPC3_ENET_REGS_SIZE, + .enet_intdelay = 0, + .enet_intdelayval = 0, + .enetr_cbp = HPC3_ENETR_CBP, + .enetr_ndbp = HPC3_ENETR_NDBP, + .enetr_bc = HPC3_ENETR_BC, + .enetr_ctl = HPC3_ENETR_CTL, + .enetr_ctl_active = HPC3_ENETR_CTL_ACTIVE, + .enetr_reset = HPC3_ENETR_RESET, + .enetr_dmacfg = HPC3_ENETR_DMACFG, + .enetr_piocfg = HPC3_ENETR_PIOCFG, + .enetx_cbp = HPC3_ENETX_CBP, + .enetx_ndbp = HPC3_ENETX_NDBP, + .enetx_bc = HPC3_ENETX_BC, + .enetx_ctl = HPC3_ENETX_CTL, + .enetx_ctl_active = HPC3_ENETX_CTL_ACTIVE, + .enetx_dev = HPC3_ENETX_DEV, + .enetr_fifo = HPC3_ENETR_FIFO, + .enetr_fifo_size = HPC3_ENETR_FIFO_SIZE, + .enetx_fifo = HPC3_ENETX_FIFO, + .enetx_fifo_size = HPC3_ENETX_FIFO_SIZE, + .enet_dma_boundary = 8192, + .enet_devregs = HPC3_ENET_DEVREGS, + .enet_devregs_size = HPC3_ENET_DEVREGS_SIZE, + .pbus_fifo = HPC3_PBUS_FIFO, + .pbus_fifo_size = HPC3_PBUS_FIFO_SIZE, + .pbus_bbram = HPC3_PBUS_BBRAM, + .scsi_dma_segs = (MAX_SCSI_XFER / 8192), + .scsi_dma_segs_size = 8192, + .scsi_dma_datain_cmd = HPC3_SCSI_DMACTL_ACTIVE, + .scsi_dma_dataout_cmd =(HPC3_SCSI_DMACTL_ACTIVE | HPC3_SCSI_DMACTL_DIR), + .scsi_dmactl_flush = HPC3_SCSI_DMACTL_FLUSH, + .scsi_dmactl_active = HPC3_SCSI_DMACTL_ACTIVE, + .scsi_dmactl_reset = HPC3_SCSI_DMACTL_RESET +}; + +int hpc_match(struct device *, void *, void *); +void hpc_attach(struct device *, struct device *, void *); +int hpc_print(void *, const char *); + +int hpc_revision(struct hpc_softc *, struct gio_attach_args *); +int hpc_submatch(struct device *, void *, void *); +int hpc_power_intr(void *); +void hpc_blink(void *); +void hpc_blink_ioc(void *); +int hpc_read_eeprom(int, bus_space_tag_t, bus_space_handle_t, uint8_t *, + size_t); + +const struct cfattach hpc_ca = { + sizeof(struct hpc_softc), hpc_match, hpc_attach +}; + +struct cfdriver hpc_cd = { + NULL, "hpc", DV_DULL +}; + +uint8_t hpc_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint16_t hpc_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t); +void hpc_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void hpc_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t); +void hpc_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t); +void hpc_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +uint32_t hpc_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint64_t hpc_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t); +void hpc_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t); +void hpc_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t); +void hpc_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void hpc_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +void hpc_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void hpc_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +int hpc_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +void hpc_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t); +int hpc_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); +void *hpc_space_vaddr(bus_space_tag_t, bus_space_handle_t); +void hpc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, int); + +int +hpc_match(struct device *parent, void *vcf, void *aux) +{ + struct gio_attach_args* ga = aux; + uint32_t dummy; + + /* Make sure it's actually there and readable */ + if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr, CCA_NC), &dummy) == 0) + return 1; + + return 0; +} + +void +hpc_attach(struct device *parent, struct device *self, void *aux) +{ + struct hpc_softc *sc = (struct hpc_softc *)self; + struct gio_attach_args* ga = aux; + struct hpc_attach_args ha; + const struct hpc_device *hd; + uint32_t dummy; + uint32_t hpctype; + int isonboard; + int isioplus; + int sysmask = 0; + + sc->sc_base = ga->ga_addr; + sc->sc_ct = ga->ga_iot; + sc->sc_ch = PHYS_TO_XKPHYS(sc->sc_base, CCA_NC); + sc->sc_dmat = ga->ga_dmat; + + switch (sys_config.system_type) { + case SGI_IP20: + sysmask = HPCDEV_IP20; + break; + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + if (sys_config.system_subtype == IP22_INDIGO2) + sysmask = HPCDEV_IP22; + else + sysmask = HPCDEV_IP24; + break; + }; + + if ((hpctype = hpc_revision(sc, ga)) == 0) { + printf(": could not identify HPC revision\n"); + return; + } + + /* force big-endian mode */ + if (hpctype == 15) + bus_space_write_4(sc->sc_ct, sc->sc_ch, HPC1_BIGENDIAN, 0); + + /* + * All machines have only one HPC on the mainboard itself. ''Extra'' + * HPCs require bus arbiter and other magic to run happily. + */ + isonboard = (sc->sc_base == HPC_BASE_ADDRESS_0); + isioplus = (sc->sc_base == HPC_BASE_ADDRESS_1 && hpctype == 3 && + sysmask == HPCDEV_IP24); + + printf(": SGI HPC%d%s (%s)\n", (hpctype == 3) ? 3 : 1, + (hpctype == 15) ? ".5" : "", (isonboard) ? "onboard" : + (isioplus) ? "IOPLUS mezzanine" : "GIO slot"); + + /* + * Configure the IOC. + */ + if (isonboard && sys_config.system_type != SGI_IP20) { + /* Reset IOC */ + bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET, + IOC_RESET_PARALLEL | IOC_RESET_PCKBC | IOC_RESET_EISA | + IOC_RESET_ISDN | IOC_RESET_LED_GREEN ); + + /* + * Set the 10BaseT port to use UTP cable, set autoselect mode + * for the Ethernet interface (AUI vs. TP), set the two serial + * ports to PC mode. + */ + bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_WRITE, + IOC_WRITE_ENET_AUTO | IOC_WRITE_ENET_UTP | + IOC_WRITE_PC_UART2 | IOC_WRITE_PC_UART1); + + /* XXX: the firmware should have taken care of this already */ +#if 0 + if (sys_config.system_subtype == IP22_INDY) { + bus_space_write_4(sc->sc_ct, sc->sc_ch, + IOC_BASE + IOC_GCSEL, 0xff); + bus_space_write_4(sc->sc_ct, sc->sc_ch, + IOC_BASE + IOC_GCREG, 0xff); + } +#endif + } + + /* + * Configure the bus arbiter appropriately. + * + * In the case of Challenge S, we must tell the IOPLUS board which + * DMA channel to use (we steal it from one of the slots). SGI allows + * an HPC1.5 in slot 1, in which case IOPLUS must use EXP0, or any + * other DMA-capable board in slot 0, which leaves us to use EXP1. Of + * course, this means that only one GIO board may use DMA. + * + * Note that this never happens on Indigo2. + */ + if (isioplus) { + int arb_slot; + + if (guarded_read_4(PHYS_TO_XKPHYS(HPC_BASE_ADDRESS_2, CCA_NC), + &dummy) != 0) + arb_slot = GIO_SLOT_EXP1; + else + arb_slot = GIO_SLOT_EXP0; + + if (gio_arb_config(arb_slot, GIO_ARB_LB | GIO_ARB_MST | + GIO_ARB_64BIT | GIO_ARB_HPC2_64BIT)) { + printf("%s: failed to configure GIO bus arbiter\n", + sc->sc_dev.dv_xname); + return; + } + + printf("%s: using EXP%d's DMA channel\n", + sc->sc_dev.dv_xname, + (arb_slot == GIO_SLOT_EXP0) ? 0 : 1); + + bus_space_write_4(sc->sc_ct, sc->sc_ch, + HPC3_PBUS_CFGPIO_REGS, 0x0003ffff); + + if (arb_slot == GIO_SLOT_EXP0) + bus_space_write_4(sc->sc_ct, sc->sc_ch, + HPC3_PBUS_CH0_DEVREGS, 0x20202020); + else + bus_space_write_4(sc->sc_ct, sc->sc_ch, + HPC3_PBUS_CH0_DEVREGS, 0x30303030); + } else if (!isonboard) { + int arb_slot; + + arb_slot = (sc->sc_base == HPC_BASE_ADDRESS_1) ? + GIO_SLOT_EXP0 : GIO_SLOT_EXP1; + + if (gio_arb_config(arb_slot, GIO_ARB_RT | GIO_ARB_MST)) { + printf("%s: failed to configure GIO bus arbiter\n", + sc->sc_dev.dv_xname); + return; + } + } + + hpc_read_eeprom(hpctype, sc->sc_ct, sc->sc_ch, + ha.hpc_eeprom, sizeof(ha.hpc_eeprom)); + + hd = hpctype == 3 ? hpc3_devices : hpc1_devices; + for (; hd->hd_name != NULL; hd++) { + if (!(hd->hd_sysmask & sysmask) || hd->hd_base != sc->sc_base) + continue; + + ha.ha_name = hd->hd_name; + ha.ha_devoff = hd->hd_devoff; + ha.ha_dmaoff = hd->hd_dmaoff; + ha.ha_irq = hd->hd_irq; + + ha.ha_st = sc->sc_ct; + ha.ha_sh = sc->sc_ch; + ha.ha_dmat = sc->sc_dmat; + if (hpctype == 3) + ha.hpc_regs = &hpc3_values; + else + ha.hpc_regs = &hpc1_values; + ha.hpc_regs->revision = hpctype; + + /* + * XXX On hpc@gio boards such as the E++, this will cause + * XXX `wdsc not configured' messages (or sq on SCSI + * XXX boards. We need to move some device detection + * XXX in there, or figure out if there is a way to know + * XXX what is really connected. + */ + config_found_sm(self, &ha, hpc_print, hpc_submatch); + } + + /* + * Attach the clock chip as well if on hpc0. + */ + if (isonboard) { + if (sys_config.system_type == SGI_IP20) { + ha.ha_name = "dpclock"; + ha.ha_devoff = HPC1_PBUS_BBRAM; + } else { + ha.ha_name = "dsclock"; + ha.ha_devoff = HPC3_PBUS_BBRAM; + } + ha.ha_dmaoff = 0; + ha.ha_irq = -1; + ha.ha_st = sc->sc_ct; + ha.ha_sh = sc->sc_ch; + ha.ha_dmat = sc->sc_dmat; + ha.hpc_regs = NULL; + + config_found_sm(self, &ha, hpc_print, hpc_submatch); + + if (sys_config.system_type == SGI_IP20) { + timeout_set(&sc->sc_blink_tmo, hpc_blink, sc); + hpc_blink(sc); + } else { + timeout_set(&sc->sc_blink_tmo, hpc_blink_ioc, sc); + hpc_blink_ioc(sc); + } + } +} + +/* + * HPC revision detection isn't as simple as it should be. Devices probe + * differently depending on their slots, but luckily there is only one + * instance in which we have to decide the major revision (HPC1 vs HPC3). + * + * The HPC is found in the following configurations: + * o Indigo R4k + * One on-board HPC1 or HPC1.5. + * Up to two additional HPC1.5's in GIO slots 0 and 1. + * o Indy + * One on-board HPC3. + * Up to two additional HPC1.5's in GIO slots 0 and 1. + * o Challenge S + * One on-board HPC3. + * Up to one additional HPC3 on the IOPLUS board (if installed). + * Up to one additional HPC1.5 in slot 1 of the IOPLUS board. + * o Indigo2, Challenge M + * One on-board HPC3. + * + * All we really have to worry about is the IP22 case. + */ +int +hpc_revision(struct hpc_softc *sc, struct gio_attach_args *ga) +{ + uint32_t reg; + + /* No hardware ever supported the last hpc base address. */ + if (ga->ga_addr == HPC_BASE_ADDRESS_3) + return 0; + + switch (sys_config.system_type) { + case SGI_IP20: + if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr + HPC1_BIGENDIAN, + CCA_NC), ®) != 0) { + if (((reg >> HPC1_REVSHIFT) & HPC1_REVMASK) == + HPC1_REV15) + return 15; + else + return 1; + } + return 1; + + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + /* + * If IP22, probe slot 0 to determine if HPC1.5 or HPC3. Slot 1 + * must be HPC1.5. + */ + if (ga->ga_addr == HPC_BASE_ADDRESS_0) + return 3; + + if (ga->ga_addr == HPC_BASE_ADDRESS_2) + return 15; + + /* + * Probe for it. We use one of the PBUS registers. Note + * that this probe succeeds with my E++ adapter in slot 1 + * (bad), but it appears to always do the right thing in + * slot 0 (good!) and we're only worried about that one + * anyhow. + */ + if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr + + HPC3_PBUS_CH7_BP, CCA_NC), ®) != 0) + return 15; + else + return 3; + } + + return 0; +} + +int +hpc_submatch(struct device *parent, void *vcf, void *aux) +{ + struct cfdata *cf = (struct cfdata *)vcf; + struct hpc_attach_args *ha = (struct hpc_attach_args *)aux; + + if (cf->cf_loc[0 /*HPCCF_OFFSET*/] != -1 && + (bus_addr_t)cf->cf_loc[0 /*HPCCF_OFFSET*/] != ha->ha_devoff) + return 0; + + return (*cf->cf_attach->ca_match)(parent, cf, aux); +} + +int +hpc_print(void *aux, const char *pnp) +{ + struct hpc_attach_args *ha = aux; + + if (pnp) + printf("%s at %s", ha->ha_name, pnp); + + printf(" offset 0x%08lx", ha->ha_devoff); + if (ha->ha_irq >= 0) + printf(" irq %d", ha->ha_irq); + + return UNCONF; +} + +void +hpc_blink(void *arg) +{ + struct hpc_softc *sc = arg; + + bus_space_write_1(sc->sc_ct, sc->sc_ch, HPC1_AUX_REGS, + bus_space_read_1(sc->sc_ct, sc->sc_ch, HPC1_AUX_REGS) ^ + HPC1_AUX_CONSLED); + + timeout_add(&sc->sc_blink_tmo, + (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1))); +} + +void +hpc_blink_ioc(void *arg) +{ + struct hpc_softc *sc = arg; + uint32_t value; + + /* This is a bit odd. To strobe the green LED, we have to toggle the + red control bit. */ + value = bus_space_read_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET) & + 0xff; + value ^= IOC_RESET_LED_RED; + bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET, value); + + timeout_add(&sc->sc_blink_tmo, + (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1))); +} + +/* + * Read the eeprom associated with one of the HPC's. + * + * NB: An eeprom is not always present, but the HPC should be able to + * handle this gracefully. Any consumers should validate the data to + * ensure it's reasonable. + */ +int +hpc_read_eeprom(int hpctype, bus_space_tag_t t, bus_space_handle_t h, + uint8_t *buf, size_t len) +{ + struct seeprom_descriptor sd; + bus_space_handle_t bsh; + bus_size_t offset; + + if (!len || len & 0x1) + return (1); + + offset = (hpctype == 3) ? HPC3_EEPROM_DATA : HPC1_AUX_REGS; + + if (bus_space_subregion(t, h, offset, 1, &bsh) != 0) + return (1); + + sd.sd_chip = C56_66; + sd.sd_tag = t; + sd.sd_bsh = bsh; + sd.sd_regsize = 1; + sd.sd_control_offset = 0; + sd.sd_status_offset = 0; + sd.sd_dataout_offset = 0; + sd.sd_DI = 0x10; /* EEPROM -> CPU */ + sd.sd_DO = 0x08; /* CPU -> EEPROM */ + sd.sd_CK = 0x04; + sd.sd_CS = 0x02; + sd.sd_MS = 0; + sd.sd_RDY = 0; + + if (read_seeprom(&sd, (uint16_t *)buf, 0, len / 2) != 1) + return (1); + + bus_space_unmap(t, bsh, 1); + + return 0; +} diff --git a/sys/arch/sgi/hpc/hpcdma.c b/sys/arch/sgi/hpc/hpcdma.c new file mode 100644 index 00000000000..53dc86994ce --- /dev/null +++ b/sys/arch/sgi/hpc/hpcdma.c @@ -0,0 +1,208 @@ +/* $OpenBSD: hpcdma.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: hpcdma.c,v 1.21 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2001 Wayne Knowles + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Wayne Knowles + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Support for SCSI DMA provided by the HPC. + * + * Note: We use SCSI0 offsets, etc. here. Since the layout of SCSI0 + * and SCSI1 are the same, this is no problem. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/buf.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> + +#include <sgi/hpc/hpcreg.h> +#include <sgi/hpc/hpcvar.h> +#include <sgi/hpc/hpcdma.h> + +/* + * Allocate DMA Chain descriptor list + */ +void +hpcdma_init(struct hpc_attach_args *haa, struct hpc_dma_softc *sc, int ndesc) +{ + bus_dma_segment_t seg; + int rseg, allocsz; + + sc->sc_bst = haa->ha_st; + sc->sc_dmat = haa->ha_dmat; + sc->sc_ndesc = ndesc; + sc->sc_flags = 0; + + if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_dmaoff, + sc->hpc->scsi0_regs_size, &sc->sc_bsh) != 0) { + printf(": can't map DMA registers\n"); + return; + } + + /* Alloc 1 additional descriptor - needed for DMA bug fix */ + allocsz = sizeof(struct hpc_dma_desc) * (ndesc + 1); + + /* + * Allocate a block of memory for dma chaining pointers + */ + if (bus_dmamem_alloc(sc->sc_dmat, allocsz, 0, 0, &seg, 1, &rseg, + BUS_DMA_NOWAIT)) { + printf(": can't allocate sglist\n"); + return; + } + /* Map pages into kernel memory */ + if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, allocsz, + (caddr_t *)&sc->sc_desc_kva, BUS_DMA_NOWAIT)) { + printf(": can't map sglist\n"); + bus_dmamem_free(sc->sc_dmat, &seg, rseg); + return; + } + + if (bus_dmamap_create(sc->sc_dmat, allocsz, 1 /*seg*/, allocsz, 0, + BUS_DMA_WAITOK, &sc->sc_dmamap) != 0) { + printf(": failed to create dmamap\n"); + return; + } + + if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, + sc->sc_desc_kva, allocsz, NULL, BUS_DMA_NOWAIT)) { + printf(": can't load sglist\n"); + return; + } + + sc->sc_desc_pa = sc->sc_dmamap->dm_segs[0].ds_addr; +} + + +void +hpcdma_sglist_create(struct hpc_dma_softc *sc, bus_dmamap_t dmamap) +{ + struct hpc_dma_desc *hva; + bus_addr_t hpa; + bus_dma_segment_t *segp; + int i; + + KASSERT(dmamap->dm_nsegs <= sc->sc_ndesc); + + hva = sc->sc_desc_kva; + hpa = sc->sc_desc_pa; + segp = dmamap->dm_segs; + +#ifdef DMA_DEBUG + printf("DMA_SGLIST<"); +#endif + for (i = dmamap->dm_nsegs; i; i--) { +#ifdef DMA_DEBUG + printf("%p:%ld, ", (void *)segp->ds_addr, segp->ds_len); +#endif + hpa += sizeof(struct hpc_dma_desc); /* next chain desc */ + if (sc->hpc->revision == 3) { + hva->hpc3_hdd_bufptr = segp->ds_addr; + hva->hpc3_hdd_ctl = segp->ds_len; + hva->hdd_descptr = hpa; + } else /* HPC 1/1.5 */ { + /* + * there doesn't seem to be any good way of doing this + * via an abstraction layer + */ + hva->hpc1_hdd_bufptr = segp->ds_addr; + hva->hpc1_hdd_ctl = segp->ds_len; + hva->hdd_descptr = hpa; + } + ++hva; + ++segp; + } + + /* Work around HPC3 DMA bug */ + if (sc->hpc->revision == 3) { + hva->hpc3_hdd_bufptr = 0; + hva->hpc3_hdd_ctl = HPC3_HDD_CTL_EOCHAIN; + hva->hdd_descptr = 0; + } else { + hva--; + hva->hpc1_hdd_bufptr |= HPC1_HDD_CTL_EOCHAIN; + hva->hdd_descptr = 0; + } + +#ifdef DMA_DEBUG + printf(">\n"); +#endif + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + 0, sizeof(struct hpc_dma_desc) * (dmamap->dm_nsegs + 1), + BUS_DMASYNC_PREWRITE); + + /* Load DMA Descriptor list */ + bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ndbp, + sc->sc_desc_pa); +} + +void +hpcdma_cntl(struct hpc_dma_softc *sc, uint32_t mode) +{ + bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, mode); +} + +void +hpcdma_reset(struct hpc_dma_softc *sc) +{ + bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, + sc->hpc->scsi_dmactl_reset); + delay(100); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, 0); + delay(1000); +} + +void +hpcdma_flush(struct hpc_dma_softc *sc) +{ + uint32_t mode; + + mode = bus_space_read_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, + sc->hpc->scsi0_ctl, mode | sc->hpc->scsi_dmactl_flush); + + /* Wait for Active bit to drop */ + while (bus_space_read_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl) & + sc->hpc->scsi_dmactl_active) { + bus_space_barrier(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, 4, + BUS_SPACE_BARRIER_READ); + } +} diff --git a/sys/arch/sgi/hpc/hpcdma.h b/sys/arch/sgi/hpc/hpcdma.h new file mode 100644 index 00000000000..bca5fc5b171 --- /dev/null +++ b/sys/arch/sgi/hpc/hpcdma.h @@ -0,0 +1,63 @@ +/* $OpenBSD: hpcdma.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: hpcdma.h,v 1.11 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2001 Wayne Knowles + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Wayne Knowles + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 hpc_dma_softc { + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + bus_dma_tag_t sc_dmat; + + uint32_t sc_flags; +#define HPCDMA_READ 0x20 /* direction of transfer */ +#define HPCDMA_LOADED 0x40 /* bus_dmamap loaded */ +#define HPCDMA_ACTIVE 0x80 /* DMA engine is busy */ + uint32_t sc_dmacmd; + int sc_ndesc; + bus_dmamap_t sc_dmamap; + struct hpc_dma_desc *sc_desc_kva; /* Virtual address */ + bus_addr_t sc_desc_pa; /* DMA address */ + ssize_t sc_dlen; /* number of bytes transfered */ + struct hpc_values *hpc; /* constants for HPC1/3 */ +}; + + +void hpcdma_init(struct hpc_attach_args *, struct hpc_dma_softc *, int); +void hpcdma_sglist_create(struct hpc_dma_softc *, bus_dmamap_t); +void hpcdma_cntl(struct hpc_dma_softc *, uint32_t); +void hpcdma_reset(struct hpc_dma_softc *); +void hpcdma_flush(struct hpc_dma_softc *); diff --git a/sys/arch/sgi/hpc/hpcreg.h b/sys/arch/sgi/hpc/hpcreg.h new file mode 100644 index 00000000000..bce6a2d2245 --- /dev/null +++ b/sys/arch/sgi/hpc/hpcreg.h @@ -0,0 +1,450 @@ +/* $OpenBSD: hpcreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: hpcreg.h,v 1.20 2011/01/25 12:21:04 tsutsui Exp $ */ + +/* + * Copyright (c) 2001 Rafal K. Boni + * 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. 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. + */ + +/* + * HPC locations are identical across all HPC-supported + * platforms. + */ +#define HPC_BASE_ADDRESS_0 0x1fb80000 /* Primary onboard */ +#define HPC_BASE_ADDRESS_1 0x1fb00000 +#define HPC_BASE_ADDRESS_2 0x1f980000 +#define HPC_BASE_ADDRESS_3 0x1f900000 /* NB: Never supported in h/w */ + +/* + * HPC3 descriptor layout. + */ +struct hpc_dma_desc { + uint32_t hdd_bufptr; /* Physical address of buffer */ + uint32_t hdd_ctl; /* Control flags and byte count */ + uint32_t hdd_descptr; /* Physical address of next descr. */ + uint32_t hdd_pad; /* Pad out to quadword alignment */ +}; + +/* + * The hdd_bufptr and hdd_ctl fields are swapped between HPC1 and + * HPC3. These fields are referenced by macro for readability. + */ +#define hpc1_hdd_ctl hdd_bufptr +#define hpc1_hdd_bufptr hdd_ctl +#define hpc3_hdd_ctl hdd_ctl +#define hpc3_hdd_bufptr hdd_bufptr + +/* + * Control flags + */ +#define HPC3_HDD_CTL_EOCHAIN 0x80000000 /* End of descriptor chain */ +#define HPC3_HDD_CTL_EOPACKET 0x40000000 /* Ethernet: end of packet */ +#define HPC3_HDD_CTL_INTR 0x20000000 /* Interrupt when finished */ +#define HPC3_HDD_CTL_XMITDONE 0x00008000 /* Ethernet transmit done */ +#define HPC3_HDD_CTL_OWN 0x00004000 /* CPU owns this frame */ + +#define HPC3_HDD_CTL_BYTECNT(x) ((x) & 0x3fff) /* Byte count: for ethernet + * rcv channel also doubles as + * length of packet received + */ + +/* + * HPC memory map, as offsets from HPC base + * + * XXXrkb: should each section be used as a base and have the specific + * registers offset from there?? + * + * XXX: define register values as well as their offsets. + * + */ +#define HPC3_PBUS_DMAREGS 0x00000000 /* DMA registers for PBus */ +#define HPC3_PBUS_DMAREGS_SIZE 0x0000ffff /* channels 0 - 7 */ + +#define HPC3_PBUS_CH0_BP 0x00000000 /* Chan 0 Buffer Ptr */ +#define HPC3_PBUS_CH0_DP 0x00000004 /* Chan 0 Descriptor Ptr */ +#define HPC3_PBUS_CH0_CTL 0x00001000 /* Chan 0 Control Register */ + +#define HPC3_PBUS_CH1_BP 0x00002000 /* Chan 1 Buffer Ptr */ +#define HPC3_PBUS_CH1_DP 0x00002004 /* Chan 1 Descriptor Ptr */ +#define HPC3_PBUS_CH1_CTL 0x00003000 /* Chan 1 Control Register */ + +#define HPC3_PBUS_CH2_BP 0x00004000 /* Chan 2 Buffer Ptr */ +#define HPC3_PBUS_CH2_DP 0x00004004 /* Chan 2 Descriptor Ptr */ +#define HPC3_PBUS_CH2_CTL 0x00005000 /* Chan 2 Control Register */ + +#define HPC3_PBUS_CH3_BP 0x00006000 /* Chan 3 Buffer Ptr */ +#define HPC3_PBUS_CH3_DP 0x00006004 /* Chan 3 Descriptor Ptr */ +#define HPC3_PBUS_CH3_CTL 0x00007000 /* Chan 3 Control Register */ + +#define HPC3_PBUS_CH4_BP 0x00008000 /* Chan 4 Buffer Ptr */ +#define HPC3_PBUS_CH4_DP 0x00008004 /* Chan 4 Descriptor Ptr */ +#define HPC3_PBUS_CH4_CTL 0x00009000 /* Chan 4 Control Register */ + +#define HPC3_PBUS_CH5_BP 0x0000a000 /* Chan 5 Buffer Ptr */ +#define HPC3_PBUS_CH5_DP 0x0000a004 /* Chan 5 Descriptor Ptr */ +#define HPC3_PBUS_CH5_CTL 0x0000b000 /* Chan 5 Control Register */ + +#define HPC3_PBUS_CH6_BP 0x0000c000 /* Chan 6 Buffer Ptr */ +#define HPC3_PBUS_CH6_DP 0x0000c004 /* Chan 6 Descriptor Ptr */ +#define HPC3_PBUS_CH6_CTL 0x0000d000 /* Chan 6 Control Register */ + +#define HPC3_PBUS_CH7_BP 0x0000e000 /* Chan 7 Buffer Ptr */ +#define HPC3_PBUS_CH7_DP 0x0000e004 /* Chan 7 Descriptor Ptr */ +#define HPC3_PBUS_CH7_CTL 0x0000f000 /* Chan 7 Control Register */ + +#define HPC3_SCSI0_REGS 0x00010000 /* SCSI channel 0 registers */ +#define HPC3_SCSI0_REGS_SIZE 0x00001fff + +#define HPC3_SCSI0_CBP 0x00000000 /* Current buffer ptr */ +#define HPC3_SCSI0_NDBP 0x00000004 /* Next descriptor ptr */ + +#define HPC3_SCSI0_BC 0x00001000 /* DMA byte count & flags */ +#define HPC3_SCSI0_CTL 0x00001004 /* DMA control flags */ +#define HPC3_SCSI0_GIO 0x00001008 /* GIO DMA FIFO pointer */ +#define HPC3_SCSI0_DEV 0x0000100c /* Device DMA FIFO pointer */ +#define HPC3_SCSI0_DMACFG 0x00001010 /* DMA configuration */ +#define HPC3_SCSI0_PIOCFG 0x00001014 /* PIO configuration */ + +#define HPC3_SCSI1_REGS 0x00012000 /* SCSI channel 1 registers */ +#define HPC3_SCSI1_REGS_SIZE 0x00001fff + +#define HPC3_SCSI1_CBP 0x00000000 /* Current buffer ptr */ +#define HPC3_SCSI1_NDBP 0x00000004 /* Next descriptor ptr */ + +#define HPC3_SCSI1_BC 0x00001000 /* DMA byte count & flags */ +#define HPC3_SCSI1_CTL 0x00001004 /* DMA control flags */ +#define HPC3_SCSI1_GIO 0x00001008 /* GIO DMA FIFO pointer */ +#define HPC3_SCSI1_DEV 0x0000100c /* Device DMA FIFO pointer */ +#define HPC3_SCSI1_DMACFG 0x00001010 /* DMA configuration */ +#define HPC3_SCSI1_PIOCFG 0x00001014 /* PIO configuration */ + +/* HPC3_SCSIx_CTL "SCSI control register" flags: */ +#define HPC3_SCSI_DMACTL_IRQ 0x01 /* IRQ asserted, dma done or parity */ +#define HPC3_SCSI_DMACTL_ENDIAN 0x02 /* DMA endian mode, 0=BE, 1=LE */ +#define HPC3_SCSI_DMACTL_DIR 0x04 /* DMA direction, 0=dev->mem, 1=mem->dev */ +#define HPC3_SCSI_DMACTL_FLUSH 0x08 /* Flush DMA FIFO's */ +#define HPC3_SCSI_DMACTL_ACTIVE 0x10 /* DMA channel is active */ +#define HPC3_SCSI_DMACTL_AMASK 0x20 /* DMA active inhibits PIO */ +#define HPC3_SCSI_DMACTL_RESET 0x40 /* Reset dma channel and ext. controller */ +#define HPC3_SCSI_DMACTL_PERR 0x80 /* Parity error: interface to controller */ + +/* HPC_PBUS_CHx_CTL read: */ +#define HPC3_PBUS_DMACTL_IRQ 0x01 /* IRQ asserted, DMA done */ +#define HPC3_PBUS_DMACTL_ISACT 0x02 /* DMA channel is active */ + +/* HPC_PBUS_CHx_CTL write: */ +#define HPC3_PBUS_DMACTL_ENDIAN 0x02 /* DMA endianness, 0=BE 1=LE */ +#define HPC3_PBUS_DMACTL_RECEIVE 0x04 /* DMA direction, 1=dev->mem, 0=mem->dev*/ +#define HPC3_PBUS_DMACTL_FLUSH 0x08 /* Flush DMA FIFO */ +#define HPC3_PBUS_DMACTL_ACT 0x10 /* Activate DMA channel */ +#define HPC3_PBUS_DMACTL_ACT_LD 0x20 /* Load enable for ACT */ +#define HPC3_PBUS_DMACTL_RT 0x40 /* Enable real time GIO service for DMA */ +#define HPC3_PBUS_DMACTL_HIGHWATER_SHIFT 8 +#define HPC3_PBUS_DMACTL_FIFOBEG_SHIFT 16 +#define HPC3_PBUS_DMACTL_FIFOEND_SHIFT 24 + +#define HPC3_ENET_REGS 0x00014000 /* Ethernet registers */ +#define HPC3_ENET_REGS_SIZE 0x00003fff + +#define HPC3_ENETR_CBP 0x00000000 /* Recv: Current buffer ptr */ +#define HPC3_ENETR_NDBP 0x00000004 /* Recv: Next descriptor ptr */ + +#define HPC3_ENETR_BC 0x00001000 /* Recv: DMA byte cnt/flags */ +#define HPC3_ENETR_CTL 0x00001004 /* Recv: DMA control flags */ + +#define HPC3_ENETR_CTL_STAT_5_0 0x003f /* Seeq irq status: bits 0-5 */ +#define HPC3_ENETR_CTL_STAT_6 0x0040 /* Irq status: late_rxdc */ +#define HPC3_ENETR_CTL_STAT_7 0x0080 /* Irq status: old/new bit */ +#define HPC3_ENETR_CTL_LENDIAN 0x0100 /* DMA channel endian mode */ +#define HPC3_ENETR_CTL_ACTIVE 0x0200 /* DMA channel active? */ +#define HPC3_ENETR_CTL_ACTIVE_MSK 0x0400 /* DMA channel active? */ +#define HPC3_ENETR_CTL_RBO 0x0800 /* Recv buffer overflow */ + +#define HPC3_ENETR_GIO 0x00001008 /* Recv: GIO DMA FIFO ptr */ +#define HPC3_ENETR_DEV 0x0000100c /* Recv: Device DMA FIFO ptr */ +#define HPC3_ENETR_RESET 0x00001014 /* Recv: Ethernet chip reset */ + +#define HPC3_ENETR_RESET_CH 0x0001 /* Reset controller & chan */ +#define HPC3_ENETR_RESET_CLRINT 0x0002 /* Clear channel interrupt */ +#define HPC3_ENETR_RESET_LOOPBK 0x0004 /* External loopback enable */ +#define HPC3_ENETR_RESET_CLRRBO 0x0008 /* Clear RBO condition (??) */ + +#define HPC3_ENETR_DMACFG 0x00001018 /* Recv: DMA configuration */ + +#define HPC3_ENETR_DMACFG_D1(_x) (((_x) << 0) & 0x000f) /* D1 gio_clk cycles */ +#define HPC3_ENETR_DMACFG_D2(_x) (((_x) << 4) & 0x00f0) /* D2 gio_clk cycles */ +#define HPC3_ENETR_DMACFG_D3(_x) (((_x) << 8) & 0x0f00) /* D3 gio_clk cycles */ +#define HPC3_ENETR_DMACFG_WRCTL 0x01000 /* Enable IPG write */ + +/* + * The following three bits work around bugs in the Seeq 8003; if you + * don't set them, the Seeq gets wonky pretty often. + */ +#define HPC3_ENETR_DMACFG_FIX_RXDC 0x02000 /* Clear EOP bits on RXDC */ +#define HPC3_ENETR_DMACFG_FIX_EOP 0x04000 /* Enable rxintr timeout */ +#define HPC3_ENETR_DMACFG_FIX_INTR 0x08000 /* Enable EOP timeout */ +#define HPC3_ENETR_DMACFG_TIMEOUT 0x30000 /* Timeout value for above two*/ + +#define HPC3_ENETR_PIOCFG 0x0000101c /* Recv: PIO configuration */ + +#define HPC3_ENETR_PIOCFG_P1(_x) (((_x) << 0) & 0x000f) /* P1 gio_clk cycles */ +#define HPC3_ENETR_PIOCFG_P2(_x) (((_x) << 4) & 0x00f0) /* P2 gio_clk cycles */ +#define HPC3_ENETR_PIOCFG_P3(_x) (((_x) << 8) & 0x0f00) /* P3 gio_clk cycles */ + +#define HPC3_ENETX_CBP 0x00002000 /* Xmit: Current buffer ptr */ +#define HPC3_ENETX_NDBP 0x00002004 /* Xmit: Next descriptor ptr */ + +#define HPC3_ENETX_BC 0x00003000 /* Xmit: DMA byte cnt/flags */ +#define HPC3_ENETX_CTL 0x00003004 /* Xmit: DMA control flags */ + +#define HPC3_ENETX_CTL_STAT_5_0 0x003f /* Seeq irq status: bits 0-5 */ +#define HPC3_ENETX_CTL_STAT_6 0x0040 /* Irq status: late_rxdc */ +#define HPC3_ENETX_CTL_STAT_7 0x0080 /* Irq status: old/new bit */ +#define HPC3_ENETX_CTL_LENDIAN 0x0100 /* DMA channel endian mode */ +#define HPC3_ENETX_CTL_ACTIVE 0x0200 /* DMA channel active? */ +#define HPC3_ENETX_CTL_ACTIVE_MSK 0x0400 /* DMA channel active? */ +#define HPC3_ENETX_CTL_RBO 0x0800 /* Recv buffer overflow */ + +#define HPC3_ENETX_GIO 0x00003008 /* Xmit: GIO DMA FIFO ptr */ +#define HPC3_ENETX_DEV 0x0000300c /* Xmit: Device DMA FIFO ptr */ + +#define HPC3_PBUS_FIFO 0x00020000 /* PBus DMA FIFO */ +#define HPC3_PBUS_FIFO_SIZE 0x00007fff /* PBus DMA FIFO size */ + +#define HPC3_SCSI0_FIFO 0x00028000 /* SCSI0 DMA FIFO */ +#define HPC3_SCSI0_FIFO_SIZE 0x00001fff /* SCSI0 DMA FIFO size */ + +#define HPC3_SCSI1_FIFO 0x0002a000 /* SCSI1 DMA FIFO */ +#define HPC3_SCSI1_FIFO_SIZE 0x00001fff /* SCSI1 DMA FIFO size */ + +#define HPC3_ENETR_FIFO 0x0002c000 /* Ether recv DMA FIFO */ +#define HPC3_ENETR_FIFO_SIZE 0x00001fff /* Ether recv DMA FIFO size */ + +#define HPC3_ENETX_FIFO 0x0002e000 /* Ether xmit DMA FIFO */ +#define HPC3_ENETX_FIFO_SIZE 0x00001fff /* Ether xmit DMA FIFO size */ + +/* + * HPCBUG: The interrupt status is split amongst two registers, and they're + * not even consecutive in the HPC address space. This is documented as a + * bug by SGI. + */ +#define HPC3_INTRSTAT_40 0x00030000 /* Interrupt stat, bits 4:0 */ +#define HPC3_INTRSTAT_95 0x0003000c /* Interrupt stat, bits 9:5 */ + +#define HPC3_GIO_MISC 0x00030004 /* GIO64 misc register */ + +#define HPC3_EEPROM_DATA 0x0003000b /* Serial EEPROM data reg. */ + /* (byte) */ + +#define HPC3_GIO_BUSERR 0x00030010 /* GIO64 bus error intr stat */ + +#define HPC3_SCSI0_DEVREGS 0x00044000 /* SCSI channel 0 chip regs */ +#define HPC3_SCSI1_DEVREGS 0x0004c000 /* SCSI channel 1 chip regs */ + +#define HPC3_ENET_DEVREGS 0x00054000 /* Ethernet chip registers */ +#define HPC3_ENET_DEVREGS_SIZE 0x000004ff /* Size of chip registers */ + +#define HPC3_PBUS_DEVREGS 0x00054000 /* PBus PIO chip registers */ +#define HPC3_PBUS_DEVREGS_SIZE 0x000003ff /* PBus PIO chip registers */ + +#define HPC3_PBUS_CH0_DEVREGS 0x00058000 /* PBus ch. 0 chip registers */ +#define HPC3_PBUS_CH0_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH1_DEVREGS 0x00058400 /* PBus ch. 1 chip registers */ +#define HPC3_PBUS_CH1_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH2_DEVREGS 0x00058800 /* PBus ch. 2 chip registers */ +#define HPC3_PBUS_CH2_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH3_DEVREGS 0x00058c00 /* PBus ch. 3 chip registers */ +#define HPC3_PBUS_CH3_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH4_DEVREGS 0x00059000 /* PBus ch. 4 chip registers */ +#define HPC3_PBUS_CH4_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH5_DEVREGS 0x00059400 /* PBus ch. 5 chip registers */ +#define HPC3_PBUS_CH5_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH6_DEVREGS 0x00059800 /* PBus ch. 6 chip registers */ +#define HPC3_PBUS_CH6_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH7_DEVREGS 0x00059c00 /* PBus ch. 7 chip registers */ +#define HPC3_PBUS_CH7_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH8_DEVREGS 0x0005a000 /* PBus ch. 8 chip registers */ +#define HPC3_PBUS_CH8_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH9_DEVREGS 0x0005a400 /* PBus ch. 9 chip registers */ +#define HPC3_PBUS_CH9_DEVREGS_SIZE 0x03ff + +#define HPC3_PBUS_CH8_DEVREGS_2 0x0005a800 /* PBus ch. 8 chip registers */ +#define HPC3_PBUS_CH8_DEVREGS_2_SIZE 0x03ff + +#define HPC3_PBUS_CH9_DEVREGS_2 0x0005ac00 /* PBus ch. 9 chip registers */ +#define HPC3_PBUS_CH9_DEVREGS_2_SIZE 0x03ff + +#define HPC3_PBUS_CH8_DEVREGS_3 0x0005b000 /* PBus ch. 8 chip registers */ +#define HPC3_PBUS_CH8_DEVREGS_3_SIZE 0x03ff + +#define HPC3_PBUS_CH9_DEVREGS_3 0x0005b400 /* PBus ch. 9 chip registers */ +#define HPC3_PBUS_CH9_DEVREGS_3_SIZE 0x03ff + +#define HPC3_PBUS_CH8_DEVREGS_4 0x0005b800 /* PBus ch. 8 chip registers */ +#define HPC3_PBUS_CH8_DEVREGS_4_SIZE 0x03ff + +#define HPC3_PBUS_CH9_DEVREGS_4 0x0005bc00 /* PBus ch. 9 chip registers */ +#define HPC3_PBUS_CH9_DEVREGS_4_SIZE 0x03ff + +#define HPC3_PBUS_CFGDMA_REGS 0x0005c000 /* PBus DMA config registers */ +#define HPC3_PBUS_CFGDMA_REGS_SIZE 0x0fff + +#define HPC3_PBUS_CH0_CFGDMA 0x0005c000 /* PBus Ch. 0 DMA config */ +#define HPC3_PBUS_CH0_CFGDMA_SIZE 0x01ff + +#define HPC3_PBUS_CH1_CFGDMA 0x0005c200 /* PBus Ch. 1 DMA config */ +#define HPC3_PBUS_CH1_CFGDMA_SIZE 0x01ff + +#define HPC3_PBUS_CH2_CFGDMA 0x0005c400 /* PBus Ch. 2 DMA config */ +#define HPC3_PBUS_CH2_CFGDMA_SIZE 0x01ff + +#define HPC3_PBUS_CH3_CFGDMA 0x0005c600 /* PBus Ch. 3 DMA config */ +#define HPC3_PBUS_CH3_CFGDMA_SIZE 0x01ff + +#define HPC3_PBUS_CH4_CFGDMA 0x0005c800 /* PBus Ch. 4 DMA config */ +#define HPC3_PBUS_CH4_CFGDMA_SIZE 0x01ff + +#define HPC3_PBUS_CH5_CFGDMA 0x0005ca00 /* PBus Ch. 5 DMA config */ +#define HPC3_PBUS_CH5_CFGDMA_SIZE 0x01ff + +#define HPC3_PBUS_CH6_CFGDMA 0x0005cc00 /* PBus Ch. 6 DMA config */ +#define HPC3_PBUS_CH6_CFGDMA_SIZE 0x01ff + +#define HPC3_PBUS_CH7_CFGDMA 0x0005ce00 /* PBus Ch. 7 DMA config */ +#define HPC3_PBUS_CH7_CFGDMA_SIZE 0x01ff + +#define HPC3_PBUS_CFGPIO_REGS 0x0005d000 /* PBus PIO config registers */ +#define HPC3_PBUS_CFGPIO_REGS_SIZE 0x0fff + +#define HPC3_PBUS_CH0_CFGPIO 0x0005d000 /* PBus Ch. 0 PIO config */ +#define HPC3_PBUS_CH1_CFGPIO 0x0005d100 /* PBus Ch. 1 PIO config */ +#define HPC3_PBUS_CH2_CFGPIO 0x0005d200 /* PBus Ch. 2 PIO config */ +#define HPC3_PBUS_CH3_CFGPIO 0x0005d300 /* PBus Ch. 3 PIO config */ +#define HPC3_PBUS_CH4_CFGPIO 0x0005d400 /* PBus Ch. 4 PIO config */ +#define HPC3_PBUS_CH5_CFGPIO 0x0005d500 /* PBus Ch. 5 PIO config */ +#define HPC3_PBUS_CH6_CFGPIO 0x0005d600 /* PBus Ch. 6 PIO config */ +#define HPC3_PBUS_CH7_CFGPIO 0x0005d700 /* PBus Ch. 7 PIO config */ +#define HPC3_PBUS_CH8_CFGPIO 0x0005d800 /* PBus Ch. 8 PIO config */ +#define HPC3_PBUS_CH9_CFGPIO 0x0005d900 /* PBus Ch. 9 PIO config */ +#define HPC3_PBUS_CH8_CFGPIO_2 0x0005da00 /* PBus Ch. 8 PIO config */ +#define HPC3_PBUS_CH9_CFGPIO_2 0x0005db00 /* PBus Ch. 9 PIO config */ +#define HPC3_PBUS_CH8_CFGPIO_3 0x0005dc00 /* PBus Ch. 8 PIO config */ +#define HPC3_PBUS_CH9_CFGPIO_3 0x0005dd00 /* PBus Ch. 9 PIO config */ +#define HPC3_PBUS_CH8_CFGPIO_4 0x0005de00 /* PBus Ch. 8 PIO config */ +#define HPC3_PBUS_CH9_CFGPIO_4 0x0005df00 /* PBus Ch. 9 PIO config */ + +#define HPC3_PBUS_PROM_WE 0x0005e000 /* PBus boot-prom write + * enable register + */ + +#define HPC3_PBUS_PROM_SWAP 0x0005e800 /* PBus boot-prom chip-select + * swap register + */ + +#define HPC3_PBUS_GEN_OUT 0x0005f000 /* PBus general-purpose output + * register + */ + +#define HPC3_PBUS_BBRAM 0x00060000 /* PBus battery-backed RAM + * external registers + */ + +/* HPC1/HPC1.5 differs from HPC3 in several details. */ + +#define HPC1_HDD_CTL_EOCHAIN 0x80000000 /* End of descriptor chain */ +#define HPC1_HDD_CTL_EOPACKET 0x80000000 /* Ethernet: end of packet */ +#define HPC1_HDD_CTL_INTR 0x00008000 /* Interrupt when finished */ +#define HPC1_HDD_CTL_OWN 0x40000000 /* CPU owns this frame */ +#define HPC1_HDD_CTL_BYTECNT(x) ((x) & 0x1fff) /* Byte count: for ethernet */ +#define HPC1_BIGENDIAN 0x000000c0 /* Endianness:5 revision:2 */ +#define HPC1_REVSHIFT 0x00000006 /* Revision rshft */ +#define HPC1_REVMASK 0x00000003 /* Revision mask */ +#define HPC1_REV15 0x00000001 /* HPC Revision 1.5 */ +#define HPC1_SCSI0_REGS 0x00000088 +#define HPC1_SCSI0_REGS_SIZE 0x00000018 +#define HPC1_SCSI0_CBP 0x00000004 /* Current buffer ptr */ +#define HPC1_SCSI0_NDBP 0x00000008 /* Next descriptor ptr */ +#define HPC1_SCSI0_BC 0x00000000 /* DMA byte count & flags */ +#define HPC1_SCSI0_CTL 0x0000000c /* DMA control flags */ +#define HPC1_SCSI0_DEV 0x00000014 /* Device DMA FIFO pointer */ +#define HPC1_SCSI0_DMACFG 0x00000010 /* DMA configuration */ +#define HPC1_SCSI0_GIO 0x00001008 /* GIO DMA FIFO pointer */ +#define HPC1_SCSI0_PIOCFG 0x00001014 /* PIO configuration */ +#define HPC1_SCSI_DMACTL_RESET 0x01 /* Reset dma channel and ext. controller */ +#define HPC1_SCSI_DMACTL_FLUSH 0x02 /* Flush DMA FIFO's */ +#define HPC1_SCSI_DMACTL_DIR 0x10 /* DMA direction: 1=dev->mem, 0=mem->dev */ +#define HPC1_SCSI_DMACTL_ACTIVE 0x80 /* DMA channel is active */ +#define HPC1_ENET_REGS 0x00000000 /* Ethernet registers */ +#define HPC1_ENET_REGS_SIZE 0x00000100 +#define HPC1_ENET_INTDELAY 0x0000002c /* Interrupt Delay Count */ +#define HPC1_ENET_INTDELAY_OFF 0x01000000 /* Disable Interrupt Delay */ +#define HPC1_ENETR_CBP 0x00000054 /* Recv: Current buffer ptr */ +#define HPC1_ENETR_NDBP 0x00000050 /* Recv: Next descriptor ptr */ +#define HPC1_ENETR_BC 0x00000048 /* Recv: DMA byte cnt/flags */ +#define HPC1_ENETR_CTL 0x00000038 /* Recv: DMA control flags */ +#define HPC1_ENETR_CTL_ACTIVE 0x00004000 /* DMA channel active? */ +#define HPC1_ENETR_RESET 0x0000003c /* Recv: Ethernet chip reset */ +#define HPC1_ENETR_RESET_CH 0x0001 /* Reset controller & chan */ +#define HPC1_ENETR_RESET_CLRINT 0x0002 /* Clear channel interrupt */ +#define HPC1_ENETR_RESET_LOOPBK 0x0004 /* External loopback enable */ +#define HPC1_ENETR_RESET_CLRRBO 0x0008 /* Clear RBO condition (??) */ +#define HPC1_ENETX_CBP 0x00000020 /* Xmit: Current buffer ptr */ +#define HPC1_ENETX_NDBP 0x00000010 /* Xmit: Next descriptor ptr */ +#define HPC1_ENETX_CFXBP 0x00000024 /* Xmit: Current first buf */ +#define HPC1_ENETX_PFXBP 0x00000028 /* Xmit: Prev. first buf */ +#define HPC1_ENETX_BC 0x00000014 /* Xmit: DMA byte cnt/flags */ +#define HPC1_ENETX_CTL 0x00000034 /* Xmit: DMA control flags */ +#define HPC1_ENETX_CTL_ACTIVE 0x00400000 +#define HPC1_ENETR_FIFO 0x0002c000 /* Ether recv DMA FIFO */ +#define HPC1_ENETR_FIFO_SIZE 0x00001fff /* Ether recv DMA FIFO size */ +#define HPC1_ENETX_FIFO 0x0002e000 /* Ether xmit DMA FIFO */ +#define HPC1_ENETX_FIFO_SIZE 0x00001fff /* Ether xmit DMA FIFO size */ +#define HPC1_SCSI0_DEVREGS 0x0000011f /* (actually 122) */ +#define HPC1_ENET_DEVREGS 0x00000100 /* Ethernet chip registers */ +#define HPC1_ENET_DEVREGS_SIZE 0x00000020 /* Size of chip registers */ +#define HPC1_PBUS_BBRAM 0x00000e00 /* PBus battery-backed RAM */ +#define HPC1_LPT_REGS 0x000000a8 /* LPT HPC Registers */ +#define HPC1_LPT_REGS_SIZE 0x00000018 +#define HPC1_LPT_BC 0x00000000 /* Byte Count */ +#define HPC1_LPT_CBP 0x00000004 /* Current Buffer Ptr */ +#define HPC1_LPT_NDBP 0x00000008 /* Next Buffer Ptr */ +#define HPC1_LPT_CTL 0x0000000c /* DMA Control Flags */ +#define HPC1_LPT_DEV 0x00000010 /* DMA Fifo Ptr */ +#define HPC1_LPT_DMACFG 0x00000014 /* DMA Configuration */ +#define HPC1_LPT_DEVREGS 0x00000132 /* Ext. Parallel Registers */ +#define HPC1_LPT_DEVREGS_SIZE 0x00000001 /* Size of External Registers */ + +/* AUX regs on the primary HPC */ +#define HPC1_AUX_REGS 0x000001bf /* EEPROM/LED Control (byte) */ +#define HPC1_AUX_CONSLED 0x01 /* Console LED */ diff --git a/sys/arch/sgi/hpc/hpcvar.h b/sys/arch/sgi/hpc/hpcvar.h new file mode 100644 index 00000000000..c79f284ff87 --- /dev/null +++ b/sys/arch/sgi/hpc/hpcvar.h @@ -0,0 +1,109 @@ +/* $OpenBSD: hpcvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: hpcvar.h,v 1.12 2011/01/25 12:21:04 tsutsui Exp $ */ + +/* + * Copyright (c) 2001 Rafal K. Boni + * 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. 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 HPCDEV_IP20 (1U << 1) /* Indigo R4k */ +#define HPCDEV_IP22 (1U << 2) /* Indigo2 */ +#define HPCDEV_IP24 (1U << 3) /* Indy */ + +/* HPC 1.5/3 differ a bit, thus we need an abstraction layer */ + +struct hpc_values { + int revision; + uint32_t scsi0_regs; + uint32_t scsi0_regs_size; + uint32_t scsi0_cbp; + uint32_t scsi0_ndbp; + uint32_t scsi0_bc; + uint32_t scsi0_ctl; + uint32_t scsi0_gio; + uint32_t scsi0_dev; + uint32_t scsi0_dmacfg; + uint32_t scsi0_piocfg; + uint32_t scsi1_regs; + uint32_t scsi1_regs_size; + uint32_t scsi1_cbp; + uint32_t scsi1_ndbp; + uint32_t scsi1_bc; + uint32_t scsi1_ctl; + uint32_t scsi1_gio; + uint32_t scsi1_dev; + uint32_t scsi1_dmacfg; + uint32_t scsi1_piocfg; + uint32_t enet_regs; + uint32_t enet_regs_size; + uint32_t enet_intdelay; + uint32_t enet_intdelayval; + uint32_t enetr_cbp; + uint32_t enetr_ndbp; + uint32_t enetr_bc; + uint32_t enetr_ctl; + uint32_t enetr_ctl_active; + uint32_t enetr_reset; + uint32_t enetr_dmacfg; + uint32_t enetr_piocfg; + uint32_t enetx_cbp; + uint32_t enetx_ndbp; + uint32_t enetx_bc; + uint32_t enetx_ctl; + uint32_t enetx_ctl_active; + uint32_t enetx_dev; + uint32_t enetr_fifo; + uint32_t enetr_fifo_size; + uint32_t enetx_fifo; + uint32_t enetx_fifo_size; + uint32_t enet_dma_boundary; + uint32_t enet_devregs; + uint32_t enet_devregs_size; + uint32_t pbus_fifo; + uint32_t pbus_fifo_size; + uint32_t pbus_bbram; + uint32_t scsi_dma_segs; + uint32_t scsi_dma_segs_size; + uint32_t scsi_dma_datain_cmd; + uint32_t scsi_dma_dataout_cmd; + uint32_t scsi_dmactl_flush; + uint32_t scsi_dmactl_active; + uint32_t scsi_dmactl_reset; +}; + +struct hpc_attach_args { + const char *ha_name; /* name of device */ + bus_addr_t ha_devoff; /* offset of device */ + bus_addr_t ha_dmaoff; /* offset of DMA regs */ + int ha_irq; /* interrupt line */ + + bus_space_tag_t ha_st; /* HPC space tag */ + bus_space_handle_t ha_sh; /* HPC space handle XXX */ + bus_dma_tag_t ha_dmat; /* HPC DMA tag */ + + struct hpc_values *hpc_regs; /* HPC register definitions */ + + uint8_t hpc_eeprom[256];/* HPC eeprom contents */ +}; diff --git a/sys/arch/sgi/hpc/if_sq.c b/sys/arch/sgi/hpc/if_sq.c new file mode 100644 index 00000000000..44521062c38 --- /dev/null +++ b/sys/arch/sgi/hpc/if_sq.c @@ -0,0 +1,1348 @@ +/* $OpenBSD: if_sq.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: if_sq.c,v 1.42 2011/07/01 18:53:47 dyoung Exp $ */ + +/* + * Copyright (c) 2001 Rafal K. Boni + * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Portions of this code are derived from software contributed to The + * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + * + * 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. 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. + */ + +#include "bpfilter.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/timeout.h> +#include <sys/mbuf.h> +#include <sys/pool.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/syslog.h> + +#include <uvm/uvm_extern.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#if NBPFILTER > 0 +#include <net/bpf.h> +#endif + +#include <netinet/if_ether.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cpu.h> /* guarded_read_4 */ +#include <machine/intr.h> +#include <mips64/arcbios.h> /* bios_enaddr */ +#include <sgi/localbus/intvar.h> + +#include <dev/ic/seeq8003reg.h> + +#include <sgi/hpc/hpcvar.h> +#include <sgi/hpc/hpcreg.h> +#include <sgi/hpc/if_sqvar.h> + +/* + * Short TODO list: + * (1) Do counters for bad-RX packets. + * (2) Allow multi-segment transmits, instead of copying to a single, + * contiguous mbuf. + * (3) Verify sq_stop() turns off enough stuff; I was still getting + * seeq interrupts after sq_stop(). + * (4) Implement EDLC modes: especially packet auto-pad and simplex + * mode. + * (5) Should the driver filter out its own transmissions in non-EDLC + * mode? + * (6) Multicast support -- multicast filter, address management, ... + * (7) Deal with RB0 (recv buffer overflow) on reception. Will need + * to figure out if RB0 is read-only as stated in one spot in the + * HPC spec or read-write (ie, is the 'write a one to clear it') + * the correct thing? + */ + +#if defined(SQ_DEBUG) +int sq_debug = 0; +#define SQ_DPRINTF(x) do { if (sq_debug) printf x; } while (0) +#else +#define SQ_DPRINTF(x) do { } while (0) +#endif + +int sq_match(struct device *, void *, void *); +void sq_attach(struct device *, struct device *, void *); +int sq_init(struct ifnet *); +void sq_start(struct ifnet *); +void sq_stop(struct ifnet *); +void sq_watchdog(struct ifnet *); +int sq_ioctl(struct ifnet *, u_long, caddr_t); + +void sq_set_filter(struct sq_softc *); +int sq_intr(void *); +void sq_rxintr(struct sq_softc *); +void sq_txintr(struct sq_softc *); +void sq_txring_hpc1(struct sq_softc *); +void sq_txring_hpc3(struct sq_softc *); +void sq_reset(struct sq_softc *); +int sq_add_rxbuf(struct sq_softc *, int); +#ifdef SQ_DEBUG +void sq_trace_dump(struct sq_softc *); +#endif + +const struct cfattach sq_ca = { + sizeof(struct sq_softc), sq_match, sq_attach +}; + +struct cfdriver sq_cd = { + NULL, "sq", DV_IFNET +}; + +/* XXX these values should be moved to <net/if_ether.h> ? */ +#define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN) + +#define sq_seeq_read(sc, off) \ + bus_space_read_1(sc->sc_regt, sc->sc_regh, ((off) << 2) | 3) +#define sq_seeq_write(sc, off, val) \ + bus_space_write_1(sc->sc_regt, sc->sc_regh, ((off) << 2) | 3, val) + +#define sq_hpc_read(sc, off) \ + bus_space_read_4(sc->sc_hpct, sc->sc_hpch, off) +#define sq_hpc_write(sc, off, val) \ + bus_space_write_4(sc->sc_hpct, sc->sc_hpch, off, val) + +/* MAC address offset for non-onboard implementations */ +#define SQ_HPC_EEPROM_ENADDR 250 + +#define SGI_OUI_0 0x08 +#define SGI_OUI_1 0x00 +#define SGI_OUI_2 0x69 + +int +sq_match(struct device *parent, void *vcf, void *aux) +{ + struct hpc_attach_args *ha = aux; + struct cfdata *cf = vcf; + vaddr_t reset, txstat; + uint32_t dummy; + + if (strcmp(ha->ha_name, cf->cf_driver->cd_name) != 0) + return 0; + + reset = PHYS_TO_XKPHYS(ha->ha_sh + ha->ha_dmaoff + + ha->hpc_regs->enetr_reset, CCA_NC); + txstat = PHYS_TO_XKPHYS(ha->ha_sh + ha->ha_devoff + (SEEQ_TXSTAT << 2), + CCA_NC); + + if (guarded_read_4(reset, &dummy) != 0) + return 0; + + *(volatile uint32_t *)reset = 0x1; + delay(20); + *(volatile uint32_t *)reset = 0x0; + + if (guarded_read_4(txstat, &dummy) != 0) + return 0; + + if ((*(volatile uint32_t *)txstat & 0xff) != TXSTAT_OLDNEW) + return 0; + + return 1; +} + +void +sq_attach(struct device *parent, struct device *self, void *aux) +{ + struct sq_softc *sc = (struct sq_softc *)self; + struct hpc_attach_args *haa = aux; + struct ifnet *ifp = &sc->sc_ac.ac_if; + int i, rc; + + sc->sc_hpct = haa->ha_st; + sc->hpc_regs = haa->hpc_regs; /* HPC register definitions */ + + if ((rc = bus_space_subregion(haa->ha_st, haa->ha_sh, + haa->ha_dmaoff, sc->hpc_regs->enet_regs_size, + &sc->sc_hpch)) != 0) { + printf(": can't HPC DMA registers, error = %d\n", rc); + goto fail_0; + } + + sc->sc_regt = haa->ha_st; + if ((rc = bus_space_subregion(haa->ha_st, haa->ha_sh, + haa->ha_devoff, sc->hpc_regs->enet_devregs_size, + &sc->sc_regh)) != 0) { + printf(": can't map Seeq registers, error = %d\n", rc); + goto fail_0; + } + + sc->sc_dmat = haa->ha_dmat; + + if ((rc = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct sq_control), + sc->hpc_regs->enet_dma_boundary, + sc->hpc_regs->enet_dma_boundary, &sc->sc_cdseg, 1, + &sc->sc_ncdseg, BUS_DMA_NOWAIT)) != 0) { + printf(": unable to allocate control data, error = %d\n", rc); + goto fail_0; + } + + if ((rc = bus_dmamem_map(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg, + sizeof(struct sq_control), (caddr_t *)&sc->sc_control, + BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { + printf(": unable to map control data, error = %d\n", rc); + goto fail_1; + } + + if ((rc = bus_dmamap_create(sc->sc_dmat, + sizeof(struct sq_control), 1, sizeof(struct sq_control), + sc->hpc_regs->enet_dma_boundary, BUS_DMA_NOWAIT, + &sc->sc_cdmap)) != 0) { + printf(": unable to create DMA map for control data, error " + "= %d\n", rc); + goto fail_2; + } + + if ((rc = bus_dmamap_load(sc->sc_dmat, sc->sc_cdmap, + sc->sc_control, sizeof(struct sq_control), NULL, + BUS_DMA_NOWAIT)) != 0) { + printf(": unable to load DMA map for control data, error " + "= %d\n", rc); + goto fail_3; + } + + memset(sc->sc_control, 0, sizeof(struct sq_control)); + + /* Create transmit buffer DMA maps */ + for (i = 0; i < SQ_NTXDESC; i++) { + if ((rc = bus_dmamap_create(sc->sc_dmat, + MCLBYTES, 1, MCLBYTES, 0, + BUS_DMA_NOWAIT, &sc->sc_txmap[i])) != 0) { + printf(": unable to create tx DMA map %d, error = %d\n", + i, rc); + goto fail_4; + } + } + + /* Create receive buffer DMA maps */ + for (i = 0; i < SQ_NRXDESC; i++) { + if ((rc = bus_dmamap_create(sc->sc_dmat, + MCLBYTES, 1, MCLBYTES, 0, + BUS_DMA_NOWAIT, &sc->sc_rxmap[i])) != 0) { + printf(": unable to create rx DMA map %d, error = %d\n", + i, rc); + goto fail_5; + } + } + + /* Pre-allocate the receive buffers. */ + for (i = 0; i < SQ_NRXDESC; i++) { + if ((rc = sq_add_rxbuf(sc, i)) != 0) { + printf(": unable to allocate or map rx buffer %d\n," + " error = %d\n", i, rc); + goto fail_6; + } + } + + bcopy(&haa->hpc_eeprom[SQ_HPC_EEPROM_ENADDR], sc->sc_ac.ac_enaddr, + ETHER_ADDR_LEN); + + /* + * If our mac address is bogus, obtain it from ARCBIOS. This will + * be true of the onboard HPC3 on IP22, since there is no eeprom, + * but rather the DS1386 RTC's battery-backed ram is used. + */ + if (sc->sc_ac.ac_enaddr[0] != SGI_OUI_0 || + sc->sc_ac.ac_enaddr[1] != SGI_OUI_1 || + sc->sc_ac.ac_enaddr[2] != SGI_OUI_2) + enaddr_aton(bios_enaddr, sc->sc_ac.ac_enaddr); + + if ((int2_intr_establish(haa->ha_irq, IPL_NET, sq_intr, sc, + self->dv_xname)) == NULL) { + printf(": unable to establish interrupt!\n"); + goto fail_6; + } + + /* Reset the chip to a known state. */ + sq_reset(sc); + + /* + * Determine if we're an 8003 or 80c03 by setting the first + * MAC address register to non-zero, and then reading it back. + * If it's zero, we have an 80c03, because we will have read + * the TxCollLSB register. + */ + sq_seeq_write(sc, SEEQ_TXCOLLS0, 0xa5); + if (sq_seeq_read(sc, SEEQ_TXCOLLS0) == 0) + sc->sc_type = SQ_TYPE_80C03; + else + sc->sc_type = SQ_TYPE_8003; + sq_seeq_write(sc, SEEQ_TXCOLLS0, 0x00); + + printf(": Seeq %s, address %s\n", + sc->sc_type == SQ_TYPE_80C03 ? "80c03" : "8003", + ether_sprintf(sc->sc_ac.ac_enaddr)); + + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; + ifp->if_mtu = ETHERMTU; + ifp->if_start = sq_start; + ifp->if_ioctl = sq_ioctl; + ifp->if_watchdog = sq_watchdog; + ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_MULTICAST; + IFQ_SET_READY(&ifp->if_snd); + + if_attach(ifp); + IFQ_SET_MAXLEN(&ifp->if_snd, SQ_NTXDESC - 1); + ether_ifattach(ifp); + + /* Done! */ + return; + + /* + * Free any resources we've allocated during the failed attach + * attempt. Do this in reverse order and fall through. + */ + fail_6: + for (i = 0; i < SQ_NRXDESC; i++) { + if (sc->sc_rxmbuf[i] != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[i]); + m_freem(sc->sc_rxmbuf[i]); + } + } + fail_5: + for (i = 0; i < SQ_NRXDESC; i++) { + if (sc->sc_rxmap[i] != NULL) + bus_dmamap_destroy(sc->sc_dmat, sc->sc_rxmap[i]); + } + fail_4: + for (i = 0; i < SQ_NTXDESC; i++) { + if (sc->sc_txmap[i] != NULL) + bus_dmamap_destroy(sc->sc_dmat, sc->sc_txmap[i]); + } + bus_dmamap_unload(sc->sc_dmat, sc->sc_cdmap); + fail_3: + bus_dmamap_destroy(sc->sc_dmat, sc->sc_cdmap); + fail_2: + bus_dmamem_unmap(sc->sc_dmat, + (void *)sc->sc_control, sizeof(struct sq_control)); + fail_1: + bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg); + fail_0: + return; +} + +/* Set up data to get the interface up and running. */ +int +sq_init(struct ifnet *ifp) +{ + struct sq_softc *sc = ifp->if_softc; + int i; + + /* Cancel any in-progress I/O */ + sq_stop(ifp); + + sc->sc_nextrx = 0; + + sc->sc_nfreetx = SQ_NTXDESC; + sc->sc_nexttx = sc->sc_prevtx = 0; + + SQ_TRACE(SQ_RESET, sc, 0, 0); + + /* Set into 8003 mode, bank 0 to program ethernet address */ + sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_BANK0); + + /* Now write the address */ + for (i = 0; i < ETHER_ADDR_LEN; i++) + sq_seeq_write(sc, i, sc->sc_ac.ac_enaddr[i]); + + sc->sc_rxcmd = + RXCMD_IE_CRC | + RXCMD_IE_DRIB | + RXCMD_IE_SHORT | + RXCMD_IE_END | + RXCMD_IE_GOOD; + + /* + * Set the receive filter -- this will add some bits to the + * prototype RXCMD register. Do this before setting the + * transmit config register, since we might need to switch + * banks. + */ + sq_set_filter(sc); + + /* Set up Seeq transmit command register */ + sq_seeq_write(sc, SEEQ_TXCMD, + TXCMD_IE_UFLOW | TXCMD_IE_COLL | TXCMD_IE_16COLL | TXCMD_IE_GOOD); + + /* Now write the receive command register. */ + sq_seeq_write(sc, SEEQ_RXCMD, sc->sc_rxcmd); + + /* + * Set up HPC ethernet PIO and DMA configurations. + * + * The PROM appears to do most of this for the onboard HPC3, but + * not for the Challenge S's IOPLUS chip. We copy how the onboard + * chip is configured and assume that it's correct for both. + */ + if (sc->hpc_regs->revision == 3) { + uint32_t dmareg, pioreg; + + pioreg = + HPC3_ENETR_PIOCFG_P1(1) | + HPC3_ENETR_PIOCFG_P2(6) | + HPC3_ENETR_PIOCFG_P3(1); + + dmareg = + HPC3_ENETR_DMACFG_D1(6) | + HPC3_ENETR_DMACFG_D2(2) | + HPC3_ENETR_DMACFG_D3(0) | + HPC3_ENETR_DMACFG_FIX_RXDC | + HPC3_ENETR_DMACFG_FIX_INTR | + HPC3_ENETR_DMACFG_FIX_EOP | + HPC3_ENETR_DMACFG_TIMEOUT; + + sq_hpc_write(sc, HPC3_ENETR_PIOCFG, pioreg); + sq_hpc_write(sc, HPC3_ENETR_DMACFG, dmareg); + } + + /* Pass the start of the receive ring to the HPC */ + sq_hpc_write(sc, sc->hpc_regs->enetr_ndbp, SQ_CDRXADDR(sc, 0)); + + /* And turn on the HPC ethernet receive channel */ + sq_hpc_write(sc, sc->hpc_regs->enetr_ctl, + sc->hpc_regs->enetr_ctl_active); + + /* + * Turn off delayed receive interrupts on HPC1. + * (see Hollywood HPC Specification 2.1.4.3) + */ + if (sc->hpc_regs->revision != 3) + sq_hpc_write(sc, HPC1_ENET_INTDELAY, HPC1_ENET_INTDELAY_OFF); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + sq_start(ifp); + + return 0; +} + +void +sq_set_filter(struct sq_softc *sc) +{ + struct arpcom *ac = &sc->sc_ac; + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct ether_multi *enm; + struct ether_multistep step; + + /* + * Check for promiscuous mode. Also implies + * all-multicast. + */ + if (ifp->if_flags & IFF_PROMISC) { + sc->sc_rxcmd |= RXCMD_REC_ALL; + ifp->if_flags |= IFF_ALLMULTI; + return; + } + + /* + * The 8003 has no hash table. If we have any multicast + * addresses on the list, enable reception of all multicast + * frames. + * + * XXX The 80c03 has a hash table. We should use it. + */ + + ETHER_FIRST_MULTI(step, ac, enm); + + if (enm == NULL) { + sc->sc_rxcmd &= ~RXCMD_REC_MASK; + sc->sc_rxcmd |= RXCMD_REC_BROAD; + + ifp->if_flags &= ~IFF_ALLMULTI; + return; + } + + sc->sc_rxcmd |= RXCMD_REC_MULTI; + ifp->if_flags |= IFF_ALLMULTI; +} + +int +sq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct sq_softc *sc = ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *)data; + int s, error = 0; + + SQ_TRACE(SQ_IOCTL, sc, 0, 0); + + s = splnet(); + + switch (cmd) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + if (!(ifp->if_flags & IFF_RUNNING)) + sq_init(ifp); +#ifdef INET + if (ifa->ifa_addr->sa_family == AF_INET) + arp_ifinit(&sc->sc_ac, ifa); +#endif + break; + + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING) + error = ENETRESET; + else + sq_init(ifp); + } else { + if (ifp->if_flags & IFF_RUNNING) + sq_stop(ifp); + } + break; + + default: + error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); + break; + } + + if (error == ENETRESET) { + /* + * Multicast list has changed; set the hardware filter + * accordingly. + */ + if (ifp->if_flags & IFF_RUNNING) + error = sq_init(ifp); + else + error = 0; + } + + splx(s); + return error; +} + +void +sq_start(struct ifnet *ifp) +{ + struct sq_softc *sc = ifp->if_softc; + uint32_t status; + struct mbuf *m0, *m; + bus_dmamap_t dmamap; + int err, len, totlen, nexttx, firsttx, lasttx = -1, ofree, seg; + + if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) + return; + + /* + * Remember the previous number of free descriptors and + * the first descriptor we'll use. + */ + ofree = sc->sc_nfreetx; + firsttx = sc->sc_nexttx; + + /* + * Loop through the send queue, setting up transmit descriptors + * until we drain the queue, or use up all available transmit + * descriptors. + */ + while (sc->sc_nfreetx != 0) { + /* + * Grab a packet off the queue. + */ + IFQ_POLL(&ifp->if_snd, m0); + if (m0 == NULL) + break; + m = NULL; + + dmamap = sc->sc_txmap[sc->sc_nexttx]; + + /* + * Load the DMA map. If this fails, the packet either + * didn't fit in the alloted number of segments, or we were + * short on resources. In this case, we'll copy and try + * again. + * Also copy it if we need to pad, so that we are sure there + * is room for the pad buffer. + * XXX the right way of doing this is to use a static buffer + * for padding and adding it to the transmit descriptor (see + * sys/dev/pci/if_tl.c for example). We can't do this here yet + * because we can't send packets with more than one fragment. + */ + len = m0->m_pkthdr.len; + if (len < ETHER_PAD_LEN || + bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, + BUS_DMA_NOWAIT) != 0) { + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + printf("%s: unable to allocate Tx mbuf\n", + sc->sc_dev.dv_xname); + break; + } + if (len > MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + printf("%s: unable to allocate Tx " + "cluster\n", + sc->sc_dev.dv_xname); + m_freem(m); + break; + } + } + + m_copydata(m0, 0, len, mtod(m, void *)); + if (len < ETHER_PAD_LEN) { + memset(mtod(m, char *) + len, 0, + ETHER_PAD_LEN - len); + len = ETHER_PAD_LEN; + } + m->m_pkthdr.len = m->m_len = len; + + if ((err = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, + m, BUS_DMA_NOWAIT)) != 0) { + printf("%s: unable to load Tx buffer, " + "error = %d\n", + sc->sc_dev.dv_xname, err); + break; + } + } + + /* + * Ensure we have enough descriptors free to describe + * the packet. + */ + if (dmamap->dm_nsegs > sc->sc_nfreetx) { + /* + * Not enough free descriptors to transmit this + * packet. We haven't committed to anything yet, + * so just unload the DMA map, put the packet + * back on the queue, and punt. Notify the upper + * layer that there are no more slots left. + * + * XXX We could allocate an mbuf and copy, but + * XXX it is worth it? + */ + ifp->if_flags |= IFF_OACTIVE; + bus_dmamap_unload(sc->sc_dmat, dmamap); + if (m != NULL) + m_freem(m); + break; + } + + IFQ_DEQUEUE(&ifp->if_snd, m0); +#if NBPFILTER > 0 + /* + * Pass the packet to any BPF listeners. + */ + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT); +#endif + if (m != NULL) { + m_freem(m0); + m0 = m; + } + + /* + * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. + */ + + SQ_TRACE(SQ_ENQUEUE, sc, sc->sc_nexttx, 0); + + /* Sync the DMA map. */ + bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + /* + * Initialize the transmit descriptors. + */ + for (nexttx = sc->sc_nexttx, seg = 0, totlen = 0; + seg < dmamap->dm_nsegs; + seg++, nexttx = SQ_NEXTTX(nexttx)) { + if (sc->hpc_regs->revision == 3) { + sc->sc_txdesc[nexttx].hpc3_hdd_bufptr = + dmamap->dm_segs[seg].ds_addr; + sc->sc_txdesc[nexttx].hpc3_hdd_ctl = + dmamap->dm_segs[seg].ds_len; + } else { + sc->sc_txdesc[nexttx].hpc1_hdd_bufptr = + dmamap->dm_segs[seg].ds_addr; + sc->sc_txdesc[nexttx].hpc1_hdd_ctl = + dmamap->dm_segs[seg].ds_len; + } + sc->sc_txdesc[nexttx].hdd_descptr = + SQ_CDTXADDR(sc, SQ_NEXTTX(nexttx)); + lasttx = nexttx; + totlen += dmamap->dm_segs[seg].ds_len; + } + + /* Last descriptor gets end-of-packet */ + KASSERT(lasttx != -1); + if (sc->hpc_regs->revision == 3) + sc->sc_txdesc[lasttx].hpc3_hdd_ctl |= + HPC3_HDD_CTL_EOPACKET; + else + sc->sc_txdesc[lasttx].hpc1_hdd_ctl |= + HPC1_HDD_CTL_EOPACKET; + + SQ_DPRINTF(("%s: transmit %d-%d, len %d\n", + sc->sc_dev.dv_xname, sc->sc_nexttx, lasttx, totlen)); + + if (ifp->if_flags & IFF_DEBUG) { + printf(" transmit chain:\n"); + for (seg = sc->sc_nexttx;; seg = SQ_NEXTTX(seg)) { + printf(" descriptor %d:\n", seg); + printf(" hdd_bufptr: 0x%08x\n", + (sc->hpc_regs->revision == 3) ? + sc->sc_txdesc[seg].hpc3_hdd_bufptr : + sc->sc_txdesc[seg].hpc1_hdd_bufptr); + printf(" hdd_ctl: 0x%08x\n", + (sc->hpc_regs->revision == 3) ? + sc->sc_txdesc[seg].hpc3_hdd_ctl: + sc->sc_txdesc[seg].hpc1_hdd_ctl); + printf(" hdd_descptr: 0x%08x\n", + sc->sc_txdesc[seg].hdd_descptr); + + if (seg == lasttx) + break; + } + } + + /* Sync the descriptors we're using. */ + SQ_CDTXSYNC(sc, sc->sc_nexttx, dmamap->dm_nsegs, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* Store a pointer to the packet so we can free it later */ + sc->sc_txmbuf[sc->sc_nexttx] = m0; + + /* Advance the tx pointer. */ + sc->sc_nfreetx -= dmamap->dm_nsegs; + sc->sc_nexttx = nexttx; + } + + /* All transmit descriptors used up, let upper layers know */ + if (sc->sc_nfreetx == 0) + ifp->if_flags |= IFF_OACTIVE; + + if (sc->sc_nfreetx != ofree) { + SQ_DPRINTF(("%s: %d packets enqueued, first %d, INTR on %d\n", + sc->sc_dev.dv_xname, lasttx - firsttx + 1, + firsttx, lasttx)); + + /* + * Cause a transmit interrupt to happen on the + * last packet we enqueued, mark it as the last + * descriptor. + * + * HPC1_HDD_CTL_INTR will generate an interrupt on + * HPC1. HPC3 requires HPC3_HDD_CTL_EOPACKET in + * addition to HPC3_HDD_CTL_INTR to interrupt. + */ + KASSERT(lasttx != -1); + if (sc->hpc_regs->revision == 3) { + sc->sc_txdesc[lasttx].hpc3_hdd_ctl |= + HPC3_HDD_CTL_INTR | HPC3_HDD_CTL_EOCHAIN; + } else { + sc->sc_txdesc[lasttx].hpc1_hdd_ctl |= HPC1_HDD_CTL_INTR; + sc->sc_txdesc[lasttx].hpc1_hdd_bufptr |= + HPC1_HDD_CTL_EOCHAIN; + } + + SQ_CDTXSYNC(sc, lasttx, 1, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* + * There is a potential race condition here if the HPC + * DMA channel is active and we try and either update + * the 'next descriptor' pointer in the HPC PIO space + * or the 'next descriptor' pointer in a previous desc- + * riptor. + * + * To avoid this, if the channel is active, we rely on + * the transmit interrupt routine noticing that there + * are more packets to send and restarting the HPC DMA + * engine, rather than mucking with the DMA state here. + */ + status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl); + + if ((status & sc->hpc_regs->enetx_ctl_active) != 0) { + SQ_TRACE(SQ_ADD_TO_DMA, sc, firsttx, status); + + /* + * NB: hpc3_hdd_ctl == hpc1_hdd_bufptr, and + * HPC1_HDD_CTL_EOCHAIN == HPC3_HDD_CTL_EOCHAIN + */ + sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc3_hdd_ctl &= + ~HPC3_HDD_CTL_EOCHAIN; + + if (sc->hpc_regs->revision != 3) + sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc1_hdd_ctl + &= ~HPC1_HDD_CTL_INTR; + + SQ_CDTXSYNC(sc, SQ_PREVTX(firsttx), 1, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + } else if (sc->hpc_regs->revision == 3) { + SQ_TRACE(SQ_START_DMA, sc, firsttx, status); + + sq_hpc_write(sc, HPC3_ENETX_NDBP, SQ_CDTXADDR(sc, + firsttx)); + + /* Kick DMA channel into life */ + sq_hpc_write(sc, HPC3_ENETX_CTL, HPC3_ENETX_CTL_ACTIVE); + } else { + /* + * In the HPC1 case where transmit DMA is + * inactive, we can either kick off if + * the ring was previously empty, or call + * our transmit interrupt handler to + * figure out if the ring stopped short + * and restart at the right place. + */ + if (ofree == SQ_NTXDESC) { + SQ_TRACE(SQ_START_DMA, sc, firsttx, status); + + sq_hpc_write(sc, HPC1_ENETX_NDBP, + SQ_CDTXADDR(sc, firsttx)); + sq_hpc_write(sc, HPC1_ENETX_CFXBP, + SQ_CDTXADDR(sc, firsttx)); + sq_hpc_write(sc, HPC1_ENETX_CBP, + SQ_CDTXADDR(sc, firsttx)); + + /* Kick DMA channel into life */ + sq_hpc_write(sc, HPC1_ENETX_CTL, + HPC1_ENETX_CTL_ACTIVE); + } else + sq_txring_hpc1(sc); + } + + /* Set a watchdog timer in case the chip flakes out. */ + ifp->if_timer = 5; + } +} + +void +sq_stop(struct ifnet *ifp) +{ + struct sq_softc *sc = ifp->if_softc; + int i; + + ifp->if_timer = 0; + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + + for (i = 0; i < SQ_NTXDESC; i++) { + if (sc->sc_txmbuf[i] != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]); + m_freem(sc->sc_txmbuf[i]); + sc->sc_txmbuf[i] = NULL; + } + } + + /* Clear Seeq transmit/receive command registers */ + sq_seeq_write(sc, SEEQ_TXCMD, 0); + sq_seeq_write(sc, SEEQ_RXCMD, 0); + + sq_reset(sc); +} + +/* Device timeout/watchdog routine. */ +void +sq_watchdog(struct ifnet *ifp) +{ + struct sq_softc *sc = ifp->if_softc; + uint32_t status; + + status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl); + log(LOG_ERR, "%s: device timeout (prev %d, next %d, free %d, " + "status %08x)\n", sc->sc_dev.dv_xname, sc->sc_prevtx, + sc->sc_nexttx, sc->sc_nfreetx, status); + +#ifdef SQ_DEBUG + sq_trace_dump(sc); +#endif + + ++ifp->if_oerrors; + + sq_init(ifp); +} + +#ifdef SQ_DEBUG +void +sq_trace_dump(struct sq_softc *sc) +{ + int i; + const char *act; + + for (i = 0; i < sc->sq_trace_idx; i++) { + switch (sc->sq_trace[i].action) { + case SQ_RESET: act = "SQ_RESET"; break; + case SQ_ADD_TO_DMA: act = "SQ_ADD_TO_DMA"; break; + case SQ_START_DMA: act = "SQ_START_DMA"; break; + case SQ_DONE_DMA: act = "SQ_DONE_DMA"; break; + case SQ_RESTART_DMA: act = "SQ_RESTART_DMA"; break; + case SQ_TXINTR_ENTER: act = "SQ_TXINTR_ENTER"; break; + case SQ_TXINTR_EXIT: act = "SQ_TXINTR_EXIT"; break; + case SQ_TXINTR_BUSY: act = "SQ_TXINTR_BUSY"; break; + case SQ_IOCTL: act = "SQ_IOCTL"; break; + case SQ_ENQUEUE: act = "SQ_ENQUEUE"; break; + default: act = "UNKNOWN"; + } + + printf("%s: [%03d] action %-16s buf %03d free %03d " + "status %08x line %d\n", sc->sc_dev.dv_xname, i, act, + sc->sq_trace[i].bufno, sc->sq_trace[i].freebuf, + sc->sq_trace[i].status, sc->sq_trace[i].line); + } + + memset(&sc->sq_trace, 0, sizeof(sc->sq_trace)); + sc->sq_trace_idx = 0; +} +#endif + +int +sq_intr(void *arg) +{ + struct sq_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ac.ac_if; + uint32_t stat; + + stat = sq_hpc_read(sc, sc->hpc_regs->enetr_reset); + + if ((stat & 2) == 0) { + SQ_DPRINTF(("%s: Unexpected interrupt!\n", + sc->sc_dev.dv_xname)); + } else + sq_hpc_write(sc, sc->hpc_regs->enetr_reset, (stat | 2)); + + /* + * If the interface isn't running, the interrupt couldn't + * possibly have come from us. + */ + if ((ifp->if_flags & IFF_RUNNING) == 0) + return 0; + + /* Always check for received packets */ + sq_rxintr(sc); + + /* Only handle transmit interrupts if we actually sent something */ + if (sc->sc_nfreetx < SQ_NTXDESC) + sq_txintr(sc); + + /* + * XXX Always claim the interrupt, even if we did nothing. + * XXX There seem to be extra interrupts when the receiver becomes + * XXX idle. + */ + return 1; +} + +void +sq_rxintr(struct sq_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct mbuf* m; + int i, framelen; + uint8_t pktstat; + uint32_t status; + uint32_t ctl_reg; + int new_end, orig_end; + + for (i = sc->sc_nextrx; ; i = SQ_NEXTRX(i)) { + SQ_CDRXSYNC(sc, i, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + /* + * If this is a CPU-owned buffer, we're at the end of the list. + */ + if (sc->hpc_regs->revision == 3) + ctl_reg = + sc->sc_rxdesc[i].hpc3_hdd_ctl & HPC3_HDD_CTL_OWN; + else + ctl_reg = + sc->sc_rxdesc[i].hpc1_hdd_ctl & HPC1_HDD_CTL_OWN; + + if (ctl_reg) { +#if defined(SQ_DEBUG) + uint32_t reg; + + reg = sq_hpc_read(sc, sc->hpc_regs->enetr_ctl); + SQ_DPRINTF(("%s: rxintr: done at %d (ctl %08x)\n", + sc->sc_dev.dv_xname, i, reg)); +#endif + break; + } + + m = sc->sc_rxmbuf[i]; + framelen = m->m_ext.ext_size - 3; + if (sc->hpc_regs->revision == 3) + framelen -= + HPC3_HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hpc3_hdd_ctl); + else + framelen -= + HPC1_HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hpc1_hdd_ctl); + + /* Now sync the actual packet data */ + bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, + sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_POSTREAD); + + pktstat = *((uint8_t *)m->m_data + framelen + 2); + + if ((pktstat & RXSTAT_GOOD) == 0) { + ifp->if_ierrors++; + + if (pktstat & RXSTAT_OFLOW) + printf("%s: receive FIFO overflow\n", + sc->sc_dev.dv_xname); + + bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, + sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD); + SQ_INIT_RXDESC(sc, i); + SQ_DPRINTF(("%s: sq_rxintr: buf %d no RXSTAT_GOOD\n", + sc->sc_dev.dv_xname, i)); + continue; + } + + if (sq_add_rxbuf(sc, i) != 0) { + ifp->if_ierrors++; + bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0, + sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD); + SQ_INIT_RXDESC(sc, i); + SQ_DPRINTF(("%s: sq_rxintr: buf %d sq_add_rxbuf() " + "failed\n", sc->sc_dev.dv_xname, i)); + continue; + } + + + m->m_data += 2; + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = framelen; + + ifp->if_ipackets++; + + SQ_DPRINTF(("%s: sq_rxintr: buf %d len %d\n", + sc->sc_dev.dv_xname, i, framelen)); + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); +#endif + + ether_input_mbuf(ifp, m); + } + + + /* If anything happened, move ring start/end pointers to new spot */ + if (i != sc->sc_nextrx) { + /* + * NB: hpc3_hdd_ctl == hpc1_hdd_bufptr, and + * HPC1_HDD_CTL_EOCHAIN == HPC3_HDD_CTL_EOCHAIN + */ + + new_end = SQ_PREVRX(i); + sc->sc_rxdesc[new_end].hpc3_hdd_ctl |= HPC3_HDD_CTL_EOCHAIN; + SQ_CDRXSYNC(sc, new_end, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + orig_end = SQ_PREVRX(sc->sc_nextrx); + sc->sc_rxdesc[orig_end].hpc3_hdd_ctl &= ~HPC3_HDD_CTL_EOCHAIN; + SQ_CDRXSYNC(sc, orig_end, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + sc->sc_nextrx = i; + } + + status = sq_hpc_read(sc, sc->hpc_regs->enetr_ctl); + + /* If receive channel is stopped, restart it... */ + if ((status & sc->hpc_regs->enetr_ctl_active) == 0) { + /* Pass the start of the receive ring to the HPC */ + sq_hpc_write(sc, sc->hpc_regs->enetr_ndbp, + SQ_CDRXADDR(sc, sc->sc_nextrx)); + + /* And turn on the HPC ethernet receive channel */ + sq_hpc_write(sc, sc->hpc_regs->enetr_ctl, + sc->hpc_regs->enetr_ctl_active); + } +} + +void +sq_txintr(struct sq_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + uint shift = 0; + uint32_t status, tmp; + + if (sc->hpc_regs->revision != 3) + shift = 16; + + status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl) >> shift; + + SQ_TRACE(SQ_TXINTR_ENTER, sc, sc->sc_prevtx, status); + + tmp = (sc->hpc_regs->enetx_ctl_active >> shift) | TXSTAT_GOOD; + if ((status & tmp) == 0) { + if (status & TXSTAT_COLL) + ifp->if_collisions++; + + if (status & TXSTAT_UFLOW) { + printf("%s: transmit underflow\n", + sc->sc_dev.dv_xname); + ifp->if_oerrors++; +#ifdef SQ_DEBUG + sq_trace_dump(sc); +#endif + sq_init(ifp); + return; + } + + if (status & TXSTAT_16COLL) { + printf("%s: max collisions reached\n", + sc->sc_dev.dv_xname); + ifp->if_oerrors++; + ifp->if_collisions += 16; + } + } + + /* prevtx now points to next xmit packet not yet finished */ + if (sc->hpc_regs->revision == 3) + sq_txring_hpc3(sc); + else + sq_txring_hpc1(sc); + + /* If we have buffers free, let upper layers know */ + if (sc->sc_nfreetx > 0) + ifp->if_flags &= ~IFF_OACTIVE; + + /* If all packets have left the coop, cancel watchdog */ + if (sc->sc_nfreetx == SQ_NTXDESC) + ifp->if_timer = 0; + + SQ_TRACE(SQ_TXINTR_EXIT, sc, sc->sc_prevtx, status); + sq_start(ifp); +} + +/* + * Reclaim used transmit descriptors and restart the transmit DMA + * engine if necessary. + */ +void +sq_txring_hpc1(struct sq_softc *sc) +{ + /* + * HPC1 doesn't tag transmitted descriptors, however, + * the NDBP register points to the next descriptor that + * has not yet been processed. If DMA is not in progress, + * we can safely reclaim all descriptors up to NDBP, and, + * if necessary, restart DMA at NDBP. Otherwise, if DMA + * is active, we can only safely reclaim up to CBP. + * + * For now, we'll only reclaim on inactive DMA and assume + * that a sufficiently large ring keeps us out of trouble. + */ + struct ifnet *ifp = &sc->sc_ac.ac_if; + uint32_t reclaimto, status; + int reclaimall, i = sc->sc_prevtx; + + status = sq_hpc_read(sc, HPC1_ENETX_CTL); + if (status & HPC1_ENETX_CTL_ACTIVE) { + SQ_TRACE(SQ_TXINTR_BUSY, sc, i, status); + return; + } else + reclaimto = sq_hpc_read(sc, HPC1_ENETX_NDBP); + + if (sc->sc_nfreetx == 0 && SQ_CDTXADDR(sc, i) == reclaimto) + reclaimall = 1; + else + reclaimall = 0; + + while (sc->sc_nfreetx < SQ_NTXDESC) { + if (SQ_CDTXADDR(sc, i) == reclaimto && !reclaimall) + break; + + SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + /* Sync the packet data, unload DMA map, free mbuf */ + bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[i], + 0, sc->sc_txmap[i]->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]); + m_freem(sc->sc_txmbuf[i]); + sc->sc_txmbuf[i] = NULL; + + ifp->if_opackets++; + sc->sc_nfreetx++; + + SQ_TRACE(SQ_DONE_DMA, sc, i, status); + + i = SQ_NEXTTX(i); + } + + if (sc->sc_nfreetx < SQ_NTXDESC) { + SQ_TRACE(SQ_RESTART_DMA, sc, i, status); + + KASSERT(reclaimto == SQ_CDTXADDR(sc, i)); + + sq_hpc_write(sc, HPC1_ENETX_CFXBP, reclaimto); + sq_hpc_write(sc, HPC1_ENETX_CBP, reclaimto); + + /* Kick DMA channel into life */ + sq_hpc_write(sc, HPC1_ENETX_CTL, HPC1_ENETX_CTL_ACTIVE); + + /* + * Set a watchdog timer in case the chip + * flakes out. + */ + ifp->if_timer = 5; + } + + sc->sc_prevtx = i; +} + +/* + * Reclaim used transmit descriptors and restart the transmit DMA + * engine if necessary. + */ +void +sq_txring_hpc3(struct sq_softc *sc) +{ + /* + * HPC3 tags descriptors with a bit once they've been + * transmitted. We need only free each XMITDONE'd + * descriptor, and restart the DMA engine if any + * descriptors are left over. + */ + struct ifnet *ifp = &sc->sc_ac.ac_if; + int i; + uint32_t status = 0; + + i = sc->sc_prevtx; + while (sc->sc_nfreetx < SQ_NTXDESC) { + /* + * Check status first so we don't end up with a case of + * the buffer not being finished while the DMA channel + * has gone idle. + */ + status = sq_hpc_read(sc, HPC3_ENETX_CTL); + + SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + /* Check for used descriptor and restart DMA chain if needed */ + if ((sc->sc_txdesc[i].hpc3_hdd_ctl & + HPC3_HDD_CTL_XMITDONE) == 0) { + if ((status & HPC3_ENETX_CTL_ACTIVE) == 0) { + SQ_TRACE(SQ_RESTART_DMA, sc, i, status); + + sq_hpc_write(sc, HPC3_ENETX_NDBP, + SQ_CDTXADDR(sc, i)); + + /* Kick DMA channel into life */ + sq_hpc_write(sc, HPC3_ENETX_CTL, + HPC3_ENETX_CTL_ACTIVE); + + /* + * Set a watchdog timer in case the chip + * flakes out. + */ + ifp->if_timer = 5; + } else + SQ_TRACE(SQ_TXINTR_BUSY, sc, i, status); + break; + } + + /* Sync the packet data, unload DMA map, free mbuf */ + bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[i], + 0, sc->sc_txmap[i]->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]); + m_freem(sc->sc_txmbuf[i]); + sc->sc_txmbuf[i] = NULL; + + ifp->if_opackets++; + sc->sc_nfreetx++; + + SQ_TRACE(SQ_DONE_DMA, sc, i, status); + i = SQ_NEXTTX(i); + } + + sc->sc_prevtx = i; +} + +void +sq_reset(struct sq_softc *sc) +{ + /* Stop HPC dma channels */ + sq_hpc_write(sc, sc->hpc_regs->enetr_ctl, 0); + sq_hpc_write(sc, sc->hpc_regs->enetx_ctl, 0); + + sq_hpc_write(sc, sc->hpc_regs->enetr_reset, 3); + delay(20); + sq_hpc_write(sc, sc->hpc_regs->enetr_reset, 0); +} + +/* sq_add_rxbuf: Add a receive buffer to the indicated descriptor. */ +int +sq_add_rxbuf(struct sq_softc *sc, int idx) +{ + int err; + struct mbuf *m; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return ENOBUFS; + + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + return ENOBUFS; + } + + if (sc->sc_rxmbuf[idx] != NULL) + bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[idx]); + + sc->sc_rxmbuf[idx] = m; + + if ((err = bus_dmamap_load(sc->sc_dmat, sc->sc_rxmap[idx], + m->m_ext.ext_buf, m->m_ext.ext_size, NULL, BUS_DMA_NOWAIT)) != 0) { + printf("%s: can't load rx DMA map %d, error = %d\n", + sc->sc_dev.dv_xname, idx, err); + panic("sq_add_rxbuf"); /* XXX */ + } + + bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx], + 0, sc->sc_rxmap[idx]->dm_mapsize, BUS_DMASYNC_PREREAD); + + SQ_INIT_RXDESC(sc, idx); + + return 0; +} diff --git a/sys/arch/sgi/hpc/if_sqvar.h b/sys/arch/sgi/hpc/if_sqvar.h new file mode 100644 index 00000000000..657025771f7 --- /dev/null +++ b/sys/arch/sgi/hpc/if_sqvar.h @@ -0,0 +1,200 @@ +/* $OpenBSD: if_sqvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: sqvar.h,v 1.12 2011/01/25 13:12:39 tsutsui Exp $ */ + +/* + * Copyright (c) 2001 Rafal K. Boni + * 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. 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. + */ + +/* Note, these must be powers of two for the magic NEXT/PREV macros to work */ +#define SQ_NRXDESC 64 +#define SQ_NTXDESC 64 + +#define SQ_NRXDESC_MASK (SQ_NRXDESC - 1) +#define SQ_NEXTRX(x) ((x + 1) & SQ_NRXDESC_MASK) +#define SQ_PREVRX(x) ((x - 1) & SQ_NRXDESC_MASK) + +#define SQ_NTXDESC_MASK (SQ_NTXDESC - 1) +#define SQ_NEXTTX(x) ((x + 1) & SQ_NTXDESC_MASK) +#define SQ_PREVTX(x) ((x - 1) & SQ_NTXDESC_MASK) + +/* + * We pack all DMA control structures into one container so we can alloc just + * one chunk of DMA-safe memory and pack them into it. Otherwise, we'd have to + * allocate a page for each descriptor, since the bus_dmamem_alloc() interface + * does not allow us to allocate smaller chunks. + */ +struct sq_control { + /* Receive descriptors */ + struct hpc_dma_desc rx_desc[SQ_NRXDESC]; + + /* Transmit descriptors */ + struct hpc_dma_desc tx_desc[SQ_NTXDESC]; +}; + +#define SQ_CDOFF(x) offsetof(struct sq_control, x) +#define SQ_CDTXOFF(x) SQ_CDOFF(tx_desc[(x)]) +#define SQ_CDRXOFF(x) SQ_CDOFF(rx_desc[(x)]) + +#define SQ_TYPE_8003 0 +#define SQ_TYPE_80C03 1 + +/* Trace Actions */ +#define SQ_RESET 1 +#define SQ_ADD_TO_DMA 2 +#define SQ_START_DMA 3 +#define SQ_DONE_DMA 4 +#define SQ_RESTART_DMA 5 +#define SQ_TXINTR_ENTER 6 +#define SQ_TXINTR_EXIT 7 +#define SQ_TXINTR_BUSY 8 +#define SQ_IOCTL 9 +#define SQ_ENQUEUE 10 + +struct sq_action_trace { + int action; + int line; + int bufno; + int status; + int freebuf; +}; + +#ifdef SQ_DEBUG +#define SQ_TRACEBUF_SIZE 100 + +#define SQ_TRACE(act, sc, buf, stat) do { \ + (sc)->sq_trace[(sc)->sq_trace_idx].action = (act); \ + (sc)->sq_trace[(sc)->sq_trace_idx].line = __LINE__; \ + (sc)->sq_trace[(sc)->sq_trace_idx].bufno = (buf); \ + (sc)->sq_trace[(sc)->sq_trace_idx].status = (stat); \ + (sc)->sq_trace[(sc)->sq_trace_idx].freebuf = (sc)->sc_nfreetx; \ + if (++(sc)->sq_trace_idx == SQ_TRACEBUF_SIZE) \ + (sc)->sq_trace_idx = 0; \ +} while (/* CONSTCOND */0) +#else +#define SQ_TRACE(act, sc, buf, stat) do { } while (/* CONSTCOND */0) +#endif + +struct sq_softc { + struct device sc_dev; + + /* HPC registers */ + bus_space_tag_t sc_hpct; + bus_space_handle_t sc_hpch; + + /* HPC external Ethernet registers: aka Seeq 8003 registers */ + bus_space_tag_t sc_regt; + bus_space_handle_t sc_regh; + + bus_dma_tag_t sc_dmat; + + struct arpcom sc_ac; + uint8_t sc_enaddr[ETHER_ADDR_LEN]; + + int sc_type; + + struct sq_control* sc_control; +#define sc_rxdesc sc_control->rx_desc +#define sc_txdesc sc_control->tx_desc + + /* DMA structures for control data (DMA RX/TX descriptors) */ + int sc_ncdseg; + bus_dma_segment_t sc_cdseg; + bus_dmamap_t sc_cdmap; +#define sc_cddma sc_cdmap->dm_segs[0].ds_addr + + int sc_nextrx; + + /* DMA structures for RX packet data */ + bus_dma_segment_t sc_rxseg[SQ_NRXDESC]; + bus_dmamap_t sc_rxmap[SQ_NRXDESC]; + struct mbuf* sc_rxmbuf[SQ_NRXDESC]; + + int sc_nexttx; + int sc_prevtx; + int sc_nfreetx; + + /* DMA structures for TX packet data */ + bus_dma_segment_t sc_txseg[SQ_NTXDESC]; + bus_dmamap_t sc_txmap[SQ_NTXDESC]; + struct mbuf* sc_txmbuf[SQ_NTXDESC]; + + uint8_t sc_rxcmd; /* prototype rxcmd */ + + struct hpc_values *hpc_regs; /* HPC register definitions */ + +#ifdef SQ_DEBUG + int sq_trace_idx; + struct sq_action_trace sq_trace[SQ_TRACEBUF_SIZE]; +#endif +}; + +#define SQ_CDTXADDR(sc, x) ((sc)->sc_cddma + SQ_CDTXOFF((x))) +#define SQ_CDRXADDR(sc, x) ((sc)->sc_cddma + SQ_CDRXOFF((x))) + +static inline void +SQ_CDTXSYNC(struct sq_softc *sc, int __x, int __n, int ops) +{ + /* If it will wrap around, sync to the end of the ring. */ + if ((__x + __n) > SQ_NTXDESC) { + bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, + SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) * + (SQ_NTXDESC - __x), (ops)); + __n -= (SQ_NTXDESC - __x); + __x = 0; + } + + /* Now sync whatever is left. */ + bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, + SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) * __n, (ops)); +} + +#define SQ_CDRXSYNC(sc, x, ops) \ + bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, \ + SQ_CDRXOFF((x)), sizeof(struct hpc_dma_desc), (ops)) + +static inline void +SQ_INIT_RXDESC(struct sq_softc *sc, unsigned int x) +{ + struct hpc_dma_desc* __rxd = &(sc)->sc_rxdesc[(x)]; + struct mbuf *__m = (sc)->sc_rxmbuf[(x)]; + + __m->m_data = __m->m_ext.ext_buf; + if (sc->hpc_regs->revision == 3) { + __rxd->hpc3_hdd_bufptr = + (sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr; + __rxd->hpc3_hdd_ctl = __m->m_ext.ext_size | HPC3_HDD_CTL_OWN | + HPC3_HDD_CTL_INTR | HPC3_HDD_CTL_EOPACKET | + ((x) == (SQ_NRXDESC - 1) ? HPC3_HDD_CTL_EOCHAIN : 0); + } else { + __rxd->hpc1_hdd_bufptr = + (sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr | + ((x) == (SQ_NRXDESC - 1) ? HPC1_HDD_CTL_EOCHAIN : 0); + __rxd->hpc1_hdd_ctl = __m->m_ext.ext_size | HPC1_HDD_CTL_OWN | + HPC1_HDD_CTL_INTR | HPC1_HDD_CTL_EOPACKET; + } + __rxd->hdd_descptr = SQ_CDRXADDR((sc), SQ_NEXTRX((x))); + SQ_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); +} diff --git a/sys/arch/sgi/hpc/iocreg.h b/sys/arch/sgi/hpc/iocreg.h new file mode 100644 index 00000000000..274454e4ddf --- /dev/null +++ b/sys/arch/sgi/hpc/iocreg.h @@ -0,0 +1,122 @@ +/* $OpenBSD: iocreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: iocreg.h,v 1.2 2005/12/11 12:18:53 christos Exp $ */ + +/* + * Copyright (c) 2003 Christopher Sekiya + * Copyright (c) 2001 Rafal K. Boni + * 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. 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. + */ + +/* + * IOC1/2 memory map. + * + * The IOC1/2 is connected to the HPC#0, PBus channel 6, so these registers + * are based from the external register window for PBus channel 6 on HPC#0. + * + */ + +#define IOC_BASE HPC3_PBUS_CH6_DEVREGS + +#define IOC_PLP_REGS 0x00 /* Parallel port registers */ +#define IOC_PLP_REGS_SIZE 0x2c + +#define IOC_PLP_DATA 0x00 /* Data register */ +#define IOC_PLP_CTL 0x04 /* Control register */ +#define IOC_PLP_STAT 0x08 /* Status register */ +#define IOC_PLP_DMACTL 0x0c /* DMA control register */ +#define IOC_PLP_INTSTAT 0x10 /* Interrupt status register */ +#define IOC_PLP_INTMASK 0x14 /* Interrupt mask register */ +#define IOC_PLP_TIMER1 0x18 /* Timer 1 register */ +#define IOC_PLP_TIMER2 0x1c /* Timer 2 register */ +#define IOC_PLP_TIMER3 0x20 /* Timer 3 register */ +#define IOC_PLP_TIMER4 0x24 /* Timer 4 register */ + +#define IOC_SERIAL_REGS 0x30 /* Serial port registers */ +#define IOC_SERIAL_REGS_SIZE 0x0c + +#define IOC_SERIAL_PORT1_CMD 0x00 /* Port 1 command transfer */ +#define IOC_SERIAL_PORT1_DATA 0x04 /* Port 1 data transfer */ +#define IOC_SERIAL_PORT2_CMD 0x08 /* Port 2 command transfer */ +#define IOC_SERIAL_PORT2_DATA 0x0c /* Port 2 data transfer */ + +#define IOC_KB_REGS 0x40 /* Keyboard/mouse registers */ +#define IOC_KB_REGS_SIZE 0x08 + +/* Miscellaneous registers */ + +#define IOC_MISC_REGS 0x48 /* Misc. IOC regs */ +#define IOC_MISC_REGS_SIZE 0x34 + +#define IOC_GCSEL 0x48 /* General select register */ + +#define IOC_GCREG 0x4c /* General control register */ + +#define IOC_PANEL 0x50 /* Front Panel register */ +#define IOC_PANEL_POWER_STATE 0x01 +#define IOC_PANEL_POWER_IRQ 0x02 +#define IOC_PANEL_VDOWN_IRQ 0x10 +#define IOC_PANEL_VDOWN_HOLD 0x20 +#define IOC_PANEL_VUP_IRQ 0x40 +#define IOC_PANEL_VUP_HOLD 0x80 + +#define IOC_SYSID 0x58 /* System ID register */ +#define IOC_SYSID_SYSTYPE 0x01 /* 0: Sapphire, 1: Full House */ +#define IOC_SYSID_BOARDREV 0x1e +#define IOC_SYSID_BOARDREV_SHIFT 1 +#define IOC_SYSID_CHIPREV 0xe0 +#define IOC_SYSID_CHIPREV_SHIFT 5 + +#define IOC_READ 0x60 /* Read register */ +#define IOC_READ_SCSI0_POWER 0x10 +#define IOC_READ_SCSI1_POWER 0x20 +#define IOC_READ_ENET_POWER 0x40 +#define IOC_READ_ENET_LINK 0x80 + +#define IOC_DMASEL 0x68 /* DMA select register */ +#define IOC_DMASEL_ISDN_B 0x01 +#define IOC_DMASEL_ISDN_A 0x02 +#define IOC_DMASEL_PARALLEL 0x04 +#define IOC_DMASEL_SERIAL_10MHZ 0x00 +#define IOC_DMASEL_SERIAL_6MHZ 0x10 +#define IOC_DMASEL_SERIAL_EXTERNAL 0x20 + +#define IOC_RESET 0x70 /* Reset register */ +#define IOC_RESET_PARALLEL 0x01 +#define IOC_RESET_PCKBC 0x02 +#define IOC_RESET_EISA 0x04 +#define IOC_RESET_ISDN 0x08 +#define IOC_RESET_LED_GREEN 0x10 +#define IOC_RESET_LED_RED 0x20 +#define IOC_RESET_LED_ORANGE 0x40 + +#define IOC_WRITE 0x78 /* Write register */ +#define IOC_WRITE_ENET_NTH 0x01 +#define IOC_WRITE_ENET_UTP 0x02 +#define IOC_WRITE_ENET_AUI 0x04 +#define IOC_WRITE_ENET_AUTO 0x08 +#define IOC_WRITE_PC_UART2 0x10 +#define IOC_WRITE_PC_UART1 0x20 +#define IOC_WRITE_MARGIN_LOW 0x40 +#define IOC_WRITE_MARGIN_HIGH 0x80 diff --git a/sys/arch/sgi/hpc/wdsc.c b/sys/arch/sgi/hpc/wdsc.c new file mode 100644 index 00000000000..101b5178819 --- /dev/null +++ b/sys/arch/sgi/hpc/wdsc.c @@ -0,0 +1,290 @@ +/* $OpenBSD: wdsc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: wdsc.c,v 1.32 2011/07/01 18:53:47 dyoung Exp $ */ + +/* + * Copyright (c) 2001 Wayne Knowles + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Wayne Knowles + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/kernel.h> +#include <sys/device.h> +#include <sys/buf.h> +#include <sys/timeout.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <mips64/archtype.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cpu.h> +#include <sgi/localbus/intvar.h> + +#include <sgi/hpc/hpcreg.h> +#include <sgi/hpc/hpcvar.h> +#include <sgi/hpc/hpcdma.h> + +#include <dev/ic/wd33c93reg.h> +#include <dev/ic/wd33c93var.h> + +struct wdsc_softc { + struct wd33c93_softc sc_wd33c93; /* Must be first */ + bus_dma_tag_t sc_dmat; + bus_dmamap_t sc_dmamap; + int sc_flags; +#define WDSC_DMA_ACTIVE 0x1 +#define WDSC_DMA_MAPLOADED 0x2 + struct hpc_dma_softc sc_hpcdma; +}; + +int wdsc_match(struct device *, void *, void *); +void wdsc_attach(struct device *, struct device *, void *); + +const struct cfattach wdsc_ca = { + sizeof(struct wdsc_softc), wdsc_match, wdsc_attach +}; + +struct cfdriver wdsc_cd = { + NULL, "wdsc", DV_DULL +}; + +int wdsc_dmasetup(struct wd33c93_softc *, void ** ,size_t *, int, size_t *); +int wdsc_dmago(struct wd33c93_softc *); +void wdsc_dmastop(struct wd33c93_softc *); +void wdsc_reset(struct wd33c93_softc *); + +struct scsi_adapter wdsc_switch = { + wd33c93_scsi_cmd, + scsi_minphys, + NULL, + NULL, +}; + +/* + * Match for SCSI devices on the onboard and GIO32 adapter WD33C93 chips + */ +int +wdsc_match(struct device *parent, void *vcf, void *aux) +{ + struct hpc_attach_args *haa = aux; + struct cfdata *cf = vcf; + vaddr_t reset, asr; + uint32_t dummy; + uint8_t reg; + + if (strcmp(haa->ha_name, cf->cf_driver->cd_name) != 0) + return 0; + + reset = PHYS_TO_XKPHYS(haa->ha_sh + haa->ha_dmaoff + + haa->hpc_regs->scsi0_ctl, CCA_NC); + if (guarded_read_4(reset, &dummy) != 0) + return 0; + *(volatile uint32_t *)reset = haa->hpc_regs->scsi_dmactl_reset; + delay(1000); + *(volatile uint32_t *)reset = 0x0; + delay(1000); + + asr = PHYS_TO_XKPHYS(haa->ha_sh + haa->ha_devoff + 3, CCA_NC); + if (guarded_read_1(asr, ®) != 0) + return 0; + if ((reg & 0xff) != SBIC_ASR_INT) + return 0; + + return 1; +} + +/* + * Attach the wdsc driver + */ +void +wdsc_attach(struct device *parent, struct device *self, void *aux) +{ + struct wdsc_softc *wsc = (struct wdsc_softc *)self; + struct wd33c93_softc *sc = &wsc->sc_wd33c93; + struct hpc_attach_args *haa = aux; + int err; + + sc->sc_regt = haa->ha_st; + wsc->sc_dmat = haa->ha_dmat; + + wsc->sc_hpcdma.hpc = haa->hpc_regs; + + if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh, + haa->ha_devoff + 3, 1, &sc->sc_asr_regh)) != 0) { + printf(": unable to map asr reg, err=%d\n", err); + return; + } + + if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh, + haa->ha_devoff + 3 + 4, 1, &sc->sc_data_regh)) != 0) { + printf(": unable to map asr reg, err=%d\n", err); + return; + } + + if (bus_dmamap_create(wsc->sc_dmat, MAXPHYS, + wsc->sc_hpcdma.hpc->scsi_dma_segs, + wsc->sc_hpcdma.hpc->scsi_dma_segs_size, + wsc->sc_hpcdma.hpc->scsi_dma_segs_size, + BUS_DMA_WAITOK, &wsc->sc_dmamap) != 0) { + printf(": failed to create dmamap\n"); + return; + } + + sc->sc_dmasetup = wdsc_dmasetup; + sc->sc_dmago = wdsc_dmago; + sc->sc_dmastop = wdsc_dmastop; + sc->sc_reset = wdsc_reset; + + sc->sc_id = 0; /* Host ID = 0 */ + sc->sc_clkfreq = 200; /* 20MHz */ + sc->sc_dmamode = SBIC_CTL_BURST_DMA; + + if (int2_intr_establish(haa->ha_irq, IPL_BIO, + wd33c93_intr, wsc, self->dv_xname) == NULL) { + printf(": unable to establish interrupt!\n"); + return; + } + + hpcdma_init(haa, &wsc->sc_hpcdma, wsc->sc_hpcdma.hpc->scsi_dma_segs); + wd33c93_attach(sc, &wdsc_switch); +} + +/* + * Prime the hardware for a DMA transfer + * + * Requires splbio() interrupts to be disabled by the caller + */ +int +wdsc_dmasetup(struct wd33c93_softc *sc, void **addr, size_t *len, int datain, + size_t *dmasize) +{ + struct wdsc_softc *wsc = (struct wdsc_softc *)sc; + struct hpc_dma_softc *dsc = &wsc->sc_hpcdma; + int count, err; + void *vaddr; + + KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0); + + vaddr = *addr; + count = dsc->sc_dlen = *len; + if (count) { + KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED) == 0); + + /* Build list of physical addresses for this transfer */ + if ((err = bus_dmamap_load(wsc->sc_dmat, wsc->sc_dmamap, + vaddr, count, NULL /* kernel address */, + BUS_DMA_NOWAIT)) != 0) + panic("%s: bus_dmamap_load err=%d", + sc->sc_dev.dv_xname, err); + + hpcdma_sglist_create(dsc, wsc->sc_dmamap); + wsc->sc_flags |= WDSC_DMA_MAPLOADED; + + if (datain) { + dsc->sc_dmacmd = + wsc->sc_hpcdma.hpc->scsi_dma_datain_cmd; + dsc->sc_flags |= HPCDMA_READ; + } else { + dsc->sc_dmacmd = + wsc->sc_hpcdma.hpc->scsi_dma_dataout_cmd; + dsc->sc_flags &= ~HPCDMA_READ; + } + } + return count; +} + +/* + * Prime the hardware for the next DMA transfer + */ +int +wdsc_dmago(struct wd33c93_softc *sc) +{ + struct wdsc_softc *wsc = (struct wdsc_softc *)sc; + struct hpc_dma_softc *dsc = &wsc->sc_hpcdma; + + if (dsc->sc_dlen == 0) + return 0; + + KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0); + KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED)); + + wsc->sc_flags |= WDSC_DMA_ACTIVE; + + bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap, + 0, wsc->sc_dmamap->dm_mapsize, + (dsc->sc_flags & HPCDMA_READ) ? + BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); + + hpcdma_cntl(dsc, dsc->sc_dmacmd); /* Thunderbirds are go! */ + + return wsc->sc_dmamap->dm_mapsize; +} + +/* + * Stop DMA and unload active DMA maps + */ +void +wdsc_dmastop(struct wd33c93_softc *sc) +{ + struct wdsc_softc *wsc = (struct wdsc_softc *)sc; + struct hpc_dma_softc *dsc = &wsc->sc_hpcdma; + + if (wsc->sc_flags & WDSC_DMA_ACTIVE) { + if (dsc->sc_flags & HPCDMA_READ) + hpcdma_flush(dsc); + hpcdma_cntl(dsc, 0); /* Stop DMA */ + bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap, + 0, wsc->sc_dmamap->dm_mapsize, + (dsc->sc_flags & HPCDMA_READ) ? + BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); + } + if (wsc->sc_flags & WDSC_DMA_MAPLOADED) + bus_dmamap_unload(wsc->sc_dmat, wsc->sc_dmamap); + wsc->sc_flags &= ~(WDSC_DMA_ACTIVE | WDSC_DMA_MAPLOADED); +} + +/* + * Reset the controller. + */ +void +wdsc_reset(struct wd33c93_softc *sc) +{ + struct wdsc_softc *wsc = (struct wdsc_softc *)sc; + struct hpc_dma_softc *dsc = &wsc->sc_hpcdma; + + hpcdma_reset(dsc); +} diff --git a/sys/arch/sgi/hpc/z8530sc.c b/sys/arch/sgi/hpc/z8530sc.c new file mode 100644 index 00000000000..fbec53846b4 --- /dev/null +++ b/sys/arch/sgi/hpc/z8530sc.c @@ -0,0 +1,409 @@ +/* $OpenBSD: z8530sc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: z8530sc.c,v 1.30 2009/05/22 03:51:30 mrg Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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: + * 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. + * 3. 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. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * + * 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: + * 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. + * 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. + * 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. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Zilog Z8530 Dual UART driver (common part) + * + * This file contains the machine-independent parts of the + * driver common to tty and keyboard/mouse sub-drivers. + */ + +#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/tty.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> + +#include <dev/ic/z8530reg.h> +#include <machine/z8530var.h> + +void +zs_break(struct zs_chanstate *cs, int set) +{ + + if (set) { + cs->cs_preg[5] |= ZSWR5_BREAK; + cs->cs_creg[5] |= ZSWR5_BREAK; + } else { + cs->cs_preg[5] &= ~ZSWR5_BREAK; + cs->cs_creg[5] &= ~ZSWR5_BREAK; + } + zs_write_reg(cs, 5, cs->cs_creg[5]); +} + + +/* + * drain on-chip fifo + */ +void +zs_iflush(struct zs_chanstate *cs) +{ + uint8_t c, rr0, rr1; + int i; + + /* + * Count how many times we loop. Some systems, such as some + * Apple PowerBooks, claim to have SCC's which they really don't. + */ + for (i = 0; i < 32; i++) { + /* Is there input available? */ + rr0 = zs_read_csr(cs); + if ((rr0 & ZSRR0_RX_READY) == 0) + break; + + /* + * First read the status, because reading the data + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + } +} + + +/* + * Write the given register set to the given zs channel in the proper order. + * The channel must not be transmitting at the time. The receiver will + * be disabled for the time it takes to write all the registers. + * Call this with interrupts disabled. + */ +void +zs_loadchannelregs(struct zs_chanstate *cs) +{ + uint8_t *reg, v; + + zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */ + +#if 1 + /* + * XXX: Is this really a good idea? + * XXX: Should go elsewhere! -gwr + */ + zs_iflush(cs); /* XXX */ +#endif + + if (cs->cs_ctl_chan != NULL) + v = ((cs->cs_ctl_chan->cs_creg[5] & (ZSWR5_RTS | ZSWR5_DTR)) != + (cs->cs_ctl_chan->cs_preg[5] & (ZSWR5_RTS | ZSWR5_DTR))); + else + v = 0; + + if (memcmp((void *)cs->cs_preg, (void *)cs->cs_creg, 16) == 0 && !v) + return; /* only change if values are different */ + + /* Copy "pending" regs to "current" */ + memcpy((void *)cs->cs_creg, (void *)cs->cs_preg, 16); + reg = cs->cs_creg; /* current regs */ + + /* disable interrupts */ + zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK); + + /* baud clock divisor, stop bits, parity */ + zs_write_reg(cs, 4, reg[4]); + + /* misc. TX/RX control bits */ + zs_write_reg(cs, 10, reg[10]); + + /* char size, enable (RX/TX) */ + zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE); + zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE); + + /* synchronous mode stuff */ + zs_write_reg(cs, 6, reg[6]); + zs_write_reg(cs, 7, reg[7]); + +#if 0 + /* + * Registers 2 and 9 are special because they are + * actually common to both channels, but must be + * programmed through channel A. The "zsc" attach + * function takes care of setting these registers + * and they should not be touched thereafter. + */ + /* interrupt vector */ + zs_write_reg(cs, 2, reg[2]); + /* master interrupt control */ + zs_write_reg(cs, 9, reg[9]); +#endif + + /* Shut down the BRG */ + zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA); + +#ifdef ZS_MD_SETCLK + /* Let the MD code setup any external clock. */ + ZS_MD_SETCLK(cs); +#endif /* ZS_MD_SETCLK */ + + /* clock mode control */ + zs_write_reg(cs, 11, reg[11]); + + /* baud rate (lo/hi) */ + zs_write_reg(cs, 12, reg[12]); + zs_write_reg(cs, 13, reg[13]); + + /* Misc. control bits */ + zs_write_reg(cs, 14, reg[14]); + + /* which lines cause status interrupts */ + zs_write_reg(cs, 15, reg[15]); + + /* + * Zilog docs recommend resetting external status twice at this + * point. Mainly as the status bits are latched, and the first + * interrupt clear might unlatch them to new values, generating + * a second interrupt request. + */ + zs_write_csr(cs, ZSM_RESET_STINT); + zs_write_csr(cs, ZSM_RESET_STINT); + + /* char size, enable (RX/TX)*/ + zs_write_reg(cs, 3, reg[3]); + zs_write_reg(cs, 5, reg[5]); + + /* Write the status bits on the alternate channel also. */ + if (cs->cs_ctl_chan != NULL) { + v = cs->cs_ctl_chan->cs_preg[5]; + cs->cs_ctl_chan->cs_creg[5] = v; + zs_write_reg(cs->cs_ctl_chan, 5, v); + } + + /* interrupt enables: RX, TX, STATUS */ + zs_write_reg(cs, 1, reg[1]); +} + +/* + * ZS hardware interrupt. Scan all ZS channels. NB: we know here that + * channels are kept in (A,B) pairs. + * + * Do just a little, then get out; set a software interrupt if more + * work is needed. + * + * We deliberately ignore the vectoring Zilog gives us, and match up + * only the number of `reset interrupt under service' operations, not + * the order. + */ +int +zsc_intr_hard(void *arg) +{ + struct zsc_softc *zsc = arg; + struct zs_chanstate *cs0, *cs1; + int handled; + uint8_t rr3; + + handled = 0; + + /* First look at channel A. */ + cs0 = zsc->zsc_cs[0]; + cs1 = zsc->zsc_cs[1]; + + /* + * We have to clear interrupt first to avoid a race condition, + * but it will be done in each MD handler. + */ + for (;;) { + /* Note: only channel A has an RR3 */ + rr3 = zs_read_reg(cs0, 3); + + if ((rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT | + ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) == 0) { + break; + } + handled = 1; + + /* First look at channel A. */ + if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) + zs_write_csr(cs0, ZSWR0_CLR_INTR); + + if (rr3 & ZSRR3_IP_A_RX) + (*cs0->cs_ops->zsop_rxint)(cs0); + if (rr3 & ZSRR3_IP_A_STAT) + (*cs0->cs_ops->zsop_stint)(cs0, 0); + if (rr3 & ZSRR3_IP_A_TX) + (*cs0->cs_ops->zsop_txint)(cs0); + + /* Now look at channel B. */ + if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) + zs_write_csr(cs1, ZSWR0_CLR_INTR); + + if (rr3 & ZSRR3_IP_B_RX) + (*cs1->cs_ops->zsop_rxint)(cs1); + if (rr3 & ZSRR3_IP_B_STAT) + (*cs1->cs_ops->zsop_stint)(cs1, 0); + if (rr3 & ZSRR3_IP_B_TX) + (*cs1->cs_ops->zsop_txint)(cs1); + } + + /* Note: caller will check cs_x->cs_softreq and DTRT. */ + return handled; +} + + +/* + * ZS software interrupt. Scan all channels for deferred interrupts. + */ +int +zsc_intr_soft(void *arg) +{ + struct zsc_softc *zsc = arg; + struct zs_chanstate *cs; + int rval, chan; + + rval = 0; + for (chan = 0; chan < 2; chan++) { + cs = zsc->zsc_cs[chan]; + + /* + * The softint flag can be safely cleared once + * we have decided to call the softint routine. + * (No need to do splzs() first.) + */ + if (cs->cs_softreq) { + cs->cs_softreq = 0; + (*cs->cs_ops->zsop_softint)(cs); + rval++; + } + } + return (rval); +} + +/* + * Provide a null zs "ops" vector. + */ + +static void zsnull_rxint (struct zs_chanstate *); +static void zsnull_stint (struct zs_chanstate *, int); +static void zsnull_txint (struct zs_chanstate *); +static void zsnull_softint(struct zs_chanstate *); + +static void +zsnull_rxint(struct zs_chanstate *cs) +{ + + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +static void +zsnull_stint(struct zs_chanstate *cs, int force) +{ + + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +static void +zsnull_txint(struct zs_chanstate *cs) +{ + + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +static void +zsnull_softint(struct zs_chanstate *cs) +{ + + zs_write_reg(cs, 1, 0); + zs_write_reg(cs, 15, 0); +} + +struct zsops zsops_null = { + zsnull_rxint, /* receive char available */ + zsnull_stint, /* external/status */ + zsnull_txint, /* xmit buffer empty */ + zsnull_softint, /* process software interrupt */ +}; diff --git a/sys/arch/sgi/hpc/z8530sc.h b/sys/arch/sgi/hpc/z8530sc.h new file mode 100644 index 00000000000..d4b707ad518 --- /dev/null +++ b/sys/arch/sgi/hpc/z8530sc.h @@ -0,0 +1,199 @@ +/* $OpenBSD: z8530sc.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: z8530sc.h,v 1.26 2009/05/22 03:51:30 mrg Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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: + * 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. + * 3. 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. + * + * @(#)zsvar.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * + * 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: + * 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. + * 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. + * 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. + * + * @(#)zsvar.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Function vector - per channel + */ +struct zs_chanstate; +struct zsops { + void (*zsop_rxint)(struct zs_chanstate *); + /* receive char available */ + void (*zsop_stint)(struct zs_chanstate *, int); + /* external/status */ + void (*zsop_txint)(struct zs_chanstate *); + /* xmit buffer empty */ + void (*zsop_softint)(struct zs_chanstate *); + /* process software interrupt */ +}; + +extern struct zsops zsops_null; + + +/* + * Software state, per zs channel. + */ +struct zs_chanstate { + + /* Pointers to the device registers. */ + volatile uint8_t *cs_reg_csr; /* ctrl, status, and reg. number. */ + volatile uint8_t *cs_reg_data; /* data or numbered register */ + + int cs_channel; /* sub-unit number */ + void *cs_private; /* sub-driver data pointer */ + struct zsops *cs_ops; + + int cs_brg_clk; /* BAUD Rate Generator clock + * (usually PCLK / 16) */ + int cs_defspeed; /* default baud rate */ + int cs_defcflag; /* default cflag */ + + /* + * We must keep a copy of the write registers as they are + * mostly write-only and we sometimes need to set and clear + * individual bits (e.g., in WR3). Not all of these are + * needed but 16 bytes is cheap and this makes the addressing + * simpler. Unfortunately, we can only write to some registers + * when the chip is not actually transmitting, so whenever + * we are expecting a `transmit done' interrupt the preg array + * is allowed to `get ahead' of the current values. In a + * few places we must change the current value of a register, + * rather than (or in addition to) the pending value; for these + * cs_creg[] contains the current value. + */ + uint8_t cs_creg[16]; /* current values */ + uint8_t cs_preg[16]; /* pending values */ + int cs_heldchange; /* change pending (creg != preg) */ + + uint8_t cs_rr0; /* last rr0 processed */ + uint8_t cs_rr0_delta; /* rr0 changes at status intr. */ + uint8_t cs_rr0_mask; /* rr0 bits that stop output */ + uint8_t cs_rr0_dcd; /* which bit to read as DCD */ + uint8_t cs_rr0_cts; /* which bit to read as CTS */ + uint8_t cs_rr0_pps; /* which bit to use for PPS */ + /* the above is set only while CRTSCTS is enabled. */ + + uint8_t cs_wr5_dtr; /* which bit to write as DTR */ + uint8_t cs_wr5_rts; /* which bit to write as RTS */ + /* the above is set only while CRTSCTS is enabled. */ + + volatile uint8_t cs_softreq; /* need soft interrupt call */ + char cs_cua; /* CUA mode flag */ + + /* + * For strange systems that have oddly wired serial ports, we + * provide a pointer to the channel state of the port that has + * our status lines on it. + */ + struct zs_chanstate *cs_ctl_chan; + + /* power management hooks */ + int (*enable)(struct zs_chanstate *); + void (*disable)(struct zs_chanstate *); + int enabled; + + /* MD code might define a larger variant of this. */ +}; + +struct consdev; +struct zsc_attach_args { + int channel; /* two serial channels per zsc */ + int hwflags; /* see definitions below */ + /* `consdev' is only valid if ZS_HWFLAG_USE_CONSDEV is set */ + struct consdev *consdev; +}; + +/* In case of split console devices, use these: */ +#define ZS_HWFLAG_CONSOLE_INPUT 1 +#define ZS_HWFLAG_CONSOLE_OUTPUT 2 +#define ZS_HWFLAG_CONSOLE \ + (ZS_HWFLAG_CONSOLE_INPUT | ZS_HWFLAG_CONSOLE_OUTPUT) +#define ZS_HWFLAG_NO_DCD 4 /* Ignore the DCD bit */ +#define ZS_HWFLAG_NO_CTS 8 /* Ignore the CTS bit */ +#define ZS_HWFLAG_RAW 16 /* advise raw mode */ +#define ZS_HWFLAG_USE_CONSDEV 32 /* Use console ops from `consdev' */ +#define ZS_HWFLAG_NORESET 64 /* Don't reset at attach time */ + +extern int zs_major; + +int zsc_intr_soft(void *); +int zsc_intr_hard(void *); + +void zs_abort(struct zs_chanstate *); +void zs_break(struct zs_chanstate *, int); +void zs_iflush(struct zs_chanstate *); +void zs_loadchannelregs(struct zs_chanstate *); +int zs_set_speed(struct zs_chanstate *, int); +int zs_set_modes(struct zs_chanstate *, int); diff --git a/sys/arch/sgi/hpc/z8530tty.c b/sys/arch/sgi/hpc/z8530tty.c new file mode 100644 index 00000000000..4108ed6ea10 --- /dev/null +++ b/sys/arch/sgi/hpc/z8530tty.c @@ -0,0 +1,1663 @@ +/* $OpenBSD: z8530tty.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: z8530tty.c,v 1.128 2011/04/24 16:27:00 rmind Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999 + * Charles M. Hannum. 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 Charles M. Hannum. + * 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) 1992, 1993 + * The Regents of the University of California. 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: + * 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. + * 3. 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. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * + * 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: + * 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. + * 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. + * 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. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Zilog Z8530 Dual UART driver (tty interface) + * + * This is the "slave" driver that will be attached to + * the "zsc" driver for plain "tty" async. serial lines. + * + * Credits, history: + * + * The original version of this code was the sparc/dev/zs.c driver + * as distributed with the Berkeley 4.4 Lite release. Since then, + * Gordon Ross reorganized the code into the current parent/child + * driver scheme, separating the Sun keyboard and mouse support + * into independent child drivers. + * + * RTS/CTS flow-control support was a collaboration of: + * Gordon Ross <gwr@NetBSD.org>, + * Bill Studenmund <wrstuden@loki.stanford.edu> + * Ian Dall <Ian.Dall@dsto.defence.gov.au> + * + * The driver was massively overhauled in November 1997 by Charles Hannum, + * fixing *many* bugs, and substantially improving performance. + */ + +#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> +#include <sys/tty.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> + +#include <dev/ic/z8530reg.h> +#include <machine/z8530var.h> + +#include <dev/cons.h> + +/* + * How many input characters we can buffer. + * The port-specific var.h may override this. + * Note: must be a power of two! + */ +#ifndef ZSTTY_RING_SIZE +#define ZSTTY_RING_SIZE 2048 +#endif + +struct cfdriver zstty_cd = { + NULL, "zstty", DV_TTY +}; + +/* + * Make this an option variable one can patch. + * But be warned: this must be a power of 2! + */ +u_int zstty_rbuf_size = ZSTTY_RING_SIZE; + +/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */ +u_int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE * 1) / 4; +u_int zstty_rbuf_lowat = (ZSTTY_RING_SIZE * 3) / 4; + +struct zstty_softc { + struct device zst_dev; /* required first: base device */ + struct tty *zst_tty; + struct zs_chanstate *zst_cs; + + struct timeout zst_diag_ch; + + u_int zst_overflows, + zst_floods, + zst_errors; + + int zst_hwflags, /* see z8530var.h */ + zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */ + + u_int zst_r_hiwat, + zst_r_lowat; + uint8_t *volatile zst_rbget, + *volatile zst_rbput; + volatile u_int zst_rbavail; + uint8_t *zst_rbuf, + *zst_ebuf; + + /* + * The transmit byte count and address are used for pseudo-DMA + * output in the hardware interrupt code. PDMA can be suspended + * to get pending changes done; heldtbc is used for this. It can + * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state. + */ + uint8_t *zst_tba; /* transmit buffer address */ + u_int zst_tbc, /* transmit byte count */ + zst_heldtbc; /* held tbc while xmission stopped */ + + /* Flags to communicate with zstty_softint() */ + volatile uint8_t zst_rx_flags, /* receiver blocked */ +#define RX_TTY_BLOCKED 0x01 +#define RX_TTY_OVERFLOWED 0x02 +#define RX_IBUF_BLOCKED 0x04 +#define RX_IBUF_OVERFLOWED 0x08 +#define RX_ANY_BLOCK 0x0f + zst_tx_busy, /* working on an output chunk */ + zst_tx_done, /* done with one output chunk */ + zst_tx_stopped, /* H/W level stop (lost CTS) */ + zst_st_check, /* got a status interrupt */ + zst_rx_ready; + + /* PPS signal on DCD, with or without inkernel clock disciplining */ + uint8_t zst_ppsmask; /* pps signal mask */ + uint8_t zst_ppsassert; /* pps leading edge */ + uint8_t zst_ppsclear; /* pps trailing edge */ +}; + +/* Definition of the driver for autoconfig. */ +int zstty_match(struct device *, void *, void *); +void zstty_attach(struct device *, struct device *, void *); + +const struct cfattach zstty_ca = { + sizeof(struct zstty_softc), zstty_match, zstty_attach +}; + +cdev_decl(zs); + +struct zsops zsops_tty; + +void zs_shutdown(struct zstty_softc *); +void zsstart(struct tty *); +int zsparam(struct tty *, struct termios *); +void zs_modem(struct zstty_softc *, int); +void tiocm_to_zs(struct zstty_softc *, u_long, int); +int zs_to_tiocm(struct zstty_softc *); +int zshwiflow(struct tty *, int); +void zs_hwiflow(struct zstty_softc *); +void zs_maskintr(struct zstty_softc *); + +struct zstty_softc *zs_device_lookup(struct cfdriver *, int); + +/* Low-level routines. */ +void zstty_rxint (struct zs_chanstate *); +void zstty_stint (struct zs_chanstate *, int); +void zstty_txint (struct zs_chanstate *); +void zstty_softint(struct zs_chanstate *); +void zstty_diag(void *); + +#define ZSUNIT(x) (minor(x) & 0x7f) +#define ZSDIALOUT(x) (minor(x) & 0x80) + +struct zstty_softc * +zs_device_lookup(struct cfdriver *cf, int unit) +{ + return (struct zstty_softc *)device_lookup(cf, unit); +} + +/* + * zstty_match: how is this zs channel configured? + */ +int +zstty_match(struct device *parent, void *vcf, void *aux) +{ + struct cfdata *cf = vcf; + struct zsc_attach_args *args = aux; + + /* Exact match is better than wildcard. */ + if (cf->cf_loc[0] == args->channel) + return 2; + + /* This driver accepts wildcard. */ + if (cf->cf_loc[0] == -1) + return 1; + + return 0; +} + +void +zstty_attach(struct device *parent, struct device *self, void *aux) +{ + struct zsc_softc *zsc = (struct zsc_softc *)parent; + struct zstty_softc *zst = (struct zstty_softc *)self; + struct cfdata *cf = self->dv_cfdata; + struct zsc_attach_args *args = aux; + struct zs_chanstate *cs; + struct tty *tp; + int channel, s, tty_unit; + dev_t dev; + const char *i, *o; + int dtr_on; + int resetbit; + + timeout_set(&zst->zst_diag_ch, zstty_diag, zst); + + tty_unit = zst->zst_dev.dv_unit; + channel = args->channel; + cs = zsc->zsc_cs[channel]; + cs->cs_private = zst; + cs->cs_ops = &zsops_tty; + + zst->zst_cs = cs; + zst->zst_swflags = cf->cf_flags; /* softcar, etc. */ + zst->zst_hwflags = args->hwflags; + dev = makedev(zs_major, tty_unit); + + if (zst->zst_swflags) + printf(" flags 0x%x", zst->zst_swflags); + + /* + * Check whether we serve as a console device. + * XXX - split console input/output channels aren't + * supported yet on /dev/console + */ + i = o = NULL; + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) { + i = " input"; + if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { + args->consdev->cn_dev = dev; + cn_tab->cn_pollc = args->consdev->cn_pollc; + cn_tab->cn_getc = args->consdev->cn_getc; + } + cn_tab->cn_dev = dev; + } + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) { + o = " output"; + if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { + cn_tab->cn_putc = args->consdev->cn_putc; + } + cn_tab->cn_dev = dev; + } + if (i != NULL || o != NULL) + printf(": console%s", i ? (o ? "" : i) : o); + +#ifdef KGDB + if (zs_check_kgdb(cs, dev)) { + /* + * Allow kgdb to "take over" this port. Returns true + * if this serial port is in-use by kgdb. + */ + printf(" (kgdb)\n"); + /* + * This is the kgdb port (exclusive use) + * so skip the normal attach code. + */ + return; + } +#endif + + printf("\n"); + + tp = ttymalloc(0); + tp->t_dev = dev; + tp->t_oproc = zsstart; + tp->t_param = zsparam; + tp->t_hwiflow = zshwiflow; + + zst->zst_tty = tp; + zst->zst_rbuf = malloc(zstty_rbuf_size << 1, M_DEVBUF, M_WAITOK); + zst->zst_ebuf = zst->zst_rbuf + (zstty_rbuf_size << 1); + /* Disable the high water mark. */ + zst->zst_r_hiwat = 0; + zst->zst_r_lowat = 0; + zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; + zst->zst_rbavail = zstty_rbuf_size; + + /* if there are no enable/disable functions, assume the device + is always enabled */ + if (!cs->enable) + cs->enabled = 1; + + /* + * Hardware init + */ + dtr_on = 0; + resetbit = 0; + if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + /* Call zsparam similar to open. */ + struct termios t; + + /* Wait a while for previous console output to complete */ + DELAY(10000); + + /* Setup the "new" parameters in t. */ + t.c_ispeed = 0; + t.c_ospeed = cs->cs_defspeed; + t.c_cflag = cs->cs_defcflag; + + s = splzs(); + + /* + * Turn on receiver and status interrupts. + * We defer the actual write of the register to zsparam(), + * but we must make sure status interrupts are turned on by + * the time zsparam() reads the initial rr0 state. + */ + SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + + splx(s); + + /* Make sure zsparam will see changes. */ + tp->t_ospeed = 0; + (void)zsparam(tp, &t); + + /* Make sure DTR is on now. */ + dtr_on = 1; + } else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) { + /* Not the console; may need reset. */ + resetbit = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; + } + + s = splzs(); + if (resetbit) + zs_write_reg(cs, 9, resetbit); + zs_modem(zst, dtr_on); + splx(s); +} + + +/* + * Return pointer to our tty. + */ +struct tty * +zstty(dev_t dev) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + + return (zst->zst_tty); +} + + +void +zs_shutdown(struct zstty_softc *zst) +{ + struct zs_chanstate *cs = zst->zst_cs; + struct tty *tp = zst->zst_tty; + int s; + + s = splzs(); + + /* If we were asserting flow control, then deassert it. */ + SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + + /* Clear any break condition set with TIOCSBRK. */ + zs_break(cs, 0); + + /* Turn off PPS capture on last close. */ + zst->zst_ppsmask = 0; + + /* + * Hang up if necessary. Wait a bit, so the other side has time to + * notice even if we immediately open the port again. + */ + if (ISSET(tp->t_cflag, HUPCL) || ISSET(tp->t_state, TS_WOPEN)) { + zs_modem(zst, 0); + /* hold low for 1 second */ + (void)tsleep(cs, TTIPRI, ttclos, hz); + } + + /* Turn off interrupts if not the console. */ + if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + + /* Call the power management hook. */ + if (cs->disable) { +#ifdef DIAGNOSTIC + if (!cs->enabled) + panic("%s: not enabled?", __func__); +#endif + (*cs->disable)(zst->zst_cs); + } + + splx(s); +} + +/* + * Open a zs serial (tty) port. + */ +int +zsopen(dev_t dev, int flags, int mode, struct proc *p) +{ + struct zstty_softc *zst; + struct zs_chanstate *cs; + struct tty *tp; + int s, s2; + int error; + + zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + if (zst == NULL) + return (ENXIO); + + tp = zst->zst_tty; + cs = zst->zst_cs; + + /* If KGDB took the line, then tp==NULL */ + if (tp == NULL) + return (EBUSY); + + if (ISSET(tp->t_state, TS_ISOPEN) && + ISSET(tp->t_state, TS_XCLUDE) && + suser(p, 0) != 0) + return (EBUSY); + + s = spltty(); + + /* + * Do the following iff this is a first open. + */ + if (!ISSET(tp->t_state, TS_ISOPEN)) { + struct termios t; + + tp->t_dev = dev; + + /* Call the power management hook. */ + if (cs->enable) { + if ((*cs->enable)(cs)) { + splx(s); + printf("%s: device enable failed\n", + zst->zst_dev.dv_xname); + return (EIO); + } + } + + /* + * Initialize the termios status to the defaults. Add in the + * sticky bits from TIOCSFLAGS. + */ + t.c_ispeed = 0; + t.c_ospeed = cs->cs_defspeed; + t.c_cflag = cs->cs_defcflag; + if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL)) + SET(t.c_cflag, CLOCAL); + if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS)) + SET(t.c_cflag, CRTSCTS); + if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF)) + SET(t.c_cflag, MDMBUF); + + s2 = splzs(); + + /* + * Turn on receiver and status interrupts. + * We defer the actual write of the register to zsparam(), + * but we must make sure status interrupts are turned on by + * the time zsparam() reads the initial rr0 state. + */ + SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + + /* Clear PPS capture state on first open. */ + zst->zst_ppsmask = 0; + + splx(s2); + + /* Make sure zsparam will see changes. */ + tp->t_ospeed = 0; + (void)zsparam(tp, &t); + + /* + * Note: zsparam has done: cflag, ispeed, ospeed + * so we just need to do: iflag, oflag, lflag, cc + * For "raw" mode, just leave all zeros. + */ + if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_lflag = TTYDEF_LFLAG; + } else { + tp->t_iflag = 0; + tp->t_oflag = 0; + tp->t_lflag = 0; + } + ttychars(tp); + ttsetwater(tp); + + if (ZSDIALOUT(dev)) + SET(tp->t_state, TS_CARR_ON); + else + CLR(tp->t_state, TS_CARR_ON); + + s2 = splzs(); + + /* Clear the input ring, and unblock. */ + zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; + zst->zst_rbavail = zstty_rbuf_size; + zs_iflush(cs); + CLR(zst->zst_rx_flags, RX_ANY_BLOCK); + zs_hwiflow(zst); + + splx(s2); + } + + if (ZSDIALOUT(dev)) { + if (ISSET(tp->t_state, TS_ISOPEN)) { + /* someone already is dialed in... */ + splx(s); + return EBUSY; + } + cs->cs_cua = 1; + } + + error = 0; + /* wait for carrier if necessary */ + if (ISSET(flags, O_NONBLOCK)) { + if (!ZSDIALOUT(dev) && cs->cs_cua) { + /* Opening TTY non-blocking... but the CUA is busy */ + error = EBUSY; + } + } else + while (cs->cs_cua || + (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON))) { + int rr0; + + error = 0; + SET(tp->t_state, TS_WOPEN); + + if (!ZSDIALOUT(dev) && !cs->cs_cua) { + /* + * Turn on DTR. We must always do this on non-CUA + * devices, even if carrier is not present, because + * otherwise we'd have to use TIOCSDTR immediately + * after setting CLOCAL, which applications do not + * expect. We always assert DTR while the device is + * open unless explicitly requested to deassert it. + */ + s2 = splzs(); + zs_modem(zst, 1); + rr0 = zs_read_csr(cs); + splx(s2); + + /* loop, turning on the device, until carrier present */ + if (ISSET(rr0, ZSRR0_DCD) || + ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR)) + SET(tp->t_state, TS_CARR_ON); + } + + if ((ISSET(tp->t_cflag, CLOCAL) || + ISSET(tp->t_state, TS_CARR_ON)) && !cs->cs_cua) + break; + + error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, + ttopen, 0); + + if (!ZSDIALOUT(dev) && cs->cs_cua && error == EINTR) { + error = 0; + continue; + } + + if (error) { + if (!ISSET(tp->t_state, TS_ISOPEN)) { + s2 = splzs(); + zs_modem(zst, 0); + splx(s2); + CLR(tp->t_state, TS_WOPEN); + ttwakeup(tp); + } + if (ZSDIALOUT(dev)) + cs->cs_cua = 0; + CLR(tp->t_state, TS_WOPEN); + break; + } + if (!ZSDIALOUT(dev) && cs->cs_cua) + continue; + } + + splx(s); + + if (error == 0) + error = ((*linesw[tp->t_line].l_open)(dev, tp, p)); + if (error) + goto bad; + + return (0); + +bad: + if (!ISSET(tp->t_state, TS_ISOPEN)) { + /* + * We failed to open the device, and nobody else had it opened. + * Clean up the state as appropriate. + */ + zs_shutdown(zst); + } + + return (error); +} + +/* + * Close a zs serial port. + */ +int +zsclose(dev_t dev, int flags, int mode, struct proc *p) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct zs_chanstate *cs = zst->zst_cs; + struct tty *tp = zst->zst_tty; + int s; + + /* XXX This is for cons.c. */ + if (!ISSET(tp->t_state, TS_ISOPEN)) + return 0; + + (*linesw[tp->t_line].l_close)(tp, flags, p); + + s = spltty(); + cs->cs_cua = 0; + ttyclose(tp); + splx(s); + + if (!ISSET(tp->t_state, TS_ISOPEN)) { + /* + * Although we got a last close, the device may still be in + * use; e.g. if this was the dialout node, and there are still + * processes waiting for carrier on the non-dialout node. + */ + zs_shutdown(zst); + } + + return (0); +} + +/* + * Read/write zs serial port. + */ +int +zsread(dev_t dev, struct uio *uio, int flags) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct tty *tp = zst->zst_tty; + + return (*linesw[tp->t_line].l_read)(tp, uio, flags); +} + +int +zswrite(dev_t dev, struct uio *uio, int flags) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct tty *tp = zst->zst_tty; + + return (*linesw[tp->t_line].l_write)(tp, uio, flags); +} + +int +zsioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct zs_chanstate *cs = zst->zst_cs; + struct tty *tp = zst->zst_tty; + int error; + int s; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return (error); + + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return (error); + +#ifdef ZS_MD_IOCTL + error = ZS_MD_IOCTL; + if (error >= 0) + return (error); +#endif /* ZS_MD_IOCTL */ + + error = 0; + + s = splzs(); + + switch (cmd) { + case TIOCSBRK: + zs_break(cs, 1); + break; + + case TIOCCBRK: + zs_break(cs, 0); + break; + + case TIOCGFLAGS: + *(int *)data = zst->zst_swflags; + break; + + case TIOCSFLAGS: + error = suser(p, 0); + if (error) + break; + zst->zst_swflags = *(int *)data; + break; + + case TIOCSDTR: + zs_modem(zst, 1); + break; + + case TIOCCDTR: + zs_modem(zst, 0); + break; + + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + tiocm_to_zs(zst, cmd, *(int *)data); + break; + + case TIOCMGET: + *(int *)data = zs_to_tiocm(zst); + break; + + default: + error = ENOTTY; + break; + } + + splx(s); + + return (error); +} + +/* + * Start or restart transmission. + */ +void +zsstart(struct tty *tp) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); + struct zs_chanstate *cs = zst->zst_cs; + u_char *tba; + int tbc; + int s; + + s = spltty(); + if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) + goto out; + if (zst->zst_tx_stopped) + goto out; + + ttwakeupwr(tp); + if (tp->t_outq.c_cc == 0) + goto out; + + /* Grab the first contiguous region of buffer space. */ + tba = tp->t_outq.c_cf; + tbc = ndqb(&tp->t_outq, 0); + + (void)splzs(); + + zst->zst_tba = tba; + zst->zst_tbc = tbc; + SET(tp->t_state, TS_BUSY); + zst->zst_tx_busy = 1; + + /* Enable transmit completion interrupts if necessary. */ + if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) { + SET(cs->cs_preg[1], ZSWR1_TIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + + /* Output the first character of the contiguous buffer. */ + zs_write_data(cs, *zst->zst_tba); + zst->zst_tbc--; + zst->zst_tba++; + +out: + splx(s); +} + +/* + * Stop output, e.g., for ^S or output flush. + */ +int +zsstop(struct tty *tp, int flag) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); + int s; + + s = splzs(); + if (ISSET(tp->t_state, TS_BUSY)) { + /* Stop transmitting at the next chunk. */ + zst->zst_tbc = 0; + zst->zst_heldtbc = 0; + if (!ISSET(tp->t_state, TS_TTSTOP)) + SET(tp->t_state, TS_FLUSH); + } + splx(s); + return 0; +} + +/* + * Set ZS tty parameters from termios. + * XXX - Should just copy the whole termios after + * making sure all the changes could be done. + */ +int +zsparam(struct tty *tp, struct termios *t) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); + struct zs_chanstate *cs = zst->zst_cs; + int ospeed; + tcflag_t cflag; + uint8_t tmp3, tmp4, tmp5; + int s, error; + + ospeed = t->c_ospeed; + cflag = t->c_cflag; + + /* Check requested parameters. */ + if (ospeed < 0) + return (EINVAL); + if (t->c_ispeed && t->c_ispeed != ospeed) + return (EINVAL); + + /* + * For the console, always force CLOCAL and !HUPCL, so that the port + * is always active. + */ + if (ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR) || + ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + SET(cflag, CLOCAL); + CLR(cflag, HUPCL); + } + + /* + * Only whack the UART when params change. + * Some callers need to clear tp->t_ospeed + * to make sure initialization gets done. + */ + if (tp->t_ospeed == ospeed && + tp->t_cflag == cflag) + return (0); + + /* + * Call MD functions to deal with changed + * clock modes or H/W flow control modes. + * The BRG divisor is set now. (reg 12,13) + */ + error = zs_set_speed(cs, ospeed); + if (error) + return (error); + error = zs_set_modes(cs, cflag); + if (error) + return (error); + + /* + * Block interrupts so that state will not + * be altered until we are done setting it up. + * + * Initial values in cs_preg are set before + * our attach routine is called. The master + * interrupt enable is handled by zsc.c + * + */ + s = splzs(); + + /* + * Recalculate which status ints to enable. + */ + zs_maskintr(zst); + + /* Recompute character size bits. */ + tmp3 = cs->cs_preg[3]; + tmp5 = cs->cs_preg[5]; + CLR(tmp3, ZSWR3_RXSIZE); + CLR(tmp5, ZSWR5_TXSIZE); + switch (ISSET(cflag, CSIZE)) { + case CS5: + SET(tmp3, ZSWR3_RX_5); + SET(tmp5, ZSWR5_TX_5); + break; + case CS6: + SET(tmp3, ZSWR3_RX_6); + SET(tmp5, ZSWR5_TX_6); + break; + case CS7: + SET(tmp3, ZSWR3_RX_7); + SET(tmp5, ZSWR5_TX_7); + break; + case CS8: + SET(tmp3, ZSWR3_RX_8); + SET(tmp5, ZSWR5_TX_8); + break; + } + cs->cs_preg[3] = tmp3; + cs->cs_preg[5] = tmp5; + + /* + * Recompute the stop bits and parity bits. Note that + * zs_set_speed() may have set clock selection bits etc. + * in wr4, so those must preserved. + */ + tmp4 = cs->cs_preg[4]; + CLR(tmp4, ZSWR4_SBMASK | ZSWR4_PARMASK); + if (ISSET(cflag, CSTOPB)) + SET(tmp4, ZSWR4_TWOSB); + else + SET(tmp4, ZSWR4_ONESB); + if (!ISSET(cflag, PARODD)) + SET(tmp4, ZSWR4_EVENP); + if (ISSET(cflag, PARENB)) + SET(tmp4, ZSWR4_PARENB); + cs->cs_preg[4] = tmp4; + + /* And copy to tty. */ + tp->t_ispeed = 0; + tp->t_ospeed = ospeed; + tp->t_cflag = cflag; + + /* + * If nothing is being transmitted, set up new current values, + * else mark them as pending. + */ + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } + + /* + * If hardware flow control is disabled, turn off the buffer water + * marks and unblock any soft flow control state. Otherwise, enable + * the water marks. + */ + if (!ISSET(cflag, CHWFLOW)) { + zst->zst_r_hiwat = 0; + zst->zst_r_lowat = 0; + if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + } else { + zst->zst_r_hiwat = zstty_rbuf_hiwat; + zst->zst_r_lowat = zstty_rbuf_lowat; + } + + /* + * Force a recheck of the hardware carrier and flow control status, + * since we may have changed which bits we're looking at. + */ + zstty_stint(cs, 1); + + splx(s); + + /* + * If hardware flow control is disabled, unblock any hard flow control + * state. + */ + if (!ISSET(cflag, CHWFLOW)) { + if (zst->zst_tx_stopped) { + zst->zst_tx_stopped = 0; + zsstart(tp); + } + } + + zstty_softint(cs); + + return (0); +} + +/* + * Compute interrupt enable bits and set in the pending bits. Called both + * in zsparam() and when PPS (pulse per second timing) state changes. + * Must be called at splzs(). + */ +void +zs_maskintr(struct zstty_softc *zst) +{ + struct zs_chanstate *cs = zst->zst_cs; + uint8_t tmp15; + + cs->cs_rr0_mask = cs->cs_rr0_cts | cs->cs_rr0_dcd; + if (zst->zst_ppsmask != 0) + cs->cs_rr0_mask |= cs->cs_rr0_pps; + tmp15 = cs->cs_preg[15]; + if (ISSET(cs->cs_rr0_mask, ZSRR0_DCD)) + SET(tmp15, ZSWR15_DCD_IE); + else + CLR(tmp15, ZSWR15_DCD_IE); + if (ISSET(cs->cs_rr0_mask, ZSRR0_CTS)) + SET(tmp15, ZSWR15_CTS_IE); + else + CLR(tmp15, ZSWR15_CTS_IE); + cs->cs_preg[15] = tmp15; +} + + +/* + * Raise or lower modem control (DTR/RTS) signals. If a character is + * in transmission, the change is deferred. + * Called at splzs(). + */ +void +zs_modem(struct zstty_softc *zst, int onoff) +{ + struct zs_chanstate *cs = zst->zst_cs, *ccs; + + if (cs->cs_wr5_dtr == 0) + return; + + ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs); + + if (onoff) + SET(ccs->cs_preg[5], cs->cs_wr5_dtr); + else + CLR(ccs->cs_preg[5], cs->cs_wr5_dtr); + + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } +} + +/* + * Set modem bits. + * Called at splzs(). + */ +void +tiocm_to_zs(struct zstty_softc *zst, u_long how, int ttybits) +{ + struct zs_chanstate *cs = zst->zst_cs, *ccs; + uint8_t zsbits; + + ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs); + + zsbits = 0; + if (ISSET(ttybits, TIOCM_DTR)) + SET(zsbits, ZSWR5_DTR); + if (ISSET(ttybits, TIOCM_RTS)) + SET(zsbits, ZSWR5_RTS); + + switch (how) { + case TIOCMBIC: + CLR(ccs->cs_preg[5], zsbits); + break; + + case TIOCMBIS: + SET(ccs->cs_preg[5], zsbits); + break; + + case TIOCMSET: + CLR(ccs->cs_preg[5], ZSWR5_RTS | ZSWR5_DTR); + SET(ccs->cs_preg[5], zsbits); + break; + } + + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } +} + +/* + * Get modem bits. + * Called at splzs(). + */ +int +zs_to_tiocm(struct zstty_softc *zst) +{ + struct zs_chanstate *cs = zst->zst_cs, *ccs; + uint8_t zsbits; + int ttybits = 0; + + ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs); + + zsbits = ccs->cs_preg[5]; + if (ISSET(zsbits, ZSWR5_DTR)) + SET(ttybits, TIOCM_DTR); + if (ISSET(zsbits, ZSWR5_RTS)) + SET(ttybits, TIOCM_RTS); + + zsbits = cs->cs_rr0; + if (ISSET(zsbits, ZSRR0_DCD)) + SET(ttybits, TIOCM_CD); + if (ISSET(zsbits, ZSRR0_CTS)) + SET(ttybits, TIOCM_CTS); + + return (ttybits); +} + +/* + * Try to block or unblock input using hardware flow-control. + * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and + * if this function returns non-zero, the TS_TBLOCK flag will + * be set or cleared according to the "block" arg passed. + */ +int +zshwiflow(struct tty *tp, int block) +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); + struct zs_chanstate *cs = zst->zst_cs; + int s; + + if (cs->cs_wr5_rts == 0) + return (0); + + s = splzs(); + if (block) { + if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + SET(zst->zst_rx_flags, RX_TTY_BLOCKED); + zs_hwiflow(zst); + } + } else { + if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_TTY_BLOCKED); + zs_hwiflow(zst); + } + } + splx(s); + return (1); +} + +/* + * Internal version of zshwiflow + * Called at splzs() + */ +void +zs_hwiflow(struct zstty_softc *zst) +{ + struct zs_chanstate *cs = zst->zst_cs, *ccs; + + if (cs->cs_wr5_rts == 0) + return; + + ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs); + + if (ISSET(zst->zst_rx_flags, RX_ANY_BLOCK)) { + CLR(ccs->cs_preg[5], cs->cs_wr5_rts); + CLR(ccs->cs_creg[5], cs->cs_wr5_rts); + } else { + SET(ccs->cs_preg[5], cs->cs_wr5_rts); + SET(ccs->cs_creg[5], cs->cs_wr5_rts); + } + zs_write_reg(ccs, 5, ccs->cs_creg[5]); +} + + +/**************************************************************** + * Interface to the lower layer (zscc) + ****************************************************************/ + +#define integrate static inline +integrate void zstty_rxsoft(struct zstty_softc *, struct tty *); +integrate void zstty_txsoft(struct zstty_softc *, struct tty *); +integrate void zstty_stsoft(struct zstty_softc *, struct tty *); +void zstty_diag(void *); + +/* + * Receiver Ready interrupt. + * Called at splzs(). + */ +void +zstty_rxint(struct zs_chanstate *cs) +{ + struct zstty_softc *zst = cs->cs_private; + uint8_t *put, *end; + u_int cc; + uint8_t rr0, rr1, c; + + end = zst->zst_ebuf; + put = zst->zst_rbput; + cc = zst->zst_rbavail; + + while (cc > 0) { + /* + * First read the status, because reading the received char + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + + put[0] = c; + put[1] = rr1; + put += 2; + if (put >= end) + put = zst->zst_rbuf; + cc--; + + rr0 = zs_read_csr(cs); + if (!ISSET(rr0, ZSRR0_RX_READY)) + break; + } + + /* + * Current string of incoming characters ended because + * no more data was available or we ran out of space. + * Schedule a receive event if any data was received. + * If we're out of space, turn off receive interrupts. + */ + zst->zst_rbput = put; + zst->zst_rbavail = cc; + if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + + /* + * See if we are in danger of overflowing a buffer. If + * so, use hardware flow control to ease the pressure. + */ + if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) && + cc < zst->zst_r_hiwat) { + SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + + /* + * If we're out of space, disable receive interrupts + * until the queue has drained a bit. + */ + if (!cc) { + SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); + CLR(cs->cs_preg[1], ZSWR1_RIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } +} + +/* + * Transmitter Ready interrupt. + * Called at splzs(). + */ +void +zstty_txint(struct zs_chanstate *cs) +{ + struct zstty_softc *zst = cs->cs_private; + + zs_write_csr(cs, ZSWR0_RESET_TXINT); + + /* + * If we've delayed a parameter change, do it now, and restart + * output. + */ + if (cs->cs_heldchange) { + zs_loadchannelregs(cs); + cs->cs_heldchange = 0; + zst->zst_tbc = zst->zst_heldtbc; + zst->zst_heldtbc = 0; + } + + /* Output the next character in the buffer, if any. */ + if (zst->zst_tbc > 0) { + zs_write_data(cs, *zst->zst_tba); + zst->zst_tbc--; + zst->zst_tba++; + } else { + /* Disable transmit completion interrupts if necessary. */ + if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) { + CLR(cs->cs_preg[1], ZSWR1_TIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + if (zst->zst_tx_busy) { + zst->zst_tx_busy = 0; + zst->zst_tx_done = 1; + cs->cs_softreq = 1; + } + } +} + +#ifdef DDB +#include <ddb/db_var.h> +#define DB_CONSOLE db_console +#else +#define DB_CONSOLE 1 +#endif + +/* + * Status Change interrupt. + * Called at splzs(). + */ +void +zstty_stint(struct zs_chanstate *cs, int force) +{ + struct zstty_softc *zst = cs->cs_private; + struct tty *tp = zst->zst_tty; + uint8_t rr0, delta; + + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_STATUS); + + /* + * Check here for console break, so that we can abort + * even when interrupts are locking up the machine. + */ + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) && + ISSET(rr0, ZSRR0_BREAK) && DB_CONSOLE) + zs_abort(cs); + + if (!force) + delta = rr0 ^ cs->cs_rr0; + else + delta = cs->cs_rr0_mask; + + ttytstamp(tp, cs->cs_rr0 & ZSRR0_CTS, rr0 & ZSRR0_CTS, + cs->cs_rr0 & ZSRR0_DCD, rr0 & ZSRR0_DCD); + + cs->cs_rr0 = rr0; + + if (ISSET(delta, cs->cs_rr0_mask)) { + SET(cs->cs_rr0_delta, delta); + + /* + * Stop output immediately if we lose the output + * flow control signal or carrier detect. + */ + if (ISSET(~rr0, cs->cs_rr0_mask)) { + zst->zst_tbc = 0; + zst->zst_heldtbc = 0; + } + + zst->zst_st_check = 1; + cs->cs_softreq = 1; + } +} + +void +zstty_diag(void *arg) +{ + struct zstty_softc *zst = arg; + int overflows, floods; + int s; + + s = splzs(); + overflows = zst->zst_overflows; + zst->zst_overflows = 0; + floods = zst->zst_floods; + zst->zst_floods = 0; + zst->zst_errors = 0; + splx(s); + + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n", + zst->zst_dev.dv_xname, + overflows, overflows == 1 ? "" : "s", + floods, floods == 1 ? "" : "s"); +} + +integrate void +zstty_rxsoft(struct zstty_softc *zst, struct tty *tp) +{ + struct zs_chanstate *cs = zst->zst_cs; + int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint; + uint8_t *get, *end; + u_int cc, scc; + uint8_t rr1; + int code; + int s; + + end = zst->zst_ebuf; + get = zst->zst_rbget; + scc = cc = zstty_rbuf_size - zst->zst_rbavail; + + if (cc == zstty_rbuf_size) { + zst->zst_floods++; + if (zst->zst_errors++ == 0) + timeout_add_sec(&zst->zst_diag_ch, 60); + } + + /* If not yet open, drop the entire buffer content here */ + if (!ISSET(tp->t_state, TS_ISOPEN)) { + get += cc << 1; + if (get >= end) + get -= zstty_rbuf_size << 1; + cc = 0; + } + while (cc) { + code = get[0]; + rr1 = get[1]; + if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) { + if (ISSET(rr1, ZSRR1_DO)) { + zst->zst_overflows++; + if (zst->zst_errors++ == 0) + timeout_add_sec(&zst->zst_diag_ch, 60); + } + if (ISSET(rr1, ZSRR1_FE)) + SET(code, TTY_FE); + if (ISSET(rr1, ZSRR1_PE)) + SET(code, TTY_PE); + } + if ((*rint)(code, tp) == -1) { + /* + * The line discipline's buffer is out of space. + */ + if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + /* + * We're either not using flow control, or the + * line discipline didn't tell us to block for + * some reason. Either way, we have no way to + * know when there's more space available, so + * just drop the rest of the data. + */ + get += cc << 1; + if (get >= end) + get -= zstty_rbuf_size << 1; + cc = 0; + } else { + /* + * Don't schedule any more receive processing + * until the line discipline tells us there's + * space available (through comhwiflow()). + * Leave the rest of the data in the input + * buffer. + */ + SET(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + } + break; + } + get += 2; + if (get >= end) + get = zst->zst_rbuf; + cc--; + } + + if (cc != scc) { + zst->zst_rbget = get; + s = splzs(); + cc = zst->zst_rbavail += scc - cc; + /* Buffers should be ok again, release possible block. */ + if (cc >= zst->zst_r_lowat) { + if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); + SET(cs->cs_preg[1], ZSWR1_RIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + } + splx(s); + } +} + +integrate void +zstty_txsoft(struct zstty_softc *zst, struct tty *tp) +{ + int s; + + CLR(tp->t_state, TS_BUSY); + if (ISSET(tp->t_state, TS_FLUSH)) + CLR(tp->t_state, TS_FLUSH); + else { + s = splzs(); + ndflush(&tp->t_outq, (int)(zst->zst_tba - tp->t_outq.c_cf)); + splx(s); + } + (*linesw[tp->t_line].l_start)(tp); +} + +integrate void +zstty_stsoft(struct zstty_softc *zst, struct tty *tp) +{ + struct zs_chanstate *cs = zst->zst_cs; + uint8_t rr0, delta; + int s; + + s = splzs(); + rr0 = cs->cs_rr0; + delta = cs->cs_rr0_delta; + cs->cs_rr0_delta = 0; + splx(s); + + if (ISSET(delta, cs->cs_rr0_dcd)) { + /* + * Inform the tty layer that carrier detect changed. + */ + (void)(*linesw[tp->t_line].l_modem)(tp, ISSET(rr0, ZSRR0_DCD)); + } + + if (ISSET(delta, cs->cs_rr0_cts)) { + /* Block or unblock output according to flow control. */ + if (ISSET(rr0, cs->cs_rr0_cts)) { + zst->zst_tx_stopped = 0; + (*linesw[tp->t_line].l_start)(tp); + } else { + zst->zst_tx_stopped = 1; + } + } +} + +/* + * Software interrupt. Called at zssoft + * + * The main job to be done here is to empty the input ring + * by passing its contents up to the tty layer. The ring is + * always emptied during this operation, therefore the ring + * must not be larger than the space after "high water" in + * the tty layer, or the tty layer might drop our input. + * + * Note: an "input blockage" condition is assumed to exist if + * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set. + */ +void +zstty_softint(struct zs_chanstate *cs) +{ + struct zstty_softc *zst = cs->cs_private; + struct tty *tp = zst->zst_tty; + int s; + + s = spltty(); + + if (zst->zst_rx_ready) { + zst->zst_rx_ready = 0; + zstty_rxsoft(zst, tp); + } + + if (zst->zst_st_check) { + zst->zst_st_check = 0; + zstty_stsoft(zst, tp); + } + + if (zst->zst_tx_done) { + zst->zst_tx_done = 0; + zstty_txsoft(zst, tp); + } + + splx(s); +} + +struct zsops zsops_tty = { + zstty_rxint, /* receive char available */ + zstty_stint, /* external/status */ + zstty_txint, /* xmit buffer empty */ + zstty_softint, /* process software interrupt */ +}; diff --git a/sys/arch/sgi/hpc/zs.c b/sys/arch/sgi/hpc/zs.c new file mode 100644 index 00000000000..c8ce8b74102 --- /dev/null +++ b/sys/arch/sgi/hpc/zs.c @@ -0,0 +1,712 @@ +/* $OpenBSD: zs.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: zs.c,v 1.37 2011/02/20 07:59:50 matt Exp $ */ + +/*- + * Copyright (c) 1996, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross and Wayne Knowles + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Zilog Z8530 Dual UART driver (machine-dependent part) + * + * Runs two serial lines per chip using slave drivers. + * Plain tty/async lines use the zs_async slave. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/tty.h> +#include <sys/time.h> +#include <sys/syslog.h> + +#include <mips64/archtype.h> +#include <mips64/arcbios.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/z8530var.h> + +#include <dev/cons.h> + +#include <dev/ic/z8530reg.h> + +#include <sgi/hpc/hpcvar.h> +#include <sgi/hpc/hpcreg.h> +#include <sgi/localbus/intvar.h> + +/* + * Some warts needed by z8530tty.c - + * The default parity REALLY needs to be the same as the PROM uses, + * or you can not see messages done with printf during boot-up... + */ +int zs_def_cflag = (CREAD | CS8 | HUPCL); +int zs_major = 19; + +#define PCLK 3672000 /* PCLK pin input clock rate */ + +#ifndef ZS_DEFSPEED +#define ZS_DEFSPEED 9600 +#endif + +/* + * Define interrupt levels. + */ +#define ZSHARD_PRI 64 + +/* SGI shouldn't need ZS_DELAY() as recovery time is done in hardware? */ +#define ZS_DELAY() delay(3) + +/* The layout of this is hardware-dependent (padding, order). */ +struct zschan { + uint8_t pad1[3]; + volatile uint8_t zc_csr; /* ctrl,status, and indirect access */ + uint8_t pad2[3]; + volatile uint8_t zc_data; /* data */ +}; + +struct zsdevice { + struct zschan zs_chan_b; + struct zschan zs_chan_a; +}; + +/* Return the byte offset of element within a structure */ +#define OFFSET(struct_def, el) ((size_t)&((struct_def *)0)->el) + +#define ZS_CHAN_A OFFSET(struct zsdevice, zs_chan_a) +#define ZS_CHAN_B OFFSET(struct zsdevice, zs_chan_b) +#define ZS_REG_CSR 3 +#define ZS_REG_DATA 7 +static int zs_chan_offset[] = {ZS_CHAN_A, ZS_CHAN_B}; + +cons_decl(zs); +struct consdev zs_cn = { + zscnprobe, + zscninit, + zscngetc, + zscnputc, + zscnpollc, + NULL +}; + + +/* Flags from cninit() */ +static int zs_consunit = -1; +static int zs_conschan = -1; + +/* Default speed for all channels */ +static int zs_defspeed = ZS_DEFSPEED; + +static uint8_t zs_init_reg[16] = { + 0, /* 0: CMD (reset, etc.) */ + 0, /* 1: No interrupts yet. */ + ZSHARD_PRI, /* 2: IVECT */ + ZSWR3_RX_8 | ZSWR3_RX_ENABLE, + ZSWR4_CLK_X16 | ZSWR4_ONESB, + ZSWR5_TX_8 | ZSWR5_TX_ENABLE, + 0, /* 6: TXSYNC/SYNCLO */ + 0, /* 7: RXSYNC/SYNCHI */ + 0, /* 8: alias for data port */ + ZSWR9_MASTER_IE, + 0, /*10: Misc. TX/RX control bits */ + ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD | ZSWR11_TRXC_OUT_ENA, + BPS_TO_TCONST(PCLK/16, ZS_DEFSPEED), /*12: BAUDLO (default=9600) */ + 0, /*13: BAUDHI (default=9600) */ + ZSWR14_BAUD_ENA, + ZSWR15_BREAK_IE, +}; + + +/**************************************************************** + * Autoconfig + ****************************************************************/ + +/* Definition of the driver for autoconfig. */ +int zs_hpc_match(struct device *, void *, void *); +void zs_hpc_attach(struct device *, struct device *, void *); +int zs_print(void *, const char *name); + +struct cfdriver zs_cd = { + NULL, "zs", DV_TTY +}; + +struct cfattach zs_hpc_ca = { + sizeof(struct zsc_softc), zs_hpc_match, zs_hpc_attach +}; + +int zshard(void *); +void zssoft(void *); +struct zschan *zs_get_chan_addr(int, int); +int zs_getc(void *); +void zs_putc(void *, int); + +/* + * Is the zs chip present? + */ +int +zs_hpc_match(struct device *parent, void *vcf, void *aux) +{ + struct cfdata *cf = vcf; + struct hpc_attach_args *ha = aux; + + if (strcmp(ha->ha_name, cf->cf_driver->cd_name) == 0) + return (1); + + return (0); +} + +/* + * Attach a found zs. + * + * Match slave number to zs unit number, so that misconfiguration will + * not set up the keyboard as ttya, etc. + */ +void +zs_hpc_attach(struct device *parent, struct device *self, void *aux) +{ + struct zsc_softc *zsc = (void *)self; + struct hpc_attach_args *haa = aux; + struct zsc_attach_args zsc_args; + struct zs_chanstate *cs; + struct zs_channel *ch; + int zs_unit, channel, err, s; + + zsc->zsc_bustag = haa->ha_st; + if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh, + haa->ha_devoff, 0x10, + &zsc->zsc_base)) != 0) { + printf(": unable to map 85c30 registers, error = %d\n", + err); + return; + } + + zs_unit = zsc->zsc_dev.dv_unit; + printf("\n"); + + /* + * Initialize software state for each channel. + * + * Done in reverse order of channels since the first serial port + * is actually attached to the *second* channel, and vice versa. + * Doing it this way should force a 'zstty*' to attach zstty0 to + * channel 1 and zstty1 to channel 0. They couldn't have wired + * it up in a more sensible fashion, could they? + */ + for (channel = 1; channel >= 0; channel--) { + zsc_args.channel = channel; + ch = &zsc->zsc_cs_store[channel]; + cs = zsc->zsc_cs[channel] = (struct zs_chanstate *)ch; + + cs->cs_reg_csr = NULL; + cs->cs_reg_data = NULL; + cs->cs_channel = channel; + cs->cs_private = NULL; + cs->cs_ops = &zsops_null; + cs->cs_brg_clk = PCLK / 16; + + if (bus_space_subregion(zsc->zsc_bustag, zsc->zsc_base, + zs_chan_offset[channel], + sizeof(struct zschan), + &ch->cs_regs) != 0) { + printf("%s: cannot map regs\n", self->dv_xname); + return; + } + ch->cs_bustag = zsc->zsc_bustag; + + memcpy(cs->cs_creg, zs_init_reg, 16); + memcpy(cs->cs_preg, zs_init_reg, 16); + + /* If console, don't stomp speed, let zstty know */ + if (zs_unit == zs_consunit && channel == zs_conschan) { + zsc_args.consdev = &zs_cn; + zsc_args.hwflags = ZS_HWFLAG_CONSOLE; + cs->cs_defspeed = bios_consrate; + } else { + zsc_args.consdev = NULL; + zsc_args.hwflags = 0; + cs->cs_defspeed = zs_defspeed; + } + + cs->cs_defcflag = zs_def_cflag; + + /* Make these correspond to cs_defcflag (-crtscts) */ + cs->cs_rr0_dcd = ZSRR0_DCD; + cs->cs_rr0_cts = 0; + cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; + cs->cs_wr5_rts = 0; + + /* + * Clear the master interrupt enable. + * The INTENA is common to both channels, + * so just do it on the A channel. + */ + if (channel == 0) { + zs_write_reg(cs, 9, 0); + } + /* + * Look for a child driver for this channel. + * The child attach will setup the hardware. + */ + if (!config_found(self, (void *)&zsc_args, zs_print)) { + /* No sub-driver. Just reset it. */ + uint8_t reset = (channel == 0) ? + ZSWR9_A_RESET : ZSWR9_B_RESET; + + s = splhigh(); + zs_write_reg(cs, 9, reset); + splx(s); + } + } + + + zsc->sc_si = softintr_establish(SI_SOFTTTY, zssoft, zsc); + int2_intr_establish(haa->ha_irq, IPL_TTY, zshard, zsc, self->dv_xname); + + /* + * Set the master interrupt enable and interrupt vector. + * (common to both channels, do it on A) + */ + cs = zsc->zsc_cs[0]; + s = splhigh(); + /* interrupt vector */ + zs_write_reg(cs, 2, zs_init_reg[2]); + /* master interrupt control (enable) */ + zs_write_reg(cs, 9, zs_init_reg[9]); + splx(s); +} + +int +zs_print(void *aux, const char *name) +{ + struct zsc_attach_args *args = aux; + + if (name != NULL) + printf("%s: ", name); + + if (args->channel != -1) + printf(" channel %d", args->channel); + + return UNCONF; +} + +/* + * Our ZS chips all share a common, autovectored interrupt, + * so we have to look at all of them on each interrupt. + */ +int +zshard(void *arg) +{ + struct zsc_softc *zsc = arg; + int rr3, rval; + + rval = 0; + while ((rr3 = zsc_intr_hard(zsc))) { + rval |= rr3; + } + + if (zsc->zsc_cs[0]->cs_softreq || + zsc->zsc_cs[1]->cs_softreq) + softintr_schedule(zsc->sc_si); + + return rval; +} + +/* + * Similar scheme as for zshard (look at all of them) + */ +void +zssoft(void *arg) +{ + struct zsc_softc *zsc = arg; + int s; + + /* Make sure we call the tty layer at spltty. */ + s = spltty(); + (void) zsc_intr_soft(zsc); + splx(s); +} + + +/* + * MD functions for setting the baud rate and control modes. + */ +int +zs_set_speed(struct zs_chanstate *cs, int bps) +{ + int tconst, real_bps; + + if (bps == 0) + return (0); + +#ifdef DIAGNOSTIC + if (cs->cs_brg_clk == 0) + panic("zs_set_speed"); +#endif + + tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); + if (tconst < 0) + return (EINVAL); + + /* Convert back to make sure we can do it. */ + real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); + +#if 0 /* PCLK is too small, 9600bps really yields 9562 */ + /* XXX - Allow some tolerance here? */ + if (real_bps != bps) + return (EINVAL); +#endif + + cs->cs_preg[12] = tconst; + cs->cs_preg[13] = tconst >> 8; + + /* Caller will stuff the pending registers. */ + return (0); +} + +int +zs_set_modes(struct zs_chanstate *cs, int cflag) +{ + int s; + + /* + * Output hardware flow control on the chip is horrendous: + * if carrier detect drops, the receiver is disabled, and if + * CTS drops, the transmitter is stoped IN MID CHARACTER! + * Therefore, NEVER set the HFC bit, and instead use the + * status interrupt to detect CTS changes. + */ + s = splzs(); + cs->cs_rr0_pps = 0; + if ((cflag & (CLOCAL | MDMBUF)) != 0) { + cs->cs_rr0_dcd = 0; + if ((cflag & MDMBUF) == 0) + cs->cs_rr0_pps = ZSRR0_DCD; + } else + cs->cs_rr0_dcd = ZSRR0_DCD; + if ((cflag & CRTSCTS) != 0) { + cs->cs_wr5_dtr = ZSWR5_DTR; + cs->cs_wr5_rts = ZSWR5_RTS; + cs->cs_rr0_cts = ZSRR0_CTS; + } else if ((cflag & MDMBUF) != 0) { + cs->cs_wr5_dtr = 0; + cs->cs_wr5_rts = ZSWR5_DTR; + cs->cs_rr0_cts = ZSRR0_DCD; + } else { + cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; + cs->cs_wr5_rts = 0; + cs->cs_rr0_cts = 0; + } + splx(s); + + /* Caller will stuff the pending registers. */ + return (0); +} + + +/* + * Read or write the chip with suitable delays. + */ + +uint8_t +zs_read_reg(struct zs_chanstate *cs, uint8_t reg) +{ + uint8_t val; + struct zs_channel *zsc = (struct zs_channel *)cs; + + bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, reg); + ZS_DELAY(); + val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR); + ZS_DELAY(); + return val; +} + +void +zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val) +{ + struct zs_channel *zsc = (struct zs_channel *)cs; + + bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, reg); + ZS_DELAY(); + bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, val); + ZS_DELAY(); +} + +uint8_t +zs_read_csr(struct zs_chanstate *cs) +{ + struct zs_channel *zsc = (struct zs_channel *)cs; + uint8_t val; + + val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR); + ZS_DELAY(); + return val; +} + +void +zs_write_csr(struct zs_chanstate *cs, uint8_t val) +{ + struct zs_channel *zsc = (struct zs_channel *)cs; + + bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, val); + ZS_DELAY(); +} + +uint8_t +zs_read_data(struct zs_chanstate *cs) +{ + struct zs_channel *zsc = (struct zs_channel *)cs; + uint8_t val; + + val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_DATA); + ZS_DELAY(); + return val; +} + +void +zs_write_data(struct zs_chanstate *cs, uint8_t val) +{ + struct zs_channel *zsc = (struct zs_channel *)cs; + + bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_DATA, val); + ZS_DELAY(); +} + +void +zs_abort(struct zs_chanstate *cs) +{ +#if defined(KGDB) + zskgdb(cs); +#elif defined(DDB) + Debugger(); +#endif +} + + +/*********************************************************/ +/* Polled character I/O functions for console and KGDB */ +/*********************************************************/ + +struct zschan * +zs_get_chan_addr(int zs_unit, int channel) +{ +#if 0 + static int dumped_addr = 0; +#endif + struct zsdevice *addr = NULL; + struct zschan *zc; + + switch (sys_config.system_type) { + case SGI_IP20: + switch (zs_unit) { + case 0: + addr = (struct zsdevice *) + PHYS_TO_XKPHYS(0x1fb80d00, CCA_NC); + break; + case 1: + addr = (struct zsdevice *) + PHYS_TO_XKPHYS(0x1fb80d10, CCA_NC); + break; + } + break; + + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + if (zs_unit == 0) + addr = (struct zsdevice *) + PHYS_TO_XKPHYS(0x1fbd9830, CCA_NC); + break; + } + if (addr == NULL) + panic("zs_get_chan_addr: bad zs_unit %d\n", zs_unit); + + /* + * We need to swap serial ports to match reality on + * non-keyboard channels. + */ + if (sys_config.system_type != SGI_IP20) { + if (channel == 0) + zc = &addr->zs_chan_b; + else + zc = &addr->zs_chan_a; + } else { + if (zs_unit == 0) { + if (channel == 0) + zc = &addr->zs_chan_a; + else + zc = &addr->zs_chan_b; + } else { + if (channel == 0) + zc = &addr->zs_chan_b; + else + zc = &addr->zs_chan_a; + } + } + +#if 0 + if (dumped_addr == 0) { + dumped_addr++; + printf("zs unit %d, channel %d had address %p\n", + zs_unit, channel, zc); + } +#endif + + return (zc); +} + +int +zs_getc(void *arg) +{ + register volatile struct zschan *zc = arg; + register int s, c, rr0; + + s = splzs(); + /* Wait for a character to arrive. */ + do { + rr0 = zc->zc_csr; + ZS_DELAY(); + } while ((rr0 & ZSRR0_RX_READY) == 0); + + c = zc->zc_data; + ZS_DELAY(); + splx(s); + + return (c); +} + +/* + * Polled output char. + */ +void +zs_putc(void *arg, int c) +{ + register volatile struct zschan *zc = arg; + register int s, rr0; + + s = splzs(); + /* Wait for transmitter to become ready. */ + do { + rr0 = zc->zc_csr; + ZS_DELAY(); + } while ((rr0 & ZSRR0_TX_READY) == 0); + + zc->zc_data = c; + __asm__ __volatile__ ("sync" ::: "memory"); /* wbflush(); */ + ZS_DELAY(); + splx(s); +} + +/***************************************************************/ + +static int cons_port; + +void +zscnprobe(struct consdev *cp) +{ + cp->cn_dev = makedev(zs_major, 0); + cp->cn_pri = CN_DEAD; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + if (strlen(bios_console) == 9 && + strncmp(bios_console, "serial", 6) == 0) + cp->cn_pri = CN_FORCED; + else + cp->cn_pri = CN_MIDPRI; + break; + } +} + +void +zscninit(struct consdev *cn) +{ + if (strlen(bios_console) == 9 && + strncmp(bios_console, "serial", 6) != 0) + cons_port = bios_console[7] - '0'; + + /* Mark this unit as the console */ + zs_consunit = 0; + + /* SGI hardware wires serial port 1 to channel B, port 2 to A */ + if (cons_port == 0) + zs_conschan = 1; + else + zs_conschan = 0; +} + +int +zscngetc(dev_t dev) +{ + struct zschan *zs; + + switch (sys_config.system_type) { + case SGI_IP20: + zs = zs_get_chan_addr(1, cons_port); + break; + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + default: + zs = zs_get_chan_addr(0, cons_port); + break; + } + + return zs_getc(zs); +} + +void +zscnputc(dev_t dev, int c) +{ + struct zschan *zs; + + switch (sys_config.system_type) { + case SGI_IP20: + zs = zs_get_chan_addr(1, cons_port); + break; + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + default: + zs = zs_get_chan_addr(0, cons_port); + break; + } + + zs_putc(zs, c); +} + +void +zscnpollc(dev_t dev, int on) +{ +} diff --git a/sys/arch/sgi/include/autoconf.h b/sys/arch/sgi/include/autoconf.h index b71366edba6..d3db14d94e5 100644 --- a/sys/arch/sgi/include/autoconf.h +++ b/sys/arch/sgi/include/autoconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.h,v 1.32 2012/03/25 13:52:52 miod Exp $ */ +/* $OpenBSD: autoconf.h,v 1.33 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -93,6 +93,7 @@ void arcs_device_register(struct device *, void *); void dksc_device_register(struct device *, void *); extern void (*_device_register)(struct device *, void *); +void ip22_setup(void); void ip27_setup(void); void ip27_autoconf(struct device *); void ip30_setup(void); diff --git a/sys/arch/sgi/include/eisa_machdep.h b/sys/arch/sgi/include/eisa_machdep.h new file mode 100644 index 00000000000..93ba8c4c4e8 --- /dev/null +++ b/sys/arch/sgi/include/eisa_machdep.h @@ -0,0 +1,68 @@ +/* $OpenBSD: eisa_machdep.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: eisa_machdep.h,v 1.4 1997/06/06 23:12:52 thorpej Exp $ */ + +/* + * Copyright (c) 1996 Christopher G. Demetriou. 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 Christopher G. Demetriou + * for the NetBSD Project. + * 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. + */ + +/* + * Machine-specific definitions for EISA autoconfiguration. + */ + +/* + * EISA spaces memory layout + */ + +#define EISA_IO_BASE 0x00080000 +#define EISA_IO_END 0x00090000 + +#define EISA_MEM0_BASE 0x00100000 +#define EISA_MEM0_END 0x08000000 + +#define EISA_MEM1_BASE 0x80000000 +#define EISA_MEM1_END 0x100000000UL + +/* + * Types provided to machine-independent EISA code. + */ +typedef void *eisa_chipset_tag_t; +typedef int eisa_intr_handle_t; + +/* + * Functions provided to machine-independent EISA code. + */ +void eisa_attach_hook(struct device *, struct device *, + struct eisabus_attach_args *); +int eisa_maxslots(eisa_chipset_tag_t); +int eisa_intr_map(eisa_chipset_tag_t, u_int, + eisa_intr_handle_t *); +const char *eisa_intr_string(eisa_chipset_tag_t, eisa_intr_handle_t); +void *eisa_intr_establish(eisa_chipset_tag_t, eisa_intr_handle_t, + int, int, int (*)(void *), void *, char *); +void eisa_intr_disestablish(eisa_chipset_tag_t, void *); diff --git a/sys/arch/sgi/include/z8530var.h b/sys/arch/sgi/include/z8530var.h new file mode 100644 index 00000000000..5fab516b720 --- /dev/null +++ b/sys/arch/sgi/include/z8530var.h @@ -0,0 +1,121 @@ +/* $OpenBSD: z8530var.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: z8530var.h,v 1.10 2011/07/01 21:00:21 dyoung Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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: + * 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. + * 3. 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. + * + * @(#)zsvar.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * + * 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: + * 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. + * 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. + * 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. + * + * @(#)zsvar.h 8.1 (Berkeley) 6/11/93 + */ + +#include <machine/bus.h> +#include <sgi/hpc/z8530sc.h> + +struct zs_channel { + struct zs_chanstate cs_zscs; /* Required: soft state */ + bus_space_tag_t cs_bustag; /* Machine-dependent */ + bus_space_handle_t cs_regs; +}; + +struct zsc_softc { + struct device zsc_dev; /* required: base device */ + struct zs_chanstate *zsc_cs[2]; /* channel soft state */ + struct zs_channel zsc_cs_store[2]; + /* Machine-dependent part follows... */ + bus_space_tag_t zsc_bustag; /* Bus type */ + bus_space_handle_t zsc_base; /* Device base address */ + void *sc_si; /* Softinterrupt handle */ +}; + +/* + * Functions to read and write individual registers in a channel. + * The SCC chip requires 3-4 PCLK cycles recovery time between accesses + */ + +uint8_t zs_read_reg(struct zs_chanstate *, uint8_t); +uint8_t zs_read_csr(struct zs_chanstate *); +uint8_t zs_read_data(struct zs_chanstate *); + +void zs_write_reg(struct zs_chanstate *, uint8_t, uint8_t); +void zs_write_csr(struct zs_chanstate *, uint8_t); +void zs_write_data(struct zs_chanstate *, uint8_t); + +/* Zilog Serial hardware interrupts (level 0) */ +#define splzs() spltty() +#define IPL_ZS IPL_TTY diff --git a/sys/arch/sgi/localbus/imc.c b/sys/arch/sgi/localbus/imc.c new file mode 100644 index 00000000000..c8544aa8788 --- /dev/null +++ b/sys/arch/sgi/localbus/imc.c @@ -0,0 +1,826 @@ +/* $OpenBSD: imc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: imc.c,v 1.32 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 2001 Rafal K. Boni + * 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. 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. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/systm.h> + +#include <mips64/archtype.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cpu.h> + +#include <sgi/sgi/ip22.h> +#include <sgi/localbus/imcreg.h> +#include <sgi/localbus/imcvar.h> + +#include <sgi/hpc/hpcreg.h> +#include <sgi/gio/giovar.h> + +#include "eisa.h" + +#if NEISA > 0 +#include <dev/eisa/eisavar.h> +#endif + +int imc_match(struct device *, void *, void *); +void imc_attach(struct device *, struct device *, void *); +int imc_print(void *, const char *); + +const struct cfattach imc_ca = { + sizeof(struct device), imc_match, imc_attach +}; + +struct cfdriver imc_cd = { + NULL, "imc", DV_DULL +}; + +uint32_t imc_bus_error(uint32_t, struct trap_frame *); +void imc_bus_reset(void); +int imc_watchdog_cb(void *, int); + +uint8_t imc_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint16_t imc_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t); +void imc_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void imc_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t); +void imc_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t); +void imc_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +uint32_t imc_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint64_t imc_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t); +void imc_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t); +void imc_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t); +void imc_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void imc_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +void imc_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + uint8_t *, bus_size_t); +void imc_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, + const uint8_t *, bus_size_t); +int imc_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +void imc_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t); +int imc_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); +void *imc_space_vaddr(bus_space_tag_t, bus_space_handle_t); +void imc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, int); + +bus_space_t imcbus_tag = {/* not static for gio_cnattch() */ + PHYS_TO_XKPHYS(0, CCA_NC), + NULL, + imc_read_1, imc_write_1, + imc_read_2, imc_write_2, + imc_read_4, imc_write_4, + imc_read_8, imc_write_8, + imc_read_raw_2, imc_write_raw_2, + imc_read_raw_4, imc_write_raw_4, + imc_read_raw_8, imc_write_raw_8, + imc_space_map, imc_space_unmap, imc_space_region, + imc_space_vaddr, imc_space_barrier +}; + +#if NEISA > 0 +int imc_eisa_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +int imc_eisa_io_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); +int imc_eisa_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +int imc_eisa_mem_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); + +static bus_space_t imcbus_eisa_io_tag = { + PHYS_TO_XKPHYS(EISA_IO_BASE, CCA_NC), + NULL, + imc_read_1, imc_write_1, + imc_read_2, imc_write_2, + imc_read_4, imc_write_4, + imc_read_8, imc_write_8, + imc_read_raw_2, imc_write_raw_2, + imc_read_raw_4, imc_write_raw_4, + imc_read_raw_8, imc_write_raw_8, + imc_eisa_io_map, imc_space_unmap, imc_eisa_io_region, + imc_space_vaddr, imc_space_barrier +}; +static bus_space_t imcbus_eisa_mem_tag = { + PHYS_TO_XKPHYS(0, CCA_NC), + NULL, + imc_read_1, imc_write_1, + imc_read_2, imc_write_2, + imc_read_4, imc_write_4, + imc_read_8, imc_write_8, + imc_read_raw_2, imc_write_raw_2, + imc_read_raw_4, imc_write_raw_4, + imc_read_raw_8, imc_write_raw_8, + imc_eisa_mem_map, imc_space_unmap, imc_eisa_mem_region, + imc_space_vaddr, imc_space_barrier +}; +#endif + +bus_addr_t imc_pa_to_device(paddr_t); +paddr_t imc_device_to_pa(bus_addr_t); + +struct machine_bus_dma_tag imc_bus_dma_tag = {/* not static for gio_cnattch() */ + NULL, /* _cookie */ + _dmamap_create, + _dmamap_destroy, + _dmamap_load, + _dmamap_load_mbuf, + _dmamap_load_uio, + _dmamap_load_raw, + _dmamap_load_buffer, + _dmamap_unload, + _dmamap_sync, + _dmamem_alloc, + _dmamem_free, + _dmamem_map, + _dmamem_unmap, + _dmamem_mmap, + imc_pa_to_device, + imc_device_to_pa, + 0 +}; + +/* + * Bus access primitives. + */ + +uint8_t +imc_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile uint8_t *)(h + o); +} + +uint16_t +imc_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile uint16_t *)(h + o); +} + +uint32_t +imc_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile uint32_t *)(h + o); +} + +uint64_t +imc_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile uint64_t *)(h + o); +} + +void +imc_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint8_t v) +{ + *(volatile uint8_t *)(h + o) = v; +} + +void +imc_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint16_t v) +{ + *(volatile uint16_t *)(h + o) = v; +} + +void +imc_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint32_t v) +{ + *(volatile uint32_t *)(h + o) = v; +} + +void +imc_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint64_t v) +{ + *(volatile uint64_t *)(h + o) = v; +} + +void +imc_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint16_t *addr = (volatile uint16_t *)(h + o); + len >>= 1; + while (len-- != 0) { + *(uint16_t *)buf = *addr; + buf += 2; + } +} + +void +imc_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint16_t *addr = (volatile uint16_t *)(h + o); + len >>= 1; + while (len-- != 0) { + *addr = *(uint16_t *)buf; + buf += 2; + } +} + +void +imc_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint32_t *addr = (volatile uint32_t *)(h + o); + len >>= 2; + while (len-- != 0) { + *(uint32_t *)buf = *addr; + buf += 4; + } +} + +void +imc_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint32_t *addr = (volatile uint32_t *)(h + o); + len >>= 2; + while (len-- != 0) { + *addr = *(uint32_t *)buf; + buf += 4; + } +} + +void +imc_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint64_t *addr = (volatile uint64_t *)(h + o); + len >>= 3; + while (len-- != 0) { + *(uint64_t *)buf = *addr; + buf += 8; + } +} + +void +imc_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint64_t *addr = (volatile uint64_t *)(h + o); + len >>= 3; + while (len-- != 0) { + *addr = *(uint64_t *)buf; + buf += 8; + } +} + +int +imc_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + *bshp = t->bus_base + offs; + return 0; +} + +void +imc_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) +{ +} + +int +imc_space_region(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) +{ + *nbshp = bsh + offset; + return 0; +} + +void * +imc_space_vaddr(bus_space_tag_t t, bus_space_handle_t h) +{ + return (void *)h; +} + +void +imc_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offs, + bus_size_t len, int flags) +{ + __asm__ __volatile__ ("sync" ::: "memory"); +} + +#if NEISA > 0 +int +imc_eisa_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + if (offs + size > EISA_IO_END - EISA_IO_BASE) + return EINVAL; + + *bshp = t->bus_base + offs; + return 0; +} + +int +imc_eisa_io_region(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, + bus_size_t size, bus_space_handle_t *nbshp) +{ + if ((bsh - t->bus_base) + offset + size > EISA_IO_END - EISA_IO_BASE) + return EINVAL; + + *nbshp = bsh + offset; + return 0; +} + +int +imc_eisa_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + if ((offs >= EISA_MEM0_BASE && offs + size <= EISA_MEM0_END) || + (offs >= EISA_MEM1_BASE && offs + size <= EISA_MEM1_END)) { + *bshp = t->bus_base + offs; + return 0; + } + + return EINVAL; +} + +int +imc_eisa_mem_region(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) +{ + bus_addr_t orig = bsh - t->bus_base; + + if ((orig >= EISA_MEM0_BASE && orig + offset + size <= EISA_MEM0_END) || + (orig >= EISA_MEM1_BASE && orig + offset + size <= EISA_MEM1_END)) { + *nbshp = t->bus_base + offset; + return 0; + } + + return EINVAL; +} +#endif + +bus_addr_t +imc_pa_to_device(paddr_t pa) +{ + return (bus_addr_t)pa; +} + +paddr_t +imc_device_to_pa(bus_addr_t addr) +{ + return (paddr_t)addr; +} + +/* + * Autoconf glue. + */ + +int +imc_match(struct device *parent, void *match, void *aux) +{ + struct mainbus_attach_args *maa = (void *)aux; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return 0; + } + + return strcmp(maa->maa_name, imc_cd.cd_name) == 0; +} + +void +imc_attach(struct device *parent, struct device *self, void *aux) +{ + struct imc_attach_args iaa; +#if NEISA > 0 + struct eisabus_attach_args eba; +#endif + uint32_t reg; + uint32_t id, rev; + int have_eisa; + + id = imc_read(IMC_SYSID); + rev = id & IMC_SYSID_REVMASK; + + /* EISA exists on Indigo2 only */ + if (sys_config.system_type != SGI_IP20 && + sys_config.system_subtype == IP22_INDIGO2) + have_eisa = (id & IMC_SYSID_HAVEISA) != 0; + else + have_eisa = 0; + + printf(": revision %d\n", rev); + + /* Clear CPU/GIO error status registers to clear any leftover bits. */ + imc_bus_reset(); + + /* Disable watchdog if leftover from previous reboot */ + imc_watchdog_cb(self, 0); + + /* Hook the bus error handler into the ISR */ + set_intr(INTPRI_BUSERR, CR_INT_4, imc_bus_error); + + /* + * Enable parity reporting on GIO/main memory transactions. + * Disable parity checking on CPU bus transactions (as turning + * it on seems to cause spurious bus errors), but enable parity + * checking on CPU reads from main memory (note that this bit + * has the opposite sense... Turning it on turns the checks off!). + * Finally, turn on interrupt writes to the CPU from the MC. + */ + reg = imc_read(IMC_CPUCTRL0); + reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; + reg |= (IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR | IMC_CPUCTRL0_INTENA); + imc_write(IMC_CPUCTRL0, reg); + + /* Setup the MC write buffer depth */ + reg = imc_read(IMC_CPUCTRL1); + reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13; + + /* + * Force endianness on the onboard HPC and both slots. + * This should be safe for Fullhouse, but leave it conditional + * for now. + */ + switch (sys_config.system_type) { + case SGI_IP22: + if (sys_config.system_subtype != IP22_INDY) + break; + /* FALLTHROUGH */ + case SGI_IP20: + reg |= IMC_CPUCTRL1_HPCFX; + reg |= IMC_CPUCTRL1_EXP0FX; + reg |= IMC_CPUCTRL1_EXP1FX; + reg &= ~IMC_CPUCTRL1_HPCLITTLE; + reg &= ~IMC_CPUCTRL1_EXP0LITTLE; + reg &= ~IMC_CPUCTRL1_EXP1LITTLE; + break; + } + imc_write(IMC_CPUCTRL1, reg); + + /* + * Set GIO64 arbitrator configuration register: + * + * Preserve PROM-set graphics-related bits, as they seem to depend + * on the graphics variant present and I'm not sure how to figure + * that out or 100% sure what the correct settings are for each. + */ + reg = imc_read(IMC_GIO64ARB); + reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST); + + /* + * Rest of settings are machine/board dependent + * XXX I wonder if this even works as advertized. The logic apparently + * XXX comes from Linux, but the EISA settings look horribly broken to + * XXX me -- miod + */ + switch (sys_config.system_type) { + case SGI_IP20: + reg |= IMC_GIO64ARB_ONEGIO; + reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT; + reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST; + reg &= ~(IMC_GIO64ARB_HPC64 | + IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 | + IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 | + IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE); + break; + default: + /* + * GIO64 invariant for all IP22 platforms: one GIO bus, + * HPC1 @ 64 + */ + reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64; + + switch (sys_config.system_subtype) { + default: + case IP22_INDY: + /* XXX is MST mutually exclusive? */ + reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT; + reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST; + + /* EISA can bus-master, is 64-bit */ + reg |= IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64; + break; + + case IP22_INDIGO2: + /* + * All Fullhouse boards have a 64-bit HPC2 and pipelined + * EXP0 slot. + */ + reg |= IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE; + + if (rev < 2) { + /* EXP0 realtime, EXP1 can master */ + reg |= IMC_GIO64ARB_EXP0RT | + IMC_GIO64ARB_EXP1MST; + } else { + /* EXP1 pipelined as well, EISA masters */ + reg |= IMC_GIO64ARB_EXP1PIPE | + IMC_GIO64ARB_EISAMST; + } + break; + } + } + + imc_write(IMC_GIO64ARB, reg); + +#if NEISA > 0 + if (have_eisa) { + memset(&eba, 0, sizeof(eba)); + eba.eba_busname = "eisa"; + eba.eba_iot = &imcbus_eisa_io_tag; + eba.eba_memt = &imcbus_eisa_mem_tag; + eba.eba_dmat = &imc_bus_dma_tag; + eba.eba_ec = NULL; + config_found(self, &eba, imc_print); + } +#endif + + memset(&iaa, 0, sizeof(iaa)); + iaa.iaa_name = "gio"; + iaa.iaa_st = &imcbus_tag; + iaa.iaa_dmat = &imc_bus_dma_tag; + config_found(self, &iaa, imc_print); + + /* Clear CPU/GIO error status registers to clear any leftover bits. */ + imc_bus_reset(); + + /* Register watchdog */ + wdog_register(self, imc_watchdog_cb); +} + +int +imc_print(void *aux, const char *name) +{ + struct imc_attach_args *iaa = aux; + + if (name != NULL) + printf("%s at %s", iaa->iaa_name, name); + + return UNCONF; +} + +void +imc_bus_reset() +{ + imc_write(IMC_CPU_ERRSTAT, 0); + imc_write(IMC_GIO_ERRSTAT, 0); +} + +uint32_t +imc_bus_error(uint32_t hwpend, struct trap_frame *tf) +{ + printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n", + imc_read(IMC_CPU_ERRSTAT), + imc_read(IMC_CPU_ERRADDR), + imc_read(IMC_GIO_ERRSTAT), + imc_read(IMC_GIO_ERRADDR)); + imc_bus_reset(); + + return hwpend; +} + +int +imc_watchdog_cb(void *v, int period) +{ + uint32_t reg; + + if (period == 0) { + /* reset... */ + imc_write(IMC_WDOG, 0); + /* ...and disable */ + reg = imc_read(IMC_CPUCTRL0); + reg &= ~(IMC_CPUCTRL0_WDOG); + imc_write(IMC_CPUCTRL0, reg); + + return 0; + } else { + /* enable... */ + reg = imc_read(IMC_CPUCTRL0); + reg |= IMC_CPUCTRL0_WDOG; + imc_write(IMC_CPUCTRL0, reg); + /* ...and reset */ + imc_write(IMC_WDOG, 0); + + /* + * The watchdog period is not controllable; it will fire + * when the 20 bit counter, running on a 64 usec clock, + * overflows. + */ + return (64 << 20) / 1000000; + } +} + +/* intended to be called from gio/gio.c only */ +int +imc_gio64_arb_config(int slot, uint32_t flags) +{ + uint32_t reg; + + if (sys_config.system_type == SGI_IP20 || + sys_config.system_subtype != IP22_INDIGO2) { + /* GIO_SLOT_GFX is only usable on Fullhouse */ + if (slot == GIO_SLOT_GFX) + return EINVAL; + } else { + /* GIO_SLOT_EXP1 is unusable on Fullhouse */ + if (slot == GIO_SLOT_EXP1) + return EINVAL; + } + + /* GIO_SLOT_GFX is always pipelined */ + if (slot == GIO_SLOT_GFX && (flags & GIO_ARB_NOPIPE)) + return EINVAL; + + /* IP20 does not support pipelining (XXX what about Indy?) */ + if (((flags & GIO_ARB_PIPE) || (flags & GIO_ARB_NOPIPE)) && + sys_config.system_type == SGI_IP20) + return EINVAL; + + reg = imc_read(IMC_GIO64ARB); + + if (flags & GIO_ARB_RT) { + if (slot == GIO_SLOT_EXP0) + reg |= IMC_GIO64ARB_EXP0RT; + else if (slot == GIO_SLOT_EXP1) + reg |= IMC_GIO64ARB_EXP1RT; + else if (slot == GIO_SLOT_GFX) + reg |= IMC_GIO64ARB_GRXRT; + } + + if (flags & GIO_ARB_MST) { + if (slot == GIO_SLOT_EXP0) + reg |= IMC_GIO64ARB_EXP0MST; + else if (slot == GIO_SLOT_EXP1) + reg |= IMC_GIO64ARB_EXP1MST; + else if (slot == GIO_SLOT_GFX) + reg |= IMC_GIO64ARB_GRXMST; + } + + if (flags & GIO_ARB_PIPE) { + if (slot == GIO_SLOT_EXP0) + reg |= IMC_GIO64ARB_EXP0PIPE; + else if (slot == GIO_SLOT_EXP1) + reg |= IMC_GIO64ARB_EXP1PIPE; + } + + if (flags & GIO_ARB_LB) { + if (slot == GIO_SLOT_EXP0) + reg &= ~IMC_GIO64ARB_EXP0RT; + else if (slot == GIO_SLOT_EXP1) + reg &= ~IMC_GIO64ARB_EXP1RT; + else if (slot == GIO_SLOT_GFX) + reg &= ~IMC_GIO64ARB_GRXRT; + } + + if (flags & GIO_ARB_SLV) { + if (slot == GIO_SLOT_EXP0) + reg &= ~IMC_GIO64ARB_EXP0MST; + else if (slot == GIO_SLOT_EXP1) + reg &= ~IMC_GIO64ARB_EXP1MST; + else if (slot == GIO_SLOT_GFX) + reg &= ~IMC_GIO64ARB_GRXMST; + } + + if (flags & GIO_ARB_NOPIPE) { + if (slot == GIO_SLOT_EXP0) + reg &= ~IMC_GIO64ARB_EXP0PIPE; + else if (slot == GIO_SLOT_EXP1) + reg &= ~IMC_GIO64ARB_EXP1PIPE; + } + + if (flags & GIO_ARB_32BIT) { + if (slot == GIO_SLOT_EXP0) + reg &= ~IMC_GIO64ARB_EXP064; + else if (slot == GIO_SLOT_EXP1) + reg &= ~IMC_GIO64ARB_EXP164; + } + + if (flags & GIO_ARB_64BIT) { + if (slot == GIO_SLOT_EXP0) + reg |= IMC_GIO64ARB_EXP064; + else if (slot == GIO_SLOT_EXP1) + reg |= IMC_GIO64ARB_EXP164; + } + + if (flags & GIO_ARB_HPC2_32BIT) + reg &= ~IMC_GIO64ARB_HPCEXP64; + + if (flags & GIO_ARB_HPC2_64BIT) + reg |= IMC_GIO64ARB_HPCEXP64; + + imc_write(IMC_GIO64ARB, reg); + + return 0; +} + +/* + * According to chapter 19 of the "IRIX Device Driver Programmer's Guide", + * some GIO devices, which do not drive all data lines, may cause false + * memory read parity errors on the SysAD bus. The workaround is to disable + * parity checking. + */ +void +imc_disable_sysad_parity(void) +{ + uint32_t reg; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return; + } + + reg = imc_read(IMC_CPUCTRL0); + reg |= IMC_CPUCTRL0_NCHKMEMPAR; + imc_write(IMC_CPUCTRL0, reg); +} + +void +imc_enable_sysad_parity(void) +{ + uint32_t reg; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return; + } + + reg = imc_read(IMC_CPUCTRL0); + reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; + imc_write(IMC_CPUCTRL0, reg); +} + +#if 0 +int +imc_is_sysad_parity_enabled(void) +{ + uint32_t reg; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return 0; + } + + reg = imc_read(IMC_CPUCTRL0); + + return reg & IMC_CPUCTRL0_NCHKMEMPAR; +} +#endif diff --git a/sys/arch/sgi/localbus/imcreg.h b/sys/arch/sgi/localbus/imcreg.h new file mode 100644 index 00000000000..fd27ff4c9be --- /dev/null +++ b/sys/arch/sgi/localbus/imcreg.h @@ -0,0 +1,143 @@ +/* $OpenBSD: imcreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: imcreg.h,v 1.4 2005/12/11 12:18:52 christos Exp $ */ + +/* + * Copyright (c) 2001 Rafal K. Boni + * 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. 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 IMC_BASE 0x1fa00000 + +#define IMC_CPUCTRL0 0x04 /* CPU control, register 0 */ + +#define IMC_CPUCTRL0_REFMASK 0x000f /* # lines to refresh */ +#define IMC_CPUCTRL0_RFE 0x0010 /* refresh enable */ +#define IMC_CPUCTRL0_GPR 0x0020 /* GIO parity enable */ +#define IMC_CPUCTRL0_MPR 0x0040 /* memory parity enable */ +#define IMC_CPUCTRL0_CPR 0x0080 /* cpu bus parity enable */ +#define IMC_CPUCTRL0_WDOG 0x0100 /* watchdog enable */ +#define IMC_CPUCTRL0_SIN 0x0200 /* reset system */ +#define IMC_CPUCTRL0_GRR 0x0400 /* graphics reset */ +#define IMC_CPUCTRL0_ENLOCK 0x0800 /* enable EISA memory lock */ +#define IMC_CPUCTRL0_CMDPAR 0x1000 /* SysCmd parity enable */ +#define IMC_CPUCTRL0_INTENA 0x2000 /* enable CPU interrupts */ +#define IMC_CPUCTRL0_SNOOPENA 0x4000 /* enable gfx DMA snoop */ +#define IMC_CPUCTRL0_PROM_WRENA 0x8000 /* disable buserr on PROM + * writes */ +#define IMC_CPUCTRL0_WRST 0x00010000 /* warm restart (reset cpu) */ +/* Bit 17 reserved 0x00020000 */ +#define IMC_CPUCTRL0_LITTLE 0x00040000 /* MC little-endian toggle */ +#define IMC_CPUCTRL0_WRRST 0x00080000 /* cpu warm reset */ +#define IMC_CPUCTRL0_MUXHWMSK 0x01f00000 /* MUX fifo high-water mask */ +#define IMC_CPUCTRL0_BADPAR 0x02000000 /* generate bad parity on + * CPU->memory writes */ +#define IMC_CPUCTRL0_NCHKMEMPAR 0x04000000 /* disable CPU parity check + * on memory reads. */ +#define IMC_CPUCTRL0_BACK2 0x08000000 /* enable back2back GIO wrt */ +#define IMC_CPUCTRL0_BUSRTMSK 0xf0000000 /* stall cycle for berr data */ + +#define IMC_CPUCTRL1 0x0c /* CPU control, register 1 */ +#define IMC_CPUCTRL1_MCHWMSK 0x0000000f /* MC FIFO high water mask */ +#define IMC_CPUCTRL1_ABORTEN 0x00000010 /* Enable GIO bus timeouts */ +/* Bits 5 - 11 reserved 0x00000fe0 */ +#define IMC_CPUCTRL1_HPCFX 0x00001000 /* HPC endian fix */ +#define IMC_CPUCTRL1_HPCLITTLE 0x00002000 /* HPC DMA is little-endian */ +#define IMC_CPUCTRL1_EXP0FX 0x00004000 /* EXP0 endian fix */ +#define IMC_CPUCTRL1_EXP0LITTLE 0x00008000 /* EXP0 DMA is little-endian */ +#define IMC_CPUCTRL1_EXP1FX 0x00010000 /* EXP1 endian fix */ +#define IMC_CPUCTRL1_EXP1LITTLE 0x00020000 /* EXP1 DMA is little-endian */ + +#define IMC_WDOG 0x14 /* Watchdog counter */ +#define IMC_WDOG_MASK 0x001fffff /* counter mask */ + +#define IMC_SYSID 0x1c /* MC revision register */ +#define IMC_SYSID_REVMASK 0x0000000f /* MC revision mask */ +#define IMC_SYSID_HAVEISA 0x00000010 /* EISA present */ + +#define IMC_RPSSDIV 0x2c /* RPSS divider */ +#define IMC_RPSSDIV_DIVMSK 0x000000ff /* RPC divider mask */ +#define IMC_RPSSDIV_INCMSK 0x0000ff00 /* RPC increment mask */ + +#define IMC_EEPROM 0x34 /* EEPROM serial interface */ +/* Bit 1 is reserved 0x00000001 */ +#define IMC_EEPROM_CS 0x00000002 /* EEPROM chip select */ +#define IMC_EEPROM_SCK 0x00000004 /* EEPROM serial clock */ +#define IMC_EEPROM_SO 0x00000008 /* Serial data to EEPROM */ +#define IMC_EEPROM_SI 0x00000010 /* Serial data from EEPROM */ + +#define IMC_CTRLD 0x44 /* Refresh counter preload */ +#define IMC_CTRLD_MSK 0x000000ff /* Counter preload mask */ + +#define IMC_REFCTR 0x4c /* Refresh counter */ +#define IMC_REFCTR_MSK 0x000000ff /* Refresh counter mask */ + +#define IMC_GIO64ARB 0x84 /* GIO64 arbitration params */ +#define IMC_GIO64ARB_HPC64 0x00000001 /* HPC addr size (32/64bit) */ +#define IMC_GIO64ARB_GRX64 0x00000002 /* Gfx addr size (32/64bit) */ +#define IMC_GIO64ARB_EXP064 0x00000004 /* EXP0 addr size (32/64bit) */ +#define IMC_GIO64ARB_EXP164 0x00000008 /* EXP0 addr size (32/64bit) */ +#define IMC_GIO64ARB_EISA64 0x00000010 /* EISA addr size (32/64bit) */ +#define IMC_GIO64ARB_HPCEXP64 0x00000020 /* HPC2 addr size (32/64bit) */ +#define IMC_GIO64ARB_GRXRT 0x00000040 /* Gfx is realtime device */ +#define IMC_GIO64ARB_EXP0RT 0x00000080 /* EXP0 is realtime device */ +#define IMC_GIO64ARB_EXP1RT 0x00000100 /* EXP1 is realtime device */ +#define IMC_GIO64ARB_EISAMST 0x00000200 /* EISA can be busmaster */ +#define IMC_GIO64ARB_ONEGIO 0x00000400 /* Only one GIO64 bus */ +#define IMC_GIO64ARB_GRXMST 0x00000800 /* Gfx can be busmaster */ +#define IMC_GIO64ARB_EXP0MST 0x00001000 /* EXP0 can be busmaster */ +#define IMC_GIO64ARB_EXP1MST 0x00002000 /* EXP1 can be busmaster */ +#define IMC_GIO64ARB_EXP0PIPE 0x00004000 /* EXP0 is pipelined */ +#define IMC_GIO64ARB_EXP1PIPE 0x00008000 /* EXP1 is pipelined */ + +#define IMC_CPUTIME 0x8c /* Arbiter CPU time period */ + +#define IMC_LBTIME 0x9c /* Arbiter long-burst time */ + +#define IMC_MEMCFG0 0xc4 /* Mem config, register 0 */ +#define IMC_MEMCFG1 0xcc /* Mem config, register 1 */ +#define IMC_MEMC_BANK_MASK 0x0000ffff +#define IMC_MEMC_BANK_SHIFT 16 +#define IMC_MEMC_ADDR_MASK 0x00ff +#define IMC_MEMC_ADDR_SHIFT 0 +#define IMC_MEMC_SIZE_MASK 0x1f00 +#define IMC_MEMC_SIZE_SHIFT 8 +#define IMC_MEMC_LSHIFT 22 /* 4MB units */ +#define IMC_MEMC_LSHIFT_HUGE 24 /* 16MB units */ +#define IMC_MEMC_VALID 0x2000 +#define IMC_MEMC_SUBBANKS 0x4000 + +#define IMC_CPU_MEMACC 0xd4 /* CPU mem access config */ + +#define IMC_GIO_MEMACC 0xdc /* GIO mem access config */ + +#define IMC_CPU_ERRADDR 0xe4 /* CPU error address */ + +#define IMC_CPU_ERRSTAT 0xec /* CPU error status */ + +#define IMC_GIO_ERRADDR 0xf4 /* GIO error address */ + +#define IMC_GIO_ERRSTAT 0xfc /* GIO error status */ + +#define IMC_RPSS 0x1004 /* RPSS counter */ diff --git a/sys/arch/sgi/localbus/imcvar.h b/sys/arch/sgi/localbus/imcvar.h new file mode 100644 index 00000000000..651d23f9d3e --- /dev/null +++ b/sys/arch/sgi/localbus/imcvar.h @@ -0,0 +1,42 @@ +/* $OpenBSD: imcvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: imcvar.h,v 1.1 2006/08/30 23:44:52 rumble Exp $ */ + +/* + * Copyright (c) 2006 Stephen M. Rumble + * 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. 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 imc_attach_args { + const char *iaa_name; + bus_space_tag_t iaa_st; + bus_dma_tag_t iaa_dmat; +}; + +int imc_gio64_arb_config(int, uint32_t); +void imc_disable_sysad_parity(void); +void imc_enable_sysad_parity(void); +int imc_is_sysad_parity_enabled(void); + +#define imc_read(o) \ + *(volatile uint32_t *)PHYS_TO_XKPHYS(IMC_BASE + (o), CCA_NC) +#define imc_write(o,v) \ + *(volatile uint32_t *)PHYS_TO_XKPHYS(IMC_BASE + (o), CCA_NC) = (v) diff --git a/sys/arch/sgi/localbus/int.c b/sys/arch/sgi/localbus/int.c new file mode 100644 index 00000000000..01e8b2a5dde --- /dev/null +++ b/sys/arch/sgi/localbus/int.c @@ -0,0 +1,369 @@ +/* $OpenBSD: int.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: int.c,v 1.24 2011/07/01 18:53:46 dyoung Exp $ */ + +/* + * Copyright (c) 2009 Stephen M. Rumble + * Copyright (c) 2004 Christopher SEKIYA + * 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. 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. + */ + +/* + * INT2 (IP20, IP22) /INT3 (IP24) interrupt controllers + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> + +#include <mips64/archtype.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cpu.h> +#include <machine/intr.h> + +#include <dev/ic/i8253reg.h> + +#include <sgi/localbus/intreg.h> +#include <sgi/localbus/intvar.h> +#include <sgi/sgi/ip22.h> + +int int2_match(struct device *, void *, void *); +void int2_attach(struct device *, struct device *, void *); +int int2_mappable_intr(void *); + +const struct cfattach int_ca = { + sizeof(struct device), int2_match, int2_attach +}; + +struct cfdriver int_cd = { + NULL, "int", DV_DULL +}; + +paddr_t int2_base; + +#define int2_read(r) *(volatile uint8_t *)(int2_base + (r)) +#define int2_write(r, v) *(volatile uint8_t *)(int2_base + (r)) = (v) + +/* + * INT2 Interrupt handling declarations: 16 local sources on 2 levels. + * (we don't use the i8254 timer interrupts) + * + * In addition to this, INT3 provides 8 so-called mappable interrupts, which + * are cascaded to either one of the unused two INT2 VME interrupts. + * To make things easier from a software viewpoint, we pretend there are + * 16 of them - one set of 8 per cascaded interrupt. This allows for + * faster recognition on where to connect these interrupts - as long as + * interrupt vector assignment makes sure no mappable interrupt is + * registered on both cascaded interrupts. + */ + +#define INT2_NINTS (8 + 8 + 2 * 8) +struct intrhand *int2_intrhand[INT2_NINTS]; + +uint32_t int2_intem; +uint8_t int2_l0imask[NIPLS], int2_l1imask[NIPLS]; + +void int2_splx(int); +uint32_t int2_l0intr(uint32_t, struct trap_frame *); +void int2_l0makemasks(void); +uint32_t int2_l1intr(uint32_t, struct trap_frame *); +void int2_l1makemasks(void); + +/* + * Level 0 interrupt handler. + */ + +uint32_t save_l0imr, save_l0isr, save_l0ipl; +#define INTR_FUNCTIONNAME int2_l0intr +#define MASK_FUNCTIONNAME int2_l0makemasks + +#define INTR_LOCAL_DECLS +#define MASK_LOCAL_DECLS +#define INTR_GETMASKS \ +do { \ + isr = int2_read(INT2_LOCAL0_STATUS); \ + imr = int2_read(INT2_LOCAL0_MASK); \ + bit = 7; \ +save_l0isr = isr; save_l0imr = imr; save_l0ipl = frame->ipl; \ +} while (0) +#define INTR_MASKPENDING \ + int2_write(INT2_LOCAL0_MASK, imr & ~isr) +#define INTR_IMASK(ipl) int2_l0imask[ipl] +#define INTR_HANDLER(bit) int2_intrhand[bit + 0] +#define INTR_SPURIOUS(bit) \ +do { \ + printf("spurious int2 interrupt %d\n", bit); \ +} while (0) +#define INTR_MASKRESTORE \ + int2_write(INT2_LOCAL0_MASK, imr) +#define INTR_MASKSIZE 8 + +#include <sgi/sgi/intr_template.c> + +/* + * Level 1 interrupt handler. + */ + +uint32_t save_l1imr, save_l1isr, save_l1ipl; +#define INTR_FUNCTIONNAME int2_l1intr +#define MASK_FUNCTIONNAME int2_l1makemasks + +#define INTR_LOCAL_DECLS +#define MASK_LOCAL_DECLS +#define INTR_GETMASKS \ +do { \ + isr = int2_read(INT2_LOCAL1_STATUS); \ + imr = int2_read(INT2_LOCAL1_MASK); \ + bit = 7; \ +save_l1isr = isr; save_l1imr = imr; save_l1ipl = frame->ipl; \ +} while (0) +#define INTR_MASKPENDING \ + int2_write(INT2_LOCAL1_MASK, imr & ~isr) +#define INTR_IMASK(ipl) int2_l1imask[ipl] +#define INTR_HANDLER(bit) int2_intrhand[bit + 8] +#define INTR_SPURIOUS(bit) \ +do { \ + printf("spurious int2 interrupt %d\n", bit + 8); \ +} while (0) +#define INTR_MASKRESTORE \ + int2_write(INT2_LOCAL1_MASK, imr) +#define INTR_MASKSIZE 8 + +#include <sgi/sgi/intr_template.c> + +void * +int2_intr_establish(int irq, int level, int (*ih_fun) (void *), + void *ih_arg, const char *ih_what) +{ + struct intrhand **p, *q, *ih; + int s; + +#ifdef DIAGNOSTIC + if (irq < 0 || irq >= INT2_NINTS) + panic("int2_intr_establish: illegal irq %d", irq); +#endif + + ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT); + if (ih == NULL) + return NULL; + + ih->ih_next = NULL; + ih->ih_fun = ih_fun; + ih->ih_arg = ih_arg; + ih->ih_level = level; + ih->ih_irq = irq; + if (ih_what != NULL) + evcount_attach(&ih->ih_count, ih_what, &ih->ih_irq); + + s = splhigh(); + + for (p = &int2_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) + ; + *p = ih; + + int2_intem |= 1 << irq; + switch (irq >> 3) { + case 0: + int2_l0makemasks(); + break; + case 1: + int2_l1makemasks(); + break; + /* + * We do not maintain masks for mappable interrupts. They are + * masked as a whole, by the level 0 or 1 interrupt they cascade to. + */ + case 2: + int2_write(INT2_MAP_MASK0, + int2_read(INT2_MAP_MASK0) | (1 << (irq & 7))); + break; + case 3: + int2_write(INT2_MAP_MASK1, + int2_read(INT2_MAP_MASK1) | (1 << (irq & 7))); + break; + } + + splx(s); /* will cause hardware mask update */ + + return ih; +} + +void +int2_splx(int newipl) +{ + struct cpu_info *ci = curcpu(); + uint32_t sr; + + __asm__ ("\t.set noreorder\n"); + ci->ci_ipl = newipl; + __asm__ ("sync\n\t.set reorder\n"); + + sr = disableintr(); /* XXX overkill? */ + int2_write(INT2_LOCAL1_MASK, (int2_intem >> 8) & ~int2_l1imask[newipl]); + int2_write(INT2_LOCAL0_MASK, int2_intem & ~int2_l0imask[newipl]); + setsr(sr); + + if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT) + setsoftintr0(); +} + +/* + * Mappable interrupts handler. + */ + +int +int2_mappable_intr(void *arg) +{ + uint which = (unsigned long)arg; + uint64_t imr, isr; + uint i, intnum; + struct intrhand *ih; + int rc, ret; + + isr = int2_read(INT2_MAP_STATUS); + imr = int2_read(INT2_MAP_MASK0 + (which << 2)); + + isr &= imr; + if (isr == 0) + return 0; /* not for us */ + + /* + * Don't bother masking sources here - all mappable interrupts are + * tied to either a level 1 or level 0 interrupt, and the dispatcher + * is registered at IPL_TTY, so we can safely assume we are running + * at IPL_TTY now. + */ + + for (i = 0; i < 8; i++) { + intnum = i + 16 + (which << 3); + if (isr & (1 << i)) { + rc = 0; + for (ih = int2_intrhand[intnum]; ih != NULL; + ih = ih->ih_next) { + ret = (*ih->ih_fun)(ih->ih_arg); + if (ret != 0) { + rc = 1; + atomic_add_uint64(&ih->ih_count.ec_count, + 1); + } + if (ret == 1) + break; + } + if (rc == 0) + printf("spurious int2 mapped interrupt %d\n", + i); + } + } + + return 1; +} + +int +int2_match(struct device *parent, void *match, void *aux) +{ + struct mainbus_attach_args *maa = (void *)aux; + + switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + break; + default: + return 0; + } + + return !strcmp(maa->maa_name, int_cd.cd_name); +} + +void +int2_attach(struct device *parent, struct device *self, void *aux) +{ + uint32_t address; + + switch (sys_config.system_type) { + case SGI_IP20: + address = INT2_IP20; + break; + default: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + if (sys_config.system_subtype == IP22_INDIGO2) + address = INT2_IP22; + else + address = INT2_IP24; + break; + } + + printf(" addr 0x%x\n", address); + int2_base = PHYS_TO_XKPHYS((uint64_t)address, CCA_NC); + + /* Clean out interrupt masks */ + int2_write(INT2_LOCAL0_MASK, 0); + int2_write(INT2_LOCAL1_MASK, 0); + int2_write(INT2_MAP_MASK0, 0); + int2_write(INT2_MAP_MASK1, 0); + + /* Reset timer interrupts */ + int2_write(INT2_TIMER_CONTROL, + TIMER_SEL0 | TIMER_16BIT | TIMER_SWSTROBE); + int2_write(INT2_TIMER_CONTROL, + TIMER_SEL1 | TIMER_16BIT | TIMER_SWSTROBE); + int2_write(INT2_TIMER_CONTROL, + TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE); + __asm__ __volatile__ ("sync" ::: "memory"); + delay(4); + int2_write(INT2_TIMER_CLEAR, 0x03); + + set_intr(INTPRI_L1, CR_INT_1, int2_l1intr); + set_intr(INTPRI_L0, CR_INT_0, int2_l0intr); + register_splx_handler(int2_splx); + + if (sys_config.system_type != SGI_IP20) { + /* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */ + int2_intr_establish(7, IPL_TTY, int2_mappable_intr, + (void *)0, NULL); + int2_intr_establish(8 + 3, IPL_TTY, int2_mappable_intr, + (void *)1, NULL); + } +} + +/* + * Wait for the FIFO Full interrupt condition (Local 0 bit 0) to clear. + */ +void +int2_wait_fifo(uint32_t flag) +{ + if (int2_base == 0) + delay(5000); /* XXX */ + else + while (int2_read(INT2_LOCAL0_STATUS) & flag) + ; +} diff --git a/sys/arch/sgi/localbus/intreg.h b/sys/arch/sgi/localbus/intreg.h new file mode 100644 index 00000000000..c6deca4e933 --- /dev/null +++ b/sys/arch/sgi/localbus/intreg.h @@ -0,0 +1,51 @@ +/* $OpenBSD: intreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: int2reg.h,v 1.5 2009/02/12 06:33:57 rumble Exp $ */ + +/* + * Copyright (c) 2004 Christopher SEKIYA + * 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. 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. + */ + +/* The INT has known locations on all SGI machines */ +#define INT2_IP20 0x1fb801c0 +#define INT2_IP22 0x1fbd9000 +#define INT2_IP24 0x1fbd9880 + +/* The following registers are all 8 bit. */ +#define INT2_LOCAL0_STATUS 0x03 +#define INT2_LOCAL0_STATUS_FIFO 0x01 +#define INT2_LOCAL0_MASK 0x07 +#define INT2_LOCAL1_STATUS 0x0b +#define INT2_LOCAL1_MASK 0x0f +#define INT2_MAP_STATUS 0x13 +#define INT2_MAP_MASK0 0x17 +#define INT2_MAP_MASK1 0x1b +#define INT2_MAP_POL 0x1f +#define INT2_TIMER_CLEAR 0x23 +#define INT2_ERROR_STATUS 0x27 +#define INT2_TIMER_0 0x33 +#define INT2_TIMER_1 0x37 +#define INT2_TIMER_2 0x3b +#define INT2_TIMER_CONTROL 0x3f diff --git a/sys/arch/sgi/localbus/intvar.h b/sys/arch/sgi/localbus/intvar.h new file mode 100644 index 00000000000..c8f6a133862 --- /dev/null +++ b/sys/arch/sgi/localbus/intvar.h @@ -0,0 +1,34 @@ +/* $OpenBSD: intvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: int2var.h,v 1.3 2008/08/23 17:25:54 tsutsui Exp $ */ + +/* + * Copyright (c) 2004 Christopher SEKIYA + * 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. 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. + */ + +void *int2_intr_establish(int, int, int (*)(void *), + void *, const char *); + +void int2_wait_fifo(uint32_t); diff --git a/sys/arch/sgi/sgi/autoconf.c b/sys/arch/sgi/sgi/autoconf.c index 6416fa757d7..0c18a9b1e0a 100644 --- a/sys/arch/sgi/sgi/autoconf.c +++ b/sys/arch/sgi/sgi/autoconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.c,v 1.33 2011/05/30 22:25:22 oga Exp $ */ +/* $OpenBSD: autoconf.c,v 1.34 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. * @@ -238,7 +238,8 @@ device_register(struct device *dev, void *aux) (*_device_register)(dev, aux); } -#if defined(TGT_O2) || defined(TGT_OCTANE) +#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2) || \ + defined(TGT_O2) || defined(TGT_OCTANE) /* * ARCS boot path traversal @@ -324,6 +325,7 @@ arcs_device_register(struct device *dev, void *aux) { static struct device *lastparent = NULL; static struct device *pciparent = NULL; + static struct device *wdscparent = NULL; static int component_pos = 0; struct device *parent = dev->dv_parent; @@ -409,22 +411,45 @@ arcs_device_register(struct device *dev, void *aux) if (parent == lastparent) goto found_advance; + if (component_pos == 0) + switch (sys_config.system_type) { #ifdef TGT_O2 /* * On O2, the pci(0) component may be omitted from * the bootpath, in which case we fake the missing * pci(0) component. */ - if (sys_config.system_type == SGI_O2 && - component_pos == 0) { + case SGI_O2: if (parent->dv_parent != NULL && strcmp(parent->dv_parent->dv_cfdata->cf_driver->cd_name, "pci") == 0) { pciparent = parent->dv_parent; goto found_advance; } - } + break; #endif +#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2) + /* + * On Ind{igo,y,i^2} systems, the bootpath + * starts at scsi(). + */ + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + if (strcmp(parent->dv_cfdata->cf_driver->cd_name, + "wdsc") == 0 && + parent->dv_parent != NULL && + strcmp(parent->dv_parent->dv_cfdata->cf_driver->cd_name, + "hpc") == 0) { + wdscparent = parent; + goto found_advance; + } + break; +#endif + default: + break; + } } if (parent == lastparent) { @@ -434,6 +459,12 @@ arcs_device_register(struct device *dev, void *aux) if (unit == paa->pa_device - (sys_config.system_type == SGI_O2 ? 1 : 0)) goto found; + } else + if (parent == wdscparent) { + /* XXX is there any better information to use + XXX than the attachment number? */ + if (unit == parent->dv_unit) + goto found; } /* * in case scsi() can follow something else then @@ -473,7 +504,7 @@ found: lastparent = dev; } -#endif /* defined(TGT_O2) || defined(TGT_OCTANE) */ +#endif /* IP20/22/24/26/28/30/32 */ #ifdef TGT_ORIGIN @@ -647,7 +678,7 @@ dksc_device_register(struct device *dev, void *aux) } } -#endif +#endif /* IP27/35 */ struct nam2blk nam2blk[] = { { "sd", 0 }, diff --git a/sys/arch/sgi/sgi/conf.c b/sys/arch/sgi/sgi/conf.c index 9a229de9161..0da5395e126 100644 --- a/sys/arch/sgi/sgi/conf.c +++ b/sys/arch/sgi/sgi/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.29 2011/10/06 20:49:28 deraadt Exp $ */ +/* $OpenBSD: conf.c,v 1.30 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 1992, 1993 @@ -97,6 +97,8 @@ cdev_decl(fd); #include "tun.h" #include "com.h" cdev_decl(com); +#include "zs.h" +cdev_decl(zs); #include "lpt.h" cdev_decl(lpt); #include "ch.h" @@ -154,7 +156,7 @@ struct cdevsw cdevsw[] = cdev_lpt_init(NLPT,lpt), /* 16: Parallel printer interface */ cdev_tty_init(NCOM,com), /* 17: 16C450 serial interface */ cdev_disk_init(NWD,wd), /* 18: ST506/ESDI/IDE disk */ - cdev_notdef(), /* 19: */ + cdev_tty_init(NZS,zs), /* 19: Z8530 serial interface */ cdev_notdef(), /* 20: */ cdev_notdef(), /* 21: */ cdev_disk_init(NRD,rd), /* 22: ramdisk device */ @@ -294,8 +296,9 @@ int nchrtoblktbl = nitems(chrtoblktbl); #include <dev/cons.h> -cons_decl(ws); cons_decl(com); +cons_decl(ws); +cons_decl(zs); struct consdev constab[] = { #if NWSDISPLAY > 0 @@ -304,5 +307,8 @@ struct consdev constab[] = { #if NCOM > 0 cons_init(com), #endif +#if NZS > 0 + cons_init(zs), +#endif { 0 }, }; diff --git a/sys/arch/sgi/sgi/ip22.h b/sys/arch/sgi/sgi/ip22.h new file mode 100644 index 00000000000..9fd00054f77 --- /dev/null +++ b/sys/arch/sgi/sgi/ip22.h @@ -0,0 +1,32 @@ +/* $OpenBSD: ip22.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * IP20/IP22/IP24 definitions + */ + +/* IP22 system types */ + +#define IP22_INDY 0 /* Indy, Challenge S */ +#define IP22_INDIGO2 1 /* Indigo 2 */ + +/* Interrupt handling priority */ + +#define INTPRI_BUSERR (INTPRI_CLOCK + 1) +#define INTPRI_L1 (INTPRI_BUSERR + 1) +#define INTPRI_L0 (INTPRI_L1 + 1) diff --git a/sys/arch/sgi/sgi/ip22_machdep.c b/sys/arch/sgi/sgi/ip22_machdep.c new file mode 100644 index 00000000000..dbe7ccbd330 --- /dev/null +++ b/sys/arch/sgi/sgi/ip22_machdep.c @@ -0,0 +1,277 @@ +/* $OpenBSD: ip22_machdep.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ + +/* + * Copyright (c) 2012 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> + +#include <uvm/uvm_extern.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cpu.h> +#include <machine/memconf.h> + +#include <mips64/arcbios.h> +#include <mips64/archtype.h> + +#include <sgi/sgi/ip22.h> +#include <sgi/localbus/imcreg.h> +#include <sgi/localbus/imcvar.h> +#include <sgi/hpc/hpcreg.h> +#include <sgi/hpc/iocreg.h> + +extern char *hw_prod; + +void ip22_arcbios_walk(void); +int ip22_arcbios_walk_component(arc_config_t *); +void ip22_memory_setup(void); + +/* + * Walk the ARCBios component tree to get L2 cache information. + * This is the only way we can get the L2 cache size. + */ + +int +ip22_arcbios_walk_component(arc_config_t *cf) +{ + struct cpu_info *ci = curcpu(); + arc_config_t *child; + + /* + * Split secondary caches are not supported. + * No IP22 processor module uses them anyway. + */ + if (cf->class == arc_CacheClass && cf->type == arc_SecondaryCache) { + /* + * Secondary cache information is encoded as WWLLSSSS, where + * WW is the number of ways (should be 01) + * LL is Log2(line size) (should be 04 or 05) + * SS is Log2(cache size in 4KB units) (should be 0007) + */ + ci->ci_l2size = (1 << 12) << (cf->key & 0x0000ffff); + /* L2 line size */ + ci->ci_cacheconfiguration = 1 << ((cf->key >> 16) & 0xff); + return 0; /* abort walk */ + } + + /* + * It is safe to assume we have a 32-bit ARCBios, until + * IP26 and IP28 support is added, hence unconditional + * use of arc_config_t. + */ + for (child = (arc_config_t *)Bios_GetChild(cf); child != NULL; + child = (arc_config_t *)Bios_GetPeer(child)) { + if (ip22_arcbios_walk_component(child) == 0) + return 0; + } + + return 1; /* continue walk */ +} + +void +ip22_arcbios_walk() +{ + (void)ip22_arcbios_walk_component((arc_config_t *)Bios_GetChild(NULL)); +} + +#define IMC_NREGION 3 + +void +ip22_memory_setup() +{ + uint i, bank, shift; + uint32_t memc0, memc1; + uint32_t memc; + paddr_t base[IMC_NREGION], size[IMC_NREGION], limit; + paddr_t start0, end0, start1, end1; + struct phys_mem_desc *mem; + + /* + * Figure out the top of memory, as reported by ARCBios. + */ + + limit = 0; + for (i = 0, mem = mem_layout; i < MAXMEMSEGS; i++, mem++) { + if (mem->mem_last_page > limit) + limit = mem->mem_last_page; + } + limit = ptoa(limit); + + /* + * Figure out where the memory controller has put memory. + */ + + memc0 = imc_read(IMC_MEMCFG0); + memc1 = imc_read(IMC_MEMCFG1); + + shift = IMC_MEMC_LSHIFT; + /* Revision D onwards uses larger units, to allow for more memory */ + if ((imc_read(IMC_SYSID) & IMC_SYSID_REVMASK) >= 5) + shift = IMC_MEMC_LSHIFT_HUGE; + + for (bank = 0; bank < IMC_NREGION; bank++) { + memc = (bank & 2) ? memc1 : memc0; + if ((bank & 1) == 0) + memc >>= IMC_MEMC_BANK_SHIFT; + memc &= IMC_MEMC_BANK_MASK; + + if ((memc & IMC_MEMC_VALID) == 0) { + base[bank] = size[bank] = 0; + continue; + } + + base[bank] = (memc & IMC_MEMC_ADDR_MASK) >> IMC_MEMC_ADDR_SHIFT; + base[bank] <<= shift; + + size[bank] = (memc & IMC_MEMC_SIZE_MASK) >> IMC_MEMC_SIZE_SHIFT; + size[bank]++; + size[bank] <<= shift; + } + + /* + * Perform sanity checks on the above data.. + */ + + /* memory should not start below 128MB */ + for (bank = 0; bank < IMC_NREGION; bank++) + if (size[bank] != 0 && base[bank] < (1ULL << 27)) + goto dopanic; + + /* banks should not overlap */ + for (bank = 1; bank < IMC_NREGION; bank++) { + if (size[bank] == 0) + continue; + start0 = base[bank]; + end0 = base[bank] + size[bank]; + for (i = 0; i < bank; i++) { + if (size[i] == 0) + continue; + start1 = base[i]; + end1 = base[i] + size[i]; + if (end0 > start1 && start0 < end1) + goto dopanic; + } + } + + /* + * Now register all the memory beyond what ARCBios stopped at. + */ + + for (bank = 0; bank < IMC_NREGION; bank++) { + if (size[bank] == 0) + continue; + + start0 = base[bank]; + end0 = base[bank] + size[bank]; + if (end0 <= limit) + continue; + + if (start0 < limit) + start0 = limit; + + memrange_register(atop(start0), atop(end0), 0); + } + + return; + +dopanic: + bios_printf("** UNEXPECTED MEMORY CONFIGURATION **\n"); + bios_printf("MEMC0 %08x MEMC1 %08x\n", memc0, memc1); + bios_printf("Please contact <sgi@openbsd.org>\n" + "Halting system.\n"); + Bios_Halt(); + for (;;) ; +} + +void +ip22_setup() +{ + u_long cpuspeed; + volatile uint32_t *sysid; + + /* + * Get CPU information. + */ + bootcpu_hwinfo.c0prid = cp0_get_prid(); + bootcpu_hwinfo.c1prid = cp1_get_prid(); + cpuspeed = bios_getenvint("cpufreq"); + if (sys_config.system_type == SGI_IP20) + cpuspeed <<= 1; + if (cpuspeed < 100) + cpuspeed = 100; /* reasonable default */ + bootcpu_hwinfo.clock = cpuspeed * 1000000; + bootcpu_hwinfo.type = (bootcpu_hwinfo.c0prid >> 8) & 0xff; + + /* + * Figure out what critter we are running on. + */ + switch (sys_config.system_type) { + case SGI_IP20: + hw_prod = "Indigo"; + break; + case SGI_IP22: + sysid = (volatile uint32_t *) + PHYS_TO_XKPHYS(HPC_BASE_ADDRESS_0 + IOC_BASE + IOC_SYSID, + CCA_NC); + if (*sysid & 0x01) { + sys_config.system_subtype = IP22_INDIGO2; + hw_prod = "Indigo2"; + } else { + sys_config.system_subtype = IP22_INDY; + hw_prod = "Indy"; + } + break; + case SGI_IP26: + sys_config.system_subtype = IP22_INDIGO2; + hw_prod = "POWER Indigo2 R8000"; + break; + case SGI_IP28: + sys_config.system_subtype = IP22_INDIGO2; + hw_prod = "POWER Indigo2 R10000"; + break; + } + + /* + * Figure out how many TLB entries are available. + */ + switch (bootcpu_hwinfo.type) { +#ifdef CPU_R10000 + case MIPS_R10000: + bootcpu_hwinfo.tlbsize = 64; + break; +#endif + default: /* R4x00, R5000 */ + bootcpu_hwinfo.tlbsize = 48; + break; + } + + /* + * Compute memory layout. ARCBios may not report all memory (on + * Indigo, it seems to only report up to 128MB, and on Indigo2, + * up to 256MB). + */ + ip22_memory_setup(); + + /* + * Scan ARCBios component list for L2 cache information. + */ + ip22_arcbios_walk(); + + _device_register = arcs_device_register; +} diff --git a/sys/arch/sgi/sgi/ip30_machdep.c b/sys/arch/sgi/sgi/ip30_machdep.c index 4a2d5dc02e2..c5077d31438 100644 --- a/sys/arch/sgi/sgi/ip30_machdep.c +++ b/sys/arch/sgi/sgi/ip30_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip30_machdep.c,v 1.50 2012/03/25 13:52:52 miod Exp $ */ +/* $OpenBSD: ip30_machdep.c,v 1.51 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2008, 2009 Miodrag Vallat. @@ -168,9 +168,7 @@ ip30_setup() comconsaddr = IOC3_UARTA_BASE; comconsfreq = 22000000 / 3; comconsiot = &sys_config.console_io; - comconsrate = bios_getenvint("dbaud"); - if (comconsrate < 50 || comconsrate > 115200) - comconsrate = 9600; + comconsrate = bios_consrate; #ifdef DDB /* diff --git a/sys/arch/sgi/sgi/ip32_machdep.c b/sys/arch/sgi/sgi/ip32_machdep.c index e3760cbd031..611f3f2d058 100644 --- a/sys/arch/sgi/sgi/ip32_machdep.c +++ b/sys/arch/sgi/sgi/ip32_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip32_machdep.c,v 1.17 2012/03/15 18:57:22 miod Exp $ */ +/* $OpenBSD: ip32_machdep.c,v 1.18 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -198,9 +198,7 @@ ip32_setup() comconsaddr = MACE_ISA_SER1_OFFS; comconsfreq = 1843200; comconsiot = &macebus_tag; - comconsrate = bios_getenvint("dbaud"); - if (comconsrate < 50 || comconsrate > 115200) - comconsrate = 9600; + comconsrate = bios_consrate; } /* not sure if there is a way to tell O2 and O2+ apart */ diff --git a/sys/arch/sgi/sgi/machdep.c b/sys/arch/sgi/sgi/machdep.c index 0d4f8811c2a..52405982621 100644 --- a/sys/arch/sgi/sgi/machdep.c +++ b/sys/arch/sgi/sgi/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.114 2012/03/25 13:52:52 miod Exp $ */ +/* $OpenBSD: machdep.c,v 1.115 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -141,11 +141,11 @@ caddr_t mips_init(int argc, void *argv, caddr_t boot_esym) { char *cp; - int i; + int i, guessed; u_int cputype; vaddr_t xtlb_handler; extern char start[], edata[], end[]; - extern char exception[], e_exception[]; + extern char cache_err[], exception[], e_exception[]; extern char *hw_vendor; #ifdef MULTIPROCESSOR @@ -222,6 +222,34 @@ mips_init(int argc, void *argv, caddr_t boot_esym) */ hw_vendor = "SGI"; switch (sys_config.system_type) { +#ifdef TGT_INDIGO + case SGI_IP20: + bios_printf("Found SGI-IP20, setting up.\n"); + /* IP22 is intentional, we use the same kernel */ + strlcpy(cpu_model, "IP22", sizeof(cpu_model)); + ip22_setup(); + break; +#endif +#if defined(TGT_INDY) || defined(TGT_INDIGO2) + case SGI_IP22: + bios_printf("Found SGI-IP22, setting up.\n"); + strlcpy(cpu_model, "IP22", sizeof(cpu_model)); + ip22_setup(); + break; +#endif +#ifdef TGT_INDIGO2 + case SGI_IP26: + bios_printf("Found SGI-IP26, setting up.\n"); + /* IP28 is intentional, we will probably use the same kernel */ + strlcpy(cpu_model, "IP28", sizeof(cpu_model)); + ip22_setup(); + break; + case SGI_IP28: + bios_printf("Found SGI-IP28, setting up.\n"); + strlcpy(cpu_model, "IP28", sizeof(cpu_model)); + ip22_setup(); + break; +#endif #ifdef TGT_O2 case SGI_O2: bios_printf("Found SGI-IP32, setting up.\n"); @@ -253,10 +281,14 @@ mips_init(int argc, void *argv, caddr_t boot_esym) break; #endif default: - bios_printf("Kernel doesn't support this system type!\n"); + bios_printf("There is no support for this system type " + "(%02x) in this kernel.\n" + "Are you sure you have booted the right kernel " + "for this machine?\n", + sys_config.system_type); bios_printf("Halting system.\n"); Bios_Halt(); - while(1); + for (;;) ; } /* @@ -277,20 +309,16 @@ mips_init(int argc, void *argv, caddr_t boot_esym) "The kernel might not be able to find out its root device.\n"); /* - * Read platform-specific environment variables. + * Read platform-specific environment variables from ARCBios. + * (Note these may not exist on all systems) */ - switch (sys_config.system_type) { -#ifdef TGT_O2 - case SGI_O2: - /* Get Ethernet address from ARCBIOS. */ - cp = Bios_GetEnvironmentVariable("eaddr"); - if (cp != NULL && strlen(cp) > 0) - strlcpy(bios_enaddr, cp, sizeof bios_enaddr); - break; -#endif - default: - break; - } + /* onboard Ethernet address (does not exist on IP27/IP35) */ + cp = Bios_GetEnvironmentVariable("eaddr"); + if (cp != NULL && strlen(cp) > 0) + strlcpy(bios_enaddr, cp, sizeof bios_enaddr); + bios_consrate = bios_getenvint("dbaud"); + if (bios_consrate < 50 || bios_consrate > 115200) + bios_consrate = 9600; /* sane default */ /* * Set pagesize to enable use of page macros and functions. @@ -345,6 +373,7 @@ mips_init(int argc, void *argv, caddr_t boot_esym) /* * Configure cache. */ + guessed = 0; switch (bootcpu_hwinfo.type) { #ifdef CPU_R10000 case MIPS_R10000: @@ -353,6 +382,16 @@ mips_init(int argc, void *argv, caddr_t boot_esym) cputype = MIPS_R10000; break; #endif +#ifdef CPU_R4000 + case MIPS_R4000: + cputype = MIPS_R4000; + break; +#endif +#ifdef CPU_R4600 + case MIPS_R4600: + cputype = MIPS_R5000; + break; +#endif #ifdef CPU_R5000 case MIPS_R5000: case MIPS_RM52X0: @@ -369,24 +408,52 @@ mips_init(int argc, void *argv, caddr_t boot_esym) /* * If we can't identify the cpu type, it must be * r10k-compatible on Octane and Origin families, and - * it is likely to be r5k-compatible on O2. + * it is likely to be r5k-compatible on O2 and + * r4k-compatible on Ind{igo*,y}. */ + guessed = 1; switch (sys_config.system_type) { + case SGI_IP20: + case SGI_IP22: + bios_printf("Unrecognized processor type, assuming" + " R4000 compatible\n"); + cputype = MIPS_R4000; + break; case SGI_O2: + bios_printf("Unrecognized processor type, assuming" + " R5000 compatible\n"); cputype = MIPS_R5000; break; + case SGI_IP26: + bios_printf("Unrecognized processor type, assuming" + " R8000 compatible\n"); + cputype = MIPS_R8000; + break; default: - case SGI_OCTANE: case SGI_IP27: + case SGI_IP28: + case SGI_OCTANE: case SGI_IP35: + bios_printf("Unrecognized processor type, assuming" + " R10000 compatible\n"); cputype = MIPS_R10000; break; } break; } switch (cputype) { - default: -#if defined(CPU_R5000) || defined(CPU_RM7000) +#ifdef CPU_R4000 + case MIPS_R4000: + Mips4k_ConfigCache(curcpu()); + sys_config._SyncCache = Mips4k_SyncCache; + sys_config._InvalidateICache = Mips4k_InvalidateICache; + sys_config._SyncDCachePage = Mips4k_SyncDCachePage; + sys_config._HitSyncDCache = Mips4k_HitSyncDCache; + sys_config._IOSyncDCache = Mips4k_IOSyncDCache; + sys_config._HitInvalidateDCache = Mips4k_HitInvalidateDCache; + break; +#endif +#if defined(CPU_R4600) || defined(CPU_R5000) || defined(CPU_RM7000) case MIPS_R5000: Mips5k_ConfigCache(curcpu()); sys_config._SyncCache = Mips5k_SyncCache; @@ -408,6 +475,20 @@ mips_init(int argc, void *argv, caddr_t boot_esym) sys_config._HitInvalidateDCache = Mips10k_HitInvalidateDCache; break; #endif + default: + if (guessed) { + bios_printf("There is no support for this processor " + "family in this kernel.\n" + "Are you sure you have booted the right kernel " + "for this machine?\n"); + } else { + bios_printf("There is no support for this processor " + "family (%02x) in this kernel.\n", cputype); + } + bios_printf("Halting system.\n"); + Bios_Halt(); + for (;;) ; + break; } /* @@ -449,13 +530,21 @@ mips_init(int argc, void *argv, caddr_t boot_esym) /* * Copy down exception vector code. */ - bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception); + bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - cache_err); bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception); /* * Build proper TLB refill handler trampolines. */ switch (cputype) { +#ifdef CPU_R4000 + case MIPS_R4000: + { + extern void xtlb_miss_err_r4k; + xtlb_handler = (vaddr_t)&xtlb_miss_err_r4k; + } + break; +#endif #if defined(CPU_R5000) || defined(CPU_RM7000) case MIPS_R5000: { @@ -744,9 +833,17 @@ arcbios_halt(int howto) #endif if (howto & RB_HALT) { - if (howto & RB_POWERDOWN) + if (howto & RB_POWERDOWN) { +#ifdef TGT_INDY + /* + * ARCBios needs to use the FPU on Indy during + * shutdown. + */ + if (sys_config.system_type == SGI_IP22) + setsr(getsr() | SR_COP_1_BIT); +#endif Bios_PowerDown(); - else + } else Bios_EnterInteractiveMode(); } else Bios_Reboot(); diff --git a/sys/arch/sgi/sgi/mainbus.c b/sys/arch/sgi/sgi/mainbus.c index 5d8e411d0d1..018bbd372a4 100644 --- a/sys/arch/sgi/sgi/mainbus.c +++ b/sys/arch/sgi/sgi/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.8 2010/01/09 20:33:16 miod Exp $ */ +/* $OpenBSD: mainbus.c,v 1.9 2012/03/28 20:44:23 miod Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -89,9 +89,9 @@ mbattach(struct device *parent, struct device *self, void *aux) } /* - * On other systems, attach the CPU we are running on early; - * other processors, if any, will get attached as they are - * discovered. + * On other systems, attach the CPU, its clock, and the + * mainbus here. + * XXX Would be worth doing as ipXX_autoconf() too. */ bzero(&caa, sizeof caa); @@ -103,6 +103,19 @@ mbattach(struct device *parent, struct device *self, void *aux) config_found(self, &caa.caa_maa, mbprint); switch (sys_config.system_type) { +#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2) + case SGI_IP20: + case SGI_IP22: + case SGI_IP26: + case SGI_IP28: + /* Interrupt Controller */ + caa.caa_maa.maa_name = "int"; + config_found(self, &caa.caa_maa, mbprint); + /* Memory Controller */ + caa.caa_maa.maa_name = "imc"; + config_found(self, &caa.caa_maa, mbprint); + break; +#endif #ifdef TGT_O2 case SGI_O2: caa.caa_maa.maa_name = "macebus"; diff --git a/sys/arch/sgi/stand/Makefile b/sys/arch/sgi/stand/Makefile index 62a19908f9c..d18503c5228 100644 --- a/sys/arch/sgi/stand/Makefile +++ b/sys/arch/sgi/stand/Makefile @@ -1,11 +1,10 @@ -# $OpenBSD: Makefile,v 1.7 2012/03/19 17:38:29 miod Exp $ +# $OpenBSD: Makefile,v 1.8 2012/03/28 20:44:23 miod Exp $ SUBDIR= sgivol .if ${MACHINE} == "sgi" SUBDIR+= libsa libsa32 libz libz32 -SUBDIR+= boot64 boot32 -#SUBDIR+= bootecoff +SUBDIR+= boot64 boot32 bootecoff .endif .include <bsd.subdir.mk> diff --git a/sys/conf/files b/sys/conf/files index 379b1e2cdb8..dad448cd616 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.534 2012/03/09 13:01:28 ariane Exp $ +# $OpenBSD: files,v 1.535 2012/03/28 20:44:23 miod Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -234,6 +234,10 @@ file dev/ic/osiop.c osiop & (osiop_gsc | osiop_eisa | osiop_pcctwo) device oosiop: scsi file dev/ic/oosiop.c oosiop +# Western Digital WD33C93 SCSI controllers +define wd33c93 +file dev/ic/wd33c93.c wd33c93 + # 3Com Etherlink-III Ethernet controller device ep: ether, ifnet, ifmedia, mii file dev/ic/elink3.c ep diff --git a/sys/dev/eisa/eisavar.h b/sys/dev/eisa/eisavar.h index d8d5b59f84c..e48cfa8f561 100644 --- a/sys/dev/eisa/eisavar.h +++ b/sys/dev/eisa/eisavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: eisavar.h,v 1.13 2010/05/23 14:50:31 deraadt Exp $ */ +/* $OpenBSD: eisavar.h,v 1.14 2012/03/28 20:44:23 miod Exp $ */ /* $NetBSD: eisavar.h,v 1.11 1997/06/06 23:30:07 thorpej Exp $ */ /* @@ -54,17 +54,12 @@ struct eisabus_attach_args; /* * Machine-dependent definitions. */ -#if (__alpha__ + __i386__ + __hppa__ != 1) -#error COMPILING FOR UNSUPPORTED MACHINE, OR MORE THAN ONE. -#endif -#if __alpha__ +#if defined(__alpha__) #include <alpha/eisa/eisa_machdep.h> -#endif -#if __i386__ +#elif defined(__i386__) #include <i386/eisa/eisa_machdep.h> -#endif -#if __hppa__ -#include <hppa/include/eisa_machdep.h> +#else +#include <machine/eisa_machdep.h> #endif typedef int eisa_slot_t; /* really only needs to be 4 bits */ diff --git a/sys/dev/ic/dp8573areg.h b/sys/dev/ic/dp8573areg.h new file mode 100644 index 00000000000..bf66e70bf1e --- /dev/null +++ b/sys/dev/ic/dp8573areg.h @@ -0,0 +1,121 @@ +/* $OpenBSD: dp8573areg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: dp8573areg.h,v 1.1 2009/02/12 06:33:57 rumble Exp $ */ + +/* + * Copyright (c) 2003 Steve Rumble + * Copyright (c) 2001 Erik Reid + * + * 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. 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. + */ + +/* + * National Semiconductor DP8573A Real Time Clock + */ + +/* Control and Status Register Offsets and Masks */ +#define DP8573A_STATUS 0x00 /* Main Status */ +#define DP8573A_STATUS_INTSTAT 0x01 /* Interrupt Status */ +#define DP8573A_STATUS_PWRFAIL 0x02 /* Power Fail Interrupt */ +#define DP8573A_STATUS_PERINT 0x04 /* Period Interrupt */ +#define DP8573A_STATUS_ALMINT 0x08 /* Alarm Interrupt */ +#define DP8573A_STATUS_REGSEL 0x40 /* Register Select */ + +/* Register Select = 0 */ +#define DP8573A_PFLAG 0x03 /* Periodic Flag */ +#define DP8573A_PFLAG_MIN 0x01 /* Minutes */ +#define DP8573A_PFLAG_10SEC 0x02 /* Ten Second */ +#define DP8573A_PFLAG_SEC 0x04 /* Seconds */ +#define DP8573A_PFLAG_100MIL 0x08 /* 100 Millisecond */ +#define DP8573A_PFLAG_10MIL 0x10 /* 10 Millisecond */ +#define DP8573A_PFLAG_MIL 0x20 /* Milliseconds */ +#define DP8573A_PFLAG_OFSS 0x40 /* Oscillator Fail/Single Supply */ +#define DP8573A_PFLAG_TESTMODE 0x80 /* Test Mode Enable */ + +#define DP8573A_TIMESAVE_CTL 0x04 /* Time Save Control */ +#define DP8573A_TIMESAVE_CTL_EN 0x80 /* Time Save Enable */ + +/* Register Select = 1 */ +#define DP8573A_RT_MODE 0x01 /* Real Time Mode */ +#define DP8573A_RT_MODE_LYLSB 0x01 /* Leap Year LSB */ +#define DP8573A_RT_MODE_LYMSB 0x02 /* Leap Year MSB */ +#define DP8573A_RT_MODE_1224 0x04 /* 12(low)/24(high) Hour Mode */ +#define DP8573A_RT_MODE_CLKSS 0x08 /* Clock Start(high)/Stop(low) */ +#define DP8573A_RT_MODE_INTPFOP 0x10 /* Interrupt PF Operation */ + +#define DP8573A_OUT_MODE 0x02 /* Output Mode */ +#define DP8573A_OUT_MODE_MFOPO 0x80 /* MFO Pin as Oscillator */ + +#define DP8573A_INT0_CTL 0x03 /* Interrupt Control 0 */ +#define DP8573A_INT0_CTL_MIN 0x01 /* Minutes Enable */ +#define DP8573A_INT0_CTL_10SEC 0x02 /* 10 Second Enable */ +#define DP8573A_INT0_CTL_SEC 0x04 /* Seconds Enable */ +#define DP8573A_INT0_CTL_100MIL 0x08 /* 100 Millisecond Enable */ +#define DP8573A_INT0_CTL_10MIL 0x10 /* 10 Millisecond Enable */ +#define DP8573A_INT0_CTL_MIL 0x20 /* Millisecond Enable */ + +#define DP8573A_INT1_CTL 0x04 /* Interrupt Control 1 */ +#define DP8573A_INT1_CTL_SECC 0x01 /* Second Compare Enable */ +#define DP8573A_INT1_CTL_MINC 0x02 /* Minute Compare Enable */ +#define DP8573A_INT1_CTL_HOURC 0x04 /* Hour Compare Enable */ +#define DP8573A_INT1_CTL_DOMC 0x08 /* Day of Month Compare Enable */ +#define DP8573A_INT1_CTL_MONTHC 0x10 /* Month Compare Enable */ +#define DP8573A_INT1_CTL_DOWC 0x20 /* Day of Week Compare Enable */ +#define DP8573A_INT1_CTL_ALMINT 0x40 /* Alarm Interrupt Enable */ +#define DP8573A_INT1_CTL_PWRINT 0x80 /* Power Fail Interrupt Enable */ + +/* Clock Counter Offsets */ +#define DP8573A_COUNTERS 0x05 /* Start of Clock Counters */ +#define DP8573A_SUBSECOND 0x05 /* 1/100 Second */ +#define DP8573A_SECOND 0x06 /* Seconds */ +#define DP8573A_MINUTE 0x07 /* Minutes */ +#define DP8573A_HOUR 0x08 /* Hours */ +#define DP8573A_DOM 0x09 /* Day of Month */ +#define DP8573A_MONTH 0x0a /* Months */ +#define DP8573A_YEAR 0x0b /* Years */ +#define DP8573A_DOW 0x0e /* Day of Week */ + +/* Comparsion Registers */ +#define DP8573A_CMP_SEC 0x13 /* Seconds */ +#define DP8573A_CMP_MIN 0x14 /* Minutes */ +#define DP8573A_CMP_HOUR 0x15 /* Hours */ +#define DP8573A_CMP_DOM 0x16 /* Day of Month */ +#define DP8573A_CMP_MONTH 0x17 /* Months */ +#define DP8573A_CMP_DOW 0x18 /* Day of Week */ + +/* Time Save Registers */ +#define DP8573A_SAVE_SEC 0x19 /* Seconds */ +#define DP8573A_SAVE_MIN 0x1a /* Minutes */ +#define DP8573A_SAVE_HOUR 0x1b /* Hours */ +#define DP8573A_SAVE_DOM 0x1c /* Day of Month */ +#define DP8573A_SAVE_MONTH 0x1d /* Months */ + +/* RAM Registers */ +#define DP8573A_RAM_0C 0x0c /* RAM */ +#define DP8573A_RAM_1E 0x1e /* RAM */ +#define DP8573A_RAM_1F 0x1f /* RAM */ + +/* 12/24 Hour Masks */ +#define DP8573A_HOUR_12HR_MASK 0x1f +#define DP8573A_HOUR_24HR_MASK 0x3f + +#define DP8573A_NREG 0x20 diff --git a/sys/dev/ic/dp857xreg.h b/sys/dev/ic/dp857xreg.h deleted file mode 100644 index 9164c574718..00000000000 --- a/sys/dev/ic/dp857xreg.h +++ /dev/null @@ -1,133 +0,0 @@ -/* $OpenBSD: dp857xreg.h,v 1.4 2012/03/07 18:15:25 miod Exp $ */ - -/* - * Copyright (c) 1996 Per Fogelstrom - * - * 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. - * - * 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. - * - */ - -#if !defined(_DP857X_H) -#define _DP857X_H - -/* - * Definition of Real Time Clock address space. - * - * Clock is a National DP8570A RTC - */ -#define BSIZE 1 /* No of Bytes for Address Spacing */ -#define MAIN_STATUS 0x00 /* Main status register */ -/* - * Registers selected with BS=0 RS=0 - */ -#define TIMER0_CTRL 0x01 /* Timer 0 control register */ -#define TIMER1_CTRL 0x02 /* Timer 0 control register */ -#define PERIODIC_FLAGS 0x03 /* Timer periodic flag register */ -#define INTERRUPT_ROUT 0x04 /* Interrupt routing register */ -/* - * Registers selected with BS=0 RS=1 - */ -#define REAL_TIME_MODE 0x01 /* Real Time Mode register */ -#define OUTPUT_MODE 0x02 /* Output mode register */ -#define INTERRUPT_CTRL0 0x03 /* Interrupt control register 0 */ -#define INTERRUPT_CTRL1 0x04 /* Interrupt control register 1 */ -/* - * Clock and timer registers when BS=0 - */ -#define CLK_SUBSECONDS 0x05 /* 1/100 seconds register */ -#define CLK_SECONDS 0x06 /* Seconds */ -#define CLK_MINUTES 0x07 /* Minutes */ -#define CLK_HOURS 0x08 /* Hours */ -#define CLK_DAY 0x09 /* Day of month */ -#define CLK_MONTH 0x0a /* Month */ -#define CLK_YEAR 0x0b /* Year */ -#define CLK_JULIAN_L 0x0c /* Lsb of Julian date */ -#define CLK_JULIAN_H 0x0d /* Msb of Julian date */ -#define CLK_WEEKDAY 0x0e /* Day of week */ -#define TIMER0_LSB 0x0f /* Timer 0 lsb */ -#define TIMER0_MSB 0x10 /* Timer 0 msb */ -#define TIMER1_LSB 0x11 /* Timer 1 lsb */ -#define TIMER1_MSB 0x12 /* Timer 1 msb */ -#define CMP_SECONDS 0x13 /* Seconds compare */ -#define CMP_MINUTES 0x14 /* Minutes compare */ -#define CMP_HOUR 0x15 /* Hours compare */ -#define CMP_DAY 0x16 /* Day of month compare */ -#define CMP_MONTH 0x17 /* Month compare */ -#define CMP_WEEKDAY 0x18 /* Day of week compare */ -#define SAVE_SECONDS 0x19 /* Seconds time save */ -#define SAVE_MINUTES 0x1a /* Minutes time save */ -#define SAVE_HOUR 0x1b /* Hours time save */ -#define SAVE_DAY 0x1c /* Day of month time save */ -#define SAVE_MONTH 0x1d /* Month time save */ -#define RAM_1E 0x1e /* Ram location 1e */ -#define RAM_1F 0x1f /* Ram location 1f */ -#define SIZE_DP857X 0x20 /* Size of dp address map */ - -#define DP_FIRSTTODREG CLK_SUBSECONDS -#define DP_LASTTODREG CLK_WEEKDAY - -typedef u_int dp_todregs[SIZE_DP857X]; -u_int dp857x_read(void *sc, u_int reg); -void dp857x_write(void *sc, u_int reg, u_int datum); - -/* - * Get all of the TOD/Alarm registers - * Must be called at splhigh(), and with the RTC properly set up. - */ -#define DP857X_GETTOD(sc, regs) \ - do { \ - int i; \ - \ - /* make sure clock regs are selected */ \ - dp857x_write(sc, MAIN_STATUS, 0); \ - /* try read until no rollover */ \ - do { \ - /* read all of the tod/alarm regs */ \ - for (i = DP_FIRSTTODREG; i < SIZE_DP857X; i++) \ - (*regs)[i] = dp857x_read(sc, i); \ - } while(dp857x_read(sc, PERIODIC_FLAGS) & 7); \ - } while (0); - -/* - * Set all of the TOD/Alarm registers - * Must be called at splhigh(), and with the RTC properly set up. - */ -#define DP857X_PUTTOD(sc, regs) \ - do { \ - int i; \ - \ - /* stop updates while setting, eg clear start bit */ \ - dp857x_write(sc, MAIN_STATUS, 0x40); \ - dp857x_write(sc, REAL_TIME_MODE, \ - dp857x_read(sc, REAL_TIME_MODE) & 0xF7); \ - \ - /* write all of the tod/alarm regs */ \ - for (i = DP_FIRSTTODREG; i <= DP_LASTTODREG; i++) \ - dp857x_write(sc, i, (*regs)[i]); \ - \ - /* reenable updates, eg set clock start bit */ \ - dp857x_write(sc, REAL_TIME_MODE, \ - dp857x_read(sc, REAL_TIME_MODE) | 0x08); \ - } while (0); - -#endif /*_DP857X_H*/ - diff --git a/sys/dev/ic/ds1286reg.h b/sys/dev/ic/ds1286reg.h new file mode 100644 index 00000000000..2b625fc181f --- /dev/null +++ b/sys/dev/ic/ds1286reg.h @@ -0,0 +1,182 @@ +/* $OpenBSD: ds1286reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: ds1286reg.h,v 1.8 2005/12/11 12:21:26 christos Exp $ */ + +/* + * Copyright (c) 2001 Rafal K. Boni + * + * 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. 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. + */ + +/* + * Originally based on mc146818reg.h, with the following license: + * + * Copyright (c) 1995 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 the + * rights to redistribute these changes. + */ + +/* + * Definitions for the Dallas Semiconductor DS1286/DS1386 Real Time Clock. + * + * Plucked right from the Dallas Semicomductor specs available at + * http://pdfserv.maxim-ic.com/arpdf/DS1286.pdf and + * http://pdfserv.maxim-ic.com/arpdf/DS1386-DS1386P.pdf + * + * The DS1286 and 1386 have 14 clock-related registers and some amount + * of user registers (50 for the 1286, 8K or 32K for the 1386). The + * first eleven registers contain time-of-day and alarm data, the rest + * contain various control bits and the watchdog timer functionality. + * + * Since the locations of these ports and the method used to access + * them can be machine-dependent, the low-level details of reading + * and writing the RTC's registers are handled by machine-specific + * functions. + * + * The DS1286/DS1386 chips always store time-of-day and alarm data in + * BCD. The "hour" time-of-year and alarm fields can either be stored + * in AM/PM format, or in 24-hour format. If AM/PM format is chosen, + * the hour fields can have the values: 1-12 (for AM) and 21-32 (for + * PM). If the 24-hour format is chosen, they can have the values 0 + * to 23. The hour format is selectable separately for the time and + * alarm fields, and is controller by bit 6 of the respective register. + */ + +/* + * The registers, and the bits within each register. + */ + +#define DS1286_SUBSEC 0x0 /* Time of year: hundredths of seconds (0-99) */ +#define DS1286_SEC 0x1 /* Time of year: seconds (0-59) */ +#define DS1286_MIN 0x2 /* Time of year: minutes (0-59) */ +#define DS1286_AMIN 0x3 /* Alarm: minutes */ +#define DS1286_HOUR 0x4 /* Time of year: hour (see above) */ + +#define DS1286_HOUR_12MODE 0x40 /* Hour mode: 12-hour (on), 24 (off) */ +#define DS1286_HOUR_12HR_PM 0x20 /* AM/PM in 12-hour mode: on = PM */ +#define DS1286_HOUR_12HR_MASK 0x1f /* Mask for hours in 12hour mode */ +#define DS1286_HOUR_24HR_MASK 0x3f /* Mask for hours in 24hour mode */ + +#define DS1286_AHOUR 0x5 /* Alarm: hour */ +#define DS1286_DOW 0x6 /* Time of year: day of week (1-7) */ +#define DS1286_ADOW 0x7 /* Alarm: day of week (1-7) */ +#define DS1286_DOM 0x8 /* Time of year: day of month (1-31) */ +#define DS1286_MONTH 0x9 /* Time of year: month (1-12), wave generator */ + +#define DS1286_MONTH_MASK 0x3f /* Mask to extract month */ +#define DS1286_WAVEGEN_MASK 0xc0 /* Mask to extract wave bits */ + +#define DS1286_YEAR 0xA /* Time of year: year in century (0-99) */ + +#define DS1286_CONTROL 0xB /* Control register A */ + +#define DS1286_TE 0x80 /* Update in progress (on == disable update) */ +#define DS1286_INTSWAP 0x40 /* Swap INTA, INTB outputs */ +#define DS1286_INTBSRC 0x20 /* INTB source (on) or sink (off) current */ +#define DS1286_INTAPLS 0x10 /* INTA pulse (on) or level (off) mode */ +#define DS1286_WAM 0x08 /* Watchdog alarm mask */ +#define DS1286_TDM 0x04 /* Time-of-day alarm mask */ +#define DS1286_WAF 0x02 /* Watchdog alarm flag */ +#define DS1286_TDF 0x01 /* Time-of-day alarm flag */ + +#define DS1286_NREGS 0xd /* 14 registers; CMOS follows */ +#define DS1286_NTODREGS 0xb /* 11 of those regs are for TOD and alarm */ + +#define DS1286_NVRAM_START 0xe /* start of NVRAM: offset 14 */ + +/* NVRAM size depends on the chip -- the 1286 only has 50 bytes, whereas + * the 1386 can have 8K or 32K + */ +#define DS1286_NVRAM_SIZE 50 /* 50 bytes of NVRAM */ + +/* + * RTC register/NVRAM read and write functions -- machine-dependent. + * Appropriately manipulate RTC registers to get/put data values. + */ +u_int ds1286_read(void *, u_int); +void ds1286_write(void *, u_int, u_int); + +/* + * A collection of TOD/Alarm registers. + */ +typedef u_int ds1286_todregs[DS1286_NTODREGS]; + +/* + * Get all of the TOD/Alarm registers + * Must be called at splhigh(), and with the RTC properly set up. + */ +#define DS1286_GETTOD(sc, regs) \ + do { \ + int i; \ + u_int ctl; \ + \ + /* turn off update for now */ \ + ctl = ds1286_read(sc, DS1286_CONTROL); \ + ds1286_write(sc, DS1286_CONTROL, ctl | DS1286_TE); \ + \ + /* read all of the tod/alarm regs */ \ + for (i = 0; i < DS1286_NTODREGS; i++) \ + (*regs)[i] = ds1286_read(sc, i); \ + \ + /* turn update back on */ \ + ds1286_write(sc, DS1286_CONTROL, ctl); \ + } while (0); + +/* + * Set all of the TOD/Alarm registers + * Must be called at splhigh(), and with the RTC properly set up. + */ +#define DS1286_PUTTOD(sc, regs) \ + do { \ + int i; \ + u_int ctl; \ + \ + /* turn off update for now */ \ + ctl = ds1286_read(sc, DS1286_CONTROL); \ + ds1286_write(sc, DS1286_CONTROL, ctl | DS1286_TE); \ + \ + /* write all of the tod/alarm regs */ \ + for (i = 0; i < DS1286_NTODREGS; i++) \ + ds1286_write(sc, i, (*regs)[i]); \ + \ + /* turn update back on */ \ + ds1286_write(sc, DS1286_CONTROL, ctl); \ + } while (0); diff --git a/sys/dev/ic/seeq8003reg.h b/sys/dev/ic/seeq8003reg.h new file mode 100644 index 00000000000..c0978c67508 --- /dev/null +++ b/sys/dev/ic/seeq8003reg.h @@ -0,0 +1,134 @@ +/* $OpenBSD: seeq8003reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: seeq8003reg.h,v 1.3 2001/06/07 05:19:26 thorpej Exp $ */ + +/* + * Copyright (c) 2000 Soren S. Jorvang. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Register definitions for the Seeq 8003 and 80C03 ethernet controllers + * + * Based on documentation available at + * http://www.lsilogic.com/techlib/techdocs/networking/eol/80c03.pdf . + */ + +#define SEEQ_ADDR0 0 /* Station Address Byte 0 */ +#define SEEQ_ADDR1 1 /* Station Address Byte 1 */ +#define SEEQ_ADDR2 2 /* Station Address Byte 2 */ +#define SEEQ_ADDR3 3 /* Station Address Byte 3 */ +#define SEEQ_ADDR4 4 /* Station Address Byte 4 */ +#define SEEQ_ADDR5 5 /* Station Address Byte 5 */ + +#define SEEQ_TXCOLLS0 0 /* Transmit Collision Counter LSB */ +#define SEEQ_TXCOLLS1 1 /* Transmit Collision Counter MSB */ +#define SEEQ_ALLCOLL0 2 /* Total Collision Counter LSB */ +#define SEEQ_ALLCOLL1 3 /* Total Collision Counter MSB */ + +#define SEEQ_TEST 4 /* "For Test Only" - Do Not Use */ + +#define SEEQ_SQE 5 /* SQE / No Carrier */ +#define SQE_FLAG 0x01 /* SQE Flag */ +#define SQE_NOCARR 0x02 /* No Carrier Flag */ + +#define SEEQ_RXCMD 6 /* Rx Command */ +#define RXCMD_IE_OFLOW 0x01 /* Interrupt on Overflow Error */ +#define RXCMD_IE_CRC 0x02 /* Interrupt on CRC Error */ +#define RXCMD_IE_DRIB 0x04 /* Interrupt on Dribble Error */ +#define RXCMD_IE_SHORT 0x08 /* Interrupt on Short Frame */ +#define RXCMD_IE_END 0x10 /* Interrupt on End of Frame */ +#define RXCMD_IE_GOOD 0x20 /* Interrupt on Good Frame */ +#define RXCMD_REC_MASK 0xc0 /* Receiver Match Mode Mask */ +#define RXCMD_REC_NONE 0x00 /* Receiver Disabled */ +#define RXCMD_REC_ALL 0x40 /* Receive All Frames */ +#define RXCMD_REC_BROAD 0x80 /* Receive Station/Broadcast Frames */ +#define RXCMD_REC_MULTI 0xc0 /* Station/Broadcast/Multicast */ + +#define SEEQ_RXSTAT 6 /* Rx Status */ +#define RXSTAT_OFLOW 0x01 /* Frame Overflow Error */ +#define RXSTAT_CRC 0x02 /* Frame CRC Error */ +#define RXSTAT_DRIB 0x04 /* Frame Dribble Error */ +#define RXSTAT_SHORT 0x08 /* Received Short Frame */ +#define RXSTAT_END 0x10 /* Received End of Frame */ +#define RXSTAT_GOOD 0x20 /* Received Good Frame */ +#define RXSTAT_OLDNEW 0x80 /* Old/New Status */ + +#define SEEQ_TXCMD 7 /* Tx Command */ +#define TXCMD_IE_UFLOW 0x01 /* Interrupt on Transmit Underflow */ +#define TXCMD_IE_COLL 0x02 /* Interrupt on Transmit Collision */ +#define TXCMD_IE_16COLL 0x04 /* Interrupt on 16 Collisions */ +#define TXCMD_IE_GOOD 0x08 /* Interrupt on Transmit Succes */ +#define TXCMD_ENABLE_C 0xf0 /* (80C03) Enable 80C03 Mode */ +#define TXCMD_BANK_MASK 0x60 /* (80C03) Register Bank Mask */ +#define TXCMD_BANK0 0x00 /* (80C03) Register Bank 0 (8003) */ +#define TXCMD_BANK1 0x20 /* (80C03) Register Bank 1 (Writes) */ +#define TXCMD_BANK2 0x40 /* (80C03) Register Bank 2 (Writes) */ + +#define SEEQ_TXSTAT 7 /* Tx Status */ +#define TXSTAT_UFLOW 0x01 /* Transmit Underflow */ +#define TXSTAT_COLL 0x02 /* Transmit Collision */ +#define TXSTAT_16COLL 0x04 /* 16 Collisions */ +#define TXSTAT_GOOD 0x08 /* Transmit Success */ +#define TXSTAT_OLDNEW 0x80 /* Old/New Status */ + +/* + * 80C03 Mode Register Bank 1 + */ + +#define SEEQ_MC_HASH0 0 /* Multicast Filter Byte 0 (LSB) */ +#define SEEQ_MC_HASH1 1 /* Multicast Filter Byte 1 */ +#define SEEQ_MC_HASH2 2 /* Multicast Filter Byte 2 */ +#define SEEQ_MC_HASH3 3 /* Multicast Filter Byte 3 */ +#define SEEQ_MC_HASH4 4 /* Multicast Filter Byte 4 */ +#define SEEQ_MC_HASH5 5 /* Multicast Filter Byte 5 */ + +/* + * 80C03 Mode Register Bank 2 + */ + +#define SEEQ_MC_HASH6 0 /* Multicast Filter Byte 6 */ +#define SEEQ_MC_HASH7 1 /* Multicast Filter Byte 7 (MSB) */ + +#define SEEQ_RESERVED0 2 /* Reserved (Set to All Zeroes) */ + +#define SEEQ_TXCTRL 3 /* Tx Control */ +#define TXCTRL_TXCOLL 0x01 /* Clear/Enable Tx Collision Counter */ +#define TXCTRL_COLL 0x02 /* Clear/Enable Collision Counter */ +#define TXCTRL_SQE 0x04 /* Clear/Enable SQE Flag */ +#define TXCTRL_HASH 0x08 /* Enable Multicast Hash Filter */ +#define TXCTRL_SHORT 0x10 /* Receive Short (<13 Bytes) Frames */ +#define TXCTRL_NOCARR 0x20 /* Clear/Enable No Carrier Flag */ + +#define SEEQ_CFG 4 /* Transmit/Receive Configuration */ +#define CFG_RX_GRPADDR 0x01 /* Ignore Last 4 Bits of Address */ +#define CFG_TX_AUTOPAD 0x02 /* Automatically Pad to 60 Bytes */ +#define CFG_TX_NOPRE 0x04 /* Do Not Add Preamble Pattern */ +#define CFG_RX_NOOWN 0x08 /* Do Not Receive Own Packets */ +#define CFG_TX_NOCRC 0x10 /* No Not Append CRC */ +#define CFG_TX_DUPLEX 0x20 /* AutoDUPLEX - Ignore Carrier */ +#define CFG_RX_CRCFIFO 0x40 /* Write CRC to FIFO */ +#define CFG_RX_FASTDISC 0x80 /* Fast Receive Discard Mode */ + +#define SEEQ_RESERVED1 5 /* Reserved */ +#define SEEQ_RESERVED2 6 /* Reserved */ +#define SEEQ_RESERVED3 7 /* Reserved */ diff --git a/sys/dev/ic/wd33c93.c b/sys/dev/ic/wd33c93.c new file mode 100644 index 00000000000..2c6fabc6660 --- /dev/null +++ b/sys/dev/ic/wd33c93.c @@ -0,0 +1,2337 @@ +/* $OpenBSD: wd33c93.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: wd33c93.c,v 1.24 2010/11/13 13:52:02 uebayasi Exp $ */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of 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. + * 3. 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. + * + * @(#)scsi.c 7.5 (Berkeley) 5/4/91 + */ + +/* + * Changes Copyright (c) 2001 Wayne Knowles + * Changes Copyright (c) 1996 Steve Woodford + * Original Copyright (c) 1994 Christian E. Hopps + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of 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. + * 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. + * 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. + * + * @(#)scsi.c 7.5 (Berkeley) 5/4/91 + */ + +/* + * This version of the driver is pretty well generic, so should work with + * any flavour of WD33C93 chip. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> /* For hz */ +#include <sys/malloc.h> +#include <sys/pool.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#include <scsi/scsi_message.h> + +#include <machine/bus.h> + +#include <dev/ic/wd33c93reg.h> +#include <dev/ic/wd33c93var.h> + +/* + * SCSI delays + * In u-seconds, primarily for state changes on the SPC. + */ +#define SBIC_CMD_WAIT 200000 /* wait per step of 'immediate' cmds */ +#define SBIC_DATA_WAIT 200000 /* wait per data in/out step */ +#define SBIC_INIT_WAIT 200000 /* wait per step (both) during init */ + +#define STATUS_UNKNOWN 0xff /* uninitialized status */ + +/* + * Convenience macro for waiting for a particular wd33c93 event + */ +#define SBIC_WAIT(regs, until, timeo) wd33c93_wait(regs, until, timeo, __LINE__) + +void wd33c93_init(struct wd33c93_softc *); +void wd33c93_reset(struct wd33c93_softc *); +int wd33c93_go(struct wd33c93_softc *, struct wd33c93_acb *); +int wd33c93_dmaok(struct wd33c93_softc *, struct scsi_xfer *); +int wd33c93_wait(struct wd33c93_softc *, u_char, int , int); +u_char wd33c93_selectbus(struct wd33c93_softc *, struct wd33c93_acb *); +int wd33c93_xfout(struct wd33c93_softc *, int, void *); +int wd33c93_xfin(struct wd33c93_softc *, int, void *); +int wd33c93_poll(struct wd33c93_softc *, struct wd33c93_acb *); +int wd33c93_nextstate(struct wd33c93_softc *, struct wd33c93_acb *, + u_char, u_char); +int wd33c93_abort(struct wd33c93_softc *, struct wd33c93_acb *, + const char *); +void wd33c93_xferdone(struct wd33c93_softc *); +void wd33c93_error(struct wd33c93_softc *, struct wd33c93_acb *); +void wd33c93_scsidone(struct wd33c93_softc *, struct wd33c93_acb *, int); +void wd33c93_sched(struct wd33c93_softc *); +void wd33c93_dequeue(struct wd33c93_softc *, struct wd33c93_acb *); +void wd33c93_dma_stop(struct wd33c93_softc *); +void wd33c93_dma_setup(struct wd33c93_softc *, int); +int wd33c93_msgin_phase(struct wd33c93_softc *, int); +void wd33c93_msgin(struct wd33c93_softc *, u_char *, int); +void wd33c93_reselect(struct wd33c93_softc *, int, int, int, int); +void wd33c93_sched_msgout(struct wd33c93_softc *, u_short); +void wd33c93_msgout(struct wd33c93_softc *); +void wd33c93_timeout(void *arg); +void wd33c93_watchdog(void *arg); +u_char wd33c93_stp2syn(struct wd33c93_softc *, struct wd33c93_tinfo *); +void wd33c93_setsync(struct wd33c93_softc *, struct wd33c93_tinfo *); + +struct pool wd33c93_pool; /* Adapter Control Blocks */ +int wd33c93_pool_initialized = 0; + +/* + * Timeouts + */ +int wd33c93_cmd_wait = SBIC_CMD_WAIT; +int wd33c93_data_wait = SBIC_DATA_WAIT; +int wd33c93_init_wait = SBIC_INIT_WAIT; + +int wd33c93_nodma = 0; /* Use polled IO transfers */ +int wd33c93_nodisc = 0; /* Allow command queues */ +int wd33c93_notags = 0; /* No Tags */ + +/* + * Some useful stuff for debugging purposes + */ +#ifdef SBICDEBUG + +#define QPRINTF(a) SBIC_DEBUG(MISC, a) + +int wd33c93_debug = 0; /* Debug flags */ + +void wd33c93_print_csr (u_char); +void wd33c93_hexdump (u_char *, int); + +#else +#define QPRINTF(a) /* */ +#endif + +static const char *wd33c93_chip_names[] = SBIC_CHIP_LIST; + +/* + * Attach instance of driver and probe for sub devices + */ +void +wd33c93_attach(struct wd33c93_softc *sc, struct scsi_adapter *adapter) +{ + struct scsibus_attach_args saa; + + sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags; + timeout_set(&sc->sc_watchdog, wd33c93_watchdog, sc); + wd33c93_init(sc); + + printf(": %s, %d.%d MHz, %s\n", + wd33c93_chip_names[sc->sc_chip], + sc->sc_clkfreq / 10, sc->sc_clkfreq % 10, + (sc->sc_dmamode == SBIC_CTL_DMA) ? "DMA" : + (sc->sc_dmamode == SBIC_CTL_DBA_DMA) ? "DBA" : + (sc->sc_dmamode == SBIC_CTL_BURST_DMA) ? "burst DMA" : "PIO"); + if (sc->sc_chip == SBIC_CHIP_WD33C93B) { + printf("%s: microcode revision 0x%02x", + sc->sc_dev.dv_xname, sc->sc_rev); + if (sc->sc_minsyncperiod < 50) + printf(", fast SCSI"); + printf("\n"); + } + + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = sc->sc_id; + sc->sc_link.adapter_buswidth = SBIC_NTARG; + sc->sc_link.adapter = adapter; + sc->sc_link.openings = 2; + sc->sc_link.luns = SBIC_NLUN; + + bzero(&saa, sizeof(saa)); + saa.saa_sc_link = &sc->sc_link; + + config_found(&sc->sc_dev, &saa, scsiprint); + timeout_add_sec(&sc->sc_watchdog, 60); +} + +/* + * Initialize driver-private structures + */ +void +wd33c93_init(struct wd33c93_softc *sc) +{ + u_int i; + + timeout_del(&sc->sc_watchdog); + + if (!wd33c93_pool_initialized) { + /* All instances share the same pool */ + pool_init(&wd33c93_pool, sizeof(struct wd33c93_acb), 0, 0, 0, + "wd33c93_acb", NULL); + ++wd33c93_pool_initialized; + } + + if (sc->sc_state == 0) { + TAILQ_INIT(&sc->ready_list); + + sc->sc_nexus = NULL; + sc->sc_disc = 0; + memset(sc->sc_tinfo, 0, sizeof(sc->sc_tinfo)); + } else { + /* XXX cancel all active commands */ + panic("wd33c93: reinitializing driver!"); + } + + sc->sc_flags = 0; + sc->sc_state = SBIC_IDLE; + wd33c93_reset(sc); + + for (i = 0; i < SBIC_NTARG; i++) { + struct wd33c93_tinfo *ti = &sc->sc_tinfo[i]; + /* + * cf_flags = 0xTTSSRR + * + * TT = Bitmask to disable Tagged Queues + * SS = Bitmask to disable Sync negotiation + * RR = Bitmask to disable disconnect/reselect + */ + ti->flags = T_NEED_RESET; + if (CFFLAGS_NOSYNC(sc->sc_cfflags, i)) + ti->flags |= T_NOSYNC; + if (CFFLAGS_NODISC(sc->sc_cfflags, i) || wd33c93_nodisc) + ti->flags |= T_NODISC; + ti->period = sc->sc_minsyncperiod; + ti->offset = 0; + } +} + +void +wd33c93_reset(struct wd33c93_softc *sc) +{ + u_int my_id, s, div, i; + u_char csr, reg; + + SET_SBIC_cmd(sc, SBIC_CMD_ABORT); + WAIT_CIP(sc); + + s = splbio(); + + if (sc->sc_reset != NULL) + (*sc->sc_reset)(sc); + + my_id = sc->sc_link.adapter_target & SBIC_ID_MASK; + + /* Enable advanced features and really(!) advanced features */ +#if 1 + my_id |= (SBIC_ID_EAF | SBIC_ID_RAF); /* XXX - MD Layer */ +#endif + + SET_SBIC_myid(sc, my_id); + + /* Reset the chip */ + SET_SBIC_cmd(sc, SBIC_CMD_RESET); + DELAY(25); + SBIC_WAIT(sc, SBIC_ASR_INT, 0); + + /* Set up various chip parameters */ + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + + GET_SBIC_csr(sc, csr); /* clears interrupt also */ + GET_SBIC_cdb1(sc, sc->sc_rev); /* valid with RAF on wd33c93b */ + + switch (csr) { + case SBIC_CSR_RESET: + sc->sc_chip = SBIC_CHIP_WD33C93; + break; + case SBIC_CSR_RESET_AM: + SET_SBIC_queue_tag(sc, 0x55); + GET_SBIC_queue_tag(sc, reg); + sc->sc_chip = (reg == 0x55) ? + SBIC_CHIP_WD33C93B : SBIC_CHIP_WD33C93A; + SET_SBIC_queue_tag(sc, 0x0); + break; + default: + sc->sc_chip = SBIC_CHIP_UNKNOWN; + } + + /* + * Choose a suitable clock divisor and work out the resulting + * sync transfer periods in 4ns units. + */ + if (sc->sc_clkfreq < 110) { + my_id |= SBIC_ID_FS_8_10; + div = 2; + } else if (sc->sc_clkfreq < 160) { + my_id |= SBIC_ID_FS_12_15; + div = 3; + } else if (sc->sc_clkfreq < 210) { + my_id |= SBIC_ID_FS_16_20; + div = 4; + } else + panic("wd33c93: invalid clock speed %d", sc->sc_clkfreq); + + for (i = 0; i < 7; i++) + sc->sc_syncperiods[i] = + (i + 2) * div * 1250 / sc->sc_clkfreq; + sc->sc_minsyncperiod = sc->sc_syncperiods[0]; + SBIC_DEBUG(SYNC, ("available sync periods: %d %d %d %d %d %d %d\n", + sc->sc_syncperiods[0], sc->sc_syncperiods[1], + sc->sc_syncperiods[2], sc->sc_syncperiods[3], + sc->sc_syncperiods[4], sc->sc_syncperiods[5], + sc->sc_syncperiods[6])); + + if (sc->sc_clkfreq >= 160 && sc->sc_chip == SBIC_CHIP_WD33C93B) { + for (i = 0; i < 3; i++) + sc->sc_fsyncperiods[i] = + (i + 2) * 2 * 1250 / sc->sc_clkfreq; + SBIC_DEBUG(SYNC, ("available fast sync periods: %d %d %d\n", + sc->sc_fsyncperiods[0], sc->sc_fsyncperiods[1], + sc->sc_fsyncperiods[2])); + sc->sc_minsyncperiod = sc->sc_fsyncperiods[0]; + } + + /* Max Sync Offset */ + if (sc->sc_chip == SBIC_CHIP_WD33C93A || + sc->sc_chip == SBIC_CHIP_WD33C93B) + sc->sc_maxoffset = SBIC_SYN_93AB_MAX_OFFSET; + else + sc->sc_maxoffset = SBIC_SYN_93_MAX_OFFSET; + + /* + * don't allow Selection (SBIC_RID_ES) + * until we can handle target mode!! + */ + SET_SBIC_rselid(sc, SBIC_RID_ER); + + /* Asynchronous for now */ + SET_SBIC_syn(sc, 0); + + sc->sc_flags = 0; + sc->sc_state = SBIC_IDLE; + + splx(s); +} + +void +wd33c93_error(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + struct scsi_xfer *xs = acb->xs; + + KASSERT(xs); + + if (xs->flags & SCSI_SILENT) + return; + + sc_print_addr(xs->sc_link); + printf("SCSI Error\n"); +} + +/* + * Determine an appropriate value for the synchronous transfer register + * given the period and offset values in *ti. + */ +u_char +wd33c93_stp2syn(struct wd33c93_softc *sc, struct wd33c93_tinfo *ti) +{ + unsigned i; + + /* see if we can handle fast scsi (100-200ns) first */ + if (ti->period < 50 && sc->sc_minsyncperiod < 50) { + for (i = 0; i < 3; i++) + if (sc->sc_fsyncperiods[i] >= ti->period) + return (SBIC_SYN(ti->offset, i + 2, 1)); + } + + for (i = 0; i < 7; i++) { + if (sc->sc_syncperiods[i] >= ti->period) { + if (i == 6) + return (SBIC_SYN(0, 0, 0)); + else + return (SBIC_SYN(ti->offset, i + 2, 0)); + } + } + + /* XXX - can't handle it; do async */ + return (SBIC_SYN(0, 0, 0)); +} + +/* + * Setup sync mode for given target + */ +void +wd33c93_setsync(struct wd33c93_softc *sc, struct wd33c93_tinfo *ti) +{ + u_char syncreg; + + if (ti->flags & T_SYNCMODE) + syncreg = wd33c93_stp2syn(sc, ti); + else + syncreg = SBIC_SYN(0, 0, 0); + + SBIC_DEBUG(SYNC, ("wd33c93_setsync: sync reg = 0x%02x\n", syncreg)); + SET_SBIC_syn(sc, syncreg); +} + +/* + * Check if current operation can be done using DMA + * + * returns 1 if DMA OK, 0 for polled I/O transfer + */ +int +wd33c93_dmaok(struct wd33c93_softc *sc, struct scsi_xfer *xs) +{ + if (wd33c93_nodma || sc->sc_dmamode == SBIC_CTL_NO_DMA || + (xs->flags & SCSI_POLL) || xs->datalen == 0) + return (0); + return(1); +} + +/* + * Setup for DMA transfer + */ +void +wd33c93_dma_setup(struct wd33c93_softc *sc, int datain) +{ + struct wd33c93_acb *acb = sc->sc_nexus; + int s; + + sc->sc_daddr = acb->daddr; + sc->sc_dleft = acb->dleft; + + s = splbio(); + /* Indicate that we're in DMA mode */ + if (sc->sc_dleft) { + sc->sc_dmasetup(sc, &sc->sc_daddr, &sc->sc_dleft, + datain, &sc->sc_dleft); + } + splx(s); + return; +} + + +/* + * Save DMA pointers. Take into account partial transfer. Shut down DMA. + */ +void +wd33c93_dma_stop(struct wd33c93_softc *sc) +{ + size_t count; + int asr; + + /* Wait until WD chip is idle */ + do { + GET_SBIC_asr(sc, asr); /* XXX */ + if (asr & SBIC_ASR_DBR) { + printf("wd33c93_dma_stop: asr %02x canceled!\n", asr); + break; + } + } while (asr & (SBIC_ASR_BSY|SBIC_ASR_CIP)); + + /* Only need to save pointers if DMA was active */ + if (sc->sc_flags & SBICF_INDMA) { + int s = splbio(); + + /* Shut down DMA and flush FIFO's */ + sc->sc_dmastop(sc); + + /* Fetch the residual count */ + SBIC_TC_GET(sc, count); + + /* Work out how many bytes were actually transferred */ + count = sc->sc_tcnt - count; + + if (sc->sc_dleft < count) + printf("xfer too large: dleft=%zu resid=%zu\n", + sc->sc_dleft, count); + + /* Fixup partial xfers */ + sc->sc_daddr = (char *)sc->sc_daddr + count; + sc->sc_dleft -= count; + sc->sc_tcnt = 0; + sc->sc_flags &= ~SBICF_INDMA; + splx(s); + SBIC_DEBUG(DMA, ("dma_stop\n")); + } + /* + * Ensure the WD chip is back in polled I/O mode, with nothing to + * transfer. + */ + SBIC_TC_PUT(sc, 0); + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); +} + + +/* + * Handle new request from scsi layer + */ +void +wd33c93_scsi_cmd(struct scsi_xfer *xs) +{ + struct scsi_link *sc_link = xs->sc_link; + struct wd33c93_softc *sc = sc_link->adapter_softc; + struct wd33c93_acb *acb; + int flags, s; + + SBIC_DEBUG(MISC, ("wd33c93_scsi_cmd\n")); + + flags = xs->flags; + + if (sc->sc_nexus && (flags & SCSI_POLL)) + panic("wd33c93_scsicmd: busy"); + + s = splbio(); + acb = (struct wd33c93_acb *)pool_get(&wd33c93_pool, + PR_NOWAIT | PR_ZERO); + splx(s); + + if (acb == NULL) { + xs->error = XS_NO_CCB; + scsi_done(xs); + return; + } + + acb->flags = ACB_ACTIVE; + acb->xs = xs; + acb->timeout = xs->timeout; + timeout_set(&acb->to, wd33c93_timeout, acb); + + memcpy(&acb->cmd, xs->cmd, xs->cmdlen); + acb->clen = xs->cmdlen; + acb->daddr = xs->data; + acb->dleft = xs->datalen; + +#if 0 + if (flags & SCSI_POLL) { + /* + * Complete currently active command(s) before + * issuing an immediate command + */ + while (sc->sc_nexus) + wd33c93_poll(sc, sc->sc_nexus); + } +#endif + + s = splbio(); + TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain); + acb->flags |= ACB_READY; + + /* If nothing is active, try to start it now. */ + if (sc->sc_state == SBIC_IDLE) + wd33c93_sched(sc); + splx(s); + + if ((flags & SCSI_POLL) == 0) + return; + + if (wd33c93_poll(sc, acb)) { + wd33c93_timeout(acb); + if (wd33c93_poll(sc, acb)) /* 2nd retry for ABORT */ + wd33c93_timeout(acb); + } +} + +/* + * attempt to start the next available command + */ +void +wd33c93_sched(struct wd33c93_softc *sc) +{ + struct scsi_link *sc_link; + struct wd33c93_acb *acb; + struct wd33c93_tinfo *ti; + struct wd33c93_linfo *li; + int lun, tag, flags; + int s; + + if (sc->sc_state != SBIC_IDLE) + return; + + KASSERT(sc->sc_nexus == NULL); + + /* Loop through the ready list looking for work to do... */ + TAILQ_FOREACH(acb, &sc->ready_list, chain) { + sc_link = acb->xs->sc_link; + lun = sc_link->lun; + ti = &sc->sc_tinfo[sc_link->target]; + + KASSERT(acb->flags & ACB_READY); + + /* Select type of tag for this command */ + if ((ti->flags & T_NODISC) != 0) + tag = 0; + else if ((ti->flags & T_TAG) == 0) + tag = 0; + else if ((acb->flags & ACB_SENSE) != 0) + tag = 0; + else if (acb->xs->flags & SCSI_POLL) + tag = 0; /* No tags for polled commands */ + else + tag = MSG_SIMPLE_Q_TAG; + + s = splbio(); + li = TINFO_LUN(ti, lun); + if (li == NULL) { + /* Initialize LUN info and add to list. */ + li = malloc(sizeof(*li), M_DEVBUF, M_NOWAIT | M_ZERO); + if (li == NULL) { + splx(s); + continue; + } + li->lun = lun; + if (lun < SBIC_NLUN) + ti->lun[lun] = li; + } + li->last_used = time_second; + + /* + * We've found a potential command, but is the target/lun busy? + */ + + if (tag == 0 && li->untagged == NULL) + li->untagged = acb; /* Issue untagged */ + + if (li->untagged != NULL) { + tag = 0; + if ((li->state != L_STATE_BUSY) && li->used == 0) { + /* Issue this untagged command now */ + acb = li->untagged; + sc_link = acb->xs->sc_link; + } else{ + /* Not ready yet */ + splx(s); + continue; + } + } + + acb->tag_type = tag; + if (tag != 0) { + int i; + + /* Allocate a tag */ + if (li->used == 255) { + /* no free tags */ + splx(s); + continue; + } + /* Start from the last used location */ + for (i = li->avail; i < 256; i++) { + if (li->queued[i] == NULL) + break; + } + /* Couldn't find one, start again from the beginning */ + if (i == 256) { + for (i = 0; i < 256; i++) { + if (li->queued[i] == NULL) + break; + } + } +#ifdef DIAGNOSTIC + if (i == 256) + panic("%s: tag alloc failure", __func__); +#endif + + /* Save where to start next time. */ + li->avail = i + 1; + li->used++; + li->queued[i] = acb; + acb->tag_id = i; + } + splx(s); + if (li->untagged != NULL && (li->state != L_STATE_BUSY)) { + li->state = L_STATE_BUSY; + break; + } + if (li->untagged == NULL && tag != 0) { + break; + } else + printf("%d:%d busy\n", sc_link->target, sc_link->lun); + } + + if (acb == NULL) { + SBIC_DEBUG(ACBS, ("wd33c93sched: no work\n")); + return; /* did not find an available command */ + } + + SBIC_DEBUG(ACBS, ("wd33c93_sched(%d,%d)\n", sc_link->target, + sc_link->lun)); + + TAILQ_REMOVE(&sc->ready_list, acb, chain); + acb->flags &= ~ACB_READY; + + flags = acb->xs->flags; + if (flags & SCSI_RESET) + wd33c93_reset(sc); + + /* XXX - Implicitly call scsidone on select timeout */ + if (wd33c93_go(sc, acb) != 0 || acb->xs->error == XS_SELTIMEOUT) { + acb->dleft = sc->sc_dleft; + wd33c93_scsidone(sc, acb, sc->sc_status); + return; + } +} + +void +wd33c93_scsidone(struct wd33c93_softc *sc, struct wd33c93_acb *acb, int status) +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct wd33c93_tinfo *ti; + struct wd33c93_linfo *li; + int s; + +#ifdef DIAGNOSTIC + KASSERT(sc->target == sc_link->target); + KASSERT(sc->lun == sc_link->lun); + KASSERT(acb->flags != ACB_FREE); +#endif + + SBIC_DEBUG(ACBS, ("scsidone: (%d,%d)->(%d,%d)%02x\n", + sc_link->target, sc_link->lun, sc->target, sc->lun, status)); + + timeout_del(&acb->to); + + if (xs->error == XS_NOERROR) { + xs->status = status & SCSI_STATUS_MASK; + xs->resid = acb->dleft; + + switch (xs->status) { + case SCSI_CHECK: + case SCSI_TERMINATED: + /* XXX Need to read sense - return busy for now */ + /*FALLTHROUGH*/ + case SCSI_QUEUE_FULL: + case SCSI_BUSY: + xs->error = XS_BUSY; + break; + } + } + + ti = &sc->sc_tinfo[sc_link->target]; + li = TINFO_LUN(ti, sc_link->lun); + ti->cmds++; + if (xs->error == XS_SELTIMEOUT) { + /* Selection timeout -- discard this LUN if empty */ + if (li->untagged == NULL && li->used == 0) { + if (sc_link->lun < SBIC_NLUN) + ti->lun[sc_link->lun] = NULL; + free(li, M_DEVBUF); + } + } + + wd33c93_dequeue(sc, acb); + if (sc->sc_nexus == acb) { + sc->sc_state = SBIC_IDLE; + sc->sc_nexus = NULL; + sc->sc_flags = 0; + + if (!TAILQ_EMPTY(&sc->ready_list)) + wd33c93_sched(sc); + } + + /* place control block back on free list. */ + if ((xs->flags & SCSI_POLL) == 0) { + s = splbio(); + acb->flags = ACB_FREE; + pool_put(&wd33c93_pool, acb); + splx(s); + } + + scsi_done(xs); +} + +void +wd33c93_dequeue(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + struct wd33c93_tinfo *ti = &sc->sc_tinfo[acb->xs->sc_link->target]; + struct wd33c93_linfo *li; + int lun = acb->xs->sc_link->lun; + + li = TINFO_LUN(ti, lun); +#ifdef DIAGNOSTIC + if (li == NULL || li->lun != lun) + panic("wd33c93_dequeue: lun %d for ecb %p does not exist", + lun, acb); +#endif + if (li->untagged == acb) { + li->state = L_STATE_IDLE; + li->untagged = NULL; + } + if (acb->tag_type && li->queued[acb->tag_id] != NULL) { +#ifdef DIAGNOSTIC + if (li->queued[acb->tag_id] != NULL && + (li->queued[acb->tag_id] != acb)) + panic("wd33c93_dequeue: slot %d for lun %d has %p " + "instead of acb %p\n", acb->tag_id, + lun, li->queued[acb->tag_id], acb); +#endif + li->queued[acb->tag_id] = NULL; + li->used--; + } +} + + +int +wd33c93_wait(struct wd33c93_softc *sc, u_char until, int timeo, int line) +{ + u_char val; + + if (timeo == 0) + timeo = 1000000; /* some large value.. */ + GET_SBIC_asr(sc, val); + while ((val & until) == 0) { + if (timeo-- == 0) { + int csr; + GET_SBIC_csr(sc, csr); +#ifdef SBICDEBUG + printf("wd33c93_wait: TIMEO @%d with asr=0x%x csr=0x%x\n", + line, val, csr); +#ifdef DDB + Debugger(); +#endif +#endif + return(val); /* Maybe I should abort */ + break; + } + DELAY(1); + GET_SBIC_asr(sc, val); + } + return(val); +} + +int +wd33c93_abort(struct wd33c93_softc *sc, struct wd33c93_acb *acb, + const char *where) +{ + u_char csr, asr; + + GET_SBIC_asr(sc, asr); + GET_SBIC_csr(sc, csr); + + sc_print_addr(acb->xs->sc_link); + printf("ABORT in %s: csr=0x%02x, asr=0x%02x\n", where, csr, asr); + + acb->timeout = SBIC_ABORT_TIMEOUT; + acb->flags |= ACB_ABORT; + + /* + * Clean up chip itself + */ + if (sc->sc_nexus == acb) { + /* Reschedule timeout. */ + timeout_add_msec(&acb->to, acb->timeout); + + while (asr & SBIC_ASR_DBR) { + /* + * wd33c93 is jammed w/data. need to clear it + * But we don't know what direction it needs to go + */ + GET_SBIC_data(sc, asr); + printf("abort %s: clearing data buffer 0x%02x\n", + where, asr); + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_DBR) /* Not the read direction */ + SET_SBIC_data(sc, asr); + GET_SBIC_asr(sc, asr); + } + + sc_print_addr(acb->xs->sc_link); + printf("sending ABORT command\n"); + + WAIT_CIP(sc); + SET_SBIC_cmd(sc, SBIC_CMD_ABORT); + WAIT_CIP(sc); + + GET_SBIC_asr(sc, asr); + + sc_print_addr(acb->xs->sc_link); + if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) { + /* + * ok, get more drastic.. + */ + printf("Resetting bus\n"); + wd33c93_reset(sc); + } else { + printf("sending DISCONNECT to target\n"); + SET_SBIC_cmd(sc, SBIC_CMD_DISC); + WAIT_CIP(sc); + + do { + SBIC_WAIT (sc, SBIC_ASR_INT, 0); + GET_SBIC_asr(sc, asr); + GET_SBIC_csr(sc, csr); + SBIC_DEBUG(MISC, ("csr: 0x%02x, asr: 0x%02x\n", + csr, asr)); + } while ((csr != SBIC_CSR_DISC) && + (csr != SBIC_CSR_DISC_1) && + (csr != SBIC_CSR_CMD_INVALID)); + } + sc->sc_state = SBIC_ERROR; + sc->sc_flags = 0; + } + return SBIC_STATE_ERROR; +} + + +/* + * select the bus, return when selected or error. + * + * Returns the current CSR following selection and optionally MSG out phase. + * i.e. the returned CSR *should* indicate CMD phase... + * If the return value is 0, some error happened. + */ +u_char +wd33c93_selectbus(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct wd33c93_tinfo *ti; + u_char target, lun, asr, csr, id; + + KASSERT(sc->sc_state == SBIC_IDLE); + + target = sc_link->target; + lun = sc_link->lun; + ti = &sc->sc_tinfo[target]; + + sc->sc_state = SBIC_SELECTING; + sc->target = target; + sc->lun = lun; + + SBIC_DEBUG(PHASE, ("wd33c93_selectbus %d: ", target)); + + if ((xs->flags & SCSI_POLL) == 0) + timeout_add_msec(&acb->to, acb->timeout); + + /* + * issue select + */ + SBIC_TC_PUT(sc, 0); + SET_SBIC_selid(sc, target); + SET_SBIC_timeo(sc, SBIC_TIMEOUT(250, sc->sc_clkfreq)); + + GET_SBIC_asr(sc, asr); + if (asr & (SBIC_ASR_INT|SBIC_ASR_BSY)) { + /* This means we got ourselves reselected upon */ + SBIC_DEBUG(PHASE, ("WD busy (reselect?) ASR=%02x\n", asr)); + return 0; + } + + SET_SBIC_cmd(sc, SBIC_CMD_SEL_ATN); + WAIT_CIP(sc); + + /* + * wait for select (merged from separate function may need + * cleanup) + */ + do { + asr = SBIC_WAIT(sc, SBIC_ASR_INT | SBIC_ASR_LCI, 0); + if (asr & SBIC_ASR_LCI) { + QPRINTF(("late LCI: asr %02x\n", asr)); + return 0; + } + + /* Clear interrupt */ + GET_SBIC_csr (sc, csr); + + /* Reselected from under our feet? */ + if (csr == SBIC_CSR_RSLT_NI || csr == SBIC_CSR_RSLT_IFY) { + SBIC_DEBUG(PHASE, ("got reselected, asr %02x\n", asr)); + /* + * We need to handle this now so we don't lock up later + */ + wd33c93_nextstate(sc, acb, csr, asr); + return 0; + } + + /* Whoops! */ + if (csr == SBIC_CSR_SLT || csr == SBIC_CSR_SLT_ATN) { + panic("wd33c93_selectbus: target issued select!"); + return 0; + } + + } while (csr != (SBIC_CSR_MIS_2 | MESG_OUT_PHASE) && + csr != (SBIC_CSR_MIS_2 | CMD_PHASE) && + csr != SBIC_CSR_SEL_TIMEO); + + /* Anyone at home? */ + if (csr == SBIC_CSR_SEL_TIMEO) { + xs->error = XS_SELTIMEOUT; + SBIC_DEBUG(PHASE, ("-- Selection Timeout\n")); + return 0; + } + + SBIC_DEBUG(PHASE, ("Selection Complete\n")); + + /* Assume we're now selected */ + GET_SBIC_selid(sc, id); + if (id != target) { + /* Something went wrong - wrong target was select */ + printf("wd33c93_selectbus: wrong target selected;" + " WANTED %d GOT %d", target, id); + return 0; /* XXX: Need to call nexstate to handle? */ + } + + sc->sc_flags |= SBICF_SELECTED; + sc->sc_state = SBIC_CONNECTED; + + /* setup correct sync mode for this target */ + wd33c93_setsync(sc, ti); + + if (ti->flags & T_NODISC && sc->sc_disc == 0) + SET_SBIC_rselid (sc, 0); /* Not expecting a reselect */ + else + SET_SBIC_rselid (sc, SBIC_RID_ER); + + /* + * We only really need to do anything when the target goes to MSG out + * If the device ignored ATN, it's probably old and brain-dead, + * but we'll try to support it anyhow. + * If it doesn't support message out, it definately doesn't + * support synchronous transfers, so no point in even asking... + */ + if (csr == (SBIC_CSR_MIS_2 | MESG_OUT_PHASE)) { + if (ti->flags & T_NEGOTIATE) { + /* Initiate a SDTR message */ + SBIC_DEBUG(SYNC, ("Sending SDTR to target %d\n", id)); + if (ti->flags & T_WANTSYNC) { + ti->period = sc->sc_minsyncperiod; + ti->offset = sc->sc_maxoffset; + } else { + ti->period = 0; + ti->offset = 0; + } + /* Send Sync negotiation message */ + sc->sc_omsg[0] = MSG_IDENTIFY(lun, 0); /* No Disc */ + sc->sc_omsg[1] = MSG_EXTENDED; + sc->sc_omsg[2] = MSG_EXT_SDTR_LEN; + sc->sc_omsg[3] = MSG_EXT_SDTR; + if (ti->flags & T_WANTSYNC) { + sc->sc_omsg[4] = sc->sc_minsyncperiod; + sc->sc_omsg[5] = sc->sc_maxoffset; + } else { + sc->sc_omsg[4] = 0; + sc->sc_omsg[5] = 0; + } + wd33c93_xfout(sc, 6, sc->sc_omsg); + sc->sc_msgout |= SEND_SDTR; /* may be rejected */ + sc->sc_flags |= SBICF_SYNCNEGO; + } else { + if (sc->sc_nexus->tag_type != 0) { + /* Use TAGS */ + SBIC_DEBUG(TAGS, ("<select %d:%d TAG=%x>\n", + sc->target, sc->lun, + sc->sc_nexus->tag_id)); + sc->sc_omsg[0] = MSG_IDENTIFY(lun, 1); + sc->sc_omsg[1] = sc->sc_nexus->tag_type; + sc->sc_omsg[2] = sc->sc_nexus->tag_id; + wd33c93_xfout(sc, 3, sc->sc_omsg); + sc->sc_msgout |= SEND_TAG; + } else { + int no_disc; + + /* Setup LUN nexus and disconnect privilege */ + no_disc = xs->flags & SCSI_POLL || + ti->flags & T_NODISC; + SEND_BYTE(sc, MSG_IDENTIFY(lun, !no_disc)); + } + } + /* + * There's one interrupt still to come: + * the change to CMD phase... + */ + SBIC_WAIT(sc, SBIC_ASR_INT , 0); + GET_SBIC_csr(sc, csr); + } + + return csr; +} + +/* + * Information Transfer *to* a SCSI Target. + * + * Note: Don't expect there to be an interrupt immediately after all + * the data is transferred out. The WD spec sheet says that the Transfer- + * Info command for non-MSG_IN phases only completes when the target + * next asserts 'REQ'. That is, when the SCSI bus changes to a new state. + * + * This can have a nasty effect on commands which take a relatively long + * time to complete, for example a START/STOP unit command may remain in + * CMD phase until the disk has spun up. Only then will the target change + * to STATUS phase. This is really only a problem for immediate commands + * since we don't allow disconnection for them (yet). + */ +int +wd33c93_xfout(struct wd33c93_softc *sc, int len, void *bp) +{ + int wait = wd33c93_data_wait; + u_char asr, *buf = bp; + + QPRINTF(("wd33c93_xfout {%d} %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x\n", len, buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9])); + + /* + * sigh.. WD-PROTO strikes again.. sending the command in one go + * causes the chip to lock up if talking to certain (misbehaving?) + * targets. Anyway, this procedure should work for all targets, but + * it's slightly slower due to the overhead + */ + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + SBIC_TC_PUT (sc, (unsigned)len); + + WAIT_CIP (sc); + SET_SBIC_cmd (sc, SBIC_CMD_XFER_INFO); + + /* + * Loop for each byte transferred + */ + do { + GET_SBIC_asr (sc, asr); + + if (asr & SBIC_ASR_DBR) { + if (len) { + SET_SBIC_data (sc, *buf); + buf++; + len--; + } else { + SET_SBIC_data (sc, 0); + } + wait = wd33c93_data_wait; + } + } while (len && (asr & SBIC_ASR_INT) == 0 && wait-- > 0); + + QPRINTF(("wd33c93_xfout done: %d bytes remaining (wait:%d)\n", len, wait)); + + /* + * Normally, an interrupt will be pending when this routing returns. + */ + return(len); +} + +/* + * Information Transfer *from* a Scsi Target + * returns # bytes left to read + */ +int +wd33c93_xfin(struct wd33c93_softc *sc, int len, void *bp) +{ + int wait = wd33c93_data_wait; + u_char *buf = bp; + u_char asr; +#ifdef SBICDEBUG + u_char *obp = bp; +#endif + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + SBIC_TC_PUT (sc, (unsigned)len); + + WAIT_CIP (sc); + SET_SBIC_cmd (sc, SBIC_CMD_XFER_INFO); + + /* + * Loop for each byte transferred + */ + do { + GET_SBIC_asr (sc, asr); + + if (asr & SBIC_ASR_DBR) { + if (len) { + GET_SBIC_data (sc, *buf); + buf++; + len--; + } else { + u_char foo; + GET_SBIC_data (sc, foo); + } + wait = wd33c93_data_wait; + } + + } while ((asr & SBIC_ASR_INT) == 0 && wait-- > 0); + + QPRINTF(("wd33c93_xfin {%d} %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2], + obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9])); + + SBIC_TC_PUT (sc, 0); + + /* + * this leaves with one csr to be read + */ + return len; +} + + +/* + * Finish SCSI xfer command: After the completion interrupt from + * a read/write operation, sequence through the final phases in + * programmed i/o. + */ +void +wd33c93_xferdone(struct wd33c93_softc *sc) +{ + u_char phase, csr; + int s; + + QPRINTF(("{")); + s = splbio(); + + /* + * have the wd33c93 complete on its own + */ + SBIC_TC_PUT(sc, 0); + SET_SBIC_cmd_phase(sc, 0x46); + SET_SBIC_cmd(sc, SBIC_CMD_SEL_ATN_XFER); + + do { + SBIC_WAIT (sc, SBIC_ASR_INT, 0); + GET_SBIC_csr (sc, csr); + QPRINTF(("%02x:", csr)); + } while ((csr != SBIC_CSR_DISC) && + (csr != SBIC_CSR_DISC_1) && + (csr != SBIC_CSR_S_XFERRED)); + + sc->sc_flags &= ~SBICF_SELECTED; + sc->sc_state = SBIC_DISCONNECT; + + GET_SBIC_cmd_phase (sc, phase); + QPRINTF(("}%02x", phase)); + + if (phase == 0x60) + GET_SBIC_tlun(sc, sc->sc_status); + else + wd33c93_error(sc, sc->sc_nexus); + + QPRINTF(("=STS:%02x=\n", sc->sc_status)); + splx(s); +} + + +int +wd33c93_go(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + int i, dmaok; + u_char csr, asr; + + SBIC_DEBUG(ACBS, ("wd33c93_go(%d:%d)\n", sc_link->target, sc_link->lun)); + + sc->sc_nexus = acb; + + sc->target = sc_link->target; + sc->lun = sc_link->lun; + + sc->sc_status = STATUS_UNKNOWN; + sc->sc_daddr = acb->daddr; + sc->sc_dleft = acb->dleft; + + sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0; + sc->sc_flags = 0; + + dmaok = wd33c93_dmaok(sc, xs); + + if (dmaok == 0) + sc->sc_flags |= SBICF_NODMA; + + SBIC_DEBUG(DMA, ("wd33c93_go dmago:%d(tcnt=%zx) dmaok=%d\n", + sc->target, sc->sc_tcnt, dmaok)); + + /* select the SCSI bus (it's an error if bus isn't free) */ + if ((csr = wd33c93_selectbus(sc, acb)) == 0) + return(0); /* Not done: needs to be rescheduled */ + + /* + * Lets cycle a while then let the interrupt handler take over. + */ + GET_SBIC_asr(sc, asr); + do { + QPRINTF(("go[0x%x] ", csr)); + + /* Handle the new phase */ + i = wd33c93_nextstate(sc, acb, csr, asr); + WAIT_CIP(sc); /* XXX */ + if (sc->sc_state == SBIC_CONNECTED) { + + GET_SBIC_asr(sc, asr); + + if (asr & SBIC_ASR_LCI) + printf("wd33c93_go: LCI asr:%02x csr:%02x\n", asr, csr); + + if (asr & SBIC_ASR_INT) + GET_SBIC_csr(sc, csr); + } + + } while (sc->sc_state == SBIC_CONNECTED && + asr & (SBIC_ASR_INT|SBIC_ASR_LCI)); + + QPRINTF(("> done i=%d stat=%02x\n", i, sc->sc_status)); + + if (i == SBIC_STATE_DONE) { + if (sc->sc_status == STATUS_UNKNOWN) { + printf("wd33c93_go: done & stat == UNKNOWN\n"); + return 1; /* Did we really finish that fast? */ + } + } + return 0; +} + + +int +wd33c93_intr(void *v) +{ + struct wd33c93_softc *sc = v; + u_char asr, csr; + int i; + + /* + * pending interrupt? + */ + GET_SBIC_asr (sc, asr); + if ((asr & SBIC_ASR_INT) == 0) + return(0); + + GET_SBIC_csr(sc, csr); + + do { + SBIC_DEBUG(INTS, ("intr[csr=0x%x]", csr)); + + i = wd33c93_nextstate(sc, sc->sc_nexus, csr, asr); + WAIT_CIP(sc); /* XXX */ + if (sc->sc_state == SBIC_CONNECTED) { + GET_SBIC_asr(sc, asr); + + if (asr & SBIC_ASR_LCI) + printf("wd33c93_intr: LCI asr:%02x csr:%02x\n", + asr, csr); + + if (asr & SBIC_ASR_INT) + GET_SBIC_csr(sc, csr); + } + } while (sc->sc_state == SBIC_CONNECTED && + asr & (SBIC_ASR_INT|SBIC_ASR_LCI)); + + SBIC_DEBUG(INTS, ("intr done. state=%d, asr=0x%02x\n", i, asr)); + + return(1); +} + +/* + * Complete current command using polled I/O. Used when interrupt driven + * I/O is not allowed (ie. during boot and shutdown) + * + * Polled I/O is very processor intensive + */ +int +wd33c93_poll(struct wd33c93_softc *sc, struct wd33c93_acb *acb) +{ + u_char asr, csr=0; + int i, count; + struct scsi_xfer *xs = acb->xs; + int s; + + SBIC_WAIT(sc, SBIC_ASR_INT, wd33c93_cmd_wait); + for (count = acb->timeout; count;) { + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_LCI) + printf("wd33c93_poll: LCI; asr:%02x csr:%02x\n", + asr, csr); + if (asr & SBIC_ASR_INT) { + GET_SBIC_csr(sc, csr); + sc->sc_flags |= SBICF_NODMA; + i = wd33c93_nextstate(sc, sc->sc_nexus, csr, asr); + WAIT_CIP(sc); /* XXX */ + } else { + DELAY(1000); + count--; + } + + if ((xs->flags & ITSDONE) != 0) { + s = splbio(); + acb->flags = ACB_FREE; + pool_put(&wd33c93_pool, acb); + splx(s); + + return (0); + } + + if (sc->sc_state == SBIC_IDLE) { + SBIC_DEBUG(ACBS, ("[poll: rescheduling] ")); + wd33c93_sched(sc); + } + } + return (1); +} + +static inline int +__verify_msg_format(u_char *p, int len) +{ + if (len == 1 && IS1BYTEMSG(p[0])) + return 1; + if (len == 2 && IS2BYTEMSG(p[0])) + return 1; + if (len >= 3 && ISEXTMSG(p[0]) && + len == p[1] + 2) + return 1; + return 0; +} + +/* + * Handle message_in phase + */ +int +wd33c93_msgin_phase(struct wd33c93_softc *sc, int reselect) +{ + int len; + u_char asr, csr, *msg; + + GET_SBIC_asr(sc, asr); + + SBIC_DEBUG(MSGS, ("wd33c93msgin asr=%02x\n", asr)); + + GET_SBIC_selid (sc, csr); + SET_SBIC_selid (sc, csr | SBIC_SID_FROM_SCSI); + + SBIC_TC_PUT(sc, 0); + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + + msg = sc->sc_imsg; + len = 0; + + do { + /* Fetch the next byte of the message */ + RECV_BYTE(sc, *msg++); + len++; + + /* + * get the command completion interrupt, or we + * can't send a new command (LCI) + */ + SBIC_WAIT(sc, SBIC_ASR_INT, 0); + GET_SBIC_csr(sc, csr); + + if (__verify_msg_format(sc->sc_imsg, len)) + break; /* Complete message received */ + + /* + * Clear ACK, and wait for the interrupt + * for the next byte or phase change + */ + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + SBIC_WAIT(sc, SBIC_ASR_INT, 0); + + GET_SBIC_csr(sc, csr); + } while (len < SBIC_MAX_MSGLEN); + + if (__verify_msg_format(sc->sc_imsg, len)) + wd33c93_msgin(sc, sc->sc_imsg, len); + + /* + * Clear ACK, and wait for the interrupt + * for the phase change + */ + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + SBIC_WAIT(sc, SBIC_ASR_INT, 0); + + /* Should still have one CSR to read */ + return SBIC_STATE_RUNNING; +} + + +void wd33c93_msgin(struct wd33c93_softc *sc, u_char *msgaddr, int msglen) +{ + struct wd33c93_acb *acb = sc->sc_nexus; + struct wd33c93_tinfo *ti = &sc->sc_tinfo[sc->target]; + struct wd33c93_linfo *li; + u_char asr; + + switch (sc->sc_state) { + case SBIC_CONNECTED: + switch (msgaddr[0]) { + case MSG_MESSAGE_REJECT: + SBIC_DEBUG(MSGS, ("msgin: MSG_REJECT, " + "last msgout=%x\n", sc->sc_msgout)); + switch (sc->sc_msgout) { + case SEND_TAG: + printf("%s: tagged queuing rejected: " + "target %d\n", + sc->sc_dev.dv_xname, sc->target); + ti->flags &= ~T_TAG; + li = TINFO_LUN(ti, sc->lun); + if (acb->tag_type && + li->queued[acb->tag_id] != NULL) { + li->queued[acb->tag_id] = NULL; + li->used--; + } + acb->tag_type = acb->tag_id = 0; + li->untagged = acb; + li->state = L_STATE_BUSY; + break; + + case SEND_SDTR: + printf("%s: sync transfer rejected: target %d\n", + sc->sc_dev.dv_xname, sc->target); + + sc->sc_flags &= ~SBICF_SYNCNEGO; + ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE); + wd33c93_setsync(sc, ti); + + case SEND_INIT_DET_ERR: + goto abort; + + default: + SBIC_DEBUG(MSGS, ("Unexpected MSG_REJECT\n")); + break; + } + sc->sc_msgout = 0; + break; + + case MSG_HEAD_OF_Q_TAG: + case MSG_ORDERED_Q_TAG: + case MSG_SIMPLE_Q_TAG: + printf("-- Out of phase TAG;" + "Nexus=%d:%d Tag=%02x/%02x\n", + sc->target, sc->lun, msgaddr[0], msgaddr[1]); + break; + + case MSG_DISCONNECT: + SBIC_DEBUG(MSGS, ("msgin: DISCONNECT")); + /* + * Mark the fact that all bytes have moved. The + * target may not bother to do a SAVE POINTERS + * at this stage. This flag will set the residual + * count to zero on MSG COMPLETE. + */ + if (sc->sc_dleft == 0) + acb->flags |= ACB_COMPLETE; + + if (acb->xs->flags & SCSI_POLL) + /* Don't allow disconnect in immediate mode */ + goto reject; + else { /* Allow disconnect */ + sc->sc_flags &= ~SBICF_SELECTED; + sc->sc_state = SBIC_DISCONNECT; + } + if ((acb->xs->sc_link->quirks & SDEV_AUTOSAVE) == 0) + break; + /*FALLTHROUGH*/ + + case MSG_SAVEDATAPOINTER: + SBIC_DEBUG(MSGS, ("msgin: SAVEDATAPTR")); + acb->daddr = sc->sc_daddr; + acb->dleft = sc->sc_dleft; + break; + + case MSG_RESTOREPOINTERS: + SBIC_DEBUG(MSGS, ("msgin: RESTOREPTR")); + sc->sc_daddr = acb->daddr; + sc->sc_dleft = acb->dleft; + break; + + case MSG_CMDCOMPLETE: + /* + * !! KLUDGE ALERT !! quite a few drives don't seem to + * really like the current way of sending the + * sync-handshake together with the ident-message, and + * they react by sending command-complete and + * disconnecting right after returning the valid sync + * handshake. So, all I can do is reselect the drive, + * and hope it won't disconnect again. I don't think + * this is valid behavior, but I can't help fixing a + * problem that apparently exists. + * + * Note: we should not get here on `normal' command + * completion, as that condition is handled by the + * high-level sel&xfer resume command used to walk + * thru status/cc-phase. + */ + SBIC_DEBUG(MSGS, ("msgin: CMD_COMPLETE")); + SBIC_DEBUG(SYNC, ("GOT MSG %d! target %d" + " acting weird.." + " waiting for disconnect...\n", + msgaddr[0], sc->target)); + + /* Check to see if wd33c93 is handling this */ + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_BSY) + break; + + /* XXX: Assume it works and set status to 00 */ + sc->sc_status = 0; + sc->sc_state = SBIC_CMDCOMPLETE; + break; + + case MSG_EXTENDED: + switch(msgaddr[2]) { + case MSG_EXT_SDTR: /* Sync negotiation */ + SBIC_DEBUG(MSGS, ("msgin: EXT_SDTR; " + "period %d, offset %d", + msgaddr[3], msgaddr[4])); + if (msgaddr[1] != 3) + goto reject; + + ti->period = + MAX(msgaddr[3], sc->sc_minsyncperiod); + ti->offset = MIN(msgaddr[4], sc->sc_maxoffset); + + /* + * <SGI, IBM DORS-32160, WA6A> will do nothing + * but attempt sync negotiation until it gets + * what it wants. To avoid an infinite loop set + * off by the identify request, oblige them. + */ + if ((sc->sc_flags&SBICF_SYNCNEGO) == 0 && + msgaddr[3] != 0) + ti->flags |= T_WANTSYNC; + + if (!(ti->flags & T_WANTSYNC)) + ti->period = ti->offset = 0; + + ti->flags &= ~T_NEGOTIATE; + + if (ti->offset == 0) + ti->flags &= ~T_SYNCMODE; /* Async */ + else + ti->flags |= T_SYNCMODE; /* Sync */ + + /* target initiated negotiation */ + if ((sc->sc_flags&SBICF_SYNCNEGO) == 0) + wd33c93_sched_msgout(sc, SEND_SDTR); + sc->sc_flags &= ~SBICF_SYNCNEGO; + + SBIC_DEBUG(SYNC, ("msgin(%d): SDTR(o=%d,p=%d)", + sc->target, ti->offset, + ti->period)); + wd33c93_setsync(sc, ti); + break; + + case MSG_EXT_WDTR: + SBIC_DEBUG(MSGS, ("msgin: EXT_WDTR rejected")); + goto reject; + + default: + sc_print_addr(acb->xs->sc_link); + printf("unrecognized MESSAGE EXTENDED;" + " sending REJECT\n"); + goto reject; + } + break; + + default: + sc_print_addr(acb->xs->sc_link); + printf("unrecognized MESSAGE; sending REJECT\n"); + + reject: + /* We don't support whatever this message is... */ + wd33c93_sched_msgout(sc, SEND_REJECT); + break; + } + break; + + case SBIC_IDENTIFIED: + /* + * IDENTIFY message was received and queue tag is expected now + */ + if ((msgaddr[0]!=MSG_SIMPLE_Q_TAG) || (sc->sc_msgify==0)) { + printf("%s: TAG reselect without IDENTIFY;" + " MSG %x; sending DEVICE RESET\n", + sc->sc_dev.dv_xname, msgaddr[0]); + goto reset; + } + SBIC_DEBUG(TAGS, ("TAG %x/%x\n", msgaddr[0], msgaddr[1])); + if (sc->sc_nexus) + printf("*TAG Recv with active nexus!!\n"); + wd33c93_reselect(sc, sc->target, sc->lun, + msgaddr[0], msgaddr[1]); + break; + + case SBIC_RESELECTED: + /* + * IDENTIFY message with target + */ + if (MSG_ISIDENTIFY(msgaddr[0])) { + SBIC_DEBUG(PHASE, ("IFFY[%x] ", msgaddr[0])); + sc->sc_msgify = msgaddr[0]; + } else { + printf("%s: reselect without IDENTIFY;" + " MSG %x;" + " sending DEVICE RESET\n", + sc->sc_dev.dv_xname, msgaddr[0]); + goto reset; + } + break; + + default: + printf("%s: unexpected MESSAGE IN. State=%d - Sending RESET\n", + sc->sc_dev.dv_xname, sc->sc_state); + reset: + wd33c93_sched_msgout(sc, SEND_DEV_RESET); + break; + abort: + wd33c93_sched_msgout(sc, SEND_ABORT); + break; + } +} + +void +wd33c93_sched_msgout(struct wd33c93_softc *sc, u_short msg) +{ + u_char asr; + + SBIC_DEBUG(SYNC,("sched_msgout: %04x\n", msg)); + sc->sc_msgpriq |= msg; + + /* Schedule MSGOUT Phase to send message */ + + WAIT_CIP(sc); + SET_SBIC_cmd(sc, SBIC_CMD_SET_ATN); + WAIT_CIP(sc); + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_LCI) { + printf("MSGOUT Failed!\n"); + } + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + WAIT_CIP(sc); +} + +/* + * Send the highest priority, scheduled message + */ +void +wd33c93_msgout(struct wd33c93_softc *sc) +{ + struct wd33c93_tinfo *ti; + struct wd33c93_acb *acb = sc->sc_nexus; + + if (acb == NULL) + panic("MSGOUT with no nexus"); + + if (sc->sc_omsglen == 0) { + /* Pick up highest priority message */ + sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; + sc->sc_msgoutq |= sc->sc_msgout; + sc->sc_msgpriq &= ~sc->sc_msgout; + sc->sc_omsglen = 1; /* "Default" message len */ + switch (sc->sc_msgout) { + case SEND_SDTR: + ti = &sc->sc_tinfo[acb->xs->sc_link->target]; + sc->sc_omsg[0] = MSG_EXTENDED; + sc->sc_omsg[1] = MSG_EXT_SDTR_LEN; + sc->sc_omsg[2] = MSG_EXT_SDTR; + if (ti->flags & T_WANTSYNC) { + sc->sc_omsg[3] = ti->period; + sc->sc_omsg[4] = ti->offset; + } else { + sc->sc_omsg[3] = 0; + sc->sc_omsg[4] = 0; + } + sc->sc_omsglen = 5; + if ((sc->sc_flags & SBICF_SYNCNEGO) == 0) { + if (ti->flags & T_WANTSYNC) + ti->flags |= T_SYNCMODE; + else + ti->flags &= ~T_SYNCMODE; + wd33c93_setsync(sc, ti); + } + break; + case SEND_IDENTIFY: + if (sc->sc_state != SBIC_CONNECTED) { + printf("%s at line %d: no nexus\n", + sc->sc_dev.dv_xname, __LINE__); + } + sc->sc_omsg[0] = + MSG_IDENTIFY(acb->xs->sc_link->lun, 0); + break; + case SEND_TAG: + if (sc->sc_state != SBIC_CONNECTED) { + printf("%s at line %d: no nexus\n", + sc->sc_dev.dv_xname, __LINE__); + } + sc->sc_omsg[0] = acb->tag_type; + sc->sc_omsg[1] = acb->tag_id; + sc->sc_omsglen = 2; + break; + case SEND_DEV_RESET: + sc->sc_omsg[0] = MSG_BUS_DEV_RESET; + ti = &sc->sc_tinfo[sc->target]; + ti->flags &= ~T_SYNCMODE; + if ((ti->flags & T_NOSYNC) == 0) + /* We can re-start sync negotiation */ + ti->flags |= T_NEGOTIATE; + break; + case SEND_PARITY_ERROR: + sc->sc_omsg[0] = MSG_PARITY_ERROR; + break; + case SEND_ABORT: + sc->sc_flags |= SBICF_ABORTING; + sc->sc_omsg[0] = MSG_ABORT; + break; + case SEND_INIT_DET_ERR: + sc->sc_omsg[0] = MSG_INITIATOR_DET_ERR; + break; + case SEND_REJECT: + sc->sc_omsg[0] = MSG_MESSAGE_REJECT; + break; + default: + /* Wasn't expecting MSGOUT Phase */ + sc->sc_omsg[0] = MSG_NOOP; + break; + } + } + + wd33c93_xfout(sc, sc->sc_omsglen, sc->sc_omsg); +} + + +/* + * wd33c93_nextstate() + * return: + * SBIC_STATE_DONE == done + * SBIC_STATE_RUNNING == working + * SBIC_STATE_DISCONNECT == disconnected + * SBIC_STATE_ERROR == error + */ +int +wd33c93_nextstate(struct wd33c93_softc *sc, struct wd33c93_acb *acb, u_char csr, u_char asr) +{ + SBIC_DEBUG(PHASE, ("next[a=%02x,c=%02x]: ",asr,csr)); + + switch (csr) { + + case SBIC_CSR_XFERRED | CMD_PHASE: + case SBIC_CSR_MIS | CMD_PHASE: + case SBIC_CSR_MIS_1 | CMD_PHASE: + case SBIC_CSR_MIS_2 | CMD_PHASE: + + if (wd33c93_xfout(sc, acb->clen, &acb->cmd)) + goto abort; + break; + + case SBIC_CSR_XFERRED | STATUS_PHASE: + case SBIC_CSR_MIS | STATUS_PHASE: + case SBIC_CSR_MIS_1 | STATUS_PHASE: + case SBIC_CSR_MIS_2 | STATUS_PHASE: + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + + /* + * this should be the normal i/o completion case. + * get the status & cmd complete msg then let the + * device driver look at what happened. + */ + wd33c93_xferdone(sc); + + wd33c93_dma_stop(sc); + + /* Fixup byte count to be passed to higher layer */ + acb->dleft = (acb->flags & ACB_COMPLETE) ? 0 : + sc->sc_dleft; + + /* + * Indicate to the upper layers that the command is done + */ + wd33c93_scsidone(sc, acb, sc->sc_status); + + return SBIC_STATE_DONE; + + + case SBIC_CSR_XFERRED | DATA_IN_PHASE: + case SBIC_CSR_MIS | DATA_IN_PHASE: + case SBIC_CSR_MIS_1 | DATA_IN_PHASE: + case SBIC_CSR_MIS_2 | DATA_IN_PHASE: + case SBIC_CSR_XFERRED | DATA_OUT_PHASE: + case SBIC_CSR_MIS | DATA_OUT_PHASE: + case SBIC_CSR_MIS_1 | DATA_OUT_PHASE: + case SBIC_CSR_MIS_2 | DATA_OUT_PHASE: + /* + * Verify that we expected to transfer data... + */ + if (acb->dleft <= 0) { + printf("next: DATA phase with xfer count == %zd, asr:0x%02x csr:0x%02x\n", + acb->dleft, asr, csr); + goto abort; + } + + /* + * Should we transfer using PIO or DMA ? + */ + if (acb->xs->flags & SCSI_POLL || + sc->sc_flags & SBICF_NODMA) { + /* Perfrom transfer using PIO */ + int resid; + + SBIC_DEBUG(DMA, ("PIO xfer: %d(%p:%zx)\n", sc->target, + sc->sc_daddr, sc->sc_dleft)); + + if (SBIC_PHASE(csr) == DATA_IN_PHASE) + /* data in */ + resid = wd33c93_xfin(sc, sc->sc_dleft, + sc->sc_daddr); + else /* data out */ + resid = wd33c93_xfout(sc, sc->sc_dleft, + sc->sc_daddr); + + sc->sc_daddr = (char *)sc->sc_daddr + + (acb->dleft - resid); + sc->sc_dleft = resid; + } else { + int datain = SBIC_PHASE(csr) == DATA_IN_PHASE; + + /* Perform transfer using DMA */ + wd33c93_dma_setup(sc, datain); + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI | + sc->sc_dmamode); + + SBIC_DEBUG(DMA, ("DMA xfer: %d(%p:%zx)\n", sc->target, + sc->sc_daddr, sc->sc_dleft)); + + /* Setup byte count for transfer */ + SBIC_TC_PUT(sc, (unsigned)sc->sc_dleft); + + /* Start the transfer */ + SET_SBIC_cmd(sc, SBIC_CMD_XFER_INFO); + + /* Start the DMA chip going */ + sc->sc_tcnt = sc->sc_dmago(sc); + + /* Indicate that we're in DMA mode */ + sc->sc_flags |= SBICF_INDMA; + } + break; + + case SBIC_CSR_XFERRED | MESG_IN_PHASE: + case SBIC_CSR_MIS | MESG_IN_PHASE: + case SBIC_CSR_MIS_1 | MESG_IN_PHASE: + case SBIC_CSR_MIS_2 | MESG_IN_PHASE: + + wd33c93_dma_stop(sc); + + /* Handle a single message in... */ + return wd33c93_msgin_phase(sc, 0); + + case SBIC_CSR_MSGIN_W_ACK: + + /* + * We should never see this since it's handled in + * 'wd33c93_msgin_phase()' but just for the sake of paranoia... + */ + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + + printf("Acking unknown msgin CSR:%02x",csr); + break; + + case SBIC_CSR_XFERRED | MESG_OUT_PHASE: + case SBIC_CSR_MIS | MESG_OUT_PHASE: + case SBIC_CSR_MIS_1 | MESG_OUT_PHASE: + case SBIC_CSR_MIS_2 | MESG_OUT_PHASE: + + /* + * Message out phase. ATN signal has been asserted + */ + wd33c93_dma_stop(sc); + wd33c93_msgout(sc); + return SBIC_STATE_RUNNING; + + case SBIC_CSR_DISC: + case SBIC_CSR_DISC_1: + SBIC_DEBUG(RSEL, ("wd33c93next target %d disconnected\n", + sc->target)); + wd33c93_dma_stop(sc); + + sc->sc_nexus = NULL; + sc->sc_state = SBIC_IDLE; + sc->sc_flags = 0; + + ++sc->sc_tinfo[sc->target].dconns; + ++sc->sc_disc; + + if (acb->xs->flags & SCSI_POLL || wd33c93_nodisc) + return SBIC_STATE_DISCONNECT; + + /* Try to schedule another target */ + wd33c93_sched(sc); + + return SBIC_STATE_DISCONNECT; + + case SBIC_CSR_RSLT_NI: + case SBIC_CSR_RSLT_IFY: + { + /* + * A reselection. + * Note that since we don't enable Advanced Features (assuming + * the WD chip is at least the 'A' revision), we're only ever + * likely to see the 'SBIC_CSR_RSLT_NI' status. But for the + * hell of it, we'll handle it anyway, for all the extra code + * it needs... + */ + u_char newtarget, newlun; + + if (sc->sc_flags & SBICF_INDMA) { + printf("**** RESELECT WHILE DMA ACTIVE!!! ***\n"); + wd33c93_dma_stop(sc); + } + + sc->sc_state = SBIC_RESELECTED; + GET_SBIC_rselid(sc, newtarget); + + /* check SBIC_RID_SIV? */ + newtarget &= SBIC_RID_MASK; + + if (csr == SBIC_CSR_RSLT_IFY) { + /* Read Identify msg to avoid lockup */ + GET_SBIC_data(sc, newlun); + WAIT_CIP(sc); + newlun &= SBIC_TLUN_MASK; + sc->sc_msgify = MSG_IDENTIFY(newlun, 0); + } else { + /* + * Need to read Identify message the hard way, assuming + * the target even sends us one... + */ + for (newlun = 255; newlun; --newlun) { + GET_SBIC_asr(sc, asr); + if (asr & SBIC_ASR_INT) + break; + DELAY(10); + } + + /* If we didn't get an interrupt, somethink's up */ + if ((asr & SBIC_ASR_INT) == 0) { + printf("%s: Reselect without identify? asr %x\n", + sc->sc_dev.dv_xname, asr); + newlun = 0; /* XXXX */ + } else { + /* + * We got an interrupt, verify that it's a + * change to message in phase, and if so + * read the message. + */ + GET_SBIC_csr(sc,csr); + + if (csr == (SBIC_CSR_MIS | MESG_IN_PHASE) || + csr == (SBIC_CSR_MIS_1 | MESG_IN_PHASE) || + csr == (SBIC_CSR_MIS_2 | MESG_IN_PHASE)) { + /* + * Yup, gone to message in. + * Fetch the target LUN + */ + sc->sc_msgify = 0; + wd33c93_msgin_phase(sc, 1); + newlun = sc->sc_msgify & SBIC_TLUN_MASK; + } else { + /* + * Whoops! Target didn't go to msg_in + * phase!! + */ + printf("RSLT_NI - not MESG_IN_PHASE %x\n", csr); + newlun = 0; /* XXXSCW */ + } + } + } + + /* Ok, we have the identity of the reselecting target. */ + SBIC_DEBUG(RSEL, ("wd33c93next: reselect from targ %d lun %d", + newtarget, newlun)); + wd33c93_reselect(sc, newtarget, newlun, 0, 0); + sc->sc_disc--; + + if (csr == SBIC_CSR_RSLT_IFY) + SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK); + break; + } + + default: + abort: + /* Something unexpected happend -- deal with it. */ + printf("next: aborting asr 0x%02x csr 0x%02x\n", asr, csr); + +#ifdef DDB + Debugger(); +#endif + + SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI); + if (acb->xs) + wd33c93_error(sc, acb); + wd33c93_abort(sc, acb, "next"); + + if (sc->sc_flags & SBICF_INDMA) { + wd33c93_dma_stop(sc); + wd33c93_scsidone(sc, acb, STATUS_UNKNOWN); + } + return SBIC_STATE_ERROR; + } + return SBIC_STATE_RUNNING; +} + + +void +wd33c93_reselect(struct wd33c93_softc *sc, int target, int lun, int tag_type, int tag_id) +{ + + struct wd33c93_tinfo *ti; + struct wd33c93_linfo *li; + struct wd33c93_acb *acb; + + if (sc->sc_nexus) { + /* + * Whoops! We've been reselected with a + * command in progress! + * The best we can do is to put the current + * command back on the ready list and hope + * for the best. + */ + SBIC_DEBUG(RSEL, ("%s: reselect with active command\n", + sc->sc_dev.dv_xname)); + ti = &sc->sc_tinfo[sc->target]; + li = TINFO_LUN(ti, sc->lun); + li->state = L_STATE_IDLE; + + wd33c93_dequeue(sc, sc->sc_nexus); + TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain); + sc->sc_nexus->flags |= ACB_READY; + + sc->sc_nexus = NULL; + } + + /* Setup state for new nexus */ + acb = NULL; + sc->sc_flags = SBICF_SELECTED; + sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0; + + ti = &sc->sc_tinfo[target]; + li = TINFO_LUN(ti, lun); + + if (li != NULL) { + if (li->untagged != NULL && li->state) + acb = li->untagged; + else if (tag_type != MSG_SIMPLE_Q_TAG) { + /* Wait for tag to come by during MESG_IN Phase */ + sc->target = target; /* setup I_T_L nexus */ + sc->lun = lun; + sc->sc_state = SBIC_IDENTIFIED; + return; + } else if (tag_type) + acb = li->queued[tag_id]; + } + + if (acb == NULL) { + printf("%s: reselect from target %d lun %d tag %x:%x " + "with no nexus; sending ABORT\n", + sc->sc_dev.dv_xname, target, lun, tag_type, tag_id); + goto abort; + } + + sc->target = target; + sc->lun = lun; + sc->sc_nexus = acb; + sc->sc_state = SBIC_CONNECTED; + + if (!wd33c93_dmaok(sc, acb->xs)) + sc->sc_flags |= SBICF_NODMA; + + /* Do an implicit RESTORE POINTERS. */ + sc->sc_daddr = acb->daddr; + sc->sc_dleft = acb->dleft; + + /* Set sync modes for new target */ + wd33c93_setsync(sc, ti); + + if (acb->flags & ACB_RESET) + wd33c93_sched_msgout(sc, SEND_DEV_RESET); + else if (acb->flags & ACB_ABORT) + wd33c93_sched_msgout(sc, SEND_ABORT); + return; + +abort: + wd33c93_sched_msgout(sc, SEND_ABORT); + return; + +} + +void +wd33c93_timeout(void *arg) +{ + struct wd33c93_acb *acb = arg; + struct scsi_xfer *xs = acb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct wd33c93_softc *sc = sc_link->adapter_softc; + int s, asr; + + s = splbio(); + + GET_SBIC_asr(sc, asr); + + sc_print_addr(sc_link); + printf("%s: timed out; asr=0x%02x [acb %p (flags 0x%x, dleft %zx)], " + "<state %d, nexus %p, resid %lx, msg(q %x,o %x)>", + sc->sc_dev.dv_xname, asr, acb, acb->flags, acb->dleft, + sc->sc_state, sc->sc_nexus, (long)sc->sc_dleft, + sc->sc_msgpriq, sc->sc_msgout); + + if (asr & SBIC_ASR_INT) { + /* We need to service a missed IRQ */ + wd33c93_intr(sc); + } else { + (void) wd33c93_abort(sc, sc->sc_nexus, "timeout"); + } + splx(s); +} + + +void +wd33c93_watchdog(void *arg) +{ + struct wd33c93_softc *sc = arg; + struct wd33c93_tinfo *ti; + struct wd33c93_linfo *li; + int t, s, l; + /* scrub LUN's that have not been used in the last 10min. */ + time_t old = time_second - (10 * 60); + + for (t = 0; t < SBIC_NTARG; t++) { + ti = &sc->sc_tinfo[t]; + for (l = 0; l < SBIC_NLUN; l++) { + s = splbio(); + li = TINFO_LUN(ti, l); + if (li && li->last_used < old && + li->untagged == NULL && li->used == 0) { + ti->lun[li->lun] = NULL; + free(li, M_DEVBUF); + } + splx(s); + } + } + timeout_add_sec(&sc->sc_watchdog, 60); +} + + +#ifdef SBICDEBUG +void +wd33c93_hexdump(u_char *buf, int len) +{ + printf("{%d}:", len); + while (len--) + printf(" %02x", *buf++); + printf("\n"); +} + + +void +wd33c93_print_csr(u_char csr) +{ + switch (SCSI_PHASE(csr)) { + case CMD_PHASE: + printf("CMD_PHASE\n"); + break; + + case STATUS_PHASE: + printf("STATUS_PHASE\n"); + break; + + case DATA_IN_PHASE: + printf("DATAIN_PHASE\n"); + break; + + case DATA_OUT_PHASE: + printf("DATAOUT_PHASE\n"); + break; + + case MESG_IN_PHASE: + printf("MESG_IN_PHASE\n"); + break; + + case MESG_OUT_PHASE: + printf("MESG_OUT_PHASE\n"); + break; + + default: + switch (csr) { + case SBIC_CSR_DISC_1: + printf("DISC_1\n"); + break; + + case SBIC_CSR_RSLT_NI: + printf("RESELECT_NO_IFY\n"); + break; + + case SBIC_CSR_RSLT_IFY: + printf("RESELECT_IFY\n"); + break; + + case SBIC_CSR_SLT: + printf("SELECT\n"); + break; + + case SBIC_CSR_SLT_ATN: + printf("SELECT, ATN\n"); + break; + + case SBIC_CSR_UNK_GROUP: + printf("UNK_GROUP\n"); + break; + + default: + printf("UNKNOWN csr=%02x\n", csr); + } + } +} +#endif diff --git a/sys/dev/ic/wd33c93reg.h b/sys/dev/ic/wd33c93reg.h new file mode 100644 index 00000000000..e1f16ad11f9 --- /dev/null +++ b/sys/dev/ic/wd33c93reg.h @@ -0,0 +1,510 @@ +/* $OpenBSD: wd33c93reg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: wd33c93reg.h,v 1.4 2009/02/12 06:24:45 rumble Exp $ */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of 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. + * 3. 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. + * + * @(#)scsireg.h 7.3 (Berkeley) 2/5/91 + */ + +/* + * Copyright (c) 2001 Wayne Knowles + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of 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. + * 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. + * 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. + * + * @(#)scsireg.h 7.3 (Berkeley) 2/5/91 + */ + +/* + * WD33C93 SCSI interface hardware description. + * + * Using parts of the Mach scsi driver for the 33C93 + */ + +#define SBIC_myid 0 +#define SBIC_cdbsize 0 +#define SBIC_control 1 +#define SBIC_timeo 2 +#define SBIC_cdb1 3 +#define SBIC_tsecs 3 +#define SBIC_cdb2 4 +#define SBIC_theads 4 +#define SBIC_cdb3 5 +#define SBIC_tcyl_hi 5 +#define SBIC_cdb4 6 +#define SBIC_tcyl_lo 6 +#define SBIC_cdb5 7 +#define SBIC_addr_hi 7 +#define SBIC_cdb6 8 +#define SBIC_addr_2 8 +#define SBIC_cdb7 9 +#define SBIC_addr_3 9 +#define SBIC_cdb8 10 +#define SBIC_addr_lo 10 +#define SBIC_cdb9 11 +#define SBIC_secno 11 +#define SBIC_cdb10 12 +#define SBIC_headno 12 +#define SBIC_cdb11 13 +#define SBIC_cylno_hi 13 +#define SBIC_cdb12 14 +#define SBIC_cylno_lo 14 +#define SBIC_tlun 15 +#define SBIC_cmd_phase 16 +#define SBIC_syn 17 +#define SBIC_count_hi 18 +#define SBIC_count_med 19 +#define SBIC_count_lo 20 +#define SBIC_selid 21 +#define SBIC_rselid 22 +#define SBIC_csr 23 +#define SBIC_cmd 24 +#define SBIC_data 25 +#define SBIC_queue_tag 26 +#define SBIC_aux_status 27 + +/* wd33c93_asr is addressed directly */ + +/* + * Register defines + */ + +/* + * Auxiliary Status Register + */ + +#define SBIC_ASR_INT 0x80 /* Interrupt pending */ +#define SBIC_ASR_LCI 0x40 /* Last command ignored */ +#define SBIC_ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */ +#define SBIC_ASR_CIP 0x10 /* Busy, cmd unavail also */ +#define SBIC_ASR_xxx 0x0c +#define SBIC_ASR_PE 0x02 /* Parity error (even) */ +#define SBIC_ASR_DBR 0x01 /* Data Buffer Ready */ + +/* + * My ID register, and/or CDB Size + */ + +#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 MHz */ + /* 11 MHz is invalid */ +#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 MHz */ +#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 MHz */ +#define SBIC_ID_RAF 0x20 /* Enable Really Advanced Features */ +#define SBIC_ID_EHP 0x10 /* Enable host parity */ +#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */ +#define SBIC_ID_MASK 0x07 +#define SBIC_ID_CBDSIZE_MASK 0x0f /* if unk SCSI cmd group */ + +/* + * Control register + */ + +#define SBIC_CTL_DMA 0x80 /* Single byte dma */ +#define SBIC_CTL_DBA_DMA 0x40 /* direct buffer access (bus master) */ +#define SBIC_CTL_BURST_DMA 0x20 /* continuous mode (8237) */ +#define SBIC_CTL_NO_DMA 0x00 /* Programmed I/O */ +#define SBIC_CTL_HHP 0x10 /* Halt on host parity error */ +#define SBIC_CTL_EDI 0x08 /* Ending disconnect interrupt */ +#define SBIC_CTL_IDI 0x04 /* Intermediate disconnect interrupt*/ +#define SBIC_CTL_HA 0x02 /* Halt on ATN */ +#define SBIC_CTL_HSP 0x01 /* Halt on SCSI parity error */ + +/* + * Timeout period register + * [val in msecs, input clk in 0.1 MHz] + */ + +#define SBIC_TIMEOUT(val,clk) ((((val) * (clk)) / 800) + 1) + +/* + * CDBn registers, note that + * cdb11 is used for status byte in target mode (send-status-and-cc) + * cdb12 sez if linked command complete, and w/flag if so + */ + +/* + * Target LUN register + * [holds target status when select-and-xfer] + */ + +#define SBIC_TLUN_VALID 0x80 /* did we receive an Identify msg */ +#define SBIC_TLUN_DOK 0x40 /* Disconnect OK */ +#define SBIC_TLUN_xxx 0x38 +#define SBIC_TLUN_MASK 0x07 + +/* + * Command Phase register + */ + +#define SBIC_CPH_MASK 0x7f /* values/restarts are cmd specific */ +#define SBIC_CPH(p) ((p) & SBIC_CPH_MASK) + +/* + * FIFO register + */ + +#define SBIC_FIFO_93_DEPTH 5 +#define SBIC_FIFO_93AB_DEPTH 12 + +/* + * maximum possible size in TC registers. Since this is 24 bit, it's easy + */ +#define SBIC_TC_MAX ((1 << 24) - 1) + +/* + * Synchronous xfer register + * + * NB: SBIC_SYN_FSS only valid on WD33C93B with 16-20MHz clock. + */ + +#define SBIC_SYN_OFF_MASK 0x0f +#define SBIC_SYN_93_MAX_OFFSET (SBIC_FIFO_93_DEPTH - 1) /* 4 is recommended */ +#define SBIC_SYN_93AB_MAX_OFFSET SBIC_FIFO_93AB_DEPTH +#define SBIC_SYN_PER_MASK 0x70 +#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */ +#define SBIC_SYN_FSS 0x80 /* Enable Fast SCSI Transfers (10MB/s)*/ + +#define SBIC_SYN(o,p,f) \ + (((o) & SBIC_SYN_OFF_MASK) | (((p) << 4) & SBIC_SYN_PER_MASK) | \ + ((f) ? SBIC_SYN_FSS : 0)) + +/* + * Transfer count register + * optimal access macros depend on addressing + */ + +/* + * Destination ID (selid) register + */ + +#define SBIC_SID_SCC 0x80 /* Select command chaining (tgt) */ +#define SBIC_SID_DPD 0x40 /* Data phase direction (inittor) */ +#define SBIC_SID_FROM_SCSI 0x40 +#define SBIC_SID_TO_SCSI 0x00 +#define SBIC_SID_xxx 0x38 +#define SBIC_SID_IDMASK 0x07 + +/* + * Source ID (rselid) register + */ + +#define SBIC_RID_ER 0x80 /* Enable reselection */ +#define SBIC_RID_ES 0x40 /* Enable selection */ +#define SBIC_RID_DSP 0x20 /* Disable select parity */ +#define SBIC_RID_SIV 0x08 /* Source ID valid */ +#define SBIC_RID_MASK 0x07 + +/* + * Status register + */ + +#define SBIC_CSR_CAUSE 0xf0 +#define SBIC_CSR_RESET 0x00 /* chip was reset */ +#define SBIC_CSR_CMD_DONE 0x10 /* cmd completed */ +#define SBIC_CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/ +#define SBIC_CSR_CMD_ERR 0x40 /* end with error */ +#define SBIC_CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */ + + +#define SBIC_CSR_QUALIFIER 0x0f +/* Reset State Interrupts */ +#define SBIC_CSR_RESET 0x00 /* reset w/advanced features*/ +#define SBIC_CSR_RESET_AM 0x01 /* reset w/advanced features*/ +/* Successful Completion Interrupts */ +#define SBIC_CSR_TARGET 0x10 /* reselect complete */ +#define SBIC_CSR_INITIATOR 0x11 /* select complete */ +#define SBIC_CSR_WO_ATN 0x13 /* tgt mode completion */ +#define SBIC_CSR_W_ATN 0x14 /* ditto */ +#define SBIC_CSR_XLATED 0x15 /* translate address cmd */ +#define SBIC_CSR_S_XFERRED 0x16 /* initiator mode completion*/ +#define SBIC_CSR_XFERRED 0x18 /* phase in low bits */ +/* Paused or Aborted Interrupts */ +#define SBIC_CSR_MSGIN_W_ACK 0x20 /* (I) msgin, ACK asserted*/ +#define SBIC_CSR_SDP 0x21 /* (I) SDP msg received */ +#define SBIC_CSR_SEL_ABRT 0x22 /* sel/resel aborted */ +#define SBIC_CSR_XFR_PAUSED 0x23 /* (T) no ATN */ +#define SBIC_CSR_XFR_PAUSED_ATN 0x24 /* (T) ATN is asserted */ +#define SBIC_CSR_RSLT_AM 0x27 /* (I) lost selection (AM) */ +#define SBIC_CSR_MIS 0x28 /* (I) xfer aborted, ph mis */ +/* Terminated Interrupts */ +#define SBIC_CSR_CMD_INVALID 0x40 +#define SBIC_CSR_DISC 0x41 /* (I) tgt disconnected */ +#define SBIC_CSR_SEL_TIMEO 0x42 +#define SBIC_CSR_PE 0x43 /* parity error */ +#define SBIC_CSR_PE_ATN 0x44 /* ditto, ATN is asserted */ +#define SBIC_CSR_XLATE_TOOBIG 0x45 +#define SBIC_CSR_RSLT_NOAM 0x46 /* (I) lost sel, no AM mode */ +#define SBIC_CSR_BAD_STATUS 0x47 /* status byte was nok */ +#define SBIC_CSR_MIS_1 0x48 /* ph mis, see low bits */ +/* Service Required Interrupts */ +#define SBIC_CSR_RSLT_NI 0x80 /* reselected, no ify msg */ +#define SBIC_CSR_RSLT_IFY 0x81 /* ditto, AM mode, got ify */ +#define SBIC_CSR_SLT 0x82 /* selected, no ATN */ +#define SBIC_CSR_SLT_ATN 0x83 /* selected with ATN */ +#define SBIC_CSR_ATN 0x84 /* (T) ATN asserted */ +#define SBIC_CSR_DISC_1 0x85 /* (I) bus is free */ +#define SBIC_CSR_UNK_GROUP 0x87 /* strange CDB1 */ +#define SBIC_CSR_MIS_2 0x88 /* (I) ph mis, see low bits */ + +#define SBIC_PHASE(csr) SCSI_PHASE(csr) + +/* + * Command register (command codes) + */ + +#define SBIC_CMD_SBT 0x80 /* Single byte xfer qualifier */ +#define SBIC_CMD_MASK 0x7f + + /* Miscellaneous */ +#define SBIC_CMD_RESET 0x00 /* (DTI) lev I */ +#define SBIC_CMD_ABORT 0x01 /* (DTI) lev I */ +#define SBIC_CMD_DISC 0x04 /* ( TI) lev I */ +#define SBIC_CMD_SSCC 0x0d /* ( TI) lev I */ +#define SBIC_CMD_SET_IDI 0x0f /* (DTI) lev I */ +#define SBIC_CMD_XLATE 0x18 /* (DT ) lev II */ + + /* Initiator state */ +#define SBIC_CMD_SET_ATN 0x02 /* ( I) lev I */ +#define SBIC_CMD_CLR_ACK 0x03 /* ( I) lev I */ +#define SBIC_CMD_XFER_PAD 0x19 /* ( I) lev II */ +#define SBIC_CMD_XFER_INFO 0x20 /* ( I) lev II */ + + /* Target state */ +#define SBIC_CMD_SND_DISC 0x0e /* ( T ) lev II */ +#define SBIC_CMD_RCV_CMD 0x10 /* ( T ) lev II */ +#define SBIC_CMD_RCV_DATA 0x11 /* ( T ) lev II */ +#define SBIC_CMD_RCV_MSG_OUT 0x12 /* ( T ) lev II */ +#define SBIC_CMD_RCV 0x13 /* ( T ) lev II */ +#define SBIC_CMD_SND_STATUS 0x14 /* ( T ) lev II */ +#define SBIC_CMD_SND_DATA 0x15 /* ( T ) lev II */ +#define SBIC_CMD_SND_MSG_IN 0x16 /* ( T ) lev II */ +#define SBIC_CMD_SND 0x17 /* ( T ) lev II */ + + /* Disconnected state */ +#define SBIC_CMD_RESELECT 0x05 /* (D ) lev II */ +#define SBIC_CMD_SEL_ATN 0x06 /* (D ) lev II */ +#define SBIC_CMD_SEL 0x07 /* (D ) lev II */ +#define SBIC_CMD_SEL_ATN_XFER 0x08 /* (D I) lev II */ +#define SBIC_CMD_SEL_XFER 0x09 /* (D I) lev II */ +#define SBIC_CMD_RESELECT_RECV 0x0a /* (DT ) lev II */ +#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */ +#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */ + + +#define PHASE_MASK 0x07 /* mask for psns/pctl phase */ +#define DATA_OUT_PHASE 0x00 +#define DATA_IN_PHASE 0x01 +#define CMD_PHASE 0x02 +#define STATUS_PHASE 0x03 +#define BUS_FREE_PHASE 0x04 +#define ARB_SEL_PHASE 0x05 /* Fuji chip combines bus arb with sel. */ +#define MESG_OUT_PHASE 0x06 +#define MESG_IN_PHASE 0x07 + +#define SCSI_PHASE(reg) ((reg) & PHASE_MASK) + +#define SCSI_STATUS_MASK 0x3e /* Mask unused bits in status byte */ + +/* approximate, but we won't do SBT on selects */ +#define wd33c93_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa)) + +#define PAD(n) char n; +#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA + +/* + * WD33C93 has two registers: + * ASR - r : Aux Status Register, w : desired register no + * DATA - rw: register value + * + * We access them via separate handles because some people *cough*SGI*cough* + * like to keep them apart. + */ + +#define wd33c93_read_reg(sc,regno,val) \ + do { \ + bus_space_write_1((sc)->sc_regt,(sc)->sc_asr_regh, 0, (regno)); \ + (val) = bus_space_read_1((sc)->sc_regt,(sc)->sc_data_regh, 0); \ + } while (0) + +#define wd33c93_write_reg(sc,regno,val) \ + do { \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_asr_regh, 0, (regno)); \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, (val)); \ + } while (0) + +#define SET_SBIC_myid(sc,val) wd33c93_write_reg(sc,SBIC_myid,val) +#define GET_SBIC_myid(sc,val) wd33c93_read_reg(sc,SBIC_myid,val) +#define SET_SBIC_cdbsize(sc,val) wd33c93_write_reg(sc,SBIC_cdbsize,val) +#define GET_SBIC_cdbsize(sc,val) wd33c93_read_reg(sc,SBIC_cdbsize,val) +#define SET_SBIC_control(sc,val) wd33c93_write_reg(sc,SBIC_control,val) +#define GET_SBIC_control(sc,val) wd33c93_read_reg(sc,SBIC_control,val) +#define SET_SBIC_timeo(sc,val) wd33c93_write_reg(sc,SBIC_timeo,val) +#define GET_SBIC_timeo(sc,val) wd33c93_read_reg(sc,SBIC_timeo,val) +#define SET_SBIC_cdb1(sc,val) wd33c93_write_reg(sc,SBIC_cdb1,val) +#define GET_SBIC_cdb1(sc,val) wd33c93_read_reg(sc,SBIC_cdb1,val) +#define SET_SBIC_cdb2(sc,val) wd33c93_write_reg(sc,SBIC_cdb2,val) +#define GET_SBIC_cdb2(sc,val) wd33c93_read_reg(sc,SBIC_cdb2,val) +#define SET_SBIC_cdb3(sc,val) wd33c93_write_reg(sc,SBIC_cdb3,val) +#define GET_SBIC_cdb3(sc,val) wd33c93_read_reg(sc,SBIC_cdb3,val) +#define SET_SBIC_cdb4(sc,val) wd33c93_write_reg(sc,SBIC_cdb4,val) +#define GET_SBIC_cdb4(sc,val) wd33c93_read_reg(sc,SBIC_cdb4,val) +#define SET_SBIC_cdb5(sc,val) wd33c93_write_reg(sc,SBIC_cdb5,val) +#define GET_SBIC_cdb5(sc,val) wd33c93_read_reg(sc,SBIC_cdb5,val) +#define SET_SBIC_cdb6(sc,val) wd33c93_write_reg(sc,SBIC_cdb6,val) +#define GET_SBIC_cdb6(sc,val) wd33c93_read_reg(sc,SBIC_cdb6,val) +#define SET_SBIC_cdb7(sc,val) wd33c93_write_reg(sc,SBIC_cdb7,val) +#define GET_SBIC_cdb7(sc,val) wd33c93_read_reg(sc,SBIC_cdb7,val) +#define SET_SBIC_cdb8(sc,val) wd33c93_write_reg(sc,SBIC_cdb8,val) +#define GET_SBIC_cdb8(sc,val) wd33c93_read_reg(sc,SBIC_cdb8,val) +#define SET_SBIC_cdb9(sc,val) wd33c93_write_reg(sc,SBIC_cdb9,val) +#define GET_SBIC_cdb9(sc,val) wd33c93_read_reg(sc,SBIC_cdb9,val) +#define SET_SBIC_cdb10(sc,val) wd33c93_write_reg(sc,SBIC_cdb10,val) +#define GET_SBIC_cdb10(sc,val) wd33c93_read_reg(sc,SBIC_cdb10,val) +#define SET_SBIC_cdb11(sc,val) wd33c93_write_reg(sc,SBIC_cdb11,val) +#define GET_SBIC_cdb11(sc,val) wd33c93_read_reg(sc,SBIC_cdb11,val) +#define SET_SBIC_cdb12(sc,val) wd33c93_write_reg(sc,SBIC_cdb12,val) +#define GET_SBIC_cdb12(sc,val) wd33c93_read_reg(sc,SBIC_cdb12,val) +#define SET_SBIC_tlun(sc,val) wd33c93_write_reg(sc,SBIC_tlun,val) +#define GET_SBIC_tlun(sc,val) wd33c93_read_reg(sc,SBIC_tlun,val) +#define SET_SBIC_cmd_phase(sc,val) wd33c93_write_reg(sc,SBIC_cmd_phase,val) +#define GET_SBIC_cmd_phase(sc,val) wd33c93_read_reg(sc,SBIC_cmd_phase,val) +#define SET_SBIC_syn(sc,val) wd33c93_write_reg(sc,SBIC_syn,val) +#define GET_SBIC_syn(sc,val) wd33c93_read_reg(sc,SBIC_syn,val) +#define SET_SBIC_count_hi(sc,val) wd33c93_write_reg(sc,SBIC_count_hi,val) +#define GET_SBIC_count_hi(sc,val) wd33c93_read_reg(sc,SBIC_count_hi,val) +#define SET_SBIC_count_med(sc,val) wd33c93_write_reg(sc,SBIC_count_med,val) +#define GET_SBIC_count_med(sc,val) wd33c93_read_reg(sc,SBIC_count_med,val) +#define SET_SBIC_count_lo(sc,val) wd33c93_write_reg(sc,SBIC_count_lo,val) +#define GET_SBIC_count_lo(sc,val) wd33c93_read_reg(sc,SBIC_count_lo,val) +#define SET_SBIC_selid(sc,val) wd33c93_write_reg(sc,SBIC_selid,val) +#define GET_SBIC_selid(sc,val) wd33c93_read_reg(sc,SBIC_selid,val) +#define SET_SBIC_rselid(sc,val) wd33c93_write_reg(sc,SBIC_rselid,val) +#define GET_SBIC_rselid(sc,val) wd33c93_read_reg(sc,SBIC_rselid,val) +#define SET_SBIC_csr(sc,val) wd33c93_write_reg(sc,SBIC_csr,val) +#define GET_SBIC_csr(sc,val) wd33c93_read_reg(sc,SBIC_csr,val) +#define SET_SBIC_cmd(sc,val) wd33c93_write_reg(sc,SBIC_cmd,val) +#define GET_SBIC_cmd(sc,val) wd33c93_read_reg(sc,SBIC_cmd,val) +#define SET_SBIC_data(sc,val) wd33c93_write_reg(sc,SBIC_data,val) +#define GET_SBIC_data(sc,val) wd33c93_read_reg(sc,SBIC_data,val) +#define SET_SBIC_queue_tag(sc,val) wd33c93_write_reg(sc,SBIC_queue_tag,val) +#define GET_SBIC_queue_tag(sc,val) wd33c93_read_reg(sc,SBIC_queue_tag,val) + +#define SBIC_TC_PUT(sc,val) \ + do { \ + wd33c93_write_reg(sc,SBIC_count_hi,((val)>>16)); \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, \ + (val)>>8); \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, 0, \ + (val)); \ + } while (0) + +#define SBIC_TC_GET(sc,val) \ + do { \ + wd33c93_read_reg(sc,SBIC_count_hi,(val)); \ + (val) = ((val)<<8) | bus_space_read_1((sc)->sc_regt, \ + (sc)->sc_data_regh, 0); \ + (val) = ((val)<<8) | bus_space_read_1((sc)->sc_regt, \ + (sc)->sc_data_regh, 0); \ + } while (0) + +#define SBIC_LOAD_COMMAND(sc,cmd,cmdsize) \ + do { \ + int n = (cmdsize) - 1; \ + char *ptr = (char *)(cmd); \ + wd33c93_write_reg(regs, SBIC_cdb1, *ptr++); \ + while(n-- > 0) \ + bus_space_write_1((sc)->sc_regt, (sc)->sc_data_regh, \ + 0, *ptr++); /* XXX write_multi */ \ + } while (0) + +#define GET_SBIC_asr(sc,val) \ + do { \ + (val) = bus_space_read_1((sc)->sc_regt,(sc)->sc_asr_regh, 0); \ + } while (0) + + +#define WAIT_CIP(sc) \ + do { \ + while (bus_space_read_1((sc)->sc_regt,(sc)->sc_asr_regh, \ + 0) & SBIC_ASR_CIP) \ + /*nop*/; \ + } while (0) + +/* + * transmit a byte in programmed I/O mode + */ +#define SEND_BYTE(sc, ch) \ + do { \ + WAIT_CIP(sc); \ + SET_SBIC_cmd(sc, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \ + SBIC_WAIT(sc, SBIC_ASR_DBR, 0); \ + SET_SBIC_data(sc, ch); \ + } while (0) + +/* + * receive a byte in programmed I/O mode + */ +#define RECV_BYTE(sc, ch) \ + do { \ + WAIT_CIP(sc); \ + SET_SBIC_cmd(sc, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \ + SBIC_WAIT(sc, SBIC_ASR_DBR, 0); \ + GET_SBIC_data(sc, ch); \ + } while (0) diff --git a/sys/dev/ic/wd33c93var.h b/sys/dev/ic/wd33c93var.h new file mode 100644 index 00000000000..45a24bcebc0 --- /dev/null +++ b/sys/dev/ic/wd33c93var.h @@ -0,0 +1,262 @@ +/* $OpenBSD: wd33c93var.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: wd33c93var.h,v 1.10 2009/05/12 14:25:18 cegger Exp $ */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of 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. + * 3. 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. + * + * @(#)scsivar.h 7.1 (Berkeley) 5/8/90 + */ + +#define SBIC_NTARG 8 +#define SBIC_NLUN 8 +#define SBIC_NTAGS 256 + +#define SBIC_MAX_MSGLEN 8 + +#define SBIC_ABORT_TIMEOUT 2000 /* time to wait for abort */ +#define SBIC_SENSE_TIMEOUT 1000 /* time to wait for sense */ + +/* + * ACB. 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. + */ +struct wd33c93_acb { + TAILQ_ENTRY(wd33c93_acb) chain; + struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */ + int flags; /* Status */ +#define ACB_FREE 0x00 +#define ACB_ACTIVE 0x01 +#define ACB_READY 0x02 /* ACB is on ready list */ +#define ACB_DONE 0x04 +#define ACB_SENSE 0x08 /* ACB Requesting sense */ +#define ACB_COMPLETE 0x10 /* Disconnected at end of xfer */ +#define ACB_RESET 0x20 /* Require Reset */ +#define ACB_ABORT 0x40 /* Require Abort */ + int timeout; + struct timeout to; + + struct scsi_generic cmd; /* SCSI command block */ + char *daddr; /* kva for data */ + int clen; + size_t dleft; /* bytes remaining */ + u_char tag_type; /* TAG Type (0x20-0x22, 0=No Tags) */ + u_char tag_id; /* TAG id number */ +}; + +/* + * 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 wd33c93_linfo { + int lun; + LIST_ENTRY(wd33c93_linfo) link; + time_t last_used; + u_char used; /* # slots in use */ + u_char avail; /* where to start scanning */ + u_char state; +#define L_STATE_IDLE 0 +#define L_STATE_BUSY 1 +#define L_STATE_ESTAT 2 + struct wd33c93_acb *untagged; + struct wd33c93_acb *queued[SBIC_NTAGS]; +}; + +struct wd33c93_tinfo { + int cmds; /* # of commands processed */ + int dconns; /* # of disconnects */ + + u_char flags; +#define T_NEED_RESET 0x01 /* Should send a BUS_DEV_RESET */ +#define T_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */ +#define T_BUSY 0x04 /* Target is busy */ +#define T_SYNCMODE 0x08 /* SYNC mode has been negotiated */ +#define T_NOSYNC 0x10 /* Force ASYNC mode */ +#define T_NODISC 0x20 /* Don't allow disconnect */ +#define T_TAG 0x40 /* Turn on TAG QUEUEs */ +#define T_WANTSYNC 0x80 /* Negotiatious should aim for sync */ + u_char period; /* Period suggestion */ + u_char offset; /* Offset suggestion */ + struct wd33c93_linfo *lun[SBIC_NLUN]; /* LUN list for this target */ +}; + +/* Look up a lun in a tinfo */ +#define TINFO_LUN(t, l) ((t)->lun[(l)]) + +struct wd33c93_softc { + struct device sc_dev; + + struct timeout sc_watchdog; + struct scsi_link sc_link; + void *sc_driver; /* driver specific field */ + + int target; /* Currently active target */ + int lun; /* Currently active LUN */ + + /* WD33c93 registers */ + bus_space_tag_t sc_regt; + bus_space_handle_t sc_asr_regh; + bus_space_handle_t sc_data_regh; + + /* Data about the current nexus (updated for every cmd switch) */ + void * sc_daddr; /* Current data pointer */ + size_t sc_dleft; /* Data left to transfer */ + ssize_t sc_tcnt; /* number of bytes transfered */ + + /* Lists of command blocks */ + TAILQ_HEAD(acb_list, wd33c93_acb) ready_list; + + struct wd33c93_acb *sc_nexus; /* current command */ + struct wd33c93_tinfo sc_tinfo[8]; + + u_short sc_state; + u_short sc_status; + int sc_disc; /* current # of active nexus's */ + int sc_flags; + + /* Message stuff */ + u_short sc_msgify; /* Last IDENTIFY message */ + u_short sc_msgout; /* Current message out */ + u_short sc_msgpriq; /* mesg_out queue (bitmap) */ + u_short sc_msgoutq; /* mesg_out queue */ + + u_char sc_imsg[SBIC_MAX_MSGLEN]; + u_char sc_omsg[SBIC_MAX_MSGLEN]; + u_char sc_imsglen; + u_char sc_omsglen; + + /* Static hardware attributes supplied by attachment */ + int sc_id; /* SCSI ID for controller */ + int sc_clkfreq; /* wd33c93 clk freq * 10 MHz */ + uint8_t sc_dmamode; /* One of SBIC_CTL_*DMA */ + + /* Static hardware attributes derived by wd33c93_attach() */ + int sc_chip; /* Chip variation */ + int sc_rev; /* Chip revision */ + int sc_cfflags; /* Copy of config flags */ + int sc_maxxfer; /* Maximum transfer size */ + uint8_t sc_maxoffset; /* Maximum sync offset (bytes) */ + uint8_t sc_minsyncperiod; /* Minimum supported sync xfer period */ + uint8_t sc_syncperiods[7]; /* Sync transfer periods (4ns units) */ + uint8_t sc_fsyncperiods[3]; /* Sync transfer periods for Fast SCSI*/ + + int (*sc_dmasetup)(struct wd33c93_softc *, void **, size_t *, int, + size_t *); + int (*sc_dmago)(struct wd33c93_softc *); + void (*sc_dmastop)(struct wd33c93_softc *); + void (*sc_reset)(struct wd33c93_softc *); +}; + +/* values for sc_flags */ +#define SBICF_SELECTED 0x01 /* bus is in selected state. */ +#define SBICF_NODMA 0x02 /* Polled transfer */ +#define SBICF_INDMA 0x04 /* DMA I/O in progress */ +#define SBICF_SYNCNEGO 0x08 /* Sync negotiation in progress */ +#define SBICF_ABORTING 0x10 /* Aborting */ + +/* values for sc_state */ +#define SBIC_UNINITIALIZED 0 /* Driver not initialized */ +#define SBIC_IDLE 1 /* waiting for something to do */ +#define SBIC_SELECTING 2 /* SCSI command is arbiting */ +#define SBIC_RESELECTED 3 /* Has been reselected */ +#define SBIC_IDENTIFIED 4 /* Has gotten IFY but not TAG */ +#define SBIC_CONNECTED 5 /* Actively using the SCSI bus */ +#define SBIC_DISCONNECT 6 /* MSG_DISCONNECT received */ +#define SBIC_CMDCOMPLETE 7 /* MSG_CMDCOMPLETE received */ +#define SBIC_ERROR 8 /* Error has occurred */ +#define SBIC_SELTIMEOUT 9 /* Select Timeout */ +#define SBIC_CLEANING 10 /* Scrubbing ACB's */ +#define SBIC_BUSRESET 11 /* SCSI RST has been issued */ + +/* values for sc_msgout */ +#define SEND_DEV_RESET 0x0001 +#define SEND_PARITY_ERROR 0x0002 +#define SEND_INIT_DET_ERR 0x0004 +#define SEND_REJECT 0x0008 +#define SEND_IDENTIFY 0x0010 +#define SEND_ABORT 0x0020 +#define SEND_WDTR 0x0040 +#define SEND_SDTR 0x0080 +#define SEND_TAG 0x0100 + +/* WD33c93 chipset revisions - values for sc_rev */ +#define SBIC_CHIP_UNKNOWN 0 +#define SBIC_CHIP_WD33C93 1 +#define SBIC_CHIP_WD33C93A 2 +#define SBIC_CHIP_WD33C93B 3 + +#define SBIC_CHIP_LIST {"UNKNOWN", "WD33C93", "WD33C93A", "WD33C93B"} + +/* macros for sc_cfflags */ +#define CFFLAGS_NODISC(_cf, _t) ((_cf) & (1 << ( 0 + (_t)))) +#define CFFLAGS_NOSYNC(_cf, _t) ((_cf) & (1 << ( 8 + (_t)))) +#define CFFLAGS_NOTAGS(_cf, _t) ((_cf) & (1 << (16 + (_t)))) + +/* + * States returned by our state machine + */ +#define SBIC_STATE_ERROR -1 +#define SBIC_STATE_DONE 0 +#define SBIC_STATE_RUNNING 1 +#define SBIC_STATE_DISCONNECT 2 + +#define DEBUG_ACBS 0x01 +#define DEBUG_INTS 0x02 +#define DEBUG_CMDS 0x04 +#define DEBUG_MISC 0x08 +#define DEBUG_TRAC 0x10 +#define DEBUG_RSEL 0x20 +#define DEBUG_PHASE 0x40 +#define DEBUG_DMA 0x80 +#define DEBUG_CCMDS 0x100 +#define DEBUG_MSGS 0x200 +#define DEBUG_TAGS 0x400 +#define DEBUG_SYNC 0x800 + +#ifdef SBICDEBUG +extern int wd33c93_debug_flags; +#define SBIC_DEBUG(level, str) \ + do { \ + if (wd33c93_debug & __CONCAT(DEBUG_,level)) \ + printf str; \ + } while (0) +#else +#define SBIC_DEBUG(level, str) +#endif + +void wd33c93_scsi_cmd(struct scsi_xfer *); +void wd33c93_attach(struct wd33c93_softc *, struct scsi_adapter *); +int wd33c93_intr(void *); diff --git a/sys/dev/ic/z8530reg.h b/sys/dev/ic/z8530reg.h index b07c6249914..4bf7ca41a4f 100644 --- a/sys/dev/ic/z8530reg.h +++ b/sys/dev/ic/z8530reg.h @@ -1,5 +1,5 @@ -/* $OpenBSD: z8530reg.h,v 1.6 2003/10/21 18:58:50 jmc Exp $ */ -/* $NetBSD: z8530reg.h,v 1.7 1996/10/23 00:32:31 gwr Exp $ */ +/* $OpenBSD: z8530reg.h,v 1.7 2012/03/28 20:44:23 miod Exp $ */ +/* $NetBSD: z8530reg.h,v 1.12 2005/12/11 12:21:29 christos Exp $ */ /* * Copyright (c) 1992, 1993 @@ -162,6 +162,8 @@ #define ZSWR1_TIE 0x02 /* transmit interrupt enable */ #define ZSWR1_SIE 0x01 /* external/status interrupt enable */ +#define ZSWR1_IMASK 0x1F /* mask of all itr. enable bits. */ + /* HSIS compat */ #define ZSWR1_REQ_ENABLE (ZSWR1_REQ_WAIT | ZSWR1_REQ_TX) @@ -184,6 +186,7 @@ #define ZSWR3_HUNT 0x10 /* enter hunt mode */ #define ZSWR3_RXCRC_ENABLE 0x08 /* enable recv crc calculation */ #define ZSWR3_ADDR_SEARCH_MODE 0x04 /* address search mode (SDLC only) */ +#define ZSWR3_SDLC_SHORT_ADDR 0x02 /* short address mode (SDLC only) */ #define ZSWR3_SYNC_LOAD_INH 0x02 /* sync character load inhibit */ #define ZSWR3_RX_ENABLE 0x01 /* receiver enable */ |