diff options
author | wpaul <wpaul@FreeBSD.org> | 1999-07-09 04:30:09 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1999-07-09 04:30:09 +0000 |
commit | faf9139e2344796b7941eda58a8ffb62c6cb907e (patch) | |
tree | 29db71df09d2ccc01985bba44e8c6f04ceaceb0d | |
parent | 68eae7f53f594dc64c39873af8517cc2f71973a0 (diff) | |
download | FreeBSD-src-faf9139e2344796b7941eda58a8ffb62c6cb907e.zip FreeBSD-src-faf9139e2344796b7941eda58a8ffb62c6cb907e.tar.gz |
This commit adds driver support for the SysKonnect SK-984x series
gigabit ethernet adapters. This includes two single port cards
(single mode and multimode fiber) and two dual port cards (also single
mode and multimode fiber). SysKonnect is currently the only
vendor with a dual port gigabit ethernet NIC.
The ports on dual port adapters are treated as separate network
interfaces. Thus, if you have an SK-9844 dual port SX card, you
should have both sk0 and sk1 interfaces attached. Dual port cards
are implemented using two XMAC II chips connected to a single
SysKonnect GEnesis controller. Hence, dual port cards are really
one PCI device, as opposed to two separate PCI devices connected
through a PCI to PCI bridge. Note that SysKonnect's drivers use
the two ports for failover purposes rather that as two separate
interfaces, plus they don't support jumbo frames. This applies to
their Linux driver too. :)
Support is provided for hardware multicast filtering, BPF and
jumbo frames. The SysKonnect cards support TCP checksum offload
however this feature is not currently enabled (hopefully it will
be once we get checksum offload support).
There are still a few things that need to be implemeted, like
the ability to communicate with the on-board LM80 voltage/temperature
monitor, but I wanted to get the driver under CVS control and into
-current so people could bang on it.
A big thanks for SysKonnect for making all their programming info
for these cards (and for their FDDI and token ring cards) available
without NDA (see www.syskonnect.com).
-rw-r--r-- | release/sysinstall/devices.c | 3 | ||||
-rw-r--r-- | release/texts/HARDWARE.TXT | 7 | ||||
-rw-r--r-- | release/texts/RELNOTES.TXT | 9 | ||||
-rw-r--r-- | share/man/man4/man4.i386/Makefile | 5 | ||||
-rw-r--r-- | share/man/man4/man4.i386/sk.4 | 159 | ||||
-rw-r--r-- | share/man/man4/sk.4 | 159 | ||||
-rw-r--r-- | sys/conf/NOTES | 10 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/dev/sk/if_sk.c | 1916 | ||||
-rw-r--r-- | sys/dev/sk/if_skreg.h | 1172 | ||||
-rw-r--r-- | sys/dev/sk/xmaciireg.h | 393 | ||||
-rw-r--r-- | sys/i386/conf/LINT | 10 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 10 | ||||
-rw-r--r-- | sys/i386/i386/userconfig.c | 5 | ||||
-rw-r--r-- | sys/pci/if_sk.c | 1916 | ||||
-rw-r--r-- | sys/pci/if_skreg.h | 1172 | ||||
-rw-r--r-- | sys/pci/xmaciireg.h | 393 | ||||
-rw-r--r-- | usr.sbin/sade/devices.c | 3 | ||||
-rw-r--r-- | usr.sbin/sysinstall/devices.c | 3 |
19 files changed, 7335 insertions, 11 deletions
diff --git a/release/sysinstall/devices.c b/release/sysinstall/devices.c index 1439cbb..e12ad06 100644 --- a/release/sysinstall/devices.c +++ b/release/sysinstall/devices.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: devices.c,v 1.94 1999/07/03 05:41:21 mharo Exp $ + * $Id: devices.c,v 1.95 1999/07/06 20:40:22 phk Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -100,6 +100,7 @@ static struct _devname { { DEVICE_TYPE_NETWORK, "mx", "Macronix 98713/98715/98725 PCI ethernet card" }, { DEVICE_TYPE_NETWORK, "pn", "Lite-On 82168/82169 PNIC PCI ethernet card" }, { DEVICE_TYPE_NETWORK, "rl", "RealTek 8129/8139 PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "sk", "SysKonnect PCI gigabit ethernet card" }, { DEVICE_TYPE_NETWORK, "tx", "SMC 9432TX ethernet card" }, { DEVICE_TYPE_NETWORK, "ti", "Alteon Networks PCI gigabit ethernet card" }, { DEVICE_TYPE_NETWORK, "tl", "Texas Instruments ThunderLAN PCI ethernet card" }, diff --git a/release/texts/HARDWARE.TXT b/release/texts/HARDWARE.TXT index 33f27da..bb0fa8c 100644 --- a/release/texts/HARDWARE.TXT +++ b/release/texts/HARDWARE.TXT @@ -109,7 +109,6 @@ lnc0 280 10 n/a dyn Lance/PCnet cards mx0 dyn dyn n/a dyn Macronix 98713/15/25 PCI based cards pn0 dyn dyn n/a dyn Lite-On PNIC PCI based cards rl0 dyn dyn n/a dyn RealTek 8129/8139 fast ethernet -ti0 dyn dyn n/a dyn Alteon Networks gigabit ethernet tl0 dyn dyn n/a dyn TI TNET100 'ThunderLAN' cards. wb0 dyn dyn n/a dyn Winbond W89C840F PCI based cards. vr0 dyn dyn n/a dyn VIA VT3043/VT86C100A PCI based cards. @@ -473,6 +472,12 @@ NICs including the following: Hawking Technologies PN102TX D-Link DFE530TX +SysKonnect SK-984x PCI gigabit ethernet cards including the following: + SK-9841 1000baseLX single mode fiber, single port + SK-9842 1000baseSX multimode fiber, single port + SK-9843 1000baseLX single mode fiber, dual port + SK-9844 1000baseSX multimode fiber, dual port + Texas Instruments ThunderLAN PCI NICs, including the following: Compaq Netelligent 10, 10/100, 10/100 Proliant, 10/100 Dual-Port Compaq Netelligent 10/100 TX Embedded UTP, 10 T PCI UTP/Coax, 10/100 TX UTP diff --git a/release/texts/RELNOTES.TXT b/release/texts/RELNOTES.TXT index 9c6bebc..3eef0af 100644 --- a/release/texts/RELNOTES.TXT +++ b/release/texts/RELNOTES.TXT @@ -74,6 +74,9 @@ on the ADMtek Inc. AL981 Comet chipset. [MERGED] Support has been added for the Rise mP6 processor. [MERGED] +Driver support has been added for SysKonnect SK-984x PCI gigabit +ethernet adapters. + 1.2. SECURITY FIXES ------------------- A new jail(2) system call and admin command (jail(8)) have been added for @@ -269,6 +272,12 @@ NICs including the following: Hawking Technologies PN102TX D-Link DFE530TX +SysKonnect SK-984x PCI gigabit ethernet cards including the following: + SK-9841 1000baseLX single mode fiber, single port + SK-9842 1000baseSX multimode fiber, single port + SK-9843 1000baseLX single mode fiber, dual port + SK-9844 1000baseSX multimode fiber, dual port + Texas Instruments ThunderLAN PCI NICs, including the following: Compaq Netelligent 10, 10/100, 10/100 Proliant, 10/100 Dual-Port Compaq Netelligent 10/100 TX Embedded UTP, 10 T PCI UTP/Coax, 10/100 TX UTP diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile index c23fc19..518e9ff 100644 --- a/share/man/man4/man4.i386/Makefile +++ b/share/man/man4/man4.i386/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.108 1999/05/21 04:37:40 wpaul Exp $ +# $Id: Makefile,v 1.109 1999/05/22 07:54:38 bde Exp $ MAN4= adv.4 adw.4 aha.4 ahb.4 ahc.4 aic.4 al.4 alpm.4 apm.4 ar.4 asc.4 \ atkbd.4 atkbdc.4 ax.4 bktr.4 bt.4 cs.4 cx.4 cy.4 de.4 \ @@ -6,7 +6,7 @@ MAN4= adv.4 adw.4 aha.4 ahb.4 ahc.4 aic.4 al.4 alpm.4 apm.4 ar.4 asc.4 \ io.4 joy.4 keyboard.4 labpc.4 le.4 lnc.4 matcd.4 mcd.4 \ mem.4 meteor.4 mouse.4 mse.4 mtio.4 mx.4 ncr.4 npx.4 \ ohci.4 pcf.4 pcm.4 pcvt.4 perfmon.4 pn.4 pnp.4 ppc.4 psm.4 \ - rdp.4 rl.4 sb.4 scd.4 screen.4 si.4 sio.4 \ + rdp.4 rl.4 sb.4 scd.4 screen.4 si.4 sio.4 sk.4 \ spkr.4 splash.4 sr.4 syscons.4 sysmouse.4 ti.4 tl.4 tw.4 tx.4 uhci.4 \ ukbd.4 umass.4 ums.4 usb.4 vga.4 vr.4 vx.4 \ wb.4 wd.4 wfd.4 wi.4 wl.4 wt.4 xl.4 ze.4 zp.4 @@ -74,6 +74,7 @@ MLINKS+= scd.4 ../scd.4 MLINKS+= screen.4 ../screen.4 MLINKS+= si.4 ../si.4 MLINKS+= sio.4 ../sio.4 +MLINKS+= sk.4 ../sk.4 MLINKS+= spkr.4 ../spkr.4 spkr.4 speaker.4 spkr.4 ../speaker.4 MLINKS+= splash.4 ../splash.4 splash.4 screensaver.4 splash.4 ../screensaver.4 MLINKS+= sr.4 ../sr.4 diff --git a/share/man/man4/man4.i386/sk.4 b/share/man/man4/man4.i386/sk.4 new file mode 100644 index 0000000..c5535c3 --- /dev/null +++ b/share/man/man4/man4.i386/sk.4 @@ -0,0 +1,159 @@ +.\" Copyright (c) 1997, 1998, 1999 +.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD +.\" 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$ +.\" +.Dd July 3, 1999 +.Dt SK 4 i386 +.Os FreeBSD +.Sh NAME +.Nm sk +.Nd +SysKonnect SK-984x PCI gigabit ethernet adapter driver +.Sh SYNOPSIS +.Cd "device sk0" +.Sh DESCRIPTION +The +.Nm +driver provides support for the SysKonnect SK-984x series PCI +gigabit ethernet adapters, including the following: +.Bl -bullet -offset indent +.It +SK-9841 SK-NET GE-LX single port, single mode fiber adapter +.It +SK-9842 SK-NET GE-SX single port, multimode fiber adapter +.It +SK-9843 SK-NET GE-LX dual port, single mode fiber adapter +.It +SK-9844 SK-NET GE-SX duak port, multimode fiber adapter +.El +.Pp +The SysKonnect adapters consist of two main components: the XaQti Corp. +XMAC II gigabit MAC and the SysKonnect GEnesis controller ASIC. The +XMAC provides the gigabit MAC and PHY suspport while the GEnesis +provides an interface to the PCI bus, DMA support, packet buffering +and arbitration. The GEnesis can control up to two XMACs simultaneously, +allowing dual-port NIC configurations. +.Pp +The +.Nm +driver configures dual port SysKonnect adapters such that each XMAC +is treated as a separate logical network interface. Both ports can +operate indepenently of each other and can be connected to separate +networks. The SysKonnect driver software currently only uses the +second port on dual port adapters for failover purposes: if the link +on the primary port fails, the SysKonnect driver will automatically +switch traffic onto the second port. +.Pp +The XaQti XMAC II supports full and half duplex operation with +autonegotiation. The XMAC also supports unlimited frame sizes. +Support for jumbo frames is provided via the interface MTU setting. +Selecting an MTU larger than 1500 bytes with the +.Xr ifconfig 8 +utility configures the adapter to receive and transmit jumbo frames. +Using jumbo frames can greatly improve performance for certain tasks, +such as file transfers and data streaming. +.Pp +The +.Nm +driver supports the following media types: +.Pp +.Bl -tag -width xxxxxxxxxxxxxxxxxxxx +.It autoselect +Enable autoselection of the media type and options. +The user can manually override +the autoselected mode by adding media options to the +.Pa /etc/rc.conf +file. +.It 1000baseSX +Set 1000Mbps (gigabit ethernet) operation. Both +.Ar full-duplex +and +.Ar half-duplex +modes are supported. +.El +.Pp +The +.Nm +driver supports the following media options: +.Pp +.Bl -tag -width xxxxxxxxxxxxxxxxxxxx +.It full-duplex +Force full duplex operation +.It half-duplex +Force half duplex operation. +.El +.Pp +For more information on configuring this device, see +.Xr ifconfig 8 . +.Sh DIAGNOSTICS +.Bl -diag +.It "sk%d: couldn't map memory" +A fatal initialization error has occurred. +.It "sk%d: couldn't map ports" +A fatal initialization error has occurred. +.It "sk%d: couldn't map interrupt" +A fatal initialization error has occurred. +.It "sk%d: no memory for softc struct!" +The driver failed to allocate memory for per-device instance information +during initialization. +.It "sk%d: failed to enable memory mapping!" +The driver failed to initialize PCI shared memory mapping. This might +happen if the card is not in a bus-master slot. +.It "sk%d: no memory for jumbo buffers!" +The driver failed to allocate memory for jumbo frames during +initialization. +.It "sk%d: watchdog timeout" +The device has stopped responding to the network, or there is a problem with +the network connection (cable). +.El +.Sh SEE ALSO +.Xr arp 4 , +.Xr netintro 4 , +.Xr ifconfig 8 , +.Xr vlan 4 +.Rs +.%T XaQti XMAC II datasheet +.%O http://www.xaqti.com +.Re +.Rs +.%T SysKonnect GEnesis programming manual +.%O http://www.syskonnect.com +.Re +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 3.0 . +.Sh AUTHOR +The +.Nm +driver was written by +.An Bill Paul Aq wpaul@ctr.columbia.edu . diff --git a/share/man/man4/sk.4 b/share/man/man4/sk.4 new file mode 100644 index 0000000..c5535c3 --- /dev/null +++ b/share/man/man4/sk.4 @@ -0,0 +1,159 @@ +.\" Copyright (c) 1997, 1998, 1999 +.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD +.\" 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$ +.\" +.Dd July 3, 1999 +.Dt SK 4 i386 +.Os FreeBSD +.Sh NAME +.Nm sk +.Nd +SysKonnect SK-984x PCI gigabit ethernet adapter driver +.Sh SYNOPSIS +.Cd "device sk0" +.Sh DESCRIPTION +The +.Nm +driver provides support for the SysKonnect SK-984x series PCI +gigabit ethernet adapters, including the following: +.Bl -bullet -offset indent +.It +SK-9841 SK-NET GE-LX single port, single mode fiber adapter +.It +SK-9842 SK-NET GE-SX single port, multimode fiber adapter +.It +SK-9843 SK-NET GE-LX dual port, single mode fiber adapter +.It +SK-9844 SK-NET GE-SX duak port, multimode fiber adapter +.El +.Pp +The SysKonnect adapters consist of two main components: the XaQti Corp. +XMAC II gigabit MAC and the SysKonnect GEnesis controller ASIC. The +XMAC provides the gigabit MAC and PHY suspport while the GEnesis +provides an interface to the PCI bus, DMA support, packet buffering +and arbitration. The GEnesis can control up to two XMACs simultaneously, +allowing dual-port NIC configurations. +.Pp +The +.Nm +driver configures dual port SysKonnect adapters such that each XMAC +is treated as a separate logical network interface. Both ports can +operate indepenently of each other and can be connected to separate +networks. The SysKonnect driver software currently only uses the +second port on dual port adapters for failover purposes: if the link +on the primary port fails, the SysKonnect driver will automatically +switch traffic onto the second port. +.Pp +The XaQti XMAC II supports full and half duplex operation with +autonegotiation. The XMAC also supports unlimited frame sizes. +Support for jumbo frames is provided via the interface MTU setting. +Selecting an MTU larger than 1500 bytes with the +.Xr ifconfig 8 +utility configures the adapter to receive and transmit jumbo frames. +Using jumbo frames can greatly improve performance for certain tasks, +such as file transfers and data streaming. +.Pp +The +.Nm +driver supports the following media types: +.Pp +.Bl -tag -width xxxxxxxxxxxxxxxxxxxx +.It autoselect +Enable autoselection of the media type and options. +The user can manually override +the autoselected mode by adding media options to the +.Pa /etc/rc.conf +file. +.It 1000baseSX +Set 1000Mbps (gigabit ethernet) operation. Both +.Ar full-duplex +and +.Ar half-duplex +modes are supported. +.El +.Pp +The +.Nm +driver supports the following media options: +.Pp +.Bl -tag -width xxxxxxxxxxxxxxxxxxxx +.It full-duplex +Force full duplex operation +.It half-duplex +Force half duplex operation. +.El +.Pp +For more information on configuring this device, see +.Xr ifconfig 8 . +.Sh DIAGNOSTICS +.Bl -diag +.It "sk%d: couldn't map memory" +A fatal initialization error has occurred. +.It "sk%d: couldn't map ports" +A fatal initialization error has occurred. +.It "sk%d: couldn't map interrupt" +A fatal initialization error has occurred. +.It "sk%d: no memory for softc struct!" +The driver failed to allocate memory for per-device instance information +during initialization. +.It "sk%d: failed to enable memory mapping!" +The driver failed to initialize PCI shared memory mapping. This might +happen if the card is not in a bus-master slot. +.It "sk%d: no memory for jumbo buffers!" +The driver failed to allocate memory for jumbo frames during +initialization. +.It "sk%d: watchdog timeout" +The device has stopped responding to the network, or there is a problem with +the network connection (cable). +.El +.Sh SEE ALSO +.Xr arp 4 , +.Xr netintro 4 , +.Xr ifconfig 8 , +.Xr vlan 4 +.Rs +.%T XaQti XMAC II datasheet +.%O http://www.xaqti.com +.Re +.Rs +.%T SysKonnect GEnesis programming manual +.%O http://www.syskonnect.com +.Re +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 3.0 . +.Sh AUTHOR +The +.Nm +driver was written by +.An Bill Paul Aq wpaul@ctr.columbia.edu . diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 5faffed..0d69fdc 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.615 1999/07/03 21:31:00 jdp Exp $ +# $Id: LINT,v 1.616 1999/07/06 19:22:40 des Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -1552,6 +1552,13 @@ options EISA_SLOTS=12 # the MPX 5030/5038, which is either a RealTek in disguise or a RealTek # workalike. # +# The 'sk' device provides support for the SysKonnect SK-984x series +# PCI gigabit ethernet NICs. This includes the SK-9841 and SK-9842 +# single port cards (single mode and multimode fiber) and the +# SK-9843 and SK-9844 dual port cards (also single mode and multimode). +# The driver will autodetect the number of ports on the card and +# attach each one as a separate network interface. +# # The 'ti' device provides support for PCI gigabit ethernet NICs based # on the Alteon Networks Tigon 1 and Tigon 2 chipsets. This includes the # Alteon AceNIC, the 3Com 3c985, the Netgear GA620 and various others. @@ -1695,6 +1702,7 @@ device fxp0 device mx0 device pn0 device rl0 +device sk0 device ti0 device tl0 device tx0 diff --git a/sys/conf/files b/sys/conf/files index 241d71b..0f0cc28 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -605,6 +605,7 @@ pci/if_mx.c optional mx pci/if_pn.c optional pn pci/if_fpa.c optional fpa pci pci/if_rl.c optional rl +pci/if_sk.c optional sk pci/if_sr_p.c optional sr pci pci/if_ti.c optional ti pci/if_tl.c optional tl diff --git a/sys/dev/sk/if_sk.c b/sys/dev/sk/if_sk.c new file mode 100644 index 0000000..fab98b2 --- /dev/null +++ b/sys/dev/sk/if_sk.c @@ -0,0 +1,1916 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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: if_sk.c,v 1.48 1999/07/06 21:37:42 wpaul Exp $ + */ + +/* + * SysKonnect SK-NET gigabit ethernet driver for FreeBSD. Supports + * the SK-984x series adapters, both single port and dual port. + * References: + * The XaQti XMAC II datasheet, http://www.xaqti.com + * The SysKonnect GEnesis manual, http://www.syskonnect.com + * + * Written by Bill Paul <wpaul@ee.columbia.edu> + * Department of Electrical Engineering + * Columbia University, New York City + */ + +/* + * The SysKonnect gigabit ethernet adapters consist of two main + * components: the SysKonnect GEnesis controller chip and the XaQti Corp. + * XMAC II gigabit ethernet MAC. The XMAC provides all of the MAC + * components and a PHY while the GEnesis controller provides a PCI + * interface with DMA support. Each card may have between 512K and + * 2MB of SRAM on board depending on the configuration. + * + * The SysKonnect GEnesis controller can have either one or two XMAC + * chips connected to it, allowing single or dual port NIC configurations. + * SysKonnect has the distinction of being the only vendor on the market + * with a dual port gigabit ethernet NIC. The GEnesis provides dual FIFOs, + * dual DMA queues, packet/MAC/transmit arbiters and direct access to the + * XMAC registers. This driver takes advantage of these features to allow + * both XMACs to operate as independent interfaces. + */ + +#include "bpf.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/queue.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#if NBPF > 0 +#include <net/bpf.h> +#endif + +#include <vm/vm.h> /* for vtophys */ +#include <vm/pmap.h> /* for vtophys */ +#include <machine/clock.h> /* for DELAY */ +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#include <machine/bus.h> + +#include <pci/pcireg.h> +#include <pci/pcivar.h> + +#define SK_USEIOSPACE + +#include <pci/if_skreg.h> +#include <pci/xmaciireg.h> + +#ifndef lint +static const char rcsid[] = + "$Id: if_sk.c,v 1.48 1999/07/06 21:37:42 wpaul Exp $"; +#endif + +static struct sk_type sk_devs[] = { + { SK_VENDORID, SK_DEVICEID_GE, "SysKonnect Gigabit Ethernet" }, + { 0, 0, NULL } +}; + +static unsigned long sk_count = 0; +static unsigned long skc_count = 0; +static const char *sk_probe __P((pcici_t, pcidi_t)); +static void sk_attach __P((pcici_t, int)); +static int sk_attach_xmac __P((struct sk_softc *, int)); +static void sk_intr __P((void *)); +static void sk_intr_xmac __P((struct sk_if_softc *)); +static void sk_rxeof __P((struct sk_if_softc *)); +static void sk_txeof __P((struct sk_if_softc *)); +static int sk_encap __P((struct sk_if_softc *, struct mbuf *, + u_int32_t *, u_int32_t *)); +static void sk_start __P((struct ifnet *)); +static int sk_ioctl __P((struct ifnet *, u_long, caddr_t)); +static void sk_init __P((void *)); +static void sk_init_xmac __P((struct sk_if_softc *)); +static void sk_stop __P((struct sk_if_softc *)); +static void sk_watchdog __P((struct ifnet *)); +static void sk_shutdown __P((int, void *)); +static int sk_ifmedia_upd __P((struct ifnet *)); +static void sk_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); +static void sk_reset __P((struct sk_softc *)); +static int sk_newbuf __P((struct sk_if_softc *, + struct sk_chain *, struct mbuf *)); +static int sk_alloc_jumbo_mem __P((struct sk_if_softc *)); +static void *sk_jalloc __P((struct sk_if_softc *)); +static void sk_jfree __P((caddr_t, u_int)); +static void sk_jref __P((caddr_t, u_int)); +static int sk_init_rx_ring __P((struct sk_if_softc *)); +static void sk_init_tx_ring __P((struct sk_if_softc *)); +#ifdef notdef +static u_int32_t sk_win_read_4 __P((struct sk_softc *, int)); +#endif +static u_int16_t sk_win_read_2 __P((struct sk_softc *, int)); +static u_int8_t sk_win_read_1 __P((struct sk_softc *, int)); +static void sk_win_write_4 __P((struct sk_softc *, int, u_int32_t)); +static void sk_win_write_2 __P((struct sk_softc *, int, u_int32_t)); +static void sk_win_write_1 __P((struct sk_softc *, int, u_int32_t)); +static u_int8_t sk_vpd_readbyte __P((struct sk_softc *, int)); +static void sk_vpd_read_res __P((struct sk_softc *, + struct vpd_res *, int)); +static void sk_vpd_read __P((struct sk_softc *)); +static u_int16_t sk_phy_readreg __P((struct sk_if_softc *, int)); +static void sk_phy_writereg __P((struct sk_if_softc *, int, u_int32_t)); +static u_int32_t sk_calchash __P((caddr_t)); +static void sk_setfilt __P((struct sk_if_softc *, caddr_t, int)); +static void sk_setmulti __P((struct sk_if_softc *)); + +#ifdef __i386__ +#define SK_BUS_SPACE_MEM I386_BUS_SPACE_MEM +#define SK_BUS_SPACE_IO I386_BUS_SPACE_IO +#endif + +#ifdef __alpha__ +#define SK_BUS_SPACE_MEM ALPHA_BUS_SPACE_MEM +#define SK_BUS_SPACE_IO ALPHA_BUS_SPACE_IO +#endif + +#define SK_SETBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | x) + +#define SK_CLRBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~x) + +#define SK_WIN_SETBIT_4(sc, reg, x) \ + sk_win_write_4(sc, reg, sk_win_read_4(sc, reg) | x) + +#define SK_WIN_CLRBIT_4(sc, reg, x) \ + sk_win_write_4(sc, reg, sk_win_read_4(sc, reg) & ~x) + +#define SK_WIN_SETBIT_2(sc, reg, x) \ + sk_win_write_2(sc, reg, sk_win_read_2(sc, reg) | x) + +#define SK_WIN_CLRBIT_2(sc, reg, x) \ + sk_win_write_2(sc, reg, sk_win_read_2(sc, reg) & ~x) + +#ifdef notdef +static u_int32_t sk_win_read_4(sc, reg) + struct sk_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + return(CSR_READ_4(sc, SK_WIN_BASE + SK_REG(reg))); +} +#endif + +static u_int16_t sk_win_read_2(sc, reg) + struct sk_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + return(CSR_READ_2(sc, SK_WIN_BASE + SK_REG(reg))); +} + +static u_int8_t sk_win_read_1(sc, reg) + struct sk_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + return(CSR_READ_1(sc, SK_WIN_BASE + SK_REG(reg))); +} + +static void sk_win_write_4(sc, reg, val) + struct sk_softc *sc; + int reg; + u_int32_t val; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + CSR_WRITE_4(sc, SK_WIN_BASE + SK_REG(reg), val); + return; +} + +static void sk_win_write_2(sc, reg, val) + struct sk_softc *sc; + int reg; + u_int32_t val; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + CSR_WRITE_2(sc, SK_WIN_BASE + SK_REG(reg), (u_int32_t)val); + return; +} + +static void sk_win_write_1(sc, reg, val) + struct sk_softc *sc; + int reg; + u_int32_t val; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + CSR_WRITE_1(sc, SK_WIN_BASE + SK_REG(reg), val); + return; +} + +/* + * The VPD EEPROM contains Vital Product Data, as suggested in + * the PCI 2.1 specification. The VPD data is separared into areas + * denoted by resource IDs. The SysKonnect VPD contains an ID string + * resource (the name of the adapter), a read-only area resource + * containing various key/data fields and a read/write area which + * can be used to store asset management information or log messages. + * We read the ID string and read-only into buffers attached to + * the controller softc structure for later use. At the moment, + * we only use the ID string during sk_attach(). + */ +static u_int8_t sk_vpd_readbyte(sc, addr) + struct sk_softc *sc; + int addr; +{ + int i; + + sk_win_write_2(sc, SK_PCI_REG(SK_PCI_VPD_ADDR), addr); + for (i = 0; i < SK_TIMEOUT; i++) { + DELAY(1); + if (sk_win_read_2(sc, + SK_PCI_REG(SK_PCI_VPD_ADDR)) & SK_VPD_FLAG) + break; + } + + if (i == SK_TIMEOUT) + return(0); + + return(sk_win_read_1(sc, SK_PCI_REG(SK_PCI_VPD_DATA))); +} + +static void sk_vpd_read_res(sc, res, addr) + struct sk_softc *sc; + struct vpd_res *res; + int addr; +{ + int i; + u_int8_t *ptr; + + ptr = (u_int8_t *)res; + for (i = 0; i < sizeof(struct vpd_res); i++) + ptr[i] = sk_vpd_readbyte(sc, i + addr); + + return; +} + +static void sk_vpd_read(sc) + struct sk_softc *sc; +{ + int pos = 0, i; + struct vpd_res res; + + if (sc->sk_vpd_prodname != NULL) + free(sc->sk_vpd_prodname, M_DEVBUF); + if (sc->sk_vpd_readonly != NULL) + free(sc->sk_vpd_readonly, M_DEVBUF); + sc->sk_vpd_prodname = NULL; + sc->sk_vpd_readonly = NULL; + + sk_vpd_read_res(sc, &res, pos); + + if (res.vr_id != VPD_RES_ID) { + printf("skc%d: bad VPD resource id: expected %x got %x\n", + sc->sk_unit, VPD_RES_ID, res.vr_id); + return; + } + + pos += sizeof(res); + sc->sk_vpd_prodname = malloc(res.vr_len + 1, M_DEVBUF, M_NOWAIT); + for (i = 0; i < res.vr_len; i++) + sc->sk_vpd_prodname[i] = sk_vpd_readbyte(sc, i + pos); + sc->sk_vpd_prodname[i] = '\0'; + pos += i; + + sk_vpd_read_res(sc, &res, pos); + + if (res.vr_id != VPD_RES_READ) { + printf("skc%d: bad VPD resource id: expected %x got %x\n", + sc->sk_unit, VPD_RES_READ, res.vr_id); + return; + } + + pos += sizeof(res); + sc->sk_vpd_readonly = malloc(res.vr_len, M_DEVBUF, M_NOWAIT); + for (i = 0; i < res.vr_len + 1; i++) + sc->sk_vpd_readonly[i] = sk_vpd_readbyte(sc, i + pos); + + return; +} + +static u_int16_t sk_phy_readreg(sc_if, reg) + struct sk_if_softc *sc_if; + int reg; +{ + int i; + + SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg); + for (i = 0; i < SK_TIMEOUT; i++) { + if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) + break; + } + + if (i == SK_TIMEOUT) { + printf("sk%d: phy failed to come ready\n", sc_if->sk_unit); + return(0); + } + + return(SK_XM_READ_2(sc_if, XM_PHY_DATA)); +} + +static void sk_phy_writereg(sc_if, reg, val) + struct sk_if_softc *sc_if; + int reg; + u_int32_t val; +{ + int i; + + SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg); + for (i = 0; i < SK_TIMEOUT; i++) { + if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) + break; + } + + if (i == SK_TIMEOUT) { + printf("sk%d: phy failed to come ready\n", sc_if->sk_unit); + return; + } + + SK_XM_WRITE_2(sc_if, XM_PHY_DATA, val); + for (i = 0; i < SK_TIMEOUT; i++) { + if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) + break; + } + + if (i == SK_TIMEOUT) + printf("sk%d: phy write timed out\n", sc_if->sk_unit); + + return; +} + +#define SK_POLY 0xEDB88320 +#define SK_BITS 6 + +static u_int32_t sk_calchash(addr) + caddr_t addr; +{ + u_int32_t idx, bit, data, crc; + + /* Compute CRC for the address value. */ + crc = 0xFFFFFFFF; /* initial value */ + + for (idx = 0; idx < 6; idx++) { + for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? SK_POLY : 0); + } + + return (~crc & ((1 << SK_BITS) - 1)); +} + +static void sk_setfilt(sc_if, addr, slot) + struct sk_if_softc *sc_if; + caddr_t addr; + int slot; +{ + int base; + + base = XM_RXFILT_ENTRY(slot); + + SK_XM_WRITE_2(sc_if, base, *(u_int16_t *)(&addr[0])); + SK_XM_WRITE_2(sc_if, base + 2, *(u_int16_t *)(&addr[2])); + SK_XM_WRITE_2(sc_if, base + 4, *(u_int16_t *)(&addr[4])); + + return; +} + +static void sk_setmulti(sc_if) + struct sk_if_softc *sc_if; +{ + struct ifnet *ifp; + u_int32_t hashes[2] = { 0, 0 }; + int h, i; + struct ifmultiaddr *ifma; + u_int8_t dummy[] = { 0, 0, 0, 0, 0 ,0 }; + + ifp = &sc_if->arpcom.ac_if; + + /* First, zot all the existing filters. */ + for (i = 1; i < XM_RXFILT_MAX; i++) + sk_setfilt(sc_if, (caddr_t)&dummy, i); + SK_XM_WRITE_4(sc_if, XM_MAR0, 0); + SK_XM_WRITE_4(sc_if, XM_MAR2, 0); + + /* Now program new ones. */ + if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { + hashes[0] = 0xFFFFFFFF; + hashes[1] = 0xFFFFFFFF; + } else { + i = 1; + /* First find the tail of the list. */ + for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; + ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_link.le_next == NULL) + break; + } + /* Now traverse the list backwards. */ + for (; ifma != NULL && ifma != (void *)&ifp->if_multiaddrs; + ifma = (struct ifmultiaddr *)ifma->ifma_link.le_prev) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + /* + * Program the first XM_RXFILT_MAX multicast groups + * into the perfect filter. For all others, + * use the hash table. + */ + if (i < XM_RXFILT_MAX) { + sk_setfilt(sc_if, + LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i); + i++; + continue; + } + + h = sk_calchash( + LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + } + } + + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_USE_HASH| + XM_MODE_RX_USE_PERFECT); + SK_XM_WRITE_4(sc_if, XM_MAR0, hashes[0]); + SK_XM_WRITE_4(sc_if, XM_MAR2, hashes[1]); + + return; +} + +static int sk_init_rx_ring(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_chain_data *cd; + struct sk_ring_data *rd; + int i; + + cd = &sc_if->sk_cdata; + rd = sc_if->sk_rdata; + + bzero((char *)rd->sk_rx_ring, + sizeof(struct sk_rx_desc) * SK_RX_RING_CNT); + + for (i = 0; i < SK_RX_RING_CNT; i++) { + cd->sk_rx_chain[i].sk_desc = &rd->sk_rx_ring[i]; + if (sk_newbuf(sc_if, &cd->sk_rx_chain[i], NULL) == ENOBUFS) + return(ENOBUFS); + if (i == (SK_RX_RING_CNT - 1)) { + cd->sk_rx_chain[i].sk_next = + &cd->sk_rx_chain[0]; + rd->sk_rx_ring[i].sk_next = + vtophys(&rd->sk_rx_ring[0]); + } else { + cd->sk_rx_chain[i].sk_next = + &cd->sk_rx_chain[i + 1]; + rd->sk_rx_ring[i].sk_next = + vtophys(&rd->sk_rx_ring[i + 1]); + } + } + + sc_if->sk_cdata.sk_rx_prod = 0; + sc_if->sk_cdata.sk_rx_cons = 0; + + return(0); +} + +static void sk_init_tx_ring(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_chain_data *cd; + struct sk_ring_data *rd; + int i; + + cd = &sc_if->sk_cdata; + rd = sc_if->sk_rdata; + + bzero((char *)sc_if->sk_rdata->sk_tx_ring, + sizeof(struct sk_tx_desc) * SK_TX_RING_CNT); + + for (i = 0; i < SK_TX_RING_CNT; i++) { + cd->sk_tx_chain[i].sk_desc = &rd->sk_tx_ring[i]; + if (i == (SK_TX_RING_CNT - 1)) { + cd->sk_tx_chain[i].sk_next = + &cd->sk_tx_chain[0]; + rd->sk_tx_ring[i].sk_next = + vtophys(&rd->sk_tx_ring[0]); + } else { + cd->sk_tx_chain[i].sk_next = + &cd->sk_tx_chain[i + 1]; + rd->sk_tx_ring[i].sk_next = + vtophys(&rd->sk_tx_ring[i + 1]); + } + } + + sc_if->sk_cdata.sk_tx_prod = 0; + sc_if->sk_cdata.sk_tx_cons = 0; + sc_if->sk_cdata.sk_tx_cnt = 0; + + return; +} + +static int sk_newbuf(sc_if, c, m) + struct sk_if_softc *sc_if; + struct sk_chain *c; + struct mbuf *m; +{ + struct mbuf *m_new = NULL; + struct sk_rx_desc *r; + + if (m == NULL) { + caddr_t *buf = NULL; + + MGETHDR(m_new, M_DONTWAIT, MT_DATA); + if (m_new == NULL) { + printf("sk%d: no memory for rx list -- " + "packet dropped!\n", sc_if->sk_unit); + return(ENOBUFS); + } + + /* Allocate the jumbo buffer */ + buf = sk_jalloc(sc_if); + if (buf == NULL) { + m_freem(m_new); +#ifdef SK_VERBOSE + printf("sk%d: jumbo allocation failed " + "-- packet dropped!\n", sc_if->sk_unit); +#endif + return(ENOBUFS); + } + + /* Attach the buffer to the mbuf */ + m_new->m_data = m_new->m_ext.ext_buf = (void *)buf; + m_new->m_flags |= M_EXT; + m_new->m_ext.ext_size = m_new->m_pkthdr.len = + m_new->m_len = SK_MCLBYTES; + m_new->m_ext.ext_free = sk_jfree; + m_new->m_ext.ext_ref = sk_jref; + } else { + /* + * We're re-using a previously allocated mbuf; + * be sure to re-init pointers and lengths to + * default values. + */ + m_new = m; + m_new->m_len = m_new->m_pkthdr.len = SK_MCLBYTES; + m_new->m_data = m_new->m_ext.ext_buf; + } + + /* + * Adjust alignment so packet payload begins on a + * longword boundary. Mandatory for Alpha, useful on + * x86 too. + */ + m_adj(m_new, ETHER_ALIGN); + + r = c->sk_desc; + c->sk_mbuf = m_new; + r->sk_data_lo = vtophys(mtod(m_new, caddr_t)); + r->sk_ctl = m_new->m_len | SK_RXSTAT; + + return(0); +} + +/* + * Allocate jumbo buffer storage. The SysKonnect adapters support + * "jumbograms" (9K frames), although SysKonnect doesn't currently + * use them in their drivers. In order for us to use them, we need + * large 9K receive buffers, however standard mbuf clusters are only + * 2048 bytes in size. Consequently, we need to allocate and manage + * our own jumbo buffer pool. Fortunately, this does not require an + * excessive amount of additional code. + */ +static int sk_alloc_jumbo_mem(sc_if) + struct sk_if_softc *sc_if; +{ + caddr_t ptr; + register int i; + struct sk_jpool_entry *entry; + + /* Grab a big chunk o' storage. */ + sc_if->sk_cdata.sk_jumbo_buf = contigmalloc(SK_JMEM, M_DEVBUF, + M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0); + + if (sc_if->sk_cdata.sk_jumbo_buf == NULL) { + printf("sk%d: no memory for jumbo buffers!\n", sc_if->sk_unit); + return(ENOBUFS); + } + + SLIST_INIT(&sc_if->sk_jfree_listhead); + SLIST_INIT(&sc_if->sk_jinuse_listhead); + + /* + * Now divide it up into 9K pieces and save the addresses + * in an array. Note that we play an evil trick here by using + * the first few bytes in the buffer to hold the the address + * of the softc structure for this interface. This is because + * sk_jfree() needs it, but it is called by the mbuf management + * code which will not pass it to us explicitly. + */ + ptr = sc_if->sk_cdata.sk_jumbo_buf; + for (i = 0; i < SK_JSLOTS; i++) { + u_int64_t **aptr; + aptr = (u_int64_t **)ptr; + aptr[0] = (u_int64_t *)sc_if; + ptr += sizeof(u_int64_t); + sc_if->sk_cdata.sk_jslots[i].sk_buf = ptr; + sc_if->sk_cdata.sk_jslots[i].sk_inuse = 0; + ptr += SK_MCLBYTES; + entry = malloc(sizeof(struct sk_jpool_entry), + M_DEVBUF, M_NOWAIT); + if (entry == NULL) { + free(sc_if->sk_cdata.sk_jumbo_buf, M_DEVBUF); + sc_if->sk_cdata.sk_jumbo_buf = NULL; + printf("sk%d: no memory for jumbo " + "buffer queue!\n", sc_if->sk_unit); + return(ENOBUFS); + } + entry->slot = i; + SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, + entry, jpool_entries); + } + + return(0); +} + +/* + * Allocate a jumbo buffer. + */ +static void *sk_jalloc(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_jpool_entry *entry; + + entry = SLIST_FIRST(&sc_if->sk_jfree_listhead); + + if (entry == NULL) { +#ifdef SK_VERBOSE + printf("sk%d: no free jumbo buffers\n", sc_if->sk_unit); +#endif + return(NULL); + } + + SLIST_REMOVE_HEAD(&sc_if->sk_jfree_listhead, jpool_entries); + SLIST_INSERT_HEAD(&sc_if->sk_jinuse_listhead, entry, jpool_entries); + sc_if->sk_cdata.sk_jslots[entry->slot].sk_inuse = 1; + return(sc_if->sk_cdata.sk_jslots[entry->slot].sk_buf); +} + +/* + * Adjust usage count on a jumbo buffer. In general this doesn't + * get used much because our jumbo buffers don't get passed around + * a lot, but it's implemented for correctness. + */ +static void sk_jref(buf, size) + caddr_t buf; + u_int size; +{ + struct sk_if_softc *sc_if; + u_int64_t **aptr; + register int i; + + /* Extract the softc struct pointer. */ + aptr = (u_int64_t **)(buf - sizeof(u_int64_t)); + sc_if = (struct sk_if_softc *)(aptr[0]); + + if (sc_if == NULL) + panic("sk_jref: can't find softc pointer!"); + + if (size != SK_MCLBYTES) + panic("sk_jref: adjusting refcount of buf of wrong size!"); + + /* calculate the slot this buffer belongs to */ + + i = ((vm_offset_t)aptr + - (vm_offset_t)sc_if->sk_cdata.sk_jumbo_buf) / SK_JLEN; + + if ((i < 0) || (i >= SK_JSLOTS)) + panic("sk_jref: asked to reference buffer " + "that we don't manage!"); + else if (sc_if->sk_cdata.sk_jslots[i].sk_inuse == 0) + panic("sk_jref: buffer already free!"); + else + sc_if->sk_cdata.sk_jslots[i].sk_inuse++; + + return; +} + +/* + * Release a jumbo buffer. + */ +static void sk_jfree(buf, size) + caddr_t buf; + u_int size; +{ + struct sk_if_softc *sc_if; + u_int64_t **aptr; + int i; + struct sk_jpool_entry *entry; + + /* Extract the softc struct pointer. */ + aptr = (u_int64_t **)(buf - sizeof(u_int64_t)); + sc_if = (struct sk_if_softc *)(aptr[0]); + + if (sc_if == NULL) + panic("sk_jfree: can't find softc pointer!"); + + if (size != SK_MCLBYTES) + panic("sk_jfree: freeing buffer of wrong size!"); + + /* calculate the slot this buffer belongs to */ + + i = ((vm_offset_t)aptr + - (vm_offset_t)sc_if->sk_cdata.sk_jumbo_buf) / SK_JLEN; + + if ((i < 0) || (i >= SK_JSLOTS)) + panic("sk_jfree: asked to free buffer that we don't manage!"); + else if (sc_if->sk_cdata.sk_jslots[i].sk_inuse == 0) + panic("sk_jfree: buffer already free!"); + else { + sc_if->sk_cdata.sk_jslots[i].sk_inuse--; + if(sc_if->sk_cdata.sk_jslots[i].sk_inuse == 0) { + entry = SLIST_FIRST(&sc_if->sk_jinuse_listhead); + if (entry == NULL) + panic("sk_jfree: buffer not in use!"); + entry->slot = i; + SLIST_REMOVE_HEAD(&sc_if->sk_jinuse_listhead, + jpool_entries); + SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, + entry, jpool_entries); + } + } + + return; +} + +/* + * Set media options. + */ +static int sk_ifmedia_upd(ifp) + struct ifnet *ifp; +{ + struct sk_if_softc *sc_if; + struct ifmedia *ifm; + + sc_if = ifp->if_softc; + ifm = &sc_if->ifmedia; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return(EINVAL); + + switch(IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + sk_phy_writereg(sc_if, XM_PHY_BMCR, + XM_BMCR_RENEGOTIATE|XM_BMCR_AUTONEGENBL); + break; + case IFM_1000_LX: + case IFM_1000_SX: + case IFM_1000_CX: + case IFM_1000_TX: + if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) + sk_phy_writereg(sc_if, XM_PHY_BMCR, XM_BMCR_DUPLEX); + else + sk_phy_writereg(sc_if, XM_PHY_BMCR, 0); + break; + default: + printf("sk%d: invalid media selected\n", sc_if->sk_unit); + return(EINVAL); + break; + } + + return(0); +} + +/* + * Report current media status. + */ +static void sk_ifmedia_sts(ifp, ifmr) + struct ifnet *ifp; + struct ifmediareq *ifmr; +{ + struct sk_softc *sc; + struct sk_if_softc *sc_if; + u_int16_t bmsr, extsts; + + sc_if = ifp->if_softc; + sc = sc_if->sk_softc; + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + bmsr = sk_phy_readreg(sc_if, XM_PHY_BMSR); + extsts = sk_phy_readreg(sc_if, XM_PHY_EXTSTS); + + if (!(bmsr & XM_BMSR_LINKSTAT)) + return; + + ifmr->ifm_status |= IFM_ACTIVE; + ifmr->ifm_active |= sc->sk_pmd;; + if (extsts & XM_EXTSTS_FULLDUPLEX) + ifmr->ifm_active |= IFM_FDX; + else + ifmr->ifm_active |= IFM_HDX; + + return; +} + +static int sk_ioctl(ifp, command, data) + struct ifnet *ifp; + u_long command; + caddr_t data; +{ + struct sk_if_softc *sc_if = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + int s, error = 0; + + s = splimp(); + + switch(command) { + case SIOCSIFADDR: + case SIOCGIFADDR: + error = ether_ioctl(ifp, command, data); + break; + case SIOCSIFMTU: + if (ifr->ifr_mtu > SK_JUMBO_MTU) + error = EINVAL; + else { + ifp->if_mtu = ifr->ifr_mtu; + sk_init(sc_if); + } + break; + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING && + ifp->if_flags & IFF_PROMISC && + !(sc_if->sk_if_flags & IFF_PROMISC)) { + SK_XM_SETBIT_4(sc_if, XM_MODE, + XM_MODE_RX_PROMISC); + sk_setmulti(sc_if); + } else if (ifp->if_flags & IFF_RUNNING && + !(ifp->if_flags & IFF_PROMISC) && + sc_if->sk_if_flags & IFF_PROMISC) { + SK_XM_CLRBIT_4(sc_if, XM_MODE, + XM_MODE_RX_PROMISC); + sk_setmulti(sc_if); + } else + sk_init(sc_if); + } else { + if (ifp->if_flags & IFF_RUNNING) + sk_stop(sc_if); + } + sc_if->sk_if_flags = ifp->if_flags; + error = 0; + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + sk_setmulti(sc_if); + error = 0; + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc_if->ifmedia, command); + break; + default: + error = EINVAL; + break; + } + + (void)splx(s); + + return(error); +} + +/* + * Probe for a SysKonnect GEnesis chip. Check the PCI vendor and device + * IDs against our list and return a device name if we find a match. + */ +static const char *sk_probe(config_id, device_id) + pcici_t config_id; + pcidi_t device_id; +{ + struct sk_type *t; + + t = sk_devs; + + while(t->sk_name != NULL) { + if ((device_id & 0xFFFF) == t->sk_vid && + ((device_id >> 16) & 0xFFFF) == t->sk_did) { + return(t->sk_name); + } + t++; + } + + return(NULL); +} + +/* + * Force the GEnesis into reset, then bring it out of reset. + */ +static void sk_reset(sc) + struct sk_softc *sc; +{ + CSR_WRITE_4(sc, SK_CSR, SK_CSR_SW_RESET); + CSR_WRITE_4(sc, SK_CSR, SK_CSR_MASTER_RESET); + DELAY(1000); + CSR_WRITE_4(sc, SK_CSR, SK_CSR_SW_UNRESET); + CSR_WRITE_4(sc, SK_CSR, SK_CSR_MASTER_UNRESET); + + /* Configure packet arbiter */ + sk_win_write_2(sc, SK_PKTARB_CTL, SK_PKTARBCTL_UNRESET); + sk_win_write_2(sc, SK_RXPA1_TINIT, SK_PKTARB_TIMEOUT); + sk_win_write_2(sc, SK_TXPA1_TINIT, SK_PKTARB_TIMEOUT); + sk_win_write_2(sc, SK_RXPA2_TINIT, SK_PKTARB_TIMEOUT); + sk_win_write_2(sc, SK_TXPA2_TINIT, SK_PKTARB_TIMEOUT); + + /* Enable RAM interface */ + sk_win_write_4(sc, SK_RAMCTL, SK_RAMCTL_UNRESET); + + /* + * Configure interrupt moderation. The moderation timer + * defers interrupts specified in the interrupt moderation + * timer mask based on the timeout specified in the interrupt + * moderation timer init register. Each bit in the timer + * register represents 18.825ns, so to specify a timeout in + * microseconds, we have to multiply by 54. + */ + sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(200)); + sk_win_write_4(sc, SK_IMMR, SK_ISR_TX1_S_EOF|SK_ISR_TX2_S_EOF| + SK_ISR_RX1_EOF|SK_ISR_RX2_EOF); + sk_win_write_1(sc, SK_IMTIMERCTL, SK_IMCTL_START); + + return; +} + +/* + * Each XMAC chip is attached as a separate logical IP interface. + * Single port cards will have only one logical interface of course. + */ +static int sk_attach_xmac(sc, port) + struct sk_softc *sc; + int port; +{ + struct sk_if_softc *sc_if; + struct ifnet *ifp; + int i; + + if (sc == NULL) + return(EINVAL); + + if (port != SK_PORT_A && port != SK_PORT_B) + return(EINVAL); + + sc_if = malloc(sizeof(struct sk_if_softc), M_DEVBUF, M_NOWAIT); + if (sc_if == NULL) { + printf("sk%d: no memory for interface softc!\n", sc->sk_unit); + return(ENOMEM); + } + bzero((char *)sc_if, sizeof(struct sk_if_softc)); + + sc_if->sk_unit = sk_count; + sc_if->sk_port = port; + sk_count++; + sc_if->sk_softc = sc; + sc->sk_if[port] = sc_if; + if (port == SK_PORT_A) + sc_if->sk_tx_bmu = SK_BMU_TXS_CSR0; + if (port == SK_PORT_B) + sc_if->sk_tx_bmu = SK_BMU_TXS_CSR1; + + /* + * Get station address for this interface. Note that + * dual port cards actually come with three station + * addresses: one for each port, plus an extra. The + * extra one is used by the SysKonnect driver software + * as a 'virtual' station address for when both ports + * are operating in failover mode. Currently we don't + * use this extra address. + */ + for (i = 0; i < ETHER_ADDR_LEN; i++) + sc_if->arpcom.ac_enaddr[i] = + sk_win_read_1(sc, SK_MAC0_0 + (port * 8) + i); + + printf("sk%d: <XaQti Corp. XMAC II> at skc%d port %d\n", + sc_if->sk_unit, sc->sk_unit, port); + + printf("sk%d: Ethernet address: %6D\n", + sc_if->sk_unit, sc_if->arpcom.ac_enaddr, ":"); + + /* + * Set up RAM buffer addresses. The NIC will have a certain + * amount of SRAM on it, somewhere between 512K and 2MB. We + * need to divide this up a) between the transmitter and + * receiver and b) between the two XMACs, if this is a + * dual port NIC. Our algotithm is to divide up the memory + * evenly so that everyone gets a fair share. + */ + if (sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC) { + u_int32_t chunk, val; + + chunk = sc->sk_ramsize / 2; + val = sc->sk_rboff / sizeof(u_int64_t); + sc_if->sk_rx_ramstart = val; + val += (chunk / sizeof(u_int64_t)); + sc_if->sk_rx_ramend = val - 1; + sc_if->sk_tx_ramstart = val; + val += (chunk / sizeof(u_int64_t)); + sc_if->sk_tx_ramend = val - 1; + } else { + u_int32_t chunk, val; + + chunk = sc->sk_ramsize / 4; + val = (sc->sk_rboff + (chunk * 2 * sc_if->sk_port)) / + sizeof(u_int64_t); + sc_if->sk_rx_ramstart = val; + val += (chunk / sizeof(u_int64_t)); + sc_if->sk_rx_ramend = val - 1; + sc_if->sk_tx_ramstart = val; + val += (chunk / sizeof(u_int64_t)); + sc_if->sk_tx_ramend = val - 1; + } + + /* Allocate the descriptor queues. */ + sc_if->sk_rdata = contigmalloc(sizeof(struct sk_ring_data), M_DEVBUF, + M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0); + + if (sc_if->sk_rdata == NULL) { + printf("sk%d: no memory for list buffers!\n", sc_if->sk_unit); + free(sc_if, M_DEVBUF); + sc->sk_if[port] = NULL; + return(ENOMEM); + } + + bzero(sc_if->sk_rdata, sizeof(struct sk_ring_data)); + + /* Try to allocate memory for jumbo buffers. */ + if (sk_alloc_jumbo_mem(sc_if)) { + printf("sk%d: jumbo buffer allocation failed\n", + sc_if->sk_unit); + free(sc_if->sk_rdata, M_DEVBUF); + free(sc_if, M_DEVBUF); + sc->sk_if[port] = NULL; + return(ENOMEM); + } + + ifp = &sc_if->arpcom.ac_if; + ifp->if_softc = sc_if; + ifp->if_unit = sc_if->sk_unit; + ifp->if_name = "sk"; + ifp->if_mtu = ETHERMTU; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = sk_ioctl; + ifp->if_output = ether_output; + ifp->if_start = sk_start; + ifp->if_watchdog = sk_watchdog; + ifp->if_init = sk_init; + ifp->if_baudrate = 1000000000; + ifp->if_snd.ifq_maxlen = SK_TX_RING_CNT - 1; + + /* + * Do ifmedia setup. + */ + ifmedia_init(&sc_if->ifmedia, 0, sk_ifmedia_upd, sk_ifmedia_sts); + ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd, 0, NULL); + ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd|IFM_FDX, 0, NULL); + ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd|IFM_HDX, 0, NULL); + ifmedia_add(&sc_if->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); + ifmedia_set(&sc_if->ifmedia, IFM_ETHER|IFM_AUTO); + + /* + * Call MI attach routines. + */ + if_attach(ifp); + ether_ifattach(ifp); + +#if NBPF > 0 + bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + + return(0); +} + +/* + * Attach the interface. Allocate softc structures, do ifmedia + * setup and ethernet/BPF attach. + */ +static void +sk_attach(config_id, unit) + pcici_t config_id; + int unit; +{ + int s; +#ifndef SK_USEIOSPACE + vm_offset_t pbase, vbase; +#endif + u_int32_t command; + struct sk_softc *sc; + + s = splimp(); + + sc = malloc(sizeof(struct sk_softc), M_DEVBUF, M_NOWAIT); + if (sc == NULL) { + printf("skc%d: no memory for softc struct!\n", unit); + goto fail; + } + bzero(sc, sizeof(struct sk_softc)); + + /* + * Handle power management nonsense. + */ + command = pci_conf_read(config_id, SK_PCI_CAPID) & 0x000000FF; + if (command == 0x01) { + + command = pci_conf_read(config_id, SK_PCI_PWRMGMTCTRL); + if (command & SK_PSTATE_MASK) { + u_int32_t iobase, membase, irq; + + /* Save important PCI config data. */ + iobase = pci_conf_read(config_id, SK_PCI_LOIO); + membase = pci_conf_read(config_id, SK_PCI_LOMEM); + irq = pci_conf_read(config_id, SK_PCI_INTLINE); + + /* Reset the power state. */ + printf("skc%d: chip is in D%d power mode " + "-- setting to D0\n", unit, command & SK_PSTATE_MASK); + command &= 0xFFFFFFFC; + pci_conf_write(config_id, SK_PCI_PWRMGMTCTRL, command); + + /* Restore PCI config data. */ + pci_conf_write(config_id, SK_PCI_LOIO, iobase); + pci_conf_write(config_id, SK_PCI_LOMEM, membase); + pci_conf_write(config_id, SK_PCI_INTLINE, irq); + } + } + + /* + * Map control/status registers. + */ + command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); + command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); + pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); + command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); + +#ifdef SK_USEIOSPACE + if (!(command & PCIM_CMD_PORTEN)) { + printf("skc%d: failed to enable I/O ports!\n", unit); + free(sc, M_DEVBUF); + goto fail; + } + + if (!pci_map_port(config_id, SK_PCI_LOIO, + (u_short *)&(sc->sk_bhandle))) { + printf ("skc%d: couldn't map ports\n", unit); + goto fail; + } + + sc->sk_btag = SK_BUS_SPACE_IO; +#else + if (!(command & PCIM_CMD_MEMEN)) { + printf("skc%d: failed to enable memory mapping!\n", unit); + goto fail; + } + + if (!pci_map_mem(config_id, SK_PCI_LOMEM, &vbase, &pbase)) { + printf ("skc%d: couldn't map memory\n", unit); + goto fail; + } + sc->sk_btag = SK_BUS_SPACE_MEM; + sc->sk_bhandle = vbase; +#endif + + /* Allocate interrupt */ + if (!pci_map_int(config_id, sk_intr, sc, &net_imask)) { + printf("skc%d: couldn't map interrupt\n", unit); + goto fail; + } + + /* Save cache line size. */ + sc->sk_cachesize = pci_conf_read(config_id, SK_PCI_CACHELEN) & 0xFF; + + /* Reset the adapter. */ + sk_reset(sc); + + sc->sk_unit = unit; + + /* Read and save vital product data from EEPROM. */ + sk_vpd_read(sc); + + /* Read and save RAM size and RAMbuffer offset */ + switch(sk_win_read_1(sc, SK_EPROM0)) { + case SK_RAMSIZE_512K_64: + sc->sk_ramsize = 0x80000; + sc->sk_rboff = SK_RBOFF_80000; + break; + case SK_RAMSIZE_1024K_64: + sc->sk_ramsize = 0x100000; + sc->sk_rboff = SK_RBOFF_80000; + break; + case SK_RAMSIZE_1024K_128: + sc->sk_ramsize = 0x100000; + sc->sk_rboff = SK_RBOFF_0; + break; + case SK_RAMSIZE_2048K_128: + sc->sk_ramsize = 0x200000; + sc->sk_rboff = SK_RBOFF_0; + break; + default: + printf("skc%d: unknown ram size: %d\n", + sc->sk_unit, sk_win_read_1(sc, SK_EPROM0)); + goto fail; + break; + } + + /* Read and save physical media type */ + switch(sk_win_read_1(sc, SK_PMDTYPE)) { + case SK_PMD_1000BASESX: + sc->sk_pmd = IFM_1000_SX; + break; + case SK_PMD_1000BASELX: + sc->sk_pmd = IFM_1000_LX; + break; + case SK_PMD_1000BASECX: + sc->sk_pmd = IFM_1000_CX; + break; + case SK_PMD_1000BASETX: + sc->sk_pmd = IFM_1000_TX; + break; + default: + printf("skc%d: unknown media type: 0x%x\n", + sc->sk_unit, sk_win_read_1(sc, SK_PMDTYPE)); + goto fail; + } + + /* Announce the product name. */ + printf("skc%d: %s\n", sc->sk_unit, sc->sk_vpd_prodname); + + sk_attach_xmac(sc, SK_PORT_A); + if (!(sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC)) + sk_attach_xmac(sc, SK_PORT_B); + + /* Turn on the 'driver is loaded' LED. */ + CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_ON); + + at_shutdown(sk_shutdown, sc, SHUTDOWN_POST_SYNC); + +fail: + splx(s); + return; +} + +static int sk_encap(sc_if, m_head, txidx, curidx) + struct sk_if_softc *sc_if; + struct mbuf *m_head; + u_int32_t *txidx; + u_int32_t *curidx; +{ + struct sk_tx_desc *f = NULL; + struct mbuf *m; + u_int32_t frag, cur, cnt = 0; + + m = m_head; + cur = frag = *txidx; + + /* + * Start packing the mbufs in this chain into + * the fragment pointers. Stop when we run out + * of fragments or hit the end of the mbuf chain. + */ + for (m = m_head; m != NULL; m = m->m_next) { + if (m->m_len != 0) { + if ((SK_TX_RING_CNT - + (sc_if->sk_cdata.sk_tx_cnt + cnt)) < 2) + return(ENOBUFS); + f = &sc_if->sk_rdata->sk_tx_ring[frag]; + f->sk_data_lo = vtophys(mtod(m, vm_offset_t)); + f->sk_ctl = m->m_len | SK_OPCODE_DEFAULT; + if (cnt == 0) + f->sk_ctl |= SK_TXCTL_FIRSTFRAG; + else + f->sk_ctl |= SK_TXCTL_OWN; + cur = frag; + SK_INC(frag, SK_TX_RING_CNT); + cnt++; + } + } + + if (m != NULL) + return(ENOBUFS); + + sc_if->sk_rdata->sk_tx_ring[cur].sk_ctl |= SK_TXCTL_LASTFRAG; + sc_if->sk_cdata.sk_tx_chain[cur].sk_mbuf = m_head; + sc_if->sk_rdata->sk_tx_ring[*txidx].sk_ctl |= SK_TXCTL_OWN; + sc_if->sk_cdata.sk_tx_cnt += cnt; + + *txidx = frag; + *curidx = cur; + + return(0); +} + +static void sk_start(ifp) + struct ifnet *ifp; +{ + struct sk_softc *sc; + struct sk_if_softc *sc_if; + struct mbuf *m_head = NULL; + u_int32_t idx = 0, cur = 0; + + sc_if = ifp->if_softc; + sc = sc_if->sk_softc; + + idx = sc_if->sk_cdata.sk_tx_prod; + + while(sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf == NULL) { + IF_DEQUEUE(&ifp->if_snd, m_head); + if (m_head == NULL) + break; + + /* + * Pack the data into the transmit ring. If we + * don't have room, set the OACTIVE flag and wait + * for the NIC to drain the ring. + */ + if (sk_encap(sc_if, m_head, &idx, &cur)) { + IF_PREPEND(&ifp->if_snd, m_head); + ifp->if_flags |= IFF_OACTIVE; + break; + } + + /* + * If there's a BPF listener, bounce a copy of this frame + * to him. + */ +#if NBPF > 0 + if (ifp->if_bpf) + bpf_mtap(ifp, m_head); +#endif + } + + /* Transmit */ + sc_if->sk_cdata.sk_tx_prod = idx; + sc_if->sk_rdata->sk_tx_ring[cur].sk_ctl |= SK_TXCTL_EOF_INTR; + CSR_WRITE_4(sc, sc_if->sk_tx_bmu, SK_TXBMU_TX_START); + + /* Set a timeout in case the chip goes out to lunch. */ + ifp->if_timer = 5; + + return; +} + + +static void sk_watchdog(ifp) + struct ifnet *ifp; +{ + struct sk_if_softc *sc_if; + + sc_if = ifp->if_softc; + + printf("sk%d: watchdog timeout\n", sc_if->sk_unit); + sk_init(sc_if); + + return; +} + +static void sk_shutdown(howto, arg) + int howto; + void *arg; +{ + struct sk_softc *sc; + + sc = arg; + + /* Turn off the 'driver is loaded' LED. */ + CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_OFF); + + /* + * Reset the GEnesis controller. Doing this should also + * assert the resets on the attached XMAC(s). + */ + sk_reset(sc); + + return; +} + +static void sk_rxeof(sc_if) + struct sk_if_softc *sc_if; +{ + struct ether_header *eh; + struct mbuf *m; + struct ifnet *ifp; + struct sk_chain *cur_rx; + int total_len = 0; + int i; + u_int32_t rxstat; + + ifp = &sc_if->arpcom.ac_if; + i = sc_if->sk_cdata.sk_rx_prod; + cur_rx = &sc_if->sk_cdata.sk_rx_chain[i]; + + while(!(sc_if->sk_rdata->sk_rx_ring[i].sk_ctl & SK_RXCTL_OWN)) { + + cur_rx = &sc_if->sk_cdata.sk_rx_chain[i]; + rxstat = sc_if->sk_rdata->sk_rx_ring[i].sk_xmac_rxstat; + m = cur_rx->sk_mbuf; + cur_rx->sk_mbuf = NULL; + total_len = SK_RXBYTES(sc_if->sk_rdata->sk_rx_ring[i].sk_ctl); + SK_INC(i, SK_RX_RING_CNT); + + if (rxstat & XM_RXSTAT_ERRFRAME) { + ifp->if_ierrors++; + sk_newbuf(sc_if, cur_rx, m); + continue; + } + + /* + * Try to allocate a new jumbo buffer. If that + * fails, copy the packet to mbufs and put the + * jumbo buffer back in the ring so it can be + * re-used. If allocating mbufs fails, then we + * have to drop the packet. + */ + if (sk_newbuf(sc_if, cur_rx, NULL) == ENOBUFS) { + struct mbuf *m0; + m0 = m_devget(mtod(m, char *) - ETHER_ALIGN, + total_len + ETHER_ALIGN, 0, ifp, NULL); + sk_newbuf(sc_if, cur_rx, m); + if (m0 == NULL) { + printf("sk%d: no receive buffers " + "available -- packet dropped!\n", + sc_if->sk_unit); + ifp->if_ierrors++; + continue; + } + m_adj(m0, ETHER_ALIGN); + m = m0; + } else { + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = total_len; + } + + ifp->if_ipackets++; + eh = mtod(m, struct ether_header *); + +#if NBPF > 0 + if (ifp->if_bpf) { + bpf_mtap(ifp, m); + if (ifp->if_flags & IFF_PROMISC && + (bcmp(eh->ether_dhost, sc_if->arpcom.ac_enaddr, + ETHER_ADDR_LEN) && !(eh->ether_dhost[0] & 1))) { + m_freem(m); + continue; + } + } +#endif + /* Remove header from mbuf and pass it on. */ + m_adj(m, sizeof(struct ether_header)); + ether_input(ifp, eh, m); + } + + sc_if->sk_cdata.sk_rx_prod = i; + + return; +} + +static void sk_txeof(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_tx_desc *cur_tx = NULL; + struct ifnet *ifp; + u_int32_t idx; + + ifp = &sc_if->arpcom.ac_if; + + /* + * Go through our tx ring and free mbufs for those + * frames that have been sent. + */ + idx = sc_if->sk_cdata.sk_tx_cons; + while(idx != sc_if->sk_cdata.sk_tx_prod) { + cur_tx = &sc_if->sk_rdata->sk_tx_ring[idx]; + if (cur_tx->sk_ctl & SK_TXCTL_OWN) + break; + if (cur_tx->sk_ctl & SK_TXCTL_LASTFRAG) + ifp->if_opackets++; + if (sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf != NULL) { + m_freem(sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf); + sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf = NULL; + } + sc_if->sk_cdata.sk_tx_cnt--; + SK_INC(idx, SK_TX_RING_CNT); + ifp->if_timer = 0; + } + + sc_if->sk_cdata.sk_tx_cons = idx; + + if (cur_tx != NULL) + ifp->if_flags &= ~IFF_OACTIVE; + + return; +} + +static void sk_intr_xmac(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_softc *sc; + u_int16_t status; + u_int16_t bmsr; + + sc = sc_if->sk_softc; + status = SK_XM_READ_2(sc_if, XM_ISR); + + if (status & XM_ISR_LINKEVENT) { + SK_XM_SETBIT_2(sc_if, XM_IMR, XM_IMR_LINKEVENT); + if (sc_if->sk_link == 1) { + printf("sk%d: gigabit link down\n", sc_if->sk_unit); + sc_if->sk_link = 0; + } + } + + if (status & XM_ISR_AUTONEG_DONE) { + bmsr = sk_phy_readreg(sc_if, XM_PHY_BMSR); + if (bmsr & XM_BMSR_LINKSTAT) { + sc_if->sk_link = 1; + SK_XM_CLRBIT_2(sc_if, XM_IMR, XM_IMR_LINKEVENT); + printf("sk%d: gigabit link up\n", sc_if->sk_unit); + } + } + + if (status & XM_IMR_TX_UNDERRUN) + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_FLUSH_TXFIFO); + + if (status & XM_IMR_RX_OVERRUN) + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_FLUSH_RXFIFO); + + return; +} + +static void sk_intr(xsc) + void *xsc; +{ + struct sk_softc *sc = xsc; + struct sk_if_softc *sc_if0 = NULL, *sc_if1 = NULL; + struct ifnet *ifp0 = NULL, *ifp1 = NULL; + u_int32_t status; + + sc_if0 = sc->sk_if[SK_PORT_A]; + sc_if1 = sc->sk_if[SK_PORT_B]; + + if (sc_if0 != NULL) + ifp0 = &sc_if0->arpcom.ac_if; + if (sc_if1 != NULL) + ifp1 = &sc_if0->arpcom.ac_if; + + for (;;) { + status = CSR_READ_4(sc, SK_ISSR); + if (!(status & sc->sk_intrmask)) + break; + + /* Handle receive interrupts first. */ + if (status & SK_ISR_RX1_EOF) { + sk_rxeof(sc_if0); + CSR_WRITE_4(sc, SK_BMU_RX_CSR0, + SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START); + } + if (status & SK_ISR_RX2_EOF) { + sk_rxeof(sc_if1); + CSR_WRITE_4(sc, SK_BMU_RX_CSR1, + SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START); + } + + /* Then transmit interrupts. */ + if (status & SK_ISR_TX1_S_EOF) { + sk_txeof(sc_if0); + CSR_WRITE_4(sc, SK_BMU_TXS_CSR0, + SK_TXBMU_CLR_IRQ_EOF); + } + if (status & SK_ISR_TX2_S_EOF) { + sk_txeof(sc_if1); + CSR_WRITE_4(sc, SK_BMU_TXS_CSR1, + SK_TXBMU_CLR_IRQ_EOF); + } + + /* Then MAC interrupts. */ + if (status & SK_ISR_MAC1) + sk_intr_xmac(sc_if0); + + if (status & SK_ISR_MAC2) + sk_intr_xmac(sc_if1); + } + + CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); + + return; +} + +static void sk_init_xmac(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_softc *sc; + struct ifnet *ifp; + + sc = sc_if->sk_softc; + ifp = &sc_if->arpcom.ac_if; + + /* Unreset the XMAC. */ + SK_IF_WRITE_2(sc_if, 0, SK_TXF1_MACCTL, SK_TXMACCTL_XMAC_UNRESET); + DELAY(1000); + + /* Save the XMAC II revision */ + sc_if->sk_xmac_rev = XM_XMAC_REV(SK_XM_READ_4(sc_if, XM_DEVID)); + + /* Set station address */ + SK_XM_WRITE_2(sc_if, XM_PAR0, + *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[0])); + SK_XM_WRITE_2(sc_if, XM_PAR1, + *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[2])); + SK_XM_WRITE_2(sc_if, XM_PAR2, + *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[4])); + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_USE_STATION); + + if (ifp->if_flags & IFF_PROMISC) { + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_PROMISC); + } else { + SK_XM_CLRBIT_4(sc_if, XM_MODE, XM_MODE_RX_PROMISC); + } + + if (ifp->if_flags & IFF_BROADCAST) { + SK_XM_CLRBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD); + } else { + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD); + } + + /* We don't need the FCS appended to the packet. */ + SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_STRIPFCS); + + /* We want short frames padded to 60 bytes. */ + SK_XM_SETBIT_2(sc_if, XM_TXCMD, XM_TXCMD_AUTOPAD); + + /* + * Enable the reception of all error frames. This is is + * a necessary evil due to the design of the XMAC. The + * XMAC's receive FIFO is only 8K in size, however jumbo + * frames can be up to 9000 bytes in length. When bad + * frame filtering is enabled, the XMAC's RX FIFO operates + * in 'store and forward' mode. For this to work, the + * entire frame has to fit into the FIFO, but that means + * that jumbo frames larger than 8192 bytes will be + * truncated. Disabling all bad frame filtering causes + * the RX FIFO to operate in streaming mode, in which + * case the XMAC will start transfering frames out of the + * RX FIFO as soon as the FIFO threshold is reached. + */ + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_BADFRAMES| + XM_MODE_RX_GIANTS|XM_MODE_RX_RUNTS|XM_MODE_RX_CRCERRS| + XM_MODE_RX_INRANGELEN); + + if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN)) + SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK); + else + SK_XM_CLRBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK); + + /* + * Bump up the transmit threshold. This helps hold off transmit + * underruns when we're blasting traffic from both ports at once. + */ + SK_XM_WRITE_2(sc_if, XM_TX_REQTHRESH, SK_XM_TX_FIFOTHRESH); + + /* Set multicast filter */ + sk_setmulti(sc_if); + + /* Clear and enable interrupts */ + SK_XM_READ_2(sc_if, XM_ISR); + SK_XM_WRITE_2(sc_if, XM_IMR, XM_INTRS); + + sc_if->sk_link = 0; + + /* Configure MAC arbiter */ + switch(sc_if->sk_xmac_rev) { + case XM_XMAC_REV_B2: + sk_win_write_1(sc, SK_RCINIT_RX1, SK_RCINIT_XMAC_B2); + sk_win_write_1(sc, SK_RCINIT_TX1, SK_RCINIT_XMAC_B2); + sk_win_write_1(sc, SK_RCINIT_RX2, SK_RCINIT_XMAC_B2); + sk_win_write_1(sc, SK_RCINIT_TX2, SK_RCINIT_XMAC_B2); + sk_win_write_1(sc, SK_MINIT_RX1, SK_MINIT_XMAC_B2); + sk_win_write_1(sc, SK_MINIT_TX1, SK_MINIT_XMAC_B2); + sk_win_write_1(sc, SK_MINIT_RX2, SK_MINIT_XMAC_B2); + sk_win_write_1(sc, SK_MINIT_TX2, SK_MINIT_XMAC_B2); + sk_win_write_1(sc, SK_RECOVERY_CTL, SK_RECOVERY_XMAC_B2); + break; + case XM_XMAC_REV_C1: + sk_win_write_1(sc, SK_RCINIT_RX1, SK_RCINIT_XMAC_C1); + sk_win_write_1(sc, SK_RCINIT_TX1, SK_RCINIT_XMAC_C1); + sk_win_write_1(sc, SK_RCINIT_RX2, SK_RCINIT_XMAC_C1); + sk_win_write_1(sc, SK_RCINIT_TX2, SK_RCINIT_XMAC_C1); + sk_win_write_1(sc, SK_MINIT_RX1, SK_MINIT_XMAC_C1); + sk_win_write_1(sc, SK_MINIT_TX1, SK_MINIT_XMAC_C1); + sk_win_write_1(sc, SK_MINIT_RX2, SK_MINIT_XMAC_C1); + sk_win_write_1(sc, SK_MINIT_TX2, SK_MINIT_XMAC_C1); + sk_win_write_1(sc, SK_RECOVERY_CTL, SK_RECOVERY_XMAC_B2); + break; + default: + break; + } + sk_win_write_2(sc, SK_MACARB_CTL, + SK_MACARBCTL_UNRESET|SK_MACARBCTL_FASTOE_OFF); + + return; +} + +/* + * Note that to properly initialize any part of the GEnesis chip, + * you first have to take it out of reset mode. + */ +static void sk_init(xsc) + void *xsc; +{ + struct sk_if_softc *sc_if = xsc; + struct sk_softc *sc; + struct ifnet *ifp; + int s; + + s = splimp(); + + ifp = &sc_if->arpcom.ac_if; + sc = sc_if->sk_softc; + + /* Cancel pending I/O and free all RX/TX buffers. */ + sk_stop(sc_if); + + /* Configure LINK_SYNC LED */ + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_ON); + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_LINKSYNC_ON); + + /* Configure RX LED */ + SK_IF_WRITE_1(sc_if, 0, SK_RXLED1_CTL, SK_RXLEDCTL_COUNTER_START); + + /* Configure TX LED */ + SK_IF_WRITE_1(sc_if, 0, SK_TXLED1_CTL, SK_TXLEDCTL_COUNTER_START); + + /* Configure I2C registers */ + + /* Configure XMAC(s) */ + sk_init_xmac(sc_if); + + /* Configure MAC FIFOs */ + SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_UNRESET); + SK_IF_WRITE_4(sc_if, 0, SK_RXF1_END, SK_FIFO_END); + SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_ON); + + SK_IF_WRITE_4(sc_if, 0, SK_TXF1_CTL, SK_FIFO_UNRESET); + SK_IF_WRITE_4(sc_if, 0, SK_TXF1_END, SK_FIFO_END); + SK_IF_WRITE_4(sc_if, 0, SK_TXF1_CTL, SK_FIFO_ON); + + /* Configure transmit arbiter(s) */ + SK_IF_WRITE_1(sc_if, 0, SK_TXAR1_COUNTERCTL, + SK_TXARCTL_ON|SK_TXARCTL_FSYNC_ON); + + /* Configure RAMbuffers */ + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_UNRESET); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_START, sc_if->sk_rx_ramstart); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_WR_PTR, sc_if->sk_rx_ramstart); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_RD_PTR, sc_if->sk_rx_ramstart); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_END, sc_if->sk_rx_ramend); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_ON); + + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_UNRESET); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_STORENFWD_ON); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_START, sc_if->sk_tx_ramstart); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_WR_PTR, sc_if->sk_tx_ramstart); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_RD_PTR, sc_if->sk_tx_ramstart); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_END, sc_if->sk_tx_ramend); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_ON); + + /* Configure BMUs */ + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_ONLINE); + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_LO, + vtophys(&sc_if->sk_rdata->sk_rx_ring[0])); + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_HI, 0); + + SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_BMU_CSR, SK_TXBMU_ONLINE); + SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_LO, + vtophys(&sc_if->sk_rdata->sk_tx_ring[0])); + SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_HI, 0); + + /* Init descriptors */ + if (sk_init_rx_ring(sc_if) == ENOBUFS) { + printf("sk%d: initialization failed: no " + "memory for rx buffers\n", sc_if->sk_unit); + sk_stop(sc_if); + (void)splx(s); + return; + } + sk_init_tx_ring(sc_if); + + /* Configure interrupt handling */ + CSR_READ_4(sc, SK_ISSR); + if (sc_if->sk_port == SK_PORT_A) + sc->sk_intrmask |= SK_INTRS1; + else + sc->sk_intrmask |= SK_INTRS2; + CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); + + /* Start BMUs. */ + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_RX_START); + + /* Enable XMACs TX and RX state machines */ + SK_XM_SETBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + splx(s); + + return; +} + +static void sk_stop(sc_if) + struct sk_if_softc *sc_if; +{ + int i; + struct sk_softc *sc; + + sc = sc_if->sk_softc; + + /* Turn off various components of this interface. */ + SK_IF_WRITE_2(sc_if, 0, SK_TXF1_MACCTL, SK_TXMACCTL_XMAC_RESET); + SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_RESET); + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_OFFLINE); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_RESET|SK_RBCTL_OFF); + SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_BMU_CSR, SK_TXBMU_OFFLINE); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_RESET|SK_RBCTL_OFF); + SK_IF_WRITE_1(sc_if, 0, SK_TXAR1_COUNTERCTL, SK_TXARCTL_OFF); + SK_IF_WRITE_1(sc_if, 0, SK_RXLED1_CTL, SK_RXLEDCTL_COUNTER_STOP); + SK_IF_WRITE_1(sc_if, 0, SK_TXLED1_CTL, SK_RXLEDCTL_COUNTER_STOP); + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_OFF); + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_LINKSYNC_OFF); + + /* Disable interrupts */ + if (sc_if->sk_port == SK_PORT_A) + sc->sk_intrmask &= ~SK_INTRS1; + else + sc->sk_intrmask &= ~SK_INTRS2; + CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); + + /* Free RX and TX mbufs still in the queues. */ + for (i = 0; i < SK_RX_RING_CNT; i++) { + if (sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf != NULL) { + m_freem(sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf); + sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf = NULL; + } + } + + for (i = 0; i < SK_TX_RING_CNT; i++) { + if (sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf != NULL) { + m_freem(sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf); + sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf = NULL; + } + } + + return; +} + +static struct pci_device sk_device = { + "skc", + sk_probe, + sk_attach, + &skc_count, + NULL +}; +COMPAT_PCI_DRIVER(sk, sk_device); diff --git a/sys/dev/sk/if_skreg.h b/sys/dev/sk/if_skreg.h new file mode 100644 index 0000000..e5dca1c --- /dev/null +++ b/sys/dev/sk/if_skreg.h @@ -0,0 +1,1172 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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: if_skreg.h,v 1.32 1999/07/06 22:07:40 wpaul Exp $ + */ + +/* + * SysKonnect PCI vendor ID + */ +#define SK_VENDORID 0x1148 + +/* + * SK-NET gigabit ethernet device ID + */ +#define SK_DEVICEID_GE 0x4300 + +/* + * GEnesis registers. The GEnesis chip has a 256-byte I/O window + * but internally it has a 16K register space. This 16K space is + * divided into 128-byte blocks. The first 128 bytes of the I/O + * window represent the first block, which is permanently mapped + * at the start of the window. The other 127 blocks can be mapped + * to the second 128 bytes of the I/O window by setting the desired + * block value in the RAP register in block 0. Not all of the 127 + * blocks are actually used. Most registers are 32 bits wide, but + * there are a few 16-bit and 8-bit ones as well. + */ + + +/* Start of remappable register window. */ +#define SK_WIN_BASE 0x0080 + +/* Size of a window */ +#define SK_WIN_LEN 0x80 + +#define SK_WIN_MASK 0x3F80 +#define SK_REG_MASK 0x7F + +/* Compute the window of a given register (for the RAP register) */ +#define SK_WIN(reg) (((reg) & SK_WIN_MASK) / SK_WIN_LEN) + +/* Compute the relative offset of a register within the window */ +#define SK_REG(reg) ((reg) & SK_REG_MASK) + +#define SK_PORT_A 0 +#define SK_PORT_B 1 + +/* + * Compute offset of port-specific register. Since there are two + * ports, there are two of some GEnesis modules (e.g. two sets of + * DMA queues, two sets of FIFO control registers, etc...). Normally, + * the block for port 0 is at offset 0x0 and the block for port 1 is + * at offset 0x80 (i.e. the next page over). However for the transmit + * BMUs and RAMbuffers, there are two blocks for each port: one for + * the sync transmit queue and one for the async queue (which we don't + * use). However instead of ordering them like this: + * TX sync 1 / TX sync 2 / TX async 1 / TX async 2 + * SysKonnect has instead ordered them like this: + * TX sync 1 / TX async 1 / TX sync 2 / TX async 2 + * This means that when referencing the TX BMU and RAMbuffer registers, + * we have to double the block offset (0x80 * 2) in order to reach the + * second queue. This prevents us from using the same formula + * (sk_port * 0x80) to compute the offsets for all of the port-specific + * blocks: we need an extra offset for the BMU and RAMbuffer registers. + * The simplest thing is to provide an extra argument to these macros: + * the 'skip' parameter. The 'skip' value is the number of extra pages + * for skip when computing the port0/port1 offsets. For most registers, + * the skip value is 0; for the BMU and RAMbuffer registers, it's 1. + */ +#define SK_IF_READ_4(sc_if, skip, reg) \ + sk_win_read_4(sc_if->sk_softc, reg + \ + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN)) +#define SK_IF_READ_2(sc_if, skip, reg) \ + sk_win_read_2(sc_if->sk_softc, reg + \ + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN)) +#define SK_IF_READ_1(sc_if, skip, reg) \ + sk_win_read_1(sc_if->sk_softc, reg + \ + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN)) + +#define SK_IF_WRITE_4(sc_if, skip, reg, val) \ + sk_win_write_4(sc_if->sk_softc, \ + reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val) +#define SK_IF_WRITE_2(sc_if, skip, reg, val) \ + sk_win_write_2(sc_if->sk_softc, \ + reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val) +#define SK_IF_WRITE_1(sc_if, skip, reg, val) \ + sk_win_write_1(sc_if->sk_softc, \ + reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val) + +/* Block 0 registers, permanently mapped at iobase. */ +#define SK_RAP 0x0000 +#define SK_CSR 0x0004 +#define SK_LED 0x0006 +#define SK_ISR 0x0008 /* interrupt source */ +#define SK_IMR 0x000C /* interrupt mask */ +#define SK_IESR 0x0010 /* interrupt hardware error source */ +#define SK_IEMR 0x0014 /* interrupt hardware error mask */ +#define SK_ISSR 0x0018 /* special interrupt source */ +#define SK_XM_IMR0 0x0020 +#define SK_XM_ISR0 0x0028 +#define SK_XM_PHYADDR0 0x0030 +#define SK_XM_PHYDATA0 0x0034 +#define SK_XM_IMR1 0x0040 +#define SK_XM_ISR1 0x0048 +#define SK_XM_PHYADDR1 0x0050 +#define SK_XM_PHYDATA1 0x0054 +#define SK_BMU_RX_CSR0 0x0060 +#define SK_BMU_RX_CSR1 0x0064 +#define SK_BMU_TXS_CSR0 0x0068 +#define SK_BMU_TXA_CSR0 0x006C +#define SK_BMU_TXS_CSR1 0x0070 +#define SK_BMU_TXA_CSR1 0x0074 + +/* SK_CSR register */ +#define SK_CSR_SW_RESET 0x0001 +#define SK_CSR_SW_UNRESET 0x0002 +#define SK_CSR_MASTER_RESET 0x0004 +#define SK_CSR_MASTER_UNRESET 0x0008 +#define SK_CSR_MASTER_STOP 0x0010 +#define SK_CSR_MASTER_DONE 0x0020 +#define SK_CSR_SW_IRQ_CLEAR 0x0040 +#define SK_CSR_SW_IRQ_SET 0x0080 +#define SK_CSR_SLOTSIZE 0x0100 /* 1 == 64 bits, 0 == 32 */ +#define SK_CSR_BUSCLOCK 0x0200 /* 1 == 33/66 Mhz, = 33 */ + +/* SK_LED register */ +#define SK_LED_GREEN_OFF 0x01 +#define SK_LED_GREEN_ON 0x02 + +/* SK_ISR register */ +#define SK_ISR_TX2_AS_CHECK 0x00000001 +#define SK_ISR_TX2_AS_EOF 0x00000002 +#define SK_ISR_TX2_AS_EOB 0x00000004 +#define SK_ISR_TX2_S_CHECK 0x00000008 +#define SK_ISR_TX2_S_EOF 0x00000010 +#define SK_ISR_TX2_S_EOB 0x00000020 +#define SK_ISR_TX1_AS_CHECK 0x00000040 +#define SK_ISR_TX1_AS_EOF 0x00000080 +#define SK_ISR_TX1_AS_EOB 0x00000100 +#define SK_ISR_TX1_S_CHECK 0x00000200 +#define SK_ISR_TX1_S_EOF 0x00000400 +#define SK_ISR_TX1_S_EOB 0x00000800 +#define SK_ISR_RX2_CHECK 0x00001000 +#define SK_ISR_RX2_EOF 0x00002000 +#define SK_ISR_RX2_EOB 0x00004000 +#define SK_ISR_RX1_CHECK 0x00008000 +#define SK_ISR_RX1_EOF 0x00010000 +#define SK_ISR_RX1_EOB 0x00020000 +#define SK_ISR_LINK2_OFLOW 0x00040000 +#define SK_ISR_MAC2 0x00080000 +#define SK_ISR_LINK1_OFLOW 0x00100000 +#define SK_ISR_MAC1 0x00200000 +#define SK_ISR_TIMER 0x00400000 +#define SK_ISR_EXTERNAL_REG 0x00800000 +#define SK_ISR_SW 0x01000000 +#define SK_ISR_I2C_RDY 0x02000000 +#define SK_ISR_TX2_TIMEO 0x04000000 +#define SK_ISR_TX1_TIMEO 0x08000000 +#define SK_ISR_RX2_TIMEO 0x10000000 +#define SK_ISR_RX1_TIMEO 0x20000000 +#define SK_ISR_RSVD 0x40000000 +#define SK_ISR_HWERR 0x80000000 + +/* SK_IMR register */ +#define SK_IMR_TX2_AS_CHECK 0x00000001 +#define SK_IMR_TX2_AS_EOF 0x00000002 +#define SK_IMR_TX2_AS_EOB 0x00000004 +#define SK_IMR_TX2_S_CHECK 0x00000008 +#define SK_IMR_TX2_S_EOF 0x00000010 +#define SK_IMR_TX2_S_EOB 0x00000020 +#define SK_IMR_TX1_AS_CHECK 0x00000040 +#define SK_IMR_TX1_AS_EOF 0x00000080 +#define SK_IMR_TX1_AS_EOB 0x00000100 +#define SK_IMR_TX1_S_CHECK 0x00000200 +#define SK_IMR_TX1_S_EOF 0x00000400 +#define SK_IMR_TX1_S_EOB 0x00000800 +#define SK_IMR_RX2_CHECK 0x00001000 +#define SK_IMR_RX2_EOF 0x00002000 +#define SK_IMR_RX2_EOB 0x00004000 +#define SK_IMR_RX1_CHECK 0x00008000 +#define SK_IMR_RX1_EOF 0x00010000 +#define SK_IMR_RX1_EOB 0x00020000 +#define SK_IMR_LINK2_OFLOW 0x00040000 +#define SK_IMR_MAC2 0x00080000 +#define SK_IMR_LINK1_OFLOW 0x00100000 +#define SK_IMR_MAC1 0x00200000 +#define SK_IMR_TIMER 0x00400000 +#define SK_IMR_EXTERNAL_REG 0x00800000 +#define SK_IMR_SW 0x01000000 +#define SK_IMR_I2C_RDY 0x02000000 +#define SK_IMR_TX2_TIMEO 0x04000000 +#define SK_IMR_TX1_TIMEO 0x08000000 +#define SK_IMR_RX2_TIMEO 0x10000000 +#define SK_IMR_RX1_TIMEO 0x20000000 +#define SK_IMR_RSVD 0x40000000 +#define SK_IMR_HWERR 0x80000000 + +#define SK_INTRS1 \ + (SK_IMR_RX1_EOF|SK_IMR_TX1_S_EOF|SK_IMR_MAC1) + +#define SK_INTRS2 \ + (SK_IMR_RX2_EOF|SK_IMR_TX2_S_EOF|SK_IMR_MAC2) + +/* SK_IESR register */ +#define SK_IESR_PAR_RX2 0x00000001 +#define SK_IESR_PAR_RX1 0x00000002 +#define SK_IESR_PAR_MAC2 0x00000004 +#define SK_IESR_PAR_MAC1 0x00000008 +#define SK_IESR_PAR_WR_RAM 0x00000010 +#define SK_IESR_PAR_RD_RAM 0x00000020 +#define SK_IESR_NO_TSTAMP_MAC2 0x00000040 +#define SK_IESR_NO_TSTAMO_MAC1 0x00000080 +#define SK_IESR_NO_STS_MAC2 0x00000100 +#define SK_IESR_NO_STS_MAC1 0x00000200 +#define SK_IESR_IRQ_STS 0x00000400 +#define SK_IESR_MASTERERR 0x00000800 + +/* SK_IEMR register */ +#define SK_IEMR_PAR_RX2 0x00000001 +#define SK_IEMR_PAR_RX1 0x00000002 +#define SK_IEMR_PAR_MAC2 0x00000004 +#define SK_IEMR_PAR_MAC1 0x00000008 +#define SK_IEMR_PAR_WR_RAM 0x00000010 +#define SK_IEMR_PAR_RD_RAM 0x00000020 +#define SK_IEMR_NO_TSTAMP_MAC2 0x00000040 +#define SK_IEMR_NO_TSTAMO_MAC1 0x00000080 +#define SK_IEMR_NO_STS_MAC2 0x00000100 +#define SK_IEMR_NO_STS_MAC1 0x00000200 +#define SK_IEMR_IRQ_STS 0x00000400 +#define SK_IEMR_MASTERERR 0x00000800 + +/* Block 2 */ +#define SK_MAC0_0 0x0100 +#define SK_MAC0_1 0x0104 +#define SK_MAC1_0 0x0108 +#define SK_MAC1_1 0x010C +#define SK_MAC2_0 0x0110 +#define SK_MAC2_1 0x0114 +#define SK_CONNTYPE 0x0118 +#define SK_PMDTYPE 0x0119 +#define SK_CONFIG 0x011A +#define SK_CHIPVER 0x011B +#define SK_EPROM0 0x011C +#define SK_EPROM1 0x011D +#define SK_EPROM2 0x011E +#define SK_EPROM3 0x011F +#define SK_EP_ADDR 0x0120 +#define SK_EP_DATA 0x0124 +#define SK_EP_LOADCTL 0x0128 +#define SK_EP_LOADTST 0x0129 +#define SK_TIMERINIT 0x0130 +#define SK_TIMER 0x0134 +#define SK_TIMERCTL 0x0138 +#define SK_TIMERTST 0x0139 +#define SK_IMTIMERINIT 0x0140 +#define SK_IMTIMER 0x0144 +#define SK_IMTIMERCTL 0x0148 +#define SK_IMTIMERTST 0x0149 +#define SK_IMMR 0x014C +#define SK_IHWEMR 0x0150 +#define SK_TESTCTL1 0x0158 +#define SK_TESTCTL2 0x0159 +#define SK_GPIO 0x015C +#define SK_I2CHWCTL 0x0160 +#define SK_I2CHWDATA 0x0164 +#define SK_I2CHWIRQ 0x0168 +#define SK_I2CSW 0x016C +#define SK_BLNKINIT 0x0170 +#define SK_BLNKCOUNT 0x0174 +#define SK_BLNKCTL 0x0178 +#define SK_BLNKSTS 0x0179 +#define SK_BLNKTST 0x017A + +#define SK_IMCTL_STOP 0x02 +#define SK_IMCTL_START 0x04 + +#define SK_IMTIMER_TICKS 54 +#define SK_IM_USECS(x) ((x) * SK_IMTIMER_TICKS) + +/* + * The SK_EPROM0 register contains a byte that describes the + * amount of SRAM mounted on the NIC. The value also tells if + * the chips are 64K or 128K. This affects the RAMbuffer address + * offset that we need to use. + */ +#define SK_RAMSIZE_512K_64 0x1 +#define SK_RAMSIZE_1024K_128 0x2 +#define SK_RAMSIZE_1024K_64 0x3 +#define SK_RAMSIZE_2048K_128 0x4 + +#define SK_RBOFF_0 0x0 +#define SK_RBOFF_80000 0x80000 + +#define SK_CONFIG_SINGLEMAC 0x01 +#define SK_CONFIG_DIS_DSL_CLK 0x02 + +#define SK_PMD_1000BASELX 0x4C +#define SK_PMD_1000BASESX 0x53 +#define SK_PMD_1000BASECX 0x43 +#define SK_PMD_1000BASETX 0x54 + +/* Block 3 Ram interface and MAC arbiter registers */ +#define SK_RAMADDR 0x0180 +#define SK_RAMDATA0 0x0184 +#define SK_RAMDATA1 0x0188 +#define SK_TO0 0x0190 +#define SK_TO1 0x0191 +#define SK_TO2 0x0192 +#define SK_TO3 0x0193 +#define SK_TO4 0x0194 +#define SK_TO5 0x0195 +#define SK_TO6 0x0196 +#define SK_TO7 0x0197 +#define SK_TO8 0x0198 +#define SK_TO9 0x0199 +#define SK_TO10 0x019A +#define SK_TO11 0x019B +#define SK_RITIMEO_TMR 0x019C +#define SK_RAMCTL 0x01A0 +#define SK_RITIMER_TST 0x01A2 + +#define SK_RAMCTL_RESET 0x0001 +#define SK_RAMCTL_UNRESET 0x0002 +#define SK_RAMCTL_CLR_IRQ_WPAR 0x0100 +#define SK_RAMCTL_CLR_IRQ_RPAR 0x0200 + +/* Mac arbiter registers */ +#define SK_MINIT_RX1 0x01B0 +#define SK_MINIT_RX2 0x01B1 +#define SK_MINIT_TX1 0x01B2 +#define SK_MINIT_TX2 0x01B3 +#define SK_MTIMEO_RX1 0x01B4 +#define SK_MTIMEO_RX2 0x01B5 +#define SK_MTIMEO_TX1 0x01B6 +#define SK_MTIEMO_TX2 0x01B7 +#define SK_MACARB_CTL 0x01B8 +#define SK_MTIMER_TST 0x01BA +#define SK_RCINIT_RX1 0x01C0 +#define SK_RCINIT_RX2 0x01C1 +#define SK_RCINIT_TX1 0x01C2 +#define SK_RCINIT_TX2 0x01C3 +#define SK_RCTIMEO_RX1 0x01C4 +#define SK_RCTIMEO_RX2 0x01C5 +#define SK_RCTIMEO_TX1 0x01C6 +#define SK_RCTIMEO_TX2 0x01C7 +#define SK_RECOVERY_CTL 0x01C8 +#define SK_RCTIMER_TST 0x01CA + +/* Packet arbiter registers */ +#define SK_RXPA1_TINIT 0x01D0 +#define SK_RXPA2_TINIT 0x01D4 +#define SK_TXPA1_TINIT 0x01D8 +#define SK_TXPA2_TINIT 0x01DC +#define SK_RXPA1_TIMEO 0x01E0 +#define SK_RXPA2_TIMEO 0x01E4 +#define SK_TXPA1_TIMEO 0x01E8 +#define SK_TXPA2_TIMEO 0x01EC +#define SK_PKTARB_CTL 0x01F0 +#define SK_PKTATB_TST 0x01F2 + +#define SK_PKTARB_TIMEOUT 0x2000 + +#define SK_PKTARBCTL_RESET 0x0001 +#define SK_PKTARBCTL_UNRESET 0x0002 +#define SK_PKTARBCTL_RXTO1_OFF 0x0004 +#define SK_PKTARBCTL_RXTO1_ON 0x0008 +#define SK_PKTARBCTL_RXTO2_OFF 0x0010 +#define SK_PKTARBCTL_RXTO2_ON 0x0020 +#define SK_PKTARBCTL_TXTO1_OFF 0x0040 +#define SK_PKTARBCTL_TXTO1_ON 0x0080 +#define SK_PKTARBCTL_TXTO2_OFF 0x0100 +#define SK_PKTARBCTL_TXTO2_ON 0x0200 +#define SK_PKTARBCTL_CLR_IRQ_RXTO1 0x0400 +#define SK_PKTARBCTL_CLR_IRQ_RXTO2 0x0800 +#define SK_PKTARBCTL_CLR_IRQ_TXTO1 0x1000 +#define SK_PKTARBCTL_CLR_IRQ_TXTO2 0x2000 + +#define SK_MINIT_XMAC_B2 54 +#define SK_MINIT_XMAC_C1 63 + +#define SK_MACARBCTL_RESET 0x0001 +#define SK_MACARBCTL_UNRESET 0x0002 +#define SK_MACARBCTL_FASTOE_OFF 0x0004 +#define SK_MACARBCRL_FASTOE_ON 0x0008 + +#define SK_RCINIT_XMAC_B2 54 +#define SK_RCINIT_XMAC_C1 0 + +#define SK_RECOVERYCTL_RX1_OFF 0x0001 +#define SK_RECOVERYCTL_RX1_ON 0x0002 +#define SK_RECOVERYCTL_RX2_OFF 0x0004 +#define SK_RECOVERYCTL_RX2_ON 0x0008 +#define SK_RECOVERYCTL_TX1_OFF 0x0010 +#define SK_RECOVERYCTL_TX1_ON 0x0020 +#define SK_RECOVERYCTL_TX2_OFF 0x0040 +#define SK_RECOVERYCTL_TX2_ON 0x0080 + +#define SK_RECOVERY_XMAC_B2 \ + (SK_RECOVERYCTL_RX1_ON|SK_RECOVERYCTL_RX2_ON| \ + SK_RECOVERYCTL_TX1_ON|SK_RECOVERYCTL_TX2_ON) + +#define SK_RECOVERY_XMAC_C1 \ + (SK_RECOVERYCTL_RX1_OFF|SK_RECOVERYCTL_RX2_OFF| \ + SK_RECOVERYCTL_TX1_OFF|SK_RECOVERYCTL_TX2_OFF) + +/* Block 4 -- TX Arbiter MAC 1 */ +#define SK_TXAR1_TIMERINIT 0x0200 +#define SK_TXAR1_TIMERVAL 0x0204 +#define SK_TXAR1_LIMITINIT 0x0208 +#define SK_TXAR1_LIMITCNT 0x020C +#define SK_TXAR1_COUNTERCTL 0x0210 +#define SK_TXAR1_COUNTERTST 0x0212 +#define SK_TXAR1_COUNTERSTS 0x0212 + +/* Block 5 -- TX Arbiter MAC 2 */ +#define SK_TXAR2_TIMERINIT 0x0280 +#define SK_TXAR2_TIMERVAL 0x0284 +#define SK_TXAR2_LIMITINIT 0x0288 +#define SK_TXAR2_LIMITCNT 0x028C +#define SK_TXAR2_COUNTERCTL 0x0290 +#define SK_TXAR2_COUNTERTST 0x0291 +#define SK_TXAR2_COUNTERSTS 0x0292 + +#define SK_TXARCTL_OFF 0x01 +#define SK_TXARCTL_ON 0x02 +#define SK_TXARCTL_RATECTL_OFF 0x04 +#define SK_TXARCTL_RATECTL_ON 0x08 +#define SK_TXARCTL_ALLOC_OFF 0x10 +#define SK_TXARCTL_ALLOC_ON 0x20 +#define SK_TXARCTL_FSYNC_OFF 0x40 +#define SK_TXARCTL_FSYNC_ON 0x80 + +/* Block 6 -- External registers */ +#define SK_EXTREG_BASE 0x300 +#define SK_EXTREG_END 0x37C + +/* Block 7 -- PCI config registers */ +#define SK_PCI_BASE 0x0380 +#define SK_PCI_END 0x03FC + +/* Compute offset of mirrored PCI register */ +#define SK_PCI_REG(reg) ((reg) + SK_PCI_BASE) + +/* Block 8 -- RX queue 1 */ +#define SK_RXQ1_BUFCNT 0x0400 +#define SK_RXQ1_BUFCTL 0x0402 +#define SK_RXQ1_NEXTDESC 0x0404 +#define SK_RXQ1_RXBUF_LO 0x0408 +#define SK_RXQ1_RXBUF_HI 0x040C +#define SK_RXQ1_RXSTAT 0x0410 +#define SK_RXQ1_TIMESTAMP 0x0414 +#define SK_RXQ1_CSUM1 0x0418 +#define SK_RXQ1_CSUM2 0x041A +#define SK_RXQ1_CSUM1_START 0x041C +#define SK_RXQ1_CSUM2_START 0x041E +#define SK_RXQ1_CURADDR_LO 0x0420 +#define SK_RXQ1_CURADDR_HI 0x0424 +#define SK_RXQ1_CURCNT_LO 0x0428 +#define SK_RXQ1_CURCNT_HI 0x042C +#define SK_RXQ1_CURBYTES 0x0430 +#define SK_RXQ1_BMU_CSR 0x0434 +#define SK_RXQ1_WATERMARK 0x0438 +#define SK_RXQ1_FLAG 0x043A +#define SK_RXQ1_TEST1 0x043C +#define SK_RXQ1_TEST2 0x0440 +#define SK_RXQ1_TEST3 0x0444 + +/* Block 9 -- RX queue 2 */ +#define SK_RXQ2_BUFCNT 0x0480 +#define SK_RXQ2_BUFCTL 0x0482 +#define SK_RXQ2_NEXTDESC 0x0484 +#define SK_RXQ2_RXBUF_LO 0x0488 +#define SK_RXQ2_RXBUF_HI 0x048C +#define SK_RXQ2_RXSTAT 0x0490 +#define SK_RXQ2_TIMESTAMP 0x0494 +#define SK_RXQ2_CSUM1 0x0498 +#define SK_RXQ2_CSUM2 0x049A +#define SK_RXQ2_CSUM1_START 0x049C +#define SK_RXQ2_CSUM2_START 0x049E +#define SK_RXQ2_CURADDR_LO 0x04A0 +#define SK_RXQ2_CURADDR_HI 0x04A4 +#define SK_RXQ2_CURCNT_LO 0x04A8 +#define SK_RXQ2_CURCNT_HI 0x04AC +#define SK_RXQ2_CURBYTES 0x04B0 +#define SK_RXQ2_BMU_CSR 0x04B4 +#define SK_RXQ2_WATERMARK 0x04B8 +#define SK_RXQ2_FLAG 0x04BA +#define SK_RXQ2_TEST1 0x04BC +#define SK_RXQ2_TEST2 0x04C0 +#define SK_RXQ2_TEST3 0x04C4 + +#define SK_RXBMU_CLR_IRQ_ERR 0x00000001 +#define SK_RXBMU_CLR_IRQ_EOF 0x00000002 +#define SK_RXBMU_CLR_IRQ_EOB 0x00000004 +#define SK_RXBMU_CLR_IRQ_PAR 0x00000008 +#define SK_RXBMU_RX_START 0x00000010 +#define SK_RXBMU_RX_STOP 0x00000020 +#define SK_RXBMU_POLL_OFF 0x00000040 +#define SK_RXBMU_POLL_ON 0x00000080 +#define SK_RXBMU_TRANSFER_SM_RESET 0x00000100 +#define SK_RXBMU_TRANSFER_SM_UNRESET 0x00000200 +#define SK_RXBMU_DESCWR_SM_RESET 0x00000400 +#define SK_RXBMU_DESCWR_SM_UNRESET 0x00000800 +#define SK_RXBMU_DESCRD_SM_RESET 0x00001000 +#define SK_RXBMU_DESCRD_SM_UNRESET 0x00002000 +#define SK_RXBMU_SUPERVISOR_SM_RESET 0x00004000 +#define SK_RXBMU_SUPERVISOR_SM_UNRESET 0x00008000 +#define SK_RXBMU_PFI_SM_RESET 0x00010000 +#define SK_RXBMU_PFI_SM_UNRESET 0x00020000 +#define SK_RXBMU_FIFO_RESET 0x00040000 +#define SK_RXBMU_FIFO_UNRESET 0x00080000 +#define SK_RXBMU_DESC_RESET 0x00100000 +#define SK_RXBMU_DESC_UNRESET 0x00200000 +#define SK_RXBMU_SUPERVISOR_IDLE 0x01000000 + +#define SK_RXBMU_ONLINE \ + (SK_RXBMU_TRANSFER_SM_UNRESET|SK_RXBMU_DESCWR_SM_UNRESET| \ + SK_RXBMU_DESCRD_SM_UNRESET|SK_RXBMU_SUPERVISOR_SM_UNRESET| \ + SK_RXBMU_PFI_SM_UNRESET|SK_RXBMU_FIFO_UNRESET| \ + SK_RXBMU_DESC_UNRESET) + +#define SK_RXBMU_OFFLINE \ + (SK_RXBMU_TRANSFER_SM_RESET|SK_RXBMU_DESCWR_SM_RESET| \ + SK_RXBMU_DESCRD_SM_RESET|SK_RXBMU_SUPERVISOR_SM_RESET| \ + SK_RXBMU_PFI_SM_RESET|SK_RXBMU_FIFO_RESET| \ + SK_RXBMU_DESC_RESET) + +/* Block 12 -- TX sync queue 1 */ +#define SK_TXQS1_BUFCNT 0x0600 +#define SK_TXQS1_BUFCTL 0x0602 +#define SK_TXQS1_NEXTDESC 0x0604 +#define SK_TXQS1_RXBUF_LO 0x0608 +#define SK_TXQS1_RXBUF_HI 0x060C +#define SK_TXQS1_RXSTAT 0x0610 +#define SK_TXQS1_CSUM_STARTVAL 0x0614 +#define SK_TXQS1_CSUM_STARTPOS 0x0618 +#define SK_TXQS1_CSUM_WRITEPOS 0x061A +#define SK_TXQS1_CURADDR_LO 0x0620 +#define SK_TXQS1_CURADDR_HI 0x0624 +#define SK_TXQS1_CURCNT_LO 0x0628 +#define SK_TXQS1_CURCNT_HI 0x062C +#define SK_TXQS1_CURBYTES 0x0630 +#define SK_TXQS1_BMU_CSR 0x0634 +#define SK_TXQS1_WATERMARK 0x0638 +#define SK_TXQS1_FLAG 0x063A +#define SK_TXQS1_TEST1 0x063C +#define SK_TXQS1_TEST2 0x0640 +#define SK_TXQS1_TEST3 0x0644 + +/* Block 13 -- TX async queue 1 */ +#define SK_TXQA1_BUFCNT 0x0680 +#define SK_TXQA1_BUFCTL 0x0682 +#define SK_TXQA1_NEXTDESC 0x0684 +#define SK_TXQA1_RXBUF_LO 0x0688 +#define SK_TXQA1_RXBUF_HI 0x068C +#define SK_TXQA1_RXSTAT 0x0690 +#define SK_TXQA1_CSUM_STARTVAL 0x0694 +#define SK_TXQA1_CSUM_STARTPOS 0x0698 +#define SK_TXQA1_CSUM_WRITEPOS 0x069A +#define SK_TXQA1_CURADDR_LO 0x06A0 +#define SK_TXQA1_CURADDR_HI 0x06A4 +#define SK_TXQA1_CURCNT_LO 0x06A8 +#define SK_TXQA1_CURCNT_HI 0x06AC +#define SK_TXQA1_CURBYTES 0x06B0 +#define SK_TXQA1_BMU_CSR 0x06B4 +#define SK_TXQA1_WATERMARK 0x06B8 +#define SK_TXQA1_FLAG 0x06BA +#define SK_TXQA1_TEST1 0x06BC +#define SK_TXQA1_TEST2 0x06C0 +#define SK_TXQA1_TEST3 0x06C4 + +/* Block 14 -- TX sync queue 2 */ +#define SK_TXQS2_BUFCNT 0x0700 +#define SK_TXQS2_BUFCTL 0x0702 +#define SK_TXQS2_NEXTDESC 0x0704 +#define SK_TXQS2_RXBUF_LO 0x0708 +#define SK_TXQS2_RXBUF_HI 0x070C +#define SK_TXQS2_RXSTAT 0x0710 +#define SK_TXQS2_CSUM_STARTVAL 0x0714 +#define SK_TXQS2_CSUM_STARTPOS 0x0718 +#define SK_TXQS2_CSUM_WRITEPOS 0x071A +#define SK_TXQS2_CURADDR_LO 0x0720 +#define SK_TXQS2_CURADDR_HI 0x0724 +#define SK_TXQS2_CURCNT_LO 0x0728 +#define SK_TXQS2_CURCNT_HI 0x072C +#define SK_TXQS2_CURBYTES 0x0730 +#define SK_TXQS2_BMU_CSR 0x0734 +#define SK_TXQS2_WATERMARK 0x0738 +#define SK_TXQS2_FLAG 0x073A +#define SK_TXQS2_TEST1 0x073C +#define SK_TXQS2_TEST2 0x0740 +#define SK_TXQS2_TEST3 0x0744 + +/* Block 15 -- TX async queue 2 */ +#define SK_TXQA2_BUFCNT 0x0780 +#define SK_TXQA2_BUFCTL 0x0782 +#define SK_TXQA2_NEXTDESC 0x0784 +#define SK_TXQA2_RXBUF_LO 0x0788 +#define SK_TXQA2_RXBUF_HI 0x078C +#define SK_TXQA2_RXSTAT 0x0790 +#define SK_TXQA2_CSUM_STARTVAL 0x0794 +#define SK_TXQA2_CSUM_STARTPOS 0x0798 +#define SK_TXQA2_CSUM_WRITEPOS 0x079A +#define SK_TXQA2_CURADDR_LO 0x07A0 +#define SK_TXQA2_CURADDR_HI 0x07A4 +#define SK_TXQA2_CURCNT_LO 0x07A8 +#define SK_TXQA2_CURCNT_HI 0x07AC +#define SK_TXQA2_CURBYTES 0x07B0 +#define SK_TXQA2_BMU_CSR 0x07B4 +#define SK_TXQA2_WATERMARK 0x07B8 +#define SK_TXQA2_FLAG 0x07BA +#define SK_TXQA2_TEST1 0x07BC +#define SK_TXQA2_TEST2 0x07C0 +#define SK_TXQA2_TEST3 0x07C4 + +#define SK_TXBMU_CLR_IRQ_ERR 0x00000001 +#define SK_TXBMU_CLR_IRQ_EOF 0x00000002 +#define SK_TXBMU_CLR_IRQ_EOB 0x00000004 +#define SK_TXBMU_TX_START 0x00000010 +#define SK_TXBMU_TX_STOP 0x00000020 +#define SK_TXBMU_POLL_OFF 0x00000040 +#define SK_TXBMU_POLL_ON 0x00000080 +#define SK_TXBMU_TRANSFER_SM_RESET 0x00000100 +#define SK_TXBMU_TRANSFER_SM_UNRESET 0x00000200 +#define SK_TXBMU_DESCWR_SM_RESET 0x00000400 +#define SK_TXBMU_DESCWR_SM_UNRESET 0x00000800 +#define SK_TXBMU_DESCRD_SM_RESET 0x00001000 +#define SK_TXBMU_DESCRD_SM_UNRESET 0x00002000 +#define SK_TXBMU_SUPERVISOR_SM_RESET 0x00004000 +#define SK_TXBMU_SUPERVISOR_SM_UNRESET 0x00008000 +#define SK_TXBMU_PFI_SM_RESET 0x00010000 +#define SK_TXBMU_PFI_SM_UNRESET 0x00020000 +#define SK_TXBMU_FIFO_RESET 0x00040000 +#define SK_TXBMU_FIFO_UNRESET 0x00080000 +#define SK_TXBMU_DESC_RESET 0x00100000 +#define SK_TXBMU_DESC_UNRESET 0x00200000 +#define SK_TXBMU_SUPERVISOR_IDLE 0x01000000 + +#define SK_TXBMU_ONLINE \ + (SK_TXBMU_TRANSFER_SM_UNRESET|SK_TXBMU_DESCWR_SM_UNRESET| \ + SK_TXBMU_DESCRD_SM_UNRESET|SK_TXBMU_SUPERVISOR_SM_UNRESET| \ + SK_TXBMU_PFI_SM_UNRESET|SK_TXBMU_FIFO_UNRESET| \ + SK_TXBMU_DESC_UNRESET) + +#define SK_TXBMU_OFFLINE \ + (SK_TXBMU_TRANSFER_SM_RESET|SK_TXBMU_DESCWR_SM_RESET| \ + SK_TXBMU_DESCRD_SM_RESET|SK_TXBMU_SUPERVISOR_SM_RESET| \ + SK_TXBMU_PFI_SM_RESET|SK_TXBMU_FIFO_RESET| \ + SK_TXBMU_DESC_RESET) + +/* Block 16 -- Receive RAMbuffer 1 */ +#define SK_RXRB1_START 0x0800 +#define SK_RXRB1_END 0x0804 +#define SK_RXRB1_WR_PTR 0x0808 +#define SK_RXRB1_RD_PTR 0x080C +#define SK_RXRB1_UTHR_PAUSE 0x0810 +#define SK_RXRB1_LTHR_PAUSE 0x0814 +#define SK_RXRB1_UTHR_HIPRIO 0x0818 +#define SK_RXRB1_UTHR_LOPRIO 0x081C +#define SK_RXRB1_PKTCNT 0x0820 +#define SK_RXRB1_LVL 0x0824 +#define SK_RXRB1_CTLTST 0x0828 + +/* Block 17 -- Receive RAMbuffer 2 */ +#define SK_RXRB2_START 0x0880 +#define SK_RXRB2_END 0x0884 +#define SK_RXRB2_WR_PTR 0x0888 +#define SK_RXRB2_RD_PTR 0x088C +#define SK_RXRB2_UTHR_PAUSE 0x0890 +#define SK_RXRB2_LTHR_PAUSE 0x0894 +#define SK_RXRB2_UTHR_HIPRIO 0x0898 +#define SK_RXRB2_UTHR_LOPRIO 0x089C +#define SK_RXRB2_PKTCNT 0x08A0 +#define SK_RXRB2_LVL 0x08A4 +#define SK_RXRB2_CTLTST 0x08A8 + +/* Block 20 -- Sync. Transmit RAMbuffer 1 */ +#define SK_TXRBS1_START 0x0A00 +#define SK_TXRBS1_END 0x0A04 +#define SK_TXRBS1_WR_PTR 0x0A08 +#define SK_TXRBS1_RD_PTR 0x0A0C +#define SK_TXRBS1_PKTCNT 0x0A20 +#define SK_TXRBS1_LVL 0x0A24 +#define SK_TXRBS1_CTLTST 0x0A28 + +/* Block 21 -- Async. Transmit RAMbuffer 1 */ +#define SK_TXRBA1_START 0x0A80 +#define SK_TXRBA1_END 0x0A84 +#define SK_TXRBA1_WR_PTR 0x0A88 +#define SK_TXRBA1_RD_PTR 0x0A8C +#define SK_TXRBA1_PKTCNT 0x0AA0 +#define SK_TXRBA1_LVL 0x0AA4 +#define SK_TXRBA1_CTLTST 0x0AA8 + +/* Block 22 -- Sync. Transmit RAMbuffer 2 */ +#define SK_TXRBS2_START 0x0B00 +#define SK_TXRBS2_END 0x0B04 +#define SK_TXRBS2_WR_PTR 0x0B08 +#define SK_TXRBS2_RD_PTR 0x0B0C +#define SK_TXRBS2_PKTCNT 0x0B20 +#define SK_TXRBS2_LVL 0x0B24 +#define SK_TXRBS2_CTLTST 0x0B28 + +/* Block 23 -- Async. Transmit RAMbuffer 2 */ +#define SK_TXRBA2_START 0x0B80 +#define SK_TXRBA2_END 0x0B84 +#define SK_TXRBA2_WR_PTR 0x0B88 +#define SK_TXRBA2_RD_PTR 0x0B8C +#define SK_TXRBA2_PKTCNT 0x0BA0 +#define SK_TXRBA2_LVL 0x0BA4 +#define SK_TXRBA2_CTLTST 0x0BA8 + +#define SK_RBCTL_RESET 0x00000001 +#define SK_RBCTL_UNRESET 0x00000002 +#define SK_RBCTL_OFF 0x00000004 +#define SK_RBCTL_ON 0x00000008 +#define SK_RBCTL_STORENFWD_OFF 0x00000010 +#define SK_RBCTL_STORENFWD_ON 0x00000020 + +/* Block 24 -- RX MAC FIFO 1 regisrers and LINK_SYNC counter */ +#define SK_RXF1_END 0x0C00 +#define SK_RXF1_WPTR 0x0C04 +#define SK_RXF1_RPTR 0x0C0C +#define SK_RXF1_PKTCNT 0x0C10 +#define SK_RXF1_LVL 0x0C14 +#define SK_RXF1_MACCTL 0x0C18 +#define SK_RXF1_CTL 0x0C1C +#define SK_RXLED1_CNTINIT 0x0C20 +#define SK_RXLED1_COUNTER 0x0C24 +#define SK_RXLED1_CTL 0x0C28 +#define SK_RXLED1_TST 0x0C29 +#define SK_LINK_SYNC1_CINIT 0x0C30 +#define SK_LINK_SYNC1_COUNTER 0x0C34 +#define SK_LINK_SYNC1_CTL 0x0C38 +#define SK_LINK_SYNC1_TST 0x0C39 +#define SK_LINKLED1_CTL 0x0C3C + +#define SK_FIFO_END 0x3F + +/* Block 25 -- RX MAC FIFO 2 regisrers and LINK_SYNC counter */ +#define SK_RXF2_END 0x0C80 +#define SK_RXF2_WPTR 0x0C84 +#define SK_RXF2_RPTR 0x0C8C +#define SK_RXF2_PKTCNT 0x0C90 +#define SK_RXF2_LVL 0x0C94 +#define SK_RXF2_MACCTL 0x0C98 +#define SK_RXF2_CTL 0x0C9C +#define SK_RXLED2_CNTINIT 0x0CA0 +#define SK_RXLED2_COUNTER 0x0CA4 +#define SK_RXLED2_CTL 0x0CA8 +#define SK_RXLED2_TST 0x0CA9 +#define SK_LINK_SYNC2_CINIT 0x0CB0 +#define SK_LINK_SYNC2_COUNTER 0x0CB4 +#define SK_LINK_SYNC2_CTL 0x0CB8 +#define SK_LINK_SYNC2_TST 0x0CB9 +#define SK_LINKLED2_CTL 0x0CBC + +#define SK_RXMACCTL_CLR_IRQ_NOSTS 0x00000001 +#define SK_RXMACCTL_CLR_IRQ_NOTSTAMP 0x00000002 +#define SK_RXMACCTL_TSTAMP_OFF 0x00000004 +#define SK_RXMACCTL_RSTAMP_ON 0x00000008 +#define SK_RXMACCTL_FLUSH_OFF 0x00000010 +#define SK_RXMACCTL_FLUSH_ON 0x00000020 +#define SK_RXMACCTL_PAUSE_OFF 0x00000040 +#define SK_RXMACCTL_PAUSE_ON 0x00000080 +#define SK_RXMACCTL_AFULL_OFF 0x00000100 +#define SK_RXMACCTL_AFULL_ON 0x00000200 +#define SK_RXMACCTL_VALIDTIME_PATCH_OFF 0x00000400 +#define SK_RXMACCTL_VALIDTIME_PATCH_ON 0x00000800 +#define SK_RXMACCTL_RXRDY_PATCH_OFF 0x00001000 +#define SK_RXMACCTL_RXRDY_PATCH_ON 0x00002000 +#define SK_RXMACCTL_STS_TIMEO 0x00FF0000 +#define SK_RXMACCTL_TSTAMP_TIMEO 0xFF000000 + +#define SK_RXLEDCTL_ENABLE 0x0001 +#define SK_RXLEDCTL_COUNTER_STOP 0x0002 +#define SK_RXLEDCTL_COUNTER_START 0x0004 + +#define SK_LINKLED_OFF 0x0001 +#define SK_LINKLED_ON 0x0002 +#define SK_LINKLED_LINKSYNC_OFF 0x0004 +#define SK_LINKLED_LINKSYNC_ON 0x0008 +#define SK_LINKLED_BLINK_OFF 0x0010 +#define SK_LINKLED_BLINK_ON 0x0020 + +/* Block 26 -- TX MAC FIFO 1 regisrers */ +#define SK_TXF1_END 0x0D00 +#define SK_TXF1_WPTR 0x0D04 +#define SK_TXF1_RPTR 0x0D0C +#define SK_TXF1_PKTCNT 0x0D10 +#define SK_TXF1_LVL 0x0D14 +#define SK_TXF1_MACCTL 0x0D18 +#define SK_TXF1_CTL 0x0D1C +#define SK_TXLED1_CNTINIT 0x0D20 +#define SK_TXLED1_COUNTER 0x0D24 +#define SK_TXLED1_CTL 0x0D28 +#define SK_TXLED1_TST 0x0D29 + +/* Block 27 -- TX MAC FIFO 2 regisrers */ +#define SK_TXF2_END 0x0D80 +#define SK_TXF2_WPTR 0x0D84 +#define SK_TXF2_RPTR 0x0D8C +#define SK_TXF2_PKTCNT 0x0D90 +#define SK_TXF2_LVL 0x0D94 +#define SK_TXF2_MACCTL 0x0D98 +#define SK_TXF2_CTL 0x0D9C +#define SK_TXLED2_CNTINIT 0x0DA0 +#define SK_TXLED2_COUNTER 0x0DA4 +#define SK_TXLED2_CTL 0x0DA8 +#define SK_TXLED2_TST 0x0DA9 + +#define SK_TXMACCTL_XMAC_RESET 0x00000001 +#define SK_TXMACCTL_XMAC_UNRESET 0x00000002 +#define SK_TXMACCTL_LOOP_OFF 0x00000004 +#define SK_TXMACCTL_LOOP_ON 0x00000008 +#define SK_TXMACCTL_FLUSH_OFF 0x00000010 +#define SK_TXMACCTL_FLUSH_ON 0x00000020 +#define SK_TXMACCTL_WAITEMPTY_OFF 0x00000040 +#define SK_TXMACCTL_WAITEMPTY_ON 0x00000080 +#define SK_TXMACCTL_AFULL_OFF 0x00000100 +#define SK_TXMACCTL_AFULL_ON 0x00000200 +#define SK_TXMACCTL_TXRDY_PATCH_OFF 0x00000400 +#define SK_TXMACCTL_RXRDY_PATCH_ON 0x00000800 +#define SK_TXMACCTL_PKT_RECOVERY_OFF 0x00001000 +#define SK_TXMACCTL_PKT_RECOVERY_ON 0x00002000 +#define SK_TXMACCTL_CLR_IRQ_PERR 0x00008000 +#define SK_TXMACCTL_WAITAFTERFLUSH 0x00010000 + +#define SK_TXLEDCTL_ENABLE 0x0001 +#define SK_TXLEDCTL_COUNTER_STOP 0x0002 +#define SK_TXLEDCTL_COUNTER_START 0x0004 + +#define SK_FIFO_RESET 0x00000001 +#define SK_FIFO_UNRESET 0x00000002 +#define SK_FIFO_OFF 0x00000004 +#define SK_FIFO_ON 0x00000008 + +/* Block 0x40 to 0x4F -- XMAC 1 registers */ +#define SK_XMAC1_BASE 0x2000 +#define SK_XMAC1_END 0x23FF + +/* Block 0x60 to 0x6F -- XMAC 2 registers */ +#define SK_XMAC2_BASE 0x3000 +#define SK_XMAC2_END 0x33FF + +/* Compute relative offset of an XMAC register in the XMAC window(s). */ +#define SK_XMAC_REG(reg, mac) (((reg) * 2) + SK_XMAC1_BASE + \ + (mac * (SK_XMAC2_BASE - SK_XMAC1_BASE))) + +#define SK_XM_READ_4(sc, reg) \ + (sk_win_read_2(sc->sk_softc, \ + SK_XMAC_REG(reg, sc->sk_port)) & 0xFFFF) | \ + ((sk_win_read_2(sc->sk_softc, \ + SK_XMAC_REG(reg + 2, sc->sk_port)) << 16) & 0xFFFF0000) + +#define SK_XM_WRITE_4(sc, reg, val) \ + sk_win_write_2(sc->sk_softc, \ + SK_XMAC_REG(reg, sc->sk_port), ((val) & 0xFFFF)); \ + sk_win_write_2(sc->sk_softc, \ + SK_XMAC_REG(reg + 2, sc->sk_port), ((val) >> 16) & 0xFFFF); + +#define SK_XM_READ_2(sc, reg) \ + sk_win_read_2(sc->sk_softc, SK_XMAC_REG(reg, sc->sk_port)) + +#define SK_XM_WRITE_2(sc, reg, val) \ + sk_win_write_2(sc->sk_softc, SK_XMAC_REG(reg, sc->sk_port), val) + +#define SK_XM_SETBIT_4(sc, reg, x) \ + SK_XM_WRITE_4(sc, reg, (SK_XM_READ_4(sc, reg)) | (x)) + +#define SK_XM_CLRBIT_4(sc, reg, x) \ + SK_XM_WRITE_4(sc, reg, (SK_XM_READ_4(sc, reg)) & ~(x)) + +#define SK_XM_SETBIT_2(sc, reg, x) \ + SK_XM_WRITE_2(sc, reg, (SK_XM_READ_2(sc, reg)) | (x)) + +#define SK_XM_CLRBIT_2(sc, reg, x) \ + SK_XM_WRITE_2(sc, reg, (SK_XM_READ_2(sc, reg)) & ~(x)) + + +/* + * The default FIFO threshold on the XMAC II is 4 bytes. On + * dual port NICs, this often leats to transmit underruns, so we + * bump the threshold a little. + */ +#define SK_XM_TX_FIFOTHRESH 512 + +#define SK_PCI_VENDOR_ID 0x0000 +#define SK_PCI_DEVICE_ID 0x0002 +#define SK_PCI_COMMAND 0x0004 +#define SK_PCI_STATUS 0x0006 +#define SK_PCI_REVID 0x0008 +#define SK_PCI_CLASSCODE 0x0009 +#define SK_PCI_CACHELEN 0x000C +#define SK_PCI_LATENCY_TIMER 0x000D +#define SK_PCI_HEADER_TYPE 0x000E +#define SK_PCI_LOMEM 0x0010 +#define SK_PCI_LOIO 0x0014 +#define SK_PCI_SUBVEN_ID 0x002C +#define SK_PCI_SYBSYS_ID 0x002E +#define SK_PCI_BIOSROM 0x0030 +#define SK_PCI_INTLINE 0x003C +#define SK_PCI_INTPIN 0x003D +#define SK_PCI_MINGNT 0x003E +#define SK_PCI_MINLAT 0x003F + +/* device specific PCI registers */ +#define SK_PCI_OURREG1 0x0040 +#define SK_PCI_OURREG2 0x0044 +#define SK_PCI_ +#define SK_PCI_CAPID 0x0048 /* 8 bits */ +#define SK_PCI_NEXTPTR 0x0049 /* 8 bits */ +#define SK_PCI_PWRMGMTCAP 0x004A /* 16 bits */ +#define SK_PCI_PWRMGMTCTRL 0x004C /* 16 bits */ +#define SK_PCI_PME_EVENT 0x004F +#define SK_PCI_VPD_CAPID 0x0050 +#define SK_PCI_VPD_NEXTPTR 0x0051 +#define SK_PCI_VPD_ADDR 0x0052 +#define SK_PCI_VPD_DATA 0x0054 + +#define SK_PSTATE_MASK 0x0003 +#define SK_PSTATE_D0 0x0000 +#define SK_PSTATE_D1 0x0001 +#define SK_PSTATE_D2 0x0002 +#define SK_PSTATE_D3 0x0003 +#define SK_PME_EN 0x0010 +#define SK_PME_STATUS 0x8000 + +/* + * VPD flag bit. Set to 0 to initiate a read, will become 1 when + * read is complete. Set to 1 to initiate a write, will become 0 + * when write is finished. + */ +#define SK_VPD_FLAG 0x8000 + +/* VPD structures */ +struct vpd_res { + u_int8_t vr_id; + u_int8_t vr_len; + u_int8_t vr_pad; +}; + +struct vpd_key { + char vk_key[2]; + u_int8_t vk_len; +}; + +#define VPD_RES_ID 0x82 /* ID string */ +#define VPD_RES_READ 0x90 /* start of read only area */ +#define VPD_RES_WRITE 0x81 /* start of read/write area */ +#define VPD_RES_END 0x78 /* end tag */ + +#define CSR_WRITE_4(sc, reg, val) \ + bus_space_write_4(sc->sk_btag, sc->sk_bhandle, reg, val) +#define CSR_WRITE_2(sc, reg, val) \ + bus_space_write_2(sc->sk_btag, sc->sk_bhandle, reg, val) +#define CSR_WRITE_1(sc, reg, val) \ + bus_space_write_1(sc->sk_btag, sc->sk_bhandle, reg, val) + +#define CSR_READ_4(sc, reg) \ + bus_space_read_4(sc->sk_btag, sc->sk_bhandle, reg) +#define CSR_READ_2(sc, reg) \ + bus_space_read_2(sc->sk_btag, sc->sk_bhandle, reg) +#define CSR_READ_1(sc, reg) \ + bus_space_read_1(sc->sk_btag, sc->sk_bhandle, reg) + +struct sk_type { + u_int16_t sk_vid; + u_int16_t sk_did; + char *sk_name; +}; + +/* RX queue descriptor data structure */ +struct sk_rx_desc { + u_int32_t sk_ctl; + u_int32_t sk_next; + u_int32_t sk_data_lo; + u_int32_t sk_data_hi; + u_int32_t sk_xmac_rxstat; + u_int32_t sk_timestamp; + u_int16_t sk_csum2; + u_int16_t sk_csum1; + u_int16_t sk_csum2_start; + u_int16_t sk_csum1_start; +}; + +#define SK_OPCODE_DEFAULT 0x00550000 +#define SK_OPCODE_CSUM 0x00560000 + +#define SK_RXCTL_LEN 0x0000FFFF +#define SK_RXCTL_OPCODE 0x00FF0000 +#define SK_RXCTL_TSTAMP_VALID 0x01000000 +#define SK_RXCTL_STATUS_VALID 0x02000000 +#define SK_RXCTL_DEV0 0x04000000 +#define SK_RXCTL_EOF_INTR 0x08000000 +#define SK_RXCTL_EOB_INTR 0x10000000 +#define SK_RXCTL_LASTFRAG 0x20000000 +#define SK_RXCTL_FIRSTFRAG 0x40000000 +#define SK_RXCTL_OWN 0x80000000 + +#define SK_RXSTAT \ + (SK_OPCODE_DEFAULT|SK_RXCTL_EOF_INTR|SK_RXCTL_LASTFRAG| \ + SK_RXCTL_FIRSTFRAG|SK_RXCTL_OWN) + +struct sk_tx_desc { + u_int32_t sk_ctl; + u_int32_t sk_next; + u_int32_t sk_data_lo; + u_int32_t sk_data_hi; + u_int32_t sk_xmac_txstat; + u_int16_t sk_rsvd0; + u_int16_t sk_csum_startval; + u_int16_t sk_csum_startpos; + u_int16_t sk_csum_writepos; + u_int32_t sk_rsvd1; +}; + +#define SK_TXCTL_LEN 0x0000FFFF +#define SK_TXCTL_OPCODE 0x00FF0000 +#define SK_TXCTL_SW 0x01000000 +#define SK_TXCTL_NOCRC 0x02000000 +#define SK_TXCTL_STORENFWD 0x04000000 +#define SK_TXCTL_EOF_INTR 0x08000000 +#define SK_TXCTL_EOB_INTR 0x10000000 +#define SK_TXCTL_LASTFRAG 0x20000000 +#define SK_TXCTL_FIRSTFRAG 0x40000000 +#define SK_TXCTL_OWN 0x80000000 + +#define SK_TXSTAT \ + (SK_OPCODE_DEFAULT|SK_TXCTL_EOF_INTR|SK_TXCTL_LASTFRAG|SK_TXCTL_OWN) + +#define SK_RXBYTES(x) (x) & 0x0000FFFF; +#define SK_TXBYTES SK_RXBYTES + +#define SK_TX_RING_CNT 512 +#define SK_RX_RING_CNT 256 + +/* + * Jumbo buffer stuff. Note that we must allocate more jumbo + * buffers than there are descriptors in the receive ring. This + * is because we don't know how long it will take for a packet + * to be released after we hand it off to the upper protocol + * layers. To be safe, we allocate 1.5 times the number of + * receive descriptors. + */ +#define SK_JUMBO_FRAMELEN 9018 +#define SK_JUMBO_MTU (SK_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN) +#define SK_JSLOTS 384 + +#define SK_JRAWLEN (SK_JUMBO_FRAMELEN + ETHER_ALIGN + sizeof(u_int64_t)) +#define SK_JLEN (SK_JRAWLEN + (sizeof(u_int64_t) - \ + (SK_JRAWLEN % sizeof(u_int64_t)))) +#define SK_MCLBYTES (SK_JLEN - sizeof(u_int64_t)) +#define SK_JPAGESZ PAGE_SIZE +#define SK_RESID (SK_JPAGESZ - (SK_JLEN * SK_JSLOTS) % SK_JPAGESZ) +#define SK_JMEM ((SK_JLEN * SK_JSLOTS) + SK_RESID) + +struct sk_jslot { + caddr_t sk_buf; + int sk_inuse; +}; + +struct sk_jpool_entry { + int slot; + SLIST_ENTRY(sk_jpool_entry) jpool_entries; +}; + +struct sk_chain { + void *sk_desc; + struct mbuf *sk_mbuf; + struct sk_chain *sk_next; +}; + +struct sk_chain_data { + struct sk_chain sk_tx_chain[SK_TX_RING_CNT]; + struct sk_chain sk_rx_chain[SK_RX_RING_CNT]; + int sk_tx_prod; + int sk_tx_cons; + int sk_tx_cnt; + int sk_rx_prod; + int sk_rx_cons; + int sk_rx_cnt; + /* Stick the jumbo mem management stuff here too. */ + struct sk_jslot sk_jslots[SK_JSLOTS]; + void *sk_jumbo_buf; + +}; + +struct sk_ring_data { + struct sk_tx_desc sk_tx_ring[SK_TX_RING_CNT]; + struct sk_rx_desc sk_rx_ring[SK_RX_RING_CNT]; +}; + +#define SK_INC(x, y) (x) = (x + 1) % y + +/* Forward decl. */ +struct sk_if_softc; + +/* Softc for the GEnesis controller. */ +struct sk_softc { + bus_space_handle_t sk_bhandle; /* bus space handle */ + bus_space_tag_t sk_btag; /* bus space tag */ + struct sk_type *sk_info; /* Starfire adapter info */ + u_int8_t sk_unit; /* controller number */ + u_int8_t sk_type; + u_int8_t sk_cachesize; + char *sk_vpd_prodname; + char *sk_vpd_readonly; + u_int32_t sk_rboff; /* RAMbuffer offset */ + u_int32_t sk_ramsize; /* amount of RAM on NIC */ + u_int32_t sk_pmd; /* physical media type */ + u_int32_t sk_intrmask; + struct sk_if_softc *sk_if[2]; +}; + +/* Softc for each logical interface */ +struct sk_if_softc { + struct arpcom arpcom; /* interface info */ + struct ifmedia ifmedia; /* media info */ + u_int8_t sk_unit; /* interface number */ + u_int8_t sk_port; /* port # on controller */ + u_int8_t sk_xmac_rev; /* XMAC chip rev (B2 or C1) */ + u_int8_t sk_link; + u_int32_t sk_rx_ramstart; + u_int32_t sk_rx_ramend; + u_int32_t sk_tx_ramstart; + u_int32_t sk_tx_ramend; + struct sk_chain_data sk_cdata; + struct sk_ring_data *sk_rdata; + struct sk_softc *sk_softc; /* parent controller */ + int sk_tx_bmu; /* TX BMU register */ + int sk_if_flags; + SLIST_HEAD(__sk_jfreehead, sk_jpool_entry) sk_jfree_listhead; + SLIST_HEAD(__sk_jinusehead, sk_jpool_entry) sk_jinuse_listhead; +}; + +#define SK_TIMEOUT 1000 +#define ETHER_ALIGN 2 + +#ifdef __alpha__ +#undef vtophys +#define vtophys(va) (pmap_kextract(((vm_offset_t) (va))) \ + + 1*1024*1024*1024) +#endif diff --git a/sys/dev/sk/xmaciireg.h b/sys/dev/sk/xmaciireg.h new file mode 100644 index 0000000..fe8946b --- /dev/null +++ b/sys/dev/sk/xmaciireg.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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: xmaciireg.h,v 1.10 1999/07/09 03:35:12 wpaul Exp $ + */ + +/* + * Registers and data structures for the XaQti Corporation XMAC II + * Gigabit Ethernet MAC. Datasheet is available from http://www.xaqti.com. + * The XMAC can be programmed for 16-bit or 32-bit register access modes. + * The SysKonnect gigabit ethernet adapters use 16-bit mode, so that's + * how the registers are laid out here. + */ + +#define XM_DEVICEID 0x00E0AE20 +#define XM_XAQTI_OUI 0x00E0AE + +#define XM_XMAC_REV(x) (((x) & 0x000000E0) >> 5) + +#define XM_XMAC_REV_B2 0x0 +#define XM_XMAC_REV_C1 0x1 + +#define XM_MMUCMD 0x0000 +#define XM_POFF 0x0008 +#define XM_BURST 0x000C +#define XM_VLAN_TAGLEV1 0x0010 +#define XM_VLAN_TAGLEV2 0x0014 +#define XM_TXCMD 0x0020 +#define XM_TX_RETRYLIMIT 0x0024 +#define XM_TX_SLOTTIME 0x0028 +#define XM_TX_IPG 0x003C +#define XM_RXCMD 0x0030 +#define XM_PHY_ADDR 0x0034 +#define XM_PHY_DATA 0x0038 +#define XM_GPIO 0x0040 +#define XM_IMR 0x0044 +#define XM_ISR 0x0048 +#define XM_HWCFG 0x004C +#define XM_TX_LOWAT 0x0060 +#define XM_TX_HIWAT 0x0062 +#define XM_TX_REQTHRESH_LO 0x0064 +#define XM_TX_REQTHRESH_HI 0x0066 +#define XM_TX_REQTHRESH XM_TX_REQTHRESH_LO +#define XM_PAUSEDST0 0x0068 +#define XM_PAUSEDST1 0x006A +#define XM_PAUSEDST2 0x006C +#define XM_CTLPARM_LO 0x0070 +#define XM_CTLPARM_HI 0x0072 +#define XM_CTLPARM XM_CTLPARM_LO +#define XM_OPCODE_PAUSE_TIMER 0x0074 +#define XM_TXSTAT_LIFO 0x0078 + +/* + * Perfect filter registers. The XMAC has a table of 16 perfect + * filter entries, spaced 8 bytes apart. This is in addition to + * the station address registers, which appear below. + */ +#define XM_RXFILT_BASE 0x0080 +#define XM_RXFILT_END 0x0107 +#define XM_RXFILT_MAX 16 +#define XM_RXFILT_ENTRY(ent) (XM_RXFILT_BASE + ((ent * 8))) + +/* Primary station address. */ +#define XM_PAR0 0x0108 +#define XM_PAR1 0x010A +#define XM_PAR2 0x010C + +/* 64-bit multicast hash table registers */ +#define XM_MAR0 0x0110 +#define XM_MAR1 0x0112 +#define XM_MAR2 0x0114 +#define XM_MAR3 0x0116 +#define XM_RX_LOWAT 0x0118 +#define XM_RX_HIWAT 0x011A +#define XM_RX_REQTHRESH_LO 0x011C +#define XM_RX_REQTHRESH_HI 0x011E +#define XM_RX_REQTHRESH XM_RX_REQTHRESH_LO +#define XM_DEVID_LO 0x0120 +#define XM_DEVID_HI 0x0122 +#define XM_DEVID XM_DEVID_LO +#define XM_MODE_LO 0x0124 +#define XM_MODE_HI 0x0126 +#define XM_MODE XM_MODE_LO +#define XM_LASTSRC0 0x0128 +#define XM_LASTSRC1 0x012A +#define XM_LASTSRC2 0x012C +#define XM_TSTAMP_READ 0x0130 +#define XM_TSTAMP_LOAD 0x0134 +#define XM_STATS_CMD 0x0200 +#define XM_RXCNT_EVENT_LO 0x0204 +#define XM_RXCNT_EVENT_HI 0x0206 +#define XM_RXCNT_EVENT XM_RXCNT_EVENT_LO +#define XM_TXCNT_EVENT_LO 0x0208 +#define XM_TXCNT_EVENT_HI 0x020A +#define XM_TXCNT_EVENT XM_TXCNT_EVENT_LO +#define XM_RXCNT_EVMASK_LO 0x020C +#define XM_RXCNT_EVMASK_HI 0x020E +#define XM_RXCNT_EVMASK XM_RXCNT_EVMASK_LO +#define XM_TXCNT_EVMASK_LO 0x0210 +#define XM_TXCNT_EVMASK_HI 0x0212 +#define XM_TXCNT_EVMASK XM_TXCNT_EVMASK_LO + +/* Statistics command register */ +#define XM_STATCMD_CLR_TX 0x0001 +#define XM_STATCMD_CLR_RX 0x0002 +#define XM_STATCMD_COPY_TX 0x0004 +#define XM_STATCMD_COPY_RX 0x0008 +#define XM_STATCMD_SNAP_TX 0x0010 +#define XM_STATCMD_SNAP_RX 0x0020 + +/* TX statistics registers */ +#define XM_TXSTATS_PKTSOK 0x280 +#define XM_TXSTATS_BYTESOK_HI 0x284 +#define XM_TXSTATS_BYTESOK_LO 0x288 +#define XM_TXSTATS_BCASTSOK 0x28C +#define XM_TXSTATS_MCASTSOK 0x290 +#define XM_TXSTATS_UCASTSOK 0x294 +#define XM_TXSTATS_GIANTS 0x298 +#define XM_TXSTATS_BURSTCNT 0x29C +#define XM_TXSTATS_PAUSEPKTS 0x2A0 +#define XM_TXSTATS_MACCTLPKTS 0x2A4 +#define XM_TXSTATS_SINGLECOLS 0x2A8 +#define XM_TXSTATS_MULTICOLS 0x2AC +#define XM_TXSTATS_EXCESSCOLS 0x2B0 +#define XM_TXSTATS_LATECOLS 0x2B4 +#define XM_TXSTATS_DEFER 0x2B8 +#define XM_TXSTATS_EXCESSDEFER 0x2BC +#define XM_TXSTATS_UNDERRUN 0x2C0 +#define XM_TXSTATS_CARRIERSENSE 0x2C4 +#define XM_TXSTATS_UTILIZATION 0x2C8 +#define XM_TXSTATS_64 0x2D0 +#define XM_TXSTATS_65_127 0x2D4 +#define XM_TXSTATS_128_255 0x2D8 +#define XM_TXSTATS_256_511 0x2DC +#define XM_TXSTATS_512_1023 0x2E0 +#define XM_TXSTATS_1024_MAX 0x2E4 + +/* RX statistics registers */ +#define XM_RXSTATS_PKTSOK 0x300 +#define XM_RXSTATS_BYTESOK_HI 0x304 +#define XM_RXSTATS_BYTESOK_LO 0x308 +#define XM_RXSTATS_BCASTSOK 0x30C +#define XM_RXSTATS_MCASTSOK 0x310 +#define XM_RXSTATS_UCASTSOK 0x314 +#define XM_RXSTATS_PAUSEPKTS 0x318 +#define XM_RXSTATS_MACCTLPKTS 0x31C +#define XM_RXSTATS_BADPAUSEPKTS 0x320 +#define XM_RXSTATS_BADMACCTLPKTS 0x324 +#define XM_RXSTATS_BURSTCNT 0x328 +#define XM_RXSTATS_MISSEDPKTS 0x32C +#define XM_RXSTATS_FRAMEERRS 0x330 +#define XM_RXSTATS_OVERRUN 0x334 +#define XM_RXSTATS_JABBER 0x338 +#define XM_RXSTATS_CARRLOSS 0x33C +#define XM_RXSTATS_INRNGLENERR 0x340 +#define XM_RXSTATS_SYMERR 0x344 +#define XM_RXSTATS_SHORTEVENT 0x348 +#define XM_RXSTATS_RUNTS 0x34C +#define XM_RXSTATS_GIANTS 0x350 +#define XM_RXSTATS_CRCERRS 0x354 +#define XM_RXSTATS_CEXTERRS 0x35C +#define XM_RXSTATS_UTILIZATION 0x360 +#define XM_RXSTATS_64 0x368 +#define XM_RXSTATS_65_127 0x36C +#define XM_RXSTATS_128_255 0x370 +#define XM_RXSTATS_256_511 0x374 +#define XM_RXSTATS_512_1023 0x378 +#define XM_RXSTATS_1024_MAX 0x37C + +#define XM_MMUCMD_TX_ENB 0x0001 +#define XM_MMUCMD_RX_ENB 0x0002 +#define XM_MMUCMD_GMIILOOP 0x0004 +#define XM_MMUCMD_RATECTL 0x0008 +#define XM_MMUCMD_GMIIFDX 0x0010 +#define XM_MMUCMD_NO_MGMT_PRMB 0x0020 +#define XM_MMUCMD_SIMCOL 0x0040 +#define XM_MMUCMD_FORCETX 0x0080 +#define XM_MMUCMD_LOOPENB 0x0200 +#define XM_MMUCMD_IGNPAUSE 0x0400 +#define XM_MMUCMD_PHYBUSY 0x0800 +#define XM_MMUCMD_PHYDATARDY 0x1000 + +#define XM_TXCMD_AUTOPAD 0x0001 +#define XM_TXCMD_NOCRC 0x0002 +#define XM_TXCMD_NOPREAMBLE 0x0004 +#define XM_TXCMD_NOGIGAMODE 0x0008 +#define XM_TXCMD_SAMPLELINE 0x0010 +#define XM_TXCMD_ENCBYPASS 0x0020 +#define XM_TXCMD_XMITBK2BK 0x0040 +#define XM_TXCMD_FAIRSHARE 0x0080 + +#define XM_RXCMD_DISABLE_CEXT 0x0001 +#define XM_RXCMD_STRIPPAD 0x0002 +#define XM_RXCMD_SAMPLELINE 0x0004 +#define XM_RXCMD_SELFRX 0x0008 +#define XM_RXCMD_STRIPFCS 0x0010 +#define XM_RXCMD_TRANSPARENT 0x0020 +#define XM_RXCMD_IPGCAPTURE 0x0040 +#define XM_RXCMD_BIGPKTOK 0x0080 +#define XM_RXCMD_LENERROK 0x0100 + +#define XM_IMR_RX_EOF 0x0001 +#define XM_IMR_TX_EOF 0x0002 +#define XM_IMR_TX_UNDERRUN 0x0004 +#define XM_IMR_RX_OVERRUN 0x0008 +#define XM_IMR_TX_STATS_OFLOW 0x0010 +#define XM_IMR_RX_STATS_OFLOW 0x0020 +#define XM_IMR_TSTAMP_OFLOW 0x0040 +#define XM_IMR_AUTONEG_DONE 0x0080 +#define XM_IMR_NEXTPAGE_RDY 0x0100 +#define XM_IMR_PAGE_RECEIVED 0x0200 +#define XM_IMR_LP_REQCFG 0x0400 +#define XM_IMR_GP0_SET 0x0800 +#define XM_IMR_FORCEINTR 0x1000 +#define XM_IMR_TX_ABORT 0x2000 +#define XM_IMR_LINKEVENT 0x4000 + +#define XM_INTRS \ + (~(XM_IMR_LINKEVENT|XM_IMR_AUTONEG_DONE|XM_IMR_TX_UNDERRUN)) + +#define XM_ISR_RX_EOF 0x0001 +#define XM_ISR_TX_EOF 0x0002 +#define XM_ISR_TX_UNDERRUN 0x0004 +#define XM_ISR_RX_OVERRUN 0x0008 +#define XM_ISR_TX_STATS_OFLOW 0x0010 +#define XM_ISR_RX_STATS_OFLOW 0x0020 +#define XM_ISR_TSTAMP_OFLOW 0x0040 +#define XM_ISR_AUTONEG_DONE 0x0080 +#define XM_ISR_NEXTPAGE_RDY 0x0100 +#define XM_ISR_PAGE_RECEIVED 0x0200 +#define XM_ISR_LP_REQCFG 0x0400 +#define XM_ISR_GP0_SET 0x0800 +#define XM_ISR_FORCEINTR 0x1000 +#define XM_ISR_TX_ABORT 0x2000 +#define XM_ISR_LINKEVENT 0x4000 + +#define XM_MODE_FLUSH_RXFIFO 0x00000001 +#define XM_MODE_FLUSH_TXFIFO 0x00000002 +#define XM_MODE_BIGENDIAN 0x00000004 +#define XM_MODE_RX_PROMISC 0x00000008 +#define XM_MODE_RX_NOBROAD 0x00000010 +#define XM_MODE_RX_NOMULTI 0x00000020 +#define XM_MODE_RX_NOUNI 0x00000040 +#define XM_MODE_RX_BADFRAMES 0x00000080 +#define XM_MODE_RX_CRCERRS 0x00000100 +#define XM_MODE_RX_GIANTS 0x00000200 +#define XM_MODE_RX_INRANGELEN 0x00000400 +#define XM_MODE_RX_RUNTS 0x00000800 +#define XM_MODE_RX_MACCTL 0x00001000 +#define XM_MODE_RX_USE_PERFECT 0x00002000 +#define XM_MODE_RX_USE_STATION 0x00004000 +#define XM_MODE_RX_USE_HASH 0x00008000 +#define XM_MODE_RX_ADDRPAIR 0x00010000 +#define XM_MODE_PAUSEONHI 0x00020000 +#define XM_MODE_PAUSEONLO 0x00040000 +#define XM_MODE_TIMESTAMP 0x00080000 +#define XM_MODE_SENDPAUSE 0x00100000 +#define XM_MODE_SENDCONTINUOUS 0x00200000 +#define XM_MODE_LE_STATUSWORD 0x00400000 +#define XM_MODE_AUTOFIFOPAUSE 0x00800000 +#define XM_MODE_EXPAUSEGEN 0x02000000 +#define XM_MODE_RX_INVERSE 0x04000000 + +#define XM_RXSTAT_MACCTL 0x00000001 +#define XM_RXSTAT_ERRFRAME 0x00000002 +#define XM_RXSTAT_CRCERR 0x00000004 +#define XM_RXSTAT_GIANT 0x00000008 +#define XM_RXSTAT_RUNT 0x00000010 +#define XM_RXSTAT_FRAMEERR 0x00000020 +#define XM_RXSTAT_INRANGEERR 0x00000040 +#define XM_RXSTAT_CARRIERERR 0x00000080 +#define XM_RXSTAT_COLLERR 0x00000100 +#define XM_RXSTAT_802_3 0x00000200 +#define XM_RXSTAT_CARREXTERR 0x00000400 +#define XM_RXSTAT_BURSTMODE 0x00000800 +#define XM_RXSTAT_UNICAST 0x00002000 +#define XM_RXSTAT_MULTICAST 0x00004000 +#define XM_RXSTAT_BROADCAST 0x00008000 +#define XM_RXSTAT_VLAN_LEV1 0x00010000 +#define XM_RXSTAT_VLAN_LEV2 0x00020000 +#define XM_RXSTAT_LEN 0xFFFC0000 + +/* + * XMAC PHY registers, indirectly accessed through + * XM_PHY_ADDR and XM_PHY_REG. + */ + +#define XM_PHY_BMCR 0x0000 /* control */ +#define XM_PHY_BMSR 0x0001 /* status */ +#define XM_PHY_VENID 0x0002 /* vendor id */ +#define XM_PHY_DEVID 0x0003 /* device id */ +#define XM_PHY_ANAR 0x0004 /* autoneg advertisenemt */ +#define XM_PHY_LPAR 0x0005 /* link partner ability */ +#define XM_PHY_ANEXP 0x0006 /* autoneg expansion */ +#define XM_PHY_NEXTP 0x0007 /* nextpage */ +#define XM_PHY_LPNEXTP 0x0008 /* link partner's nextpage */ +#define XM_PHY_EXTSTS 0x000F /* extented status */ +#define XM_PHY_RESAB 0x0010 /* resolved ability */ + +#define XM_BMCR_DUPLEX 0x0100 +#define XM_BMCR_RENEGOTIATE 0x0200 +#define XM_BMCR_AUTONEGENBL 0x1000 +#define XM_BMCR_LOOPBACK 0x4000 +#define XM_BMCR_RESET 0x8000 + +#define XM_BMSR_EXTCAP 0x0001 +#define XM_BMSR_LINKSTAT 0x0004 +#define XM_BMSR_AUTONEGABLE 0x0008 +#define XM_BMSR_REMFAULT 0x0010 +#define XM_BMSR_AUTONEGDONE 0x0020 +#define XM_BMSR_EXTSTAT 0x0100 + +#define XM_VENID_XAQTI 0xD14C +#define XM_DEVID_XMAC 0x0002 + +#define XM_ANAR_FULLDUPLEX 0x0020 +#define XM_ANAR_HALFDUPLEX 0x0040 +#define XM_ANAR_PAUSEBITS 0x0180 +#define XM_ANAR_REMFAULTBITS 0x1800 +#define XM_ANAR_ACK 0x4000 +#define XM_ANAR_NEXTPAGE 0x8000 + +#define XM_LPAR_FULLDUPLEX 0x0020 +#define XM_LPAR_HALFDUPLEX 0x0040 +#define XM_LPAR_PAUSEBITS 0x0180 +#define XM_LPAR_REMFAULTBITS 0x1800 +#define XM_LPAR_ACK 0x4000 +#define XM_LPAR_NEXTPAGE 0x8000 + +#define XM_PAUSE_NOPAUSE 0x0000 +#define XM_PAUSE_SYMPAUSE 0x0080 +#define XM_PAUSE_ASYMPAUSE 0x0100 +#define XM_PAUSE_BOTH 0x0180 + +#define XM_REMFAULT_LINKOK 0x0000 +#define XM_REMFAULT_LINKFAIL 0x0800 +#define XM_REMFAULT_OFFLINE 0x1000 +#define XM_REMFAULT_ANEGERR 0x1800 + +#define XM_ANEXP_GOTPAGE 0x0002 +#define XM_ANEXP_NEXTPAGE_SELF 0x0004 +#define XM_ANEXP_NEXTPAGE_LP 0x0008 + +#define XM_NEXTP_MESSAGE 0x07FF +#define XM_NEXTP_TOGGLE 0x0800 +#define XM_NEXTP_ACK2 0x1000 +#define XM_NEXTP_MPAGE 0x2000 +#define XM_NEXTP_ACK1 0x4000 +#define XM_NEXTP_NPAGE 0x8000 + +#define XM_LPNEXTP_MESSAGE 0x07FF +#define XM_LPNEXTP_TOGGLE 0x0800 +#define XM_LPNEXTP_ACK2 0x1000 +#define XM_LPNEXTP_MPAGE 0x2000 +#define XM_LPNEXTP_ACK1 0x4000 +#define XM_LPNEXTP_NPAGE 0x8000 + +#define XM_EXTSTS_HALFDUPLEX 0x4000 +#define XM_EXTSTS_FULLDUPLEX 0x8000 + +#define XM_RESAB_PAUSEMISMATCH 0x0008 +#define XM_RESAB_ABLMISMATCH 0x0010 +#define XM_RESAB_FDMODESEL 0x0020 +#define XM_RESAB_HDMODESEL 0x0040 +#define XM_RESAB_PAUSEBITS 0x0180 diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 5faffed..0d69fdc 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.615 1999/07/03 21:31:00 jdp Exp $ +# $Id: LINT,v 1.616 1999/07/06 19:22:40 des Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -1552,6 +1552,13 @@ options EISA_SLOTS=12 # the MPX 5030/5038, which is either a RealTek in disguise or a RealTek # workalike. # +# The 'sk' device provides support for the SysKonnect SK-984x series +# PCI gigabit ethernet NICs. This includes the SK-9841 and SK-9842 +# single port cards (single mode and multimode fiber) and the +# SK-9843 and SK-9844 dual port cards (also single mode and multimode). +# The driver will autodetect the number of ports on the card and +# attach each one as a separate network interface. +# # The 'ti' device provides support for PCI gigabit ethernet NICs based # on the Alteon Networks Tigon 1 and Tigon 2 chipsets. This includes the # Alteon AceNIC, the 3Com 3c985, the Netgear GA620 and various others. @@ -1695,6 +1702,7 @@ device fxp0 device mx0 device pn0 device rl0 +device sk0 device ti0 device tl0 device tx0 diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 5faffed..0d69fdc 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.615 1999/07/03 21:31:00 jdp Exp $ +# $Id: LINT,v 1.616 1999/07/06 19:22:40 des Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -1552,6 +1552,13 @@ options EISA_SLOTS=12 # the MPX 5030/5038, which is either a RealTek in disguise or a RealTek # workalike. # +# The 'sk' device provides support for the SysKonnect SK-984x series +# PCI gigabit ethernet NICs. This includes the SK-9841 and SK-9842 +# single port cards (single mode and multimode fiber) and the +# SK-9843 and SK-9844 dual port cards (also single mode and multimode). +# The driver will autodetect the number of ports on the card and +# attach each one as a separate network interface. +# # The 'ti' device provides support for PCI gigabit ethernet NICs based # on the Alteon Networks Tigon 1 and Tigon 2 chipsets. This includes the # Alteon AceNIC, the 3Com 3c985, the Netgear GA620 and various others. @@ -1695,6 +1702,7 @@ device fxp0 device mx0 device pn0 device rl0 +device sk0 device ti0 device tl0 device tx0 diff --git a/sys/i386/i386/userconfig.c b/sys/i386/i386/userconfig.c index ac517d0..f5e8236 100644 --- a/sys/i386/i386/userconfig.c +++ b/sys/i386/i386/userconfig.c @@ -46,7 +46,7 @@ ** (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: userconfig.c,v 1.146 1999/06/28 12:07:36 peter Exp $ + ** $Id: userconfig.c,v 1.147 1999/06/29 17:37:44 yokota Exp $ **/ /** @@ -387,6 +387,7 @@ static DEV_INFO device_info[] = { {"ix", "Intel EtherExpress Ethernet adapter", 0, CLS_NETWORK}, {"le", "DEC Etherworks 2 and 3 Ethernet adapters", 0, CLS_NETWORK}, {"lnc", "Isolan, Novell NE2100/NE32-VL Ethernet adapters", 0,CLS_NETWORK}, +{"sk", "SysKonnect SK-984x gigabit Ethernet adapters", 0,CLS_NETWORK}, {"ti", "Alteon Networks Tigon gigabit Ethernet adapters", 0,CLS_NETWORK}, {"tl", "Texas Instruments ThunderLAN Ethernet adapters", 0,CLS_NETWORK}, {"tx", "SMC 9432TX Ethernet adapters", 0, CLS_NETWORK}, @@ -2542,7 +2543,7 @@ visuserconfig(void) * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: userconfig.c,v 1.146 1999/06/28 12:07:36 peter Exp $ + * $Id: userconfig.c,v 1.147 1999/06/29 17:37:44 yokota Exp $ */ #include "scbus.h" diff --git a/sys/pci/if_sk.c b/sys/pci/if_sk.c new file mode 100644 index 0000000..fab98b2 --- /dev/null +++ b/sys/pci/if_sk.c @@ -0,0 +1,1916 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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: if_sk.c,v 1.48 1999/07/06 21:37:42 wpaul Exp $ + */ + +/* + * SysKonnect SK-NET gigabit ethernet driver for FreeBSD. Supports + * the SK-984x series adapters, both single port and dual port. + * References: + * The XaQti XMAC II datasheet, http://www.xaqti.com + * The SysKonnect GEnesis manual, http://www.syskonnect.com + * + * Written by Bill Paul <wpaul@ee.columbia.edu> + * Department of Electrical Engineering + * Columbia University, New York City + */ + +/* + * The SysKonnect gigabit ethernet adapters consist of two main + * components: the SysKonnect GEnesis controller chip and the XaQti Corp. + * XMAC II gigabit ethernet MAC. The XMAC provides all of the MAC + * components and a PHY while the GEnesis controller provides a PCI + * interface with DMA support. Each card may have between 512K and + * 2MB of SRAM on board depending on the configuration. + * + * The SysKonnect GEnesis controller can have either one or two XMAC + * chips connected to it, allowing single or dual port NIC configurations. + * SysKonnect has the distinction of being the only vendor on the market + * with a dual port gigabit ethernet NIC. The GEnesis provides dual FIFOs, + * dual DMA queues, packet/MAC/transmit arbiters and direct access to the + * XMAC registers. This driver takes advantage of these features to allow + * both XMACs to operate as independent interfaces. + */ + +#include "bpf.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/queue.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#if NBPF > 0 +#include <net/bpf.h> +#endif + +#include <vm/vm.h> /* for vtophys */ +#include <vm/pmap.h> /* for vtophys */ +#include <machine/clock.h> /* for DELAY */ +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#include <machine/bus.h> + +#include <pci/pcireg.h> +#include <pci/pcivar.h> + +#define SK_USEIOSPACE + +#include <pci/if_skreg.h> +#include <pci/xmaciireg.h> + +#ifndef lint +static const char rcsid[] = + "$Id: if_sk.c,v 1.48 1999/07/06 21:37:42 wpaul Exp $"; +#endif + +static struct sk_type sk_devs[] = { + { SK_VENDORID, SK_DEVICEID_GE, "SysKonnect Gigabit Ethernet" }, + { 0, 0, NULL } +}; + +static unsigned long sk_count = 0; +static unsigned long skc_count = 0; +static const char *sk_probe __P((pcici_t, pcidi_t)); +static void sk_attach __P((pcici_t, int)); +static int sk_attach_xmac __P((struct sk_softc *, int)); +static void sk_intr __P((void *)); +static void sk_intr_xmac __P((struct sk_if_softc *)); +static void sk_rxeof __P((struct sk_if_softc *)); +static void sk_txeof __P((struct sk_if_softc *)); +static int sk_encap __P((struct sk_if_softc *, struct mbuf *, + u_int32_t *, u_int32_t *)); +static void sk_start __P((struct ifnet *)); +static int sk_ioctl __P((struct ifnet *, u_long, caddr_t)); +static void sk_init __P((void *)); +static void sk_init_xmac __P((struct sk_if_softc *)); +static void sk_stop __P((struct sk_if_softc *)); +static void sk_watchdog __P((struct ifnet *)); +static void sk_shutdown __P((int, void *)); +static int sk_ifmedia_upd __P((struct ifnet *)); +static void sk_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); +static void sk_reset __P((struct sk_softc *)); +static int sk_newbuf __P((struct sk_if_softc *, + struct sk_chain *, struct mbuf *)); +static int sk_alloc_jumbo_mem __P((struct sk_if_softc *)); +static void *sk_jalloc __P((struct sk_if_softc *)); +static void sk_jfree __P((caddr_t, u_int)); +static void sk_jref __P((caddr_t, u_int)); +static int sk_init_rx_ring __P((struct sk_if_softc *)); +static void sk_init_tx_ring __P((struct sk_if_softc *)); +#ifdef notdef +static u_int32_t sk_win_read_4 __P((struct sk_softc *, int)); +#endif +static u_int16_t sk_win_read_2 __P((struct sk_softc *, int)); +static u_int8_t sk_win_read_1 __P((struct sk_softc *, int)); +static void sk_win_write_4 __P((struct sk_softc *, int, u_int32_t)); +static void sk_win_write_2 __P((struct sk_softc *, int, u_int32_t)); +static void sk_win_write_1 __P((struct sk_softc *, int, u_int32_t)); +static u_int8_t sk_vpd_readbyte __P((struct sk_softc *, int)); +static void sk_vpd_read_res __P((struct sk_softc *, + struct vpd_res *, int)); +static void sk_vpd_read __P((struct sk_softc *)); +static u_int16_t sk_phy_readreg __P((struct sk_if_softc *, int)); +static void sk_phy_writereg __P((struct sk_if_softc *, int, u_int32_t)); +static u_int32_t sk_calchash __P((caddr_t)); +static void sk_setfilt __P((struct sk_if_softc *, caddr_t, int)); +static void sk_setmulti __P((struct sk_if_softc *)); + +#ifdef __i386__ +#define SK_BUS_SPACE_MEM I386_BUS_SPACE_MEM +#define SK_BUS_SPACE_IO I386_BUS_SPACE_IO +#endif + +#ifdef __alpha__ +#define SK_BUS_SPACE_MEM ALPHA_BUS_SPACE_MEM +#define SK_BUS_SPACE_IO ALPHA_BUS_SPACE_IO +#endif + +#define SK_SETBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | x) + +#define SK_CLRBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~x) + +#define SK_WIN_SETBIT_4(sc, reg, x) \ + sk_win_write_4(sc, reg, sk_win_read_4(sc, reg) | x) + +#define SK_WIN_CLRBIT_4(sc, reg, x) \ + sk_win_write_4(sc, reg, sk_win_read_4(sc, reg) & ~x) + +#define SK_WIN_SETBIT_2(sc, reg, x) \ + sk_win_write_2(sc, reg, sk_win_read_2(sc, reg) | x) + +#define SK_WIN_CLRBIT_2(sc, reg, x) \ + sk_win_write_2(sc, reg, sk_win_read_2(sc, reg) & ~x) + +#ifdef notdef +static u_int32_t sk_win_read_4(sc, reg) + struct sk_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + return(CSR_READ_4(sc, SK_WIN_BASE + SK_REG(reg))); +} +#endif + +static u_int16_t sk_win_read_2(sc, reg) + struct sk_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + return(CSR_READ_2(sc, SK_WIN_BASE + SK_REG(reg))); +} + +static u_int8_t sk_win_read_1(sc, reg) + struct sk_softc *sc; + int reg; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + return(CSR_READ_1(sc, SK_WIN_BASE + SK_REG(reg))); +} + +static void sk_win_write_4(sc, reg, val) + struct sk_softc *sc; + int reg; + u_int32_t val; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + CSR_WRITE_4(sc, SK_WIN_BASE + SK_REG(reg), val); + return; +} + +static void sk_win_write_2(sc, reg, val) + struct sk_softc *sc; + int reg; + u_int32_t val; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + CSR_WRITE_2(sc, SK_WIN_BASE + SK_REG(reg), (u_int32_t)val); + return; +} + +static void sk_win_write_1(sc, reg, val) + struct sk_softc *sc; + int reg; + u_int32_t val; +{ + CSR_WRITE_4(sc, SK_RAP, SK_WIN(reg)); + CSR_WRITE_1(sc, SK_WIN_BASE + SK_REG(reg), val); + return; +} + +/* + * The VPD EEPROM contains Vital Product Data, as suggested in + * the PCI 2.1 specification. The VPD data is separared into areas + * denoted by resource IDs. The SysKonnect VPD contains an ID string + * resource (the name of the adapter), a read-only area resource + * containing various key/data fields and a read/write area which + * can be used to store asset management information or log messages. + * We read the ID string and read-only into buffers attached to + * the controller softc structure for later use. At the moment, + * we only use the ID string during sk_attach(). + */ +static u_int8_t sk_vpd_readbyte(sc, addr) + struct sk_softc *sc; + int addr; +{ + int i; + + sk_win_write_2(sc, SK_PCI_REG(SK_PCI_VPD_ADDR), addr); + for (i = 0; i < SK_TIMEOUT; i++) { + DELAY(1); + if (sk_win_read_2(sc, + SK_PCI_REG(SK_PCI_VPD_ADDR)) & SK_VPD_FLAG) + break; + } + + if (i == SK_TIMEOUT) + return(0); + + return(sk_win_read_1(sc, SK_PCI_REG(SK_PCI_VPD_DATA))); +} + +static void sk_vpd_read_res(sc, res, addr) + struct sk_softc *sc; + struct vpd_res *res; + int addr; +{ + int i; + u_int8_t *ptr; + + ptr = (u_int8_t *)res; + for (i = 0; i < sizeof(struct vpd_res); i++) + ptr[i] = sk_vpd_readbyte(sc, i + addr); + + return; +} + +static void sk_vpd_read(sc) + struct sk_softc *sc; +{ + int pos = 0, i; + struct vpd_res res; + + if (sc->sk_vpd_prodname != NULL) + free(sc->sk_vpd_prodname, M_DEVBUF); + if (sc->sk_vpd_readonly != NULL) + free(sc->sk_vpd_readonly, M_DEVBUF); + sc->sk_vpd_prodname = NULL; + sc->sk_vpd_readonly = NULL; + + sk_vpd_read_res(sc, &res, pos); + + if (res.vr_id != VPD_RES_ID) { + printf("skc%d: bad VPD resource id: expected %x got %x\n", + sc->sk_unit, VPD_RES_ID, res.vr_id); + return; + } + + pos += sizeof(res); + sc->sk_vpd_prodname = malloc(res.vr_len + 1, M_DEVBUF, M_NOWAIT); + for (i = 0; i < res.vr_len; i++) + sc->sk_vpd_prodname[i] = sk_vpd_readbyte(sc, i + pos); + sc->sk_vpd_prodname[i] = '\0'; + pos += i; + + sk_vpd_read_res(sc, &res, pos); + + if (res.vr_id != VPD_RES_READ) { + printf("skc%d: bad VPD resource id: expected %x got %x\n", + sc->sk_unit, VPD_RES_READ, res.vr_id); + return; + } + + pos += sizeof(res); + sc->sk_vpd_readonly = malloc(res.vr_len, M_DEVBUF, M_NOWAIT); + for (i = 0; i < res.vr_len + 1; i++) + sc->sk_vpd_readonly[i] = sk_vpd_readbyte(sc, i + pos); + + return; +} + +static u_int16_t sk_phy_readreg(sc_if, reg) + struct sk_if_softc *sc_if; + int reg; +{ + int i; + + SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg); + for (i = 0; i < SK_TIMEOUT; i++) { + if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) + break; + } + + if (i == SK_TIMEOUT) { + printf("sk%d: phy failed to come ready\n", sc_if->sk_unit); + return(0); + } + + return(SK_XM_READ_2(sc_if, XM_PHY_DATA)); +} + +static void sk_phy_writereg(sc_if, reg, val) + struct sk_if_softc *sc_if; + int reg; + u_int32_t val; +{ + int i; + + SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg); + for (i = 0; i < SK_TIMEOUT; i++) { + if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) + break; + } + + if (i == SK_TIMEOUT) { + printf("sk%d: phy failed to come ready\n", sc_if->sk_unit); + return; + } + + SK_XM_WRITE_2(sc_if, XM_PHY_DATA, val); + for (i = 0; i < SK_TIMEOUT; i++) { + if (!(SK_XM_READ_2(sc_if, XM_MMUCMD) & XM_MMUCMD_PHYBUSY)) + break; + } + + if (i == SK_TIMEOUT) + printf("sk%d: phy write timed out\n", sc_if->sk_unit); + + return; +} + +#define SK_POLY 0xEDB88320 +#define SK_BITS 6 + +static u_int32_t sk_calchash(addr) + caddr_t addr; +{ + u_int32_t idx, bit, data, crc; + + /* Compute CRC for the address value. */ + crc = 0xFFFFFFFF; /* initial value */ + + for (idx = 0; idx < 6; idx++) { + for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? SK_POLY : 0); + } + + return (~crc & ((1 << SK_BITS) - 1)); +} + +static void sk_setfilt(sc_if, addr, slot) + struct sk_if_softc *sc_if; + caddr_t addr; + int slot; +{ + int base; + + base = XM_RXFILT_ENTRY(slot); + + SK_XM_WRITE_2(sc_if, base, *(u_int16_t *)(&addr[0])); + SK_XM_WRITE_2(sc_if, base + 2, *(u_int16_t *)(&addr[2])); + SK_XM_WRITE_2(sc_if, base + 4, *(u_int16_t *)(&addr[4])); + + return; +} + +static void sk_setmulti(sc_if) + struct sk_if_softc *sc_if; +{ + struct ifnet *ifp; + u_int32_t hashes[2] = { 0, 0 }; + int h, i; + struct ifmultiaddr *ifma; + u_int8_t dummy[] = { 0, 0, 0, 0, 0 ,0 }; + + ifp = &sc_if->arpcom.ac_if; + + /* First, zot all the existing filters. */ + for (i = 1; i < XM_RXFILT_MAX; i++) + sk_setfilt(sc_if, (caddr_t)&dummy, i); + SK_XM_WRITE_4(sc_if, XM_MAR0, 0); + SK_XM_WRITE_4(sc_if, XM_MAR2, 0); + + /* Now program new ones. */ + if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { + hashes[0] = 0xFFFFFFFF; + hashes[1] = 0xFFFFFFFF; + } else { + i = 1; + /* First find the tail of the list. */ + for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; + ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_link.le_next == NULL) + break; + } + /* Now traverse the list backwards. */ + for (; ifma != NULL && ifma != (void *)&ifp->if_multiaddrs; + ifma = (struct ifmultiaddr *)ifma->ifma_link.le_prev) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + /* + * Program the first XM_RXFILT_MAX multicast groups + * into the perfect filter. For all others, + * use the hash table. + */ + if (i < XM_RXFILT_MAX) { + sk_setfilt(sc_if, + LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i); + i++; + continue; + } + + h = sk_calchash( + LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + } + } + + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_USE_HASH| + XM_MODE_RX_USE_PERFECT); + SK_XM_WRITE_4(sc_if, XM_MAR0, hashes[0]); + SK_XM_WRITE_4(sc_if, XM_MAR2, hashes[1]); + + return; +} + +static int sk_init_rx_ring(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_chain_data *cd; + struct sk_ring_data *rd; + int i; + + cd = &sc_if->sk_cdata; + rd = sc_if->sk_rdata; + + bzero((char *)rd->sk_rx_ring, + sizeof(struct sk_rx_desc) * SK_RX_RING_CNT); + + for (i = 0; i < SK_RX_RING_CNT; i++) { + cd->sk_rx_chain[i].sk_desc = &rd->sk_rx_ring[i]; + if (sk_newbuf(sc_if, &cd->sk_rx_chain[i], NULL) == ENOBUFS) + return(ENOBUFS); + if (i == (SK_RX_RING_CNT - 1)) { + cd->sk_rx_chain[i].sk_next = + &cd->sk_rx_chain[0]; + rd->sk_rx_ring[i].sk_next = + vtophys(&rd->sk_rx_ring[0]); + } else { + cd->sk_rx_chain[i].sk_next = + &cd->sk_rx_chain[i + 1]; + rd->sk_rx_ring[i].sk_next = + vtophys(&rd->sk_rx_ring[i + 1]); + } + } + + sc_if->sk_cdata.sk_rx_prod = 0; + sc_if->sk_cdata.sk_rx_cons = 0; + + return(0); +} + +static void sk_init_tx_ring(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_chain_data *cd; + struct sk_ring_data *rd; + int i; + + cd = &sc_if->sk_cdata; + rd = sc_if->sk_rdata; + + bzero((char *)sc_if->sk_rdata->sk_tx_ring, + sizeof(struct sk_tx_desc) * SK_TX_RING_CNT); + + for (i = 0; i < SK_TX_RING_CNT; i++) { + cd->sk_tx_chain[i].sk_desc = &rd->sk_tx_ring[i]; + if (i == (SK_TX_RING_CNT - 1)) { + cd->sk_tx_chain[i].sk_next = + &cd->sk_tx_chain[0]; + rd->sk_tx_ring[i].sk_next = + vtophys(&rd->sk_tx_ring[0]); + } else { + cd->sk_tx_chain[i].sk_next = + &cd->sk_tx_chain[i + 1]; + rd->sk_tx_ring[i].sk_next = + vtophys(&rd->sk_tx_ring[i + 1]); + } + } + + sc_if->sk_cdata.sk_tx_prod = 0; + sc_if->sk_cdata.sk_tx_cons = 0; + sc_if->sk_cdata.sk_tx_cnt = 0; + + return; +} + +static int sk_newbuf(sc_if, c, m) + struct sk_if_softc *sc_if; + struct sk_chain *c; + struct mbuf *m; +{ + struct mbuf *m_new = NULL; + struct sk_rx_desc *r; + + if (m == NULL) { + caddr_t *buf = NULL; + + MGETHDR(m_new, M_DONTWAIT, MT_DATA); + if (m_new == NULL) { + printf("sk%d: no memory for rx list -- " + "packet dropped!\n", sc_if->sk_unit); + return(ENOBUFS); + } + + /* Allocate the jumbo buffer */ + buf = sk_jalloc(sc_if); + if (buf == NULL) { + m_freem(m_new); +#ifdef SK_VERBOSE + printf("sk%d: jumbo allocation failed " + "-- packet dropped!\n", sc_if->sk_unit); +#endif + return(ENOBUFS); + } + + /* Attach the buffer to the mbuf */ + m_new->m_data = m_new->m_ext.ext_buf = (void *)buf; + m_new->m_flags |= M_EXT; + m_new->m_ext.ext_size = m_new->m_pkthdr.len = + m_new->m_len = SK_MCLBYTES; + m_new->m_ext.ext_free = sk_jfree; + m_new->m_ext.ext_ref = sk_jref; + } else { + /* + * We're re-using a previously allocated mbuf; + * be sure to re-init pointers and lengths to + * default values. + */ + m_new = m; + m_new->m_len = m_new->m_pkthdr.len = SK_MCLBYTES; + m_new->m_data = m_new->m_ext.ext_buf; + } + + /* + * Adjust alignment so packet payload begins on a + * longword boundary. Mandatory for Alpha, useful on + * x86 too. + */ + m_adj(m_new, ETHER_ALIGN); + + r = c->sk_desc; + c->sk_mbuf = m_new; + r->sk_data_lo = vtophys(mtod(m_new, caddr_t)); + r->sk_ctl = m_new->m_len | SK_RXSTAT; + + return(0); +} + +/* + * Allocate jumbo buffer storage. The SysKonnect adapters support + * "jumbograms" (9K frames), although SysKonnect doesn't currently + * use them in their drivers. In order for us to use them, we need + * large 9K receive buffers, however standard mbuf clusters are only + * 2048 bytes in size. Consequently, we need to allocate and manage + * our own jumbo buffer pool. Fortunately, this does not require an + * excessive amount of additional code. + */ +static int sk_alloc_jumbo_mem(sc_if) + struct sk_if_softc *sc_if; +{ + caddr_t ptr; + register int i; + struct sk_jpool_entry *entry; + + /* Grab a big chunk o' storage. */ + sc_if->sk_cdata.sk_jumbo_buf = contigmalloc(SK_JMEM, M_DEVBUF, + M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0); + + if (sc_if->sk_cdata.sk_jumbo_buf == NULL) { + printf("sk%d: no memory for jumbo buffers!\n", sc_if->sk_unit); + return(ENOBUFS); + } + + SLIST_INIT(&sc_if->sk_jfree_listhead); + SLIST_INIT(&sc_if->sk_jinuse_listhead); + + /* + * Now divide it up into 9K pieces and save the addresses + * in an array. Note that we play an evil trick here by using + * the first few bytes in the buffer to hold the the address + * of the softc structure for this interface. This is because + * sk_jfree() needs it, but it is called by the mbuf management + * code which will not pass it to us explicitly. + */ + ptr = sc_if->sk_cdata.sk_jumbo_buf; + for (i = 0; i < SK_JSLOTS; i++) { + u_int64_t **aptr; + aptr = (u_int64_t **)ptr; + aptr[0] = (u_int64_t *)sc_if; + ptr += sizeof(u_int64_t); + sc_if->sk_cdata.sk_jslots[i].sk_buf = ptr; + sc_if->sk_cdata.sk_jslots[i].sk_inuse = 0; + ptr += SK_MCLBYTES; + entry = malloc(sizeof(struct sk_jpool_entry), + M_DEVBUF, M_NOWAIT); + if (entry == NULL) { + free(sc_if->sk_cdata.sk_jumbo_buf, M_DEVBUF); + sc_if->sk_cdata.sk_jumbo_buf = NULL; + printf("sk%d: no memory for jumbo " + "buffer queue!\n", sc_if->sk_unit); + return(ENOBUFS); + } + entry->slot = i; + SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, + entry, jpool_entries); + } + + return(0); +} + +/* + * Allocate a jumbo buffer. + */ +static void *sk_jalloc(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_jpool_entry *entry; + + entry = SLIST_FIRST(&sc_if->sk_jfree_listhead); + + if (entry == NULL) { +#ifdef SK_VERBOSE + printf("sk%d: no free jumbo buffers\n", sc_if->sk_unit); +#endif + return(NULL); + } + + SLIST_REMOVE_HEAD(&sc_if->sk_jfree_listhead, jpool_entries); + SLIST_INSERT_HEAD(&sc_if->sk_jinuse_listhead, entry, jpool_entries); + sc_if->sk_cdata.sk_jslots[entry->slot].sk_inuse = 1; + return(sc_if->sk_cdata.sk_jslots[entry->slot].sk_buf); +} + +/* + * Adjust usage count on a jumbo buffer. In general this doesn't + * get used much because our jumbo buffers don't get passed around + * a lot, but it's implemented for correctness. + */ +static void sk_jref(buf, size) + caddr_t buf; + u_int size; +{ + struct sk_if_softc *sc_if; + u_int64_t **aptr; + register int i; + + /* Extract the softc struct pointer. */ + aptr = (u_int64_t **)(buf - sizeof(u_int64_t)); + sc_if = (struct sk_if_softc *)(aptr[0]); + + if (sc_if == NULL) + panic("sk_jref: can't find softc pointer!"); + + if (size != SK_MCLBYTES) + panic("sk_jref: adjusting refcount of buf of wrong size!"); + + /* calculate the slot this buffer belongs to */ + + i = ((vm_offset_t)aptr + - (vm_offset_t)sc_if->sk_cdata.sk_jumbo_buf) / SK_JLEN; + + if ((i < 0) || (i >= SK_JSLOTS)) + panic("sk_jref: asked to reference buffer " + "that we don't manage!"); + else if (sc_if->sk_cdata.sk_jslots[i].sk_inuse == 0) + panic("sk_jref: buffer already free!"); + else + sc_if->sk_cdata.sk_jslots[i].sk_inuse++; + + return; +} + +/* + * Release a jumbo buffer. + */ +static void sk_jfree(buf, size) + caddr_t buf; + u_int size; +{ + struct sk_if_softc *sc_if; + u_int64_t **aptr; + int i; + struct sk_jpool_entry *entry; + + /* Extract the softc struct pointer. */ + aptr = (u_int64_t **)(buf - sizeof(u_int64_t)); + sc_if = (struct sk_if_softc *)(aptr[0]); + + if (sc_if == NULL) + panic("sk_jfree: can't find softc pointer!"); + + if (size != SK_MCLBYTES) + panic("sk_jfree: freeing buffer of wrong size!"); + + /* calculate the slot this buffer belongs to */ + + i = ((vm_offset_t)aptr + - (vm_offset_t)sc_if->sk_cdata.sk_jumbo_buf) / SK_JLEN; + + if ((i < 0) || (i >= SK_JSLOTS)) + panic("sk_jfree: asked to free buffer that we don't manage!"); + else if (sc_if->sk_cdata.sk_jslots[i].sk_inuse == 0) + panic("sk_jfree: buffer already free!"); + else { + sc_if->sk_cdata.sk_jslots[i].sk_inuse--; + if(sc_if->sk_cdata.sk_jslots[i].sk_inuse == 0) { + entry = SLIST_FIRST(&sc_if->sk_jinuse_listhead); + if (entry == NULL) + panic("sk_jfree: buffer not in use!"); + entry->slot = i; + SLIST_REMOVE_HEAD(&sc_if->sk_jinuse_listhead, + jpool_entries); + SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, + entry, jpool_entries); + } + } + + return; +} + +/* + * Set media options. + */ +static int sk_ifmedia_upd(ifp) + struct ifnet *ifp; +{ + struct sk_if_softc *sc_if; + struct ifmedia *ifm; + + sc_if = ifp->if_softc; + ifm = &sc_if->ifmedia; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return(EINVAL); + + switch(IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + sk_phy_writereg(sc_if, XM_PHY_BMCR, + XM_BMCR_RENEGOTIATE|XM_BMCR_AUTONEGENBL); + break; + case IFM_1000_LX: + case IFM_1000_SX: + case IFM_1000_CX: + case IFM_1000_TX: + if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) + sk_phy_writereg(sc_if, XM_PHY_BMCR, XM_BMCR_DUPLEX); + else + sk_phy_writereg(sc_if, XM_PHY_BMCR, 0); + break; + default: + printf("sk%d: invalid media selected\n", sc_if->sk_unit); + return(EINVAL); + break; + } + + return(0); +} + +/* + * Report current media status. + */ +static void sk_ifmedia_sts(ifp, ifmr) + struct ifnet *ifp; + struct ifmediareq *ifmr; +{ + struct sk_softc *sc; + struct sk_if_softc *sc_if; + u_int16_t bmsr, extsts; + + sc_if = ifp->if_softc; + sc = sc_if->sk_softc; + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + bmsr = sk_phy_readreg(sc_if, XM_PHY_BMSR); + extsts = sk_phy_readreg(sc_if, XM_PHY_EXTSTS); + + if (!(bmsr & XM_BMSR_LINKSTAT)) + return; + + ifmr->ifm_status |= IFM_ACTIVE; + ifmr->ifm_active |= sc->sk_pmd;; + if (extsts & XM_EXTSTS_FULLDUPLEX) + ifmr->ifm_active |= IFM_FDX; + else + ifmr->ifm_active |= IFM_HDX; + + return; +} + +static int sk_ioctl(ifp, command, data) + struct ifnet *ifp; + u_long command; + caddr_t data; +{ + struct sk_if_softc *sc_if = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + int s, error = 0; + + s = splimp(); + + switch(command) { + case SIOCSIFADDR: + case SIOCGIFADDR: + error = ether_ioctl(ifp, command, data); + break; + case SIOCSIFMTU: + if (ifr->ifr_mtu > SK_JUMBO_MTU) + error = EINVAL; + else { + ifp->if_mtu = ifr->ifr_mtu; + sk_init(sc_if); + } + break; + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING && + ifp->if_flags & IFF_PROMISC && + !(sc_if->sk_if_flags & IFF_PROMISC)) { + SK_XM_SETBIT_4(sc_if, XM_MODE, + XM_MODE_RX_PROMISC); + sk_setmulti(sc_if); + } else if (ifp->if_flags & IFF_RUNNING && + !(ifp->if_flags & IFF_PROMISC) && + sc_if->sk_if_flags & IFF_PROMISC) { + SK_XM_CLRBIT_4(sc_if, XM_MODE, + XM_MODE_RX_PROMISC); + sk_setmulti(sc_if); + } else + sk_init(sc_if); + } else { + if (ifp->if_flags & IFF_RUNNING) + sk_stop(sc_if); + } + sc_if->sk_if_flags = ifp->if_flags; + error = 0; + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + sk_setmulti(sc_if); + error = 0; + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc_if->ifmedia, command); + break; + default: + error = EINVAL; + break; + } + + (void)splx(s); + + return(error); +} + +/* + * Probe for a SysKonnect GEnesis chip. Check the PCI vendor and device + * IDs against our list and return a device name if we find a match. + */ +static const char *sk_probe(config_id, device_id) + pcici_t config_id; + pcidi_t device_id; +{ + struct sk_type *t; + + t = sk_devs; + + while(t->sk_name != NULL) { + if ((device_id & 0xFFFF) == t->sk_vid && + ((device_id >> 16) & 0xFFFF) == t->sk_did) { + return(t->sk_name); + } + t++; + } + + return(NULL); +} + +/* + * Force the GEnesis into reset, then bring it out of reset. + */ +static void sk_reset(sc) + struct sk_softc *sc; +{ + CSR_WRITE_4(sc, SK_CSR, SK_CSR_SW_RESET); + CSR_WRITE_4(sc, SK_CSR, SK_CSR_MASTER_RESET); + DELAY(1000); + CSR_WRITE_4(sc, SK_CSR, SK_CSR_SW_UNRESET); + CSR_WRITE_4(sc, SK_CSR, SK_CSR_MASTER_UNRESET); + + /* Configure packet arbiter */ + sk_win_write_2(sc, SK_PKTARB_CTL, SK_PKTARBCTL_UNRESET); + sk_win_write_2(sc, SK_RXPA1_TINIT, SK_PKTARB_TIMEOUT); + sk_win_write_2(sc, SK_TXPA1_TINIT, SK_PKTARB_TIMEOUT); + sk_win_write_2(sc, SK_RXPA2_TINIT, SK_PKTARB_TIMEOUT); + sk_win_write_2(sc, SK_TXPA2_TINIT, SK_PKTARB_TIMEOUT); + + /* Enable RAM interface */ + sk_win_write_4(sc, SK_RAMCTL, SK_RAMCTL_UNRESET); + + /* + * Configure interrupt moderation. The moderation timer + * defers interrupts specified in the interrupt moderation + * timer mask based on the timeout specified in the interrupt + * moderation timer init register. Each bit in the timer + * register represents 18.825ns, so to specify a timeout in + * microseconds, we have to multiply by 54. + */ + sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(200)); + sk_win_write_4(sc, SK_IMMR, SK_ISR_TX1_S_EOF|SK_ISR_TX2_S_EOF| + SK_ISR_RX1_EOF|SK_ISR_RX2_EOF); + sk_win_write_1(sc, SK_IMTIMERCTL, SK_IMCTL_START); + + return; +} + +/* + * Each XMAC chip is attached as a separate logical IP interface. + * Single port cards will have only one logical interface of course. + */ +static int sk_attach_xmac(sc, port) + struct sk_softc *sc; + int port; +{ + struct sk_if_softc *sc_if; + struct ifnet *ifp; + int i; + + if (sc == NULL) + return(EINVAL); + + if (port != SK_PORT_A && port != SK_PORT_B) + return(EINVAL); + + sc_if = malloc(sizeof(struct sk_if_softc), M_DEVBUF, M_NOWAIT); + if (sc_if == NULL) { + printf("sk%d: no memory for interface softc!\n", sc->sk_unit); + return(ENOMEM); + } + bzero((char *)sc_if, sizeof(struct sk_if_softc)); + + sc_if->sk_unit = sk_count; + sc_if->sk_port = port; + sk_count++; + sc_if->sk_softc = sc; + sc->sk_if[port] = sc_if; + if (port == SK_PORT_A) + sc_if->sk_tx_bmu = SK_BMU_TXS_CSR0; + if (port == SK_PORT_B) + sc_if->sk_tx_bmu = SK_BMU_TXS_CSR1; + + /* + * Get station address for this interface. Note that + * dual port cards actually come with three station + * addresses: one for each port, plus an extra. The + * extra one is used by the SysKonnect driver software + * as a 'virtual' station address for when both ports + * are operating in failover mode. Currently we don't + * use this extra address. + */ + for (i = 0; i < ETHER_ADDR_LEN; i++) + sc_if->arpcom.ac_enaddr[i] = + sk_win_read_1(sc, SK_MAC0_0 + (port * 8) + i); + + printf("sk%d: <XaQti Corp. XMAC II> at skc%d port %d\n", + sc_if->sk_unit, sc->sk_unit, port); + + printf("sk%d: Ethernet address: %6D\n", + sc_if->sk_unit, sc_if->arpcom.ac_enaddr, ":"); + + /* + * Set up RAM buffer addresses. The NIC will have a certain + * amount of SRAM on it, somewhere between 512K and 2MB. We + * need to divide this up a) between the transmitter and + * receiver and b) between the two XMACs, if this is a + * dual port NIC. Our algotithm is to divide up the memory + * evenly so that everyone gets a fair share. + */ + if (sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC) { + u_int32_t chunk, val; + + chunk = sc->sk_ramsize / 2; + val = sc->sk_rboff / sizeof(u_int64_t); + sc_if->sk_rx_ramstart = val; + val += (chunk / sizeof(u_int64_t)); + sc_if->sk_rx_ramend = val - 1; + sc_if->sk_tx_ramstart = val; + val += (chunk / sizeof(u_int64_t)); + sc_if->sk_tx_ramend = val - 1; + } else { + u_int32_t chunk, val; + + chunk = sc->sk_ramsize / 4; + val = (sc->sk_rboff + (chunk * 2 * sc_if->sk_port)) / + sizeof(u_int64_t); + sc_if->sk_rx_ramstart = val; + val += (chunk / sizeof(u_int64_t)); + sc_if->sk_rx_ramend = val - 1; + sc_if->sk_tx_ramstart = val; + val += (chunk / sizeof(u_int64_t)); + sc_if->sk_tx_ramend = val - 1; + } + + /* Allocate the descriptor queues. */ + sc_if->sk_rdata = contigmalloc(sizeof(struct sk_ring_data), M_DEVBUF, + M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0); + + if (sc_if->sk_rdata == NULL) { + printf("sk%d: no memory for list buffers!\n", sc_if->sk_unit); + free(sc_if, M_DEVBUF); + sc->sk_if[port] = NULL; + return(ENOMEM); + } + + bzero(sc_if->sk_rdata, sizeof(struct sk_ring_data)); + + /* Try to allocate memory for jumbo buffers. */ + if (sk_alloc_jumbo_mem(sc_if)) { + printf("sk%d: jumbo buffer allocation failed\n", + sc_if->sk_unit); + free(sc_if->sk_rdata, M_DEVBUF); + free(sc_if, M_DEVBUF); + sc->sk_if[port] = NULL; + return(ENOMEM); + } + + ifp = &sc_if->arpcom.ac_if; + ifp->if_softc = sc_if; + ifp->if_unit = sc_if->sk_unit; + ifp->if_name = "sk"; + ifp->if_mtu = ETHERMTU; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = sk_ioctl; + ifp->if_output = ether_output; + ifp->if_start = sk_start; + ifp->if_watchdog = sk_watchdog; + ifp->if_init = sk_init; + ifp->if_baudrate = 1000000000; + ifp->if_snd.ifq_maxlen = SK_TX_RING_CNT - 1; + + /* + * Do ifmedia setup. + */ + ifmedia_init(&sc_if->ifmedia, 0, sk_ifmedia_upd, sk_ifmedia_sts); + ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd, 0, NULL); + ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd|IFM_FDX, 0, NULL); + ifmedia_add(&sc_if->ifmedia, IFM_ETHER|sc->sk_pmd|IFM_HDX, 0, NULL); + ifmedia_add(&sc_if->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); + ifmedia_set(&sc_if->ifmedia, IFM_ETHER|IFM_AUTO); + + /* + * Call MI attach routines. + */ + if_attach(ifp); + ether_ifattach(ifp); + +#if NBPF > 0 + bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + + return(0); +} + +/* + * Attach the interface. Allocate softc structures, do ifmedia + * setup and ethernet/BPF attach. + */ +static void +sk_attach(config_id, unit) + pcici_t config_id; + int unit; +{ + int s; +#ifndef SK_USEIOSPACE + vm_offset_t pbase, vbase; +#endif + u_int32_t command; + struct sk_softc *sc; + + s = splimp(); + + sc = malloc(sizeof(struct sk_softc), M_DEVBUF, M_NOWAIT); + if (sc == NULL) { + printf("skc%d: no memory for softc struct!\n", unit); + goto fail; + } + bzero(sc, sizeof(struct sk_softc)); + + /* + * Handle power management nonsense. + */ + command = pci_conf_read(config_id, SK_PCI_CAPID) & 0x000000FF; + if (command == 0x01) { + + command = pci_conf_read(config_id, SK_PCI_PWRMGMTCTRL); + if (command & SK_PSTATE_MASK) { + u_int32_t iobase, membase, irq; + + /* Save important PCI config data. */ + iobase = pci_conf_read(config_id, SK_PCI_LOIO); + membase = pci_conf_read(config_id, SK_PCI_LOMEM); + irq = pci_conf_read(config_id, SK_PCI_INTLINE); + + /* Reset the power state. */ + printf("skc%d: chip is in D%d power mode " + "-- setting to D0\n", unit, command & SK_PSTATE_MASK); + command &= 0xFFFFFFFC; + pci_conf_write(config_id, SK_PCI_PWRMGMTCTRL, command); + + /* Restore PCI config data. */ + pci_conf_write(config_id, SK_PCI_LOIO, iobase); + pci_conf_write(config_id, SK_PCI_LOMEM, membase); + pci_conf_write(config_id, SK_PCI_INTLINE, irq); + } + } + + /* + * Map control/status registers. + */ + command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); + command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); + pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); + command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); + +#ifdef SK_USEIOSPACE + if (!(command & PCIM_CMD_PORTEN)) { + printf("skc%d: failed to enable I/O ports!\n", unit); + free(sc, M_DEVBUF); + goto fail; + } + + if (!pci_map_port(config_id, SK_PCI_LOIO, + (u_short *)&(sc->sk_bhandle))) { + printf ("skc%d: couldn't map ports\n", unit); + goto fail; + } + + sc->sk_btag = SK_BUS_SPACE_IO; +#else + if (!(command & PCIM_CMD_MEMEN)) { + printf("skc%d: failed to enable memory mapping!\n", unit); + goto fail; + } + + if (!pci_map_mem(config_id, SK_PCI_LOMEM, &vbase, &pbase)) { + printf ("skc%d: couldn't map memory\n", unit); + goto fail; + } + sc->sk_btag = SK_BUS_SPACE_MEM; + sc->sk_bhandle = vbase; +#endif + + /* Allocate interrupt */ + if (!pci_map_int(config_id, sk_intr, sc, &net_imask)) { + printf("skc%d: couldn't map interrupt\n", unit); + goto fail; + } + + /* Save cache line size. */ + sc->sk_cachesize = pci_conf_read(config_id, SK_PCI_CACHELEN) & 0xFF; + + /* Reset the adapter. */ + sk_reset(sc); + + sc->sk_unit = unit; + + /* Read and save vital product data from EEPROM. */ + sk_vpd_read(sc); + + /* Read and save RAM size and RAMbuffer offset */ + switch(sk_win_read_1(sc, SK_EPROM0)) { + case SK_RAMSIZE_512K_64: + sc->sk_ramsize = 0x80000; + sc->sk_rboff = SK_RBOFF_80000; + break; + case SK_RAMSIZE_1024K_64: + sc->sk_ramsize = 0x100000; + sc->sk_rboff = SK_RBOFF_80000; + break; + case SK_RAMSIZE_1024K_128: + sc->sk_ramsize = 0x100000; + sc->sk_rboff = SK_RBOFF_0; + break; + case SK_RAMSIZE_2048K_128: + sc->sk_ramsize = 0x200000; + sc->sk_rboff = SK_RBOFF_0; + break; + default: + printf("skc%d: unknown ram size: %d\n", + sc->sk_unit, sk_win_read_1(sc, SK_EPROM0)); + goto fail; + break; + } + + /* Read and save physical media type */ + switch(sk_win_read_1(sc, SK_PMDTYPE)) { + case SK_PMD_1000BASESX: + sc->sk_pmd = IFM_1000_SX; + break; + case SK_PMD_1000BASELX: + sc->sk_pmd = IFM_1000_LX; + break; + case SK_PMD_1000BASECX: + sc->sk_pmd = IFM_1000_CX; + break; + case SK_PMD_1000BASETX: + sc->sk_pmd = IFM_1000_TX; + break; + default: + printf("skc%d: unknown media type: 0x%x\n", + sc->sk_unit, sk_win_read_1(sc, SK_PMDTYPE)); + goto fail; + } + + /* Announce the product name. */ + printf("skc%d: %s\n", sc->sk_unit, sc->sk_vpd_prodname); + + sk_attach_xmac(sc, SK_PORT_A); + if (!(sk_win_read_1(sc, SK_CONFIG) & SK_CONFIG_SINGLEMAC)) + sk_attach_xmac(sc, SK_PORT_B); + + /* Turn on the 'driver is loaded' LED. */ + CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_ON); + + at_shutdown(sk_shutdown, sc, SHUTDOWN_POST_SYNC); + +fail: + splx(s); + return; +} + +static int sk_encap(sc_if, m_head, txidx, curidx) + struct sk_if_softc *sc_if; + struct mbuf *m_head; + u_int32_t *txidx; + u_int32_t *curidx; +{ + struct sk_tx_desc *f = NULL; + struct mbuf *m; + u_int32_t frag, cur, cnt = 0; + + m = m_head; + cur = frag = *txidx; + + /* + * Start packing the mbufs in this chain into + * the fragment pointers. Stop when we run out + * of fragments or hit the end of the mbuf chain. + */ + for (m = m_head; m != NULL; m = m->m_next) { + if (m->m_len != 0) { + if ((SK_TX_RING_CNT - + (sc_if->sk_cdata.sk_tx_cnt + cnt)) < 2) + return(ENOBUFS); + f = &sc_if->sk_rdata->sk_tx_ring[frag]; + f->sk_data_lo = vtophys(mtod(m, vm_offset_t)); + f->sk_ctl = m->m_len | SK_OPCODE_DEFAULT; + if (cnt == 0) + f->sk_ctl |= SK_TXCTL_FIRSTFRAG; + else + f->sk_ctl |= SK_TXCTL_OWN; + cur = frag; + SK_INC(frag, SK_TX_RING_CNT); + cnt++; + } + } + + if (m != NULL) + return(ENOBUFS); + + sc_if->sk_rdata->sk_tx_ring[cur].sk_ctl |= SK_TXCTL_LASTFRAG; + sc_if->sk_cdata.sk_tx_chain[cur].sk_mbuf = m_head; + sc_if->sk_rdata->sk_tx_ring[*txidx].sk_ctl |= SK_TXCTL_OWN; + sc_if->sk_cdata.sk_tx_cnt += cnt; + + *txidx = frag; + *curidx = cur; + + return(0); +} + +static void sk_start(ifp) + struct ifnet *ifp; +{ + struct sk_softc *sc; + struct sk_if_softc *sc_if; + struct mbuf *m_head = NULL; + u_int32_t idx = 0, cur = 0; + + sc_if = ifp->if_softc; + sc = sc_if->sk_softc; + + idx = sc_if->sk_cdata.sk_tx_prod; + + while(sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf == NULL) { + IF_DEQUEUE(&ifp->if_snd, m_head); + if (m_head == NULL) + break; + + /* + * Pack the data into the transmit ring. If we + * don't have room, set the OACTIVE flag and wait + * for the NIC to drain the ring. + */ + if (sk_encap(sc_if, m_head, &idx, &cur)) { + IF_PREPEND(&ifp->if_snd, m_head); + ifp->if_flags |= IFF_OACTIVE; + break; + } + + /* + * If there's a BPF listener, bounce a copy of this frame + * to him. + */ +#if NBPF > 0 + if (ifp->if_bpf) + bpf_mtap(ifp, m_head); +#endif + } + + /* Transmit */ + sc_if->sk_cdata.sk_tx_prod = idx; + sc_if->sk_rdata->sk_tx_ring[cur].sk_ctl |= SK_TXCTL_EOF_INTR; + CSR_WRITE_4(sc, sc_if->sk_tx_bmu, SK_TXBMU_TX_START); + + /* Set a timeout in case the chip goes out to lunch. */ + ifp->if_timer = 5; + + return; +} + + +static void sk_watchdog(ifp) + struct ifnet *ifp; +{ + struct sk_if_softc *sc_if; + + sc_if = ifp->if_softc; + + printf("sk%d: watchdog timeout\n", sc_if->sk_unit); + sk_init(sc_if); + + return; +} + +static void sk_shutdown(howto, arg) + int howto; + void *arg; +{ + struct sk_softc *sc; + + sc = arg; + + /* Turn off the 'driver is loaded' LED. */ + CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_OFF); + + /* + * Reset the GEnesis controller. Doing this should also + * assert the resets on the attached XMAC(s). + */ + sk_reset(sc); + + return; +} + +static void sk_rxeof(sc_if) + struct sk_if_softc *sc_if; +{ + struct ether_header *eh; + struct mbuf *m; + struct ifnet *ifp; + struct sk_chain *cur_rx; + int total_len = 0; + int i; + u_int32_t rxstat; + + ifp = &sc_if->arpcom.ac_if; + i = sc_if->sk_cdata.sk_rx_prod; + cur_rx = &sc_if->sk_cdata.sk_rx_chain[i]; + + while(!(sc_if->sk_rdata->sk_rx_ring[i].sk_ctl & SK_RXCTL_OWN)) { + + cur_rx = &sc_if->sk_cdata.sk_rx_chain[i]; + rxstat = sc_if->sk_rdata->sk_rx_ring[i].sk_xmac_rxstat; + m = cur_rx->sk_mbuf; + cur_rx->sk_mbuf = NULL; + total_len = SK_RXBYTES(sc_if->sk_rdata->sk_rx_ring[i].sk_ctl); + SK_INC(i, SK_RX_RING_CNT); + + if (rxstat & XM_RXSTAT_ERRFRAME) { + ifp->if_ierrors++; + sk_newbuf(sc_if, cur_rx, m); + continue; + } + + /* + * Try to allocate a new jumbo buffer. If that + * fails, copy the packet to mbufs and put the + * jumbo buffer back in the ring so it can be + * re-used. If allocating mbufs fails, then we + * have to drop the packet. + */ + if (sk_newbuf(sc_if, cur_rx, NULL) == ENOBUFS) { + struct mbuf *m0; + m0 = m_devget(mtod(m, char *) - ETHER_ALIGN, + total_len + ETHER_ALIGN, 0, ifp, NULL); + sk_newbuf(sc_if, cur_rx, m); + if (m0 == NULL) { + printf("sk%d: no receive buffers " + "available -- packet dropped!\n", + sc_if->sk_unit); + ifp->if_ierrors++; + continue; + } + m_adj(m0, ETHER_ALIGN); + m = m0; + } else { + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = total_len; + } + + ifp->if_ipackets++; + eh = mtod(m, struct ether_header *); + +#if NBPF > 0 + if (ifp->if_bpf) { + bpf_mtap(ifp, m); + if (ifp->if_flags & IFF_PROMISC && + (bcmp(eh->ether_dhost, sc_if->arpcom.ac_enaddr, + ETHER_ADDR_LEN) && !(eh->ether_dhost[0] & 1))) { + m_freem(m); + continue; + } + } +#endif + /* Remove header from mbuf and pass it on. */ + m_adj(m, sizeof(struct ether_header)); + ether_input(ifp, eh, m); + } + + sc_if->sk_cdata.sk_rx_prod = i; + + return; +} + +static void sk_txeof(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_tx_desc *cur_tx = NULL; + struct ifnet *ifp; + u_int32_t idx; + + ifp = &sc_if->arpcom.ac_if; + + /* + * Go through our tx ring and free mbufs for those + * frames that have been sent. + */ + idx = sc_if->sk_cdata.sk_tx_cons; + while(idx != sc_if->sk_cdata.sk_tx_prod) { + cur_tx = &sc_if->sk_rdata->sk_tx_ring[idx]; + if (cur_tx->sk_ctl & SK_TXCTL_OWN) + break; + if (cur_tx->sk_ctl & SK_TXCTL_LASTFRAG) + ifp->if_opackets++; + if (sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf != NULL) { + m_freem(sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf); + sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf = NULL; + } + sc_if->sk_cdata.sk_tx_cnt--; + SK_INC(idx, SK_TX_RING_CNT); + ifp->if_timer = 0; + } + + sc_if->sk_cdata.sk_tx_cons = idx; + + if (cur_tx != NULL) + ifp->if_flags &= ~IFF_OACTIVE; + + return; +} + +static void sk_intr_xmac(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_softc *sc; + u_int16_t status; + u_int16_t bmsr; + + sc = sc_if->sk_softc; + status = SK_XM_READ_2(sc_if, XM_ISR); + + if (status & XM_ISR_LINKEVENT) { + SK_XM_SETBIT_2(sc_if, XM_IMR, XM_IMR_LINKEVENT); + if (sc_if->sk_link == 1) { + printf("sk%d: gigabit link down\n", sc_if->sk_unit); + sc_if->sk_link = 0; + } + } + + if (status & XM_ISR_AUTONEG_DONE) { + bmsr = sk_phy_readreg(sc_if, XM_PHY_BMSR); + if (bmsr & XM_BMSR_LINKSTAT) { + sc_if->sk_link = 1; + SK_XM_CLRBIT_2(sc_if, XM_IMR, XM_IMR_LINKEVENT); + printf("sk%d: gigabit link up\n", sc_if->sk_unit); + } + } + + if (status & XM_IMR_TX_UNDERRUN) + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_FLUSH_TXFIFO); + + if (status & XM_IMR_RX_OVERRUN) + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_FLUSH_RXFIFO); + + return; +} + +static void sk_intr(xsc) + void *xsc; +{ + struct sk_softc *sc = xsc; + struct sk_if_softc *sc_if0 = NULL, *sc_if1 = NULL; + struct ifnet *ifp0 = NULL, *ifp1 = NULL; + u_int32_t status; + + sc_if0 = sc->sk_if[SK_PORT_A]; + sc_if1 = sc->sk_if[SK_PORT_B]; + + if (sc_if0 != NULL) + ifp0 = &sc_if0->arpcom.ac_if; + if (sc_if1 != NULL) + ifp1 = &sc_if0->arpcom.ac_if; + + for (;;) { + status = CSR_READ_4(sc, SK_ISSR); + if (!(status & sc->sk_intrmask)) + break; + + /* Handle receive interrupts first. */ + if (status & SK_ISR_RX1_EOF) { + sk_rxeof(sc_if0); + CSR_WRITE_4(sc, SK_BMU_RX_CSR0, + SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START); + } + if (status & SK_ISR_RX2_EOF) { + sk_rxeof(sc_if1); + CSR_WRITE_4(sc, SK_BMU_RX_CSR1, + SK_RXBMU_CLR_IRQ_EOF|SK_RXBMU_RX_START); + } + + /* Then transmit interrupts. */ + if (status & SK_ISR_TX1_S_EOF) { + sk_txeof(sc_if0); + CSR_WRITE_4(sc, SK_BMU_TXS_CSR0, + SK_TXBMU_CLR_IRQ_EOF); + } + if (status & SK_ISR_TX2_S_EOF) { + sk_txeof(sc_if1); + CSR_WRITE_4(sc, SK_BMU_TXS_CSR1, + SK_TXBMU_CLR_IRQ_EOF); + } + + /* Then MAC interrupts. */ + if (status & SK_ISR_MAC1) + sk_intr_xmac(sc_if0); + + if (status & SK_ISR_MAC2) + sk_intr_xmac(sc_if1); + } + + CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); + + return; +} + +static void sk_init_xmac(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_softc *sc; + struct ifnet *ifp; + + sc = sc_if->sk_softc; + ifp = &sc_if->arpcom.ac_if; + + /* Unreset the XMAC. */ + SK_IF_WRITE_2(sc_if, 0, SK_TXF1_MACCTL, SK_TXMACCTL_XMAC_UNRESET); + DELAY(1000); + + /* Save the XMAC II revision */ + sc_if->sk_xmac_rev = XM_XMAC_REV(SK_XM_READ_4(sc_if, XM_DEVID)); + + /* Set station address */ + SK_XM_WRITE_2(sc_if, XM_PAR0, + *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[0])); + SK_XM_WRITE_2(sc_if, XM_PAR1, + *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[2])); + SK_XM_WRITE_2(sc_if, XM_PAR2, + *(u_int16_t *)(&sc_if->arpcom.ac_enaddr[4])); + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_USE_STATION); + + if (ifp->if_flags & IFF_PROMISC) { + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_PROMISC); + } else { + SK_XM_CLRBIT_4(sc_if, XM_MODE, XM_MODE_RX_PROMISC); + } + + if (ifp->if_flags & IFF_BROADCAST) { + SK_XM_CLRBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD); + } else { + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_NOBROAD); + } + + /* We don't need the FCS appended to the packet. */ + SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_STRIPFCS); + + /* We want short frames padded to 60 bytes. */ + SK_XM_SETBIT_2(sc_if, XM_TXCMD, XM_TXCMD_AUTOPAD); + + /* + * Enable the reception of all error frames. This is is + * a necessary evil due to the design of the XMAC. The + * XMAC's receive FIFO is only 8K in size, however jumbo + * frames can be up to 9000 bytes in length. When bad + * frame filtering is enabled, the XMAC's RX FIFO operates + * in 'store and forward' mode. For this to work, the + * entire frame has to fit into the FIFO, but that means + * that jumbo frames larger than 8192 bytes will be + * truncated. Disabling all bad frame filtering causes + * the RX FIFO to operate in streaming mode, in which + * case the XMAC will start transfering frames out of the + * RX FIFO as soon as the FIFO threshold is reached. + */ + SK_XM_SETBIT_4(sc_if, XM_MODE, XM_MODE_RX_BADFRAMES| + XM_MODE_RX_GIANTS|XM_MODE_RX_RUNTS|XM_MODE_RX_CRCERRS| + XM_MODE_RX_INRANGELEN); + + if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN)) + SK_XM_SETBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK); + else + SK_XM_CLRBIT_2(sc_if, XM_RXCMD, XM_RXCMD_BIGPKTOK); + + /* + * Bump up the transmit threshold. This helps hold off transmit + * underruns when we're blasting traffic from both ports at once. + */ + SK_XM_WRITE_2(sc_if, XM_TX_REQTHRESH, SK_XM_TX_FIFOTHRESH); + + /* Set multicast filter */ + sk_setmulti(sc_if); + + /* Clear and enable interrupts */ + SK_XM_READ_2(sc_if, XM_ISR); + SK_XM_WRITE_2(sc_if, XM_IMR, XM_INTRS); + + sc_if->sk_link = 0; + + /* Configure MAC arbiter */ + switch(sc_if->sk_xmac_rev) { + case XM_XMAC_REV_B2: + sk_win_write_1(sc, SK_RCINIT_RX1, SK_RCINIT_XMAC_B2); + sk_win_write_1(sc, SK_RCINIT_TX1, SK_RCINIT_XMAC_B2); + sk_win_write_1(sc, SK_RCINIT_RX2, SK_RCINIT_XMAC_B2); + sk_win_write_1(sc, SK_RCINIT_TX2, SK_RCINIT_XMAC_B2); + sk_win_write_1(sc, SK_MINIT_RX1, SK_MINIT_XMAC_B2); + sk_win_write_1(sc, SK_MINIT_TX1, SK_MINIT_XMAC_B2); + sk_win_write_1(sc, SK_MINIT_RX2, SK_MINIT_XMAC_B2); + sk_win_write_1(sc, SK_MINIT_TX2, SK_MINIT_XMAC_B2); + sk_win_write_1(sc, SK_RECOVERY_CTL, SK_RECOVERY_XMAC_B2); + break; + case XM_XMAC_REV_C1: + sk_win_write_1(sc, SK_RCINIT_RX1, SK_RCINIT_XMAC_C1); + sk_win_write_1(sc, SK_RCINIT_TX1, SK_RCINIT_XMAC_C1); + sk_win_write_1(sc, SK_RCINIT_RX2, SK_RCINIT_XMAC_C1); + sk_win_write_1(sc, SK_RCINIT_TX2, SK_RCINIT_XMAC_C1); + sk_win_write_1(sc, SK_MINIT_RX1, SK_MINIT_XMAC_C1); + sk_win_write_1(sc, SK_MINIT_TX1, SK_MINIT_XMAC_C1); + sk_win_write_1(sc, SK_MINIT_RX2, SK_MINIT_XMAC_C1); + sk_win_write_1(sc, SK_MINIT_TX2, SK_MINIT_XMAC_C1); + sk_win_write_1(sc, SK_RECOVERY_CTL, SK_RECOVERY_XMAC_B2); + break; + default: + break; + } + sk_win_write_2(sc, SK_MACARB_CTL, + SK_MACARBCTL_UNRESET|SK_MACARBCTL_FASTOE_OFF); + + return; +} + +/* + * Note that to properly initialize any part of the GEnesis chip, + * you first have to take it out of reset mode. + */ +static void sk_init(xsc) + void *xsc; +{ + struct sk_if_softc *sc_if = xsc; + struct sk_softc *sc; + struct ifnet *ifp; + int s; + + s = splimp(); + + ifp = &sc_if->arpcom.ac_if; + sc = sc_if->sk_softc; + + /* Cancel pending I/O and free all RX/TX buffers. */ + sk_stop(sc_if); + + /* Configure LINK_SYNC LED */ + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_ON); + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_LINKSYNC_ON); + + /* Configure RX LED */ + SK_IF_WRITE_1(sc_if, 0, SK_RXLED1_CTL, SK_RXLEDCTL_COUNTER_START); + + /* Configure TX LED */ + SK_IF_WRITE_1(sc_if, 0, SK_TXLED1_CTL, SK_TXLEDCTL_COUNTER_START); + + /* Configure I2C registers */ + + /* Configure XMAC(s) */ + sk_init_xmac(sc_if); + + /* Configure MAC FIFOs */ + SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_UNRESET); + SK_IF_WRITE_4(sc_if, 0, SK_RXF1_END, SK_FIFO_END); + SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_ON); + + SK_IF_WRITE_4(sc_if, 0, SK_TXF1_CTL, SK_FIFO_UNRESET); + SK_IF_WRITE_4(sc_if, 0, SK_TXF1_END, SK_FIFO_END); + SK_IF_WRITE_4(sc_if, 0, SK_TXF1_CTL, SK_FIFO_ON); + + /* Configure transmit arbiter(s) */ + SK_IF_WRITE_1(sc_if, 0, SK_TXAR1_COUNTERCTL, + SK_TXARCTL_ON|SK_TXARCTL_FSYNC_ON); + + /* Configure RAMbuffers */ + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_UNRESET); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_START, sc_if->sk_rx_ramstart); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_WR_PTR, sc_if->sk_rx_ramstart); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_RD_PTR, sc_if->sk_rx_ramstart); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_END, sc_if->sk_rx_ramend); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_ON); + + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_UNRESET); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_STORENFWD_ON); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_START, sc_if->sk_tx_ramstart); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_WR_PTR, sc_if->sk_tx_ramstart); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_RD_PTR, sc_if->sk_tx_ramstart); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_END, sc_if->sk_tx_ramend); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_ON); + + /* Configure BMUs */ + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_ONLINE); + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_LO, + vtophys(&sc_if->sk_rdata->sk_rx_ring[0])); + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_CURADDR_HI, 0); + + SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_BMU_CSR, SK_TXBMU_ONLINE); + SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_LO, + vtophys(&sc_if->sk_rdata->sk_tx_ring[0])); + SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_CURADDR_HI, 0); + + /* Init descriptors */ + if (sk_init_rx_ring(sc_if) == ENOBUFS) { + printf("sk%d: initialization failed: no " + "memory for rx buffers\n", sc_if->sk_unit); + sk_stop(sc_if); + (void)splx(s); + return; + } + sk_init_tx_ring(sc_if); + + /* Configure interrupt handling */ + CSR_READ_4(sc, SK_ISSR); + if (sc_if->sk_port == SK_PORT_A) + sc->sk_intrmask |= SK_INTRS1; + else + sc->sk_intrmask |= SK_INTRS2; + CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); + + /* Start BMUs. */ + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_RX_START); + + /* Enable XMACs TX and RX state machines */ + SK_XM_SETBIT_2(sc_if, XM_MMUCMD, XM_MMUCMD_TX_ENB|XM_MMUCMD_RX_ENB); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + splx(s); + + return; +} + +static void sk_stop(sc_if) + struct sk_if_softc *sc_if; +{ + int i; + struct sk_softc *sc; + + sc = sc_if->sk_softc; + + /* Turn off various components of this interface. */ + SK_IF_WRITE_2(sc_if, 0, SK_TXF1_MACCTL, SK_TXMACCTL_XMAC_RESET); + SK_IF_WRITE_4(sc_if, 0, SK_RXF1_CTL, SK_FIFO_RESET); + SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_OFFLINE); + SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_RESET|SK_RBCTL_OFF); + SK_IF_WRITE_4(sc_if, 1, SK_TXQS1_BMU_CSR, SK_TXBMU_OFFLINE); + SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_RESET|SK_RBCTL_OFF); + SK_IF_WRITE_1(sc_if, 0, SK_TXAR1_COUNTERCTL, SK_TXARCTL_OFF); + SK_IF_WRITE_1(sc_if, 0, SK_RXLED1_CTL, SK_RXLEDCTL_COUNTER_STOP); + SK_IF_WRITE_1(sc_if, 0, SK_TXLED1_CTL, SK_RXLEDCTL_COUNTER_STOP); + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_OFF); + SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_LINKSYNC_OFF); + + /* Disable interrupts */ + if (sc_if->sk_port == SK_PORT_A) + sc->sk_intrmask &= ~SK_INTRS1; + else + sc->sk_intrmask &= ~SK_INTRS2; + CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask); + + /* Free RX and TX mbufs still in the queues. */ + for (i = 0; i < SK_RX_RING_CNT; i++) { + if (sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf != NULL) { + m_freem(sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf); + sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf = NULL; + } + } + + for (i = 0; i < SK_TX_RING_CNT; i++) { + if (sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf != NULL) { + m_freem(sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf); + sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf = NULL; + } + } + + return; +} + +static struct pci_device sk_device = { + "skc", + sk_probe, + sk_attach, + &skc_count, + NULL +}; +COMPAT_PCI_DRIVER(sk, sk_device); diff --git a/sys/pci/if_skreg.h b/sys/pci/if_skreg.h new file mode 100644 index 0000000..e5dca1c --- /dev/null +++ b/sys/pci/if_skreg.h @@ -0,0 +1,1172 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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: if_skreg.h,v 1.32 1999/07/06 22:07:40 wpaul Exp $ + */ + +/* + * SysKonnect PCI vendor ID + */ +#define SK_VENDORID 0x1148 + +/* + * SK-NET gigabit ethernet device ID + */ +#define SK_DEVICEID_GE 0x4300 + +/* + * GEnesis registers. The GEnesis chip has a 256-byte I/O window + * but internally it has a 16K register space. This 16K space is + * divided into 128-byte blocks. The first 128 bytes of the I/O + * window represent the first block, which is permanently mapped + * at the start of the window. The other 127 blocks can be mapped + * to the second 128 bytes of the I/O window by setting the desired + * block value in the RAP register in block 0. Not all of the 127 + * blocks are actually used. Most registers are 32 bits wide, but + * there are a few 16-bit and 8-bit ones as well. + */ + + +/* Start of remappable register window. */ +#define SK_WIN_BASE 0x0080 + +/* Size of a window */ +#define SK_WIN_LEN 0x80 + +#define SK_WIN_MASK 0x3F80 +#define SK_REG_MASK 0x7F + +/* Compute the window of a given register (for the RAP register) */ +#define SK_WIN(reg) (((reg) & SK_WIN_MASK) / SK_WIN_LEN) + +/* Compute the relative offset of a register within the window */ +#define SK_REG(reg) ((reg) & SK_REG_MASK) + +#define SK_PORT_A 0 +#define SK_PORT_B 1 + +/* + * Compute offset of port-specific register. Since there are two + * ports, there are two of some GEnesis modules (e.g. two sets of + * DMA queues, two sets of FIFO control registers, etc...). Normally, + * the block for port 0 is at offset 0x0 and the block for port 1 is + * at offset 0x80 (i.e. the next page over). However for the transmit + * BMUs and RAMbuffers, there are two blocks for each port: one for + * the sync transmit queue and one for the async queue (which we don't + * use). However instead of ordering them like this: + * TX sync 1 / TX sync 2 / TX async 1 / TX async 2 + * SysKonnect has instead ordered them like this: + * TX sync 1 / TX async 1 / TX sync 2 / TX async 2 + * This means that when referencing the TX BMU and RAMbuffer registers, + * we have to double the block offset (0x80 * 2) in order to reach the + * second queue. This prevents us from using the same formula + * (sk_port * 0x80) to compute the offsets for all of the port-specific + * blocks: we need an extra offset for the BMU and RAMbuffer registers. + * The simplest thing is to provide an extra argument to these macros: + * the 'skip' parameter. The 'skip' value is the number of extra pages + * for skip when computing the port0/port1 offsets. For most registers, + * the skip value is 0; for the BMU and RAMbuffer registers, it's 1. + */ +#define SK_IF_READ_4(sc_if, skip, reg) \ + sk_win_read_4(sc_if->sk_softc, reg + \ + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN)) +#define SK_IF_READ_2(sc_if, skip, reg) \ + sk_win_read_2(sc_if->sk_softc, reg + \ + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN)) +#define SK_IF_READ_1(sc_if, skip, reg) \ + sk_win_read_1(sc_if->sk_softc, reg + \ + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN)) + +#define SK_IF_WRITE_4(sc_if, skip, reg, val) \ + sk_win_write_4(sc_if->sk_softc, \ + reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val) +#define SK_IF_WRITE_2(sc_if, skip, reg, val) \ + sk_win_write_2(sc_if->sk_softc, \ + reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val) +#define SK_IF_WRITE_1(sc_if, skip, reg, val) \ + sk_win_write_1(sc_if->sk_softc, \ + reg + ((sc_if->sk_port * (skip + 1)) * SK_WIN_LEN), val) + +/* Block 0 registers, permanently mapped at iobase. */ +#define SK_RAP 0x0000 +#define SK_CSR 0x0004 +#define SK_LED 0x0006 +#define SK_ISR 0x0008 /* interrupt source */ +#define SK_IMR 0x000C /* interrupt mask */ +#define SK_IESR 0x0010 /* interrupt hardware error source */ +#define SK_IEMR 0x0014 /* interrupt hardware error mask */ +#define SK_ISSR 0x0018 /* special interrupt source */ +#define SK_XM_IMR0 0x0020 +#define SK_XM_ISR0 0x0028 +#define SK_XM_PHYADDR0 0x0030 +#define SK_XM_PHYDATA0 0x0034 +#define SK_XM_IMR1 0x0040 +#define SK_XM_ISR1 0x0048 +#define SK_XM_PHYADDR1 0x0050 +#define SK_XM_PHYDATA1 0x0054 +#define SK_BMU_RX_CSR0 0x0060 +#define SK_BMU_RX_CSR1 0x0064 +#define SK_BMU_TXS_CSR0 0x0068 +#define SK_BMU_TXA_CSR0 0x006C +#define SK_BMU_TXS_CSR1 0x0070 +#define SK_BMU_TXA_CSR1 0x0074 + +/* SK_CSR register */ +#define SK_CSR_SW_RESET 0x0001 +#define SK_CSR_SW_UNRESET 0x0002 +#define SK_CSR_MASTER_RESET 0x0004 +#define SK_CSR_MASTER_UNRESET 0x0008 +#define SK_CSR_MASTER_STOP 0x0010 +#define SK_CSR_MASTER_DONE 0x0020 +#define SK_CSR_SW_IRQ_CLEAR 0x0040 +#define SK_CSR_SW_IRQ_SET 0x0080 +#define SK_CSR_SLOTSIZE 0x0100 /* 1 == 64 bits, 0 == 32 */ +#define SK_CSR_BUSCLOCK 0x0200 /* 1 == 33/66 Mhz, = 33 */ + +/* SK_LED register */ +#define SK_LED_GREEN_OFF 0x01 +#define SK_LED_GREEN_ON 0x02 + +/* SK_ISR register */ +#define SK_ISR_TX2_AS_CHECK 0x00000001 +#define SK_ISR_TX2_AS_EOF 0x00000002 +#define SK_ISR_TX2_AS_EOB 0x00000004 +#define SK_ISR_TX2_S_CHECK 0x00000008 +#define SK_ISR_TX2_S_EOF 0x00000010 +#define SK_ISR_TX2_S_EOB 0x00000020 +#define SK_ISR_TX1_AS_CHECK 0x00000040 +#define SK_ISR_TX1_AS_EOF 0x00000080 +#define SK_ISR_TX1_AS_EOB 0x00000100 +#define SK_ISR_TX1_S_CHECK 0x00000200 +#define SK_ISR_TX1_S_EOF 0x00000400 +#define SK_ISR_TX1_S_EOB 0x00000800 +#define SK_ISR_RX2_CHECK 0x00001000 +#define SK_ISR_RX2_EOF 0x00002000 +#define SK_ISR_RX2_EOB 0x00004000 +#define SK_ISR_RX1_CHECK 0x00008000 +#define SK_ISR_RX1_EOF 0x00010000 +#define SK_ISR_RX1_EOB 0x00020000 +#define SK_ISR_LINK2_OFLOW 0x00040000 +#define SK_ISR_MAC2 0x00080000 +#define SK_ISR_LINK1_OFLOW 0x00100000 +#define SK_ISR_MAC1 0x00200000 +#define SK_ISR_TIMER 0x00400000 +#define SK_ISR_EXTERNAL_REG 0x00800000 +#define SK_ISR_SW 0x01000000 +#define SK_ISR_I2C_RDY 0x02000000 +#define SK_ISR_TX2_TIMEO 0x04000000 +#define SK_ISR_TX1_TIMEO 0x08000000 +#define SK_ISR_RX2_TIMEO 0x10000000 +#define SK_ISR_RX1_TIMEO 0x20000000 +#define SK_ISR_RSVD 0x40000000 +#define SK_ISR_HWERR 0x80000000 + +/* SK_IMR register */ +#define SK_IMR_TX2_AS_CHECK 0x00000001 +#define SK_IMR_TX2_AS_EOF 0x00000002 +#define SK_IMR_TX2_AS_EOB 0x00000004 +#define SK_IMR_TX2_S_CHECK 0x00000008 +#define SK_IMR_TX2_S_EOF 0x00000010 +#define SK_IMR_TX2_S_EOB 0x00000020 +#define SK_IMR_TX1_AS_CHECK 0x00000040 +#define SK_IMR_TX1_AS_EOF 0x00000080 +#define SK_IMR_TX1_AS_EOB 0x00000100 +#define SK_IMR_TX1_S_CHECK 0x00000200 +#define SK_IMR_TX1_S_EOF 0x00000400 +#define SK_IMR_TX1_S_EOB 0x00000800 +#define SK_IMR_RX2_CHECK 0x00001000 +#define SK_IMR_RX2_EOF 0x00002000 +#define SK_IMR_RX2_EOB 0x00004000 +#define SK_IMR_RX1_CHECK 0x00008000 +#define SK_IMR_RX1_EOF 0x00010000 +#define SK_IMR_RX1_EOB 0x00020000 +#define SK_IMR_LINK2_OFLOW 0x00040000 +#define SK_IMR_MAC2 0x00080000 +#define SK_IMR_LINK1_OFLOW 0x00100000 +#define SK_IMR_MAC1 0x00200000 +#define SK_IMR_TIMER 0x00400000 +#define SK_IMR_EXTERNAL_REG 0x00800000 +#define SK_IMR_SW 0x01000000 +#define SK_IMR_I2C_RDY 0x02000000 +#define SK_IMR_TX2_TIMEO 0x04000000 +#define SK_IMR_TX1_TIMEO 0x08000000 +#define SK_IMR_RX2_TIMEO 0x10000000 +#define SK_IMR_RX1_TIMEO 0x20000000 +#define SK_IMR_RSVD 0x40000000 +#define SK_IMR_HWERR 0x80000000 + +#define SK_INTRS1 \ + (SK_IMR_RX1_EOF|SK_IMR_TX1_S_EOF|SK_IMR_MAC1) + +#define SK_INTRS2 \ + (SK_IMR_RX2_EOF|SK_IMR_TX2_S_EOF|SK_IMR_MAC2) + +/* SK_IESR register */ +#define SK_IESR_PAR_RX2 0x00000001 +#define SK_IESR_PAR_RX1 0x00000002 +#define SK_IESR_PAR_MAC2 0x00000004 +#define SK_IESR_PAR_MAC1 0x00000008 +#define SK_IESR_PAR_WR_RAM 0x00000010 +#define SK_IESR_PAR_RD_RAM 0x00000020 +#define SK_IESR_NO_TSTAMP_MAC2 0x00000040 +#define SK_IESR_NO_TSTAMO_MAC1 0x00000080 +#define SK_IESR_NO_STS_MAC2 0x00000100 +#define SK_IESR_NO_STS_MAC1 0x00000200 +#define SK_IESR_IRQ_STS 0x00000400 +#define SK_IESR_MASTERERR 0x00000800 + +/* SK_IEMR register */ +#define SK_IEMR_PAR_RX2 0x00000001 +#define SK_IEMR_PAR_RX1 0x00000002 +#define SK_IEMR_PAR_MAC2 0x00000004 +#define SK_IEMR_PAR_MAC1 0x00000008 +#define SK_IEMR_PAR_WR_RAM 0x00000010 +#define SK_IEMR_PAR_RD_RAM 0x00000020 +#define SK_IEMR_NO_TSTAMP_MAC2 0x00000040 +#define SK_IEMR_NO_TSTAMO_MAC1 0x00000080 +#define SK_IEMR_NO_STS_MAC2 0x00000100 +#define SK_IEMR_NO_STS_MAC1 0x00000200 +#define SK_IEMR_IRQ_STS 0x00000400 +#define SK_IEMR_MASTERERR 0x00000800 + +/* Block 2 */ +#define SK_MAC0_0 0x0100 +#define SK_MAC0_1 0x0104 +#define SK_MAC1_0 0x0108 +#define SK_MAC1_1 0x010C +#define SK_MAC2_0 0x0110 +#define SK_MAC2_1 0x0114 +#define SK_CONNTYPE 0x0118 +#define SK_PMDTYPE 0x0119 +#define SK_CONFIG 0x011A +#define SK_CHIPVER 0x011B +#define SK_EPROM0 0x011C +#define SK_EPROM1 0x011D +#define SK_EPROM2 0x011E +#define SK_EPROM3 0x011F +#define SK_EP_ADDR 0x0120 +#define SK_EP_DATA 0x0124 +#define SK_EP_LOADCTL 0x0128 +#define SK_EP_LOADTST 0x0129 +#define SK_TIMERINIT 0x0130 +#define SK_TIMER 0x0134 +#define SK_TIMERCTL 0x0138 +#define SK_TIMERTST 0x0139 +#define SK_IMTIMERINIT 0x0140 +#define SK_IMTIMER 0x0144 +#define SK_IMTIMERCTL 0x0148 +#define SK_IMTIMERTST 0x0149 +#define SK_IMMR 0x014C +#define SK_IHWEMR 0x0150 +#define SK_TESTCTL1 0x0158 +#define SK_TESTCTL2 0x0159 +#define SK_GPIO 0x015C +#define SK_I2CHWCTL 0x0160 +#define SK_I2CHWDATA 0x0164 +#define SK_I2CHWIRQ 0x0168 +#define SK_I2CSW 0x016C +#define SK_BLNKINIT 0x0170 +#define SK_BLNKCOUNT 0x0174 +#define SK_BLNKCTL 0x0178 +#define SK_BLNKSTS 0x0179 +#define SK_BLNKTST 0x017A + +#define SK_IMCTL_STOP 0x02 +#define SK_IMCTL_START 0x04 + +#define SK_IMTIMER_TICKS 54 +#define SK_IM_USECS(x) ((x) * SK_IMTIMER_TICKS) + +/* + * The SK_EPROM0 register contains a byte that describes the + * amount of SRAM mounted on the NIC. The value also tells if + * the chips are 64K or 128K. This affects the RAMbuffer address + * offset that we need to use. + */ +#define SK_RAMSIZE_512K_64 0x1 +#define SK_RAMSIZE_1024K_128 0x2 +#define SK_RAMSIZE_1024K_64 0x3 +#define SK_RAMSIZE_2048K_128 0x4 + +#define SK_RBOFF_0 0x0 +#define SK_RBOFF_80000 0x80000 + +#define SK_CONFIG_SINGLEMAC 0x01 +#define SK_CONFIG_DIS_DSL_CLK 0x02 + +#define SK_PMD_1000BASELX 0x4C +#define SK_PMD_1000BASESX 0x53 +#define SK_PMD_1000BASECX 0x43 +#define SK_PMD_1000BASETX 0x54 + +/* Block 3 Ram interface and MAC arbiter registers */ +#define SK_RAMADDR 0x0180 +#define SK_RAMDATA0 0x0184 +#define SK_RAMDATA1 0x0188 +#define SK_TO0 0x0190 +#define SK_TO1 0x0191 +#define SK_TO2 0x0192 +#define SK_TO3 0x0193 +#define SK_TO4 0x0194 +#define SK_TO5 0x0195 +#define SK_TO6 0x0196 +#define SK_TO7 0x0197 +#define SK_TO8 0x0198 +#define SK_TO9 0x0199 +#define SK_TO10 0x019A +#define SK_TO11 0x019B +#define SK_RITIMEO_TMR 0x019C +#define SK_RAMCTL 0x01A0 +#define SK_RITIMER_TST 0x01A2 + +#define SK_RAMCTL_RESET 0x0001 +#define SK_RAMCTL_UNRESET 0x0002 +#define SK_RAMCTL_CLR_IRQ_WPAR 0x0100 +#define SK_RAMCTL_CLR_IRQ_RPAR 0x0200 + +/* Mac arbiter registers */ +#define SK_MINIT_RX1 0x01B0 +#define SK_MINIT_RX2 0x01B1 +#define SK_MINIT_TX1 0x01B2 +#define SK_MINIT_TX2 0x01B3 +#define SK_MTIMEO_RX1 0x01B4 +#define SK_MTIMEO_RX2 0x01B5 +#define SK_MTIMEO_TX1 0x01B6 +#define SK_MTIEMO_TX2 0x01B7 +#define SK_MACARB_CTL 0x01B8 +#define SK_MTIMER_TST 0x01BA +#define SK_RCINIT_RX1 0x01C0 +#define SK_RCINIT_RX2 0x01C1 +#define SK_RCINIT_TX1 0x01C2 +#define SK_RCINIT_TX2 0x01C3 +#define SK_RCTIMEO_RX1 0x01C4 +#define SK_RCTIMEO_RX2 0x01C5 +#define SK_RCTIMEO_TX1 0x01C6 +#define SK_RCTIMEO_TX2 0x01C7 +#define SK_RECOVERY_CTL 0x01C8 +#define SK_RCTIMER_TST 0x01CA + +/* Packet arbiter registers */ +#define SK_RXPA1_TINIT 0x01D0 +#define SK_RXPA2_TINIT 0x01D4 +#define SK_TXPA1_TINIT 0x01D8 +#define SK_TXPA2_TINIT 0x01DC +#define SK_RXPA1_TIMEO 0x01E0 +#define SK_RXPA2_TIMEO 0x01E4 +#define SK_TXPA1_TIMEO 0x01E8 +#define SK_TXPA2_TIMEO 0x01EC +#define SK_PKTARB_CTL 0x01F0 +#define SK_PKTATB_TST 0x01F2 + +#define SK_PKTARB_TIMEOUT 0x2000 + +#define SK_PKTARBCTL_RESET 0x0001 +#define SK_PKTARBCTL_UNRESET 0x0002 +#define SK_PKTARBCTL_RXTO1_OFF 0x0004 +#define SK_PKTARBCTL_RXTO1_ON 0x0008 +#define SK_PKTARBCTL_RXTO2_OFF 0x0010 +#define SK_PKTARBCTL_RXTO2_ON 0x0020 +#define SK_PKTARBCTL_TXTO1_OFF 0x0040 +#define SK_PKTARBCTL_TXTO1_ON 0x0080 +#define SK_PKTARBCTL_TXTO2_OFF 0x0100 +#define SK_PKTARBCTL_TXTO2_ON 0x0200 +#define SK_PKTARBCTL_CLR_IRQ_RXTO1 0x0400 +#define SK_PKTARBCTL_CLR_IRQ_RXTO2 0x0800 +#define SK_PKTARBCTL_CLR_IRQ_TXTO1 0x1000 +#define SK_PKTARBCTL_CLR_IRQ_TXTO2 0x2000 + +#define SK_MINIT_XMAC_B2 54 +#define SK_MINIT_XMAC_C1 63 + +#define SK_MACARBCTL_RESET 0x0001 +#define SK_MACARBCTL_UNRESET 0x0002 +#define SK_MACARBCTL_FASTOE_OFF 0x0004 +#define SK_MACARBCRL_FASTOE_ON 0x0008 + +#define SK_RCINIT_XMAC_B2 54 +#define SK_RCINIT_XMAC_C1 0 + +#define SK_RECOVERYCTL_RX1_OFF 0x0001 +#define SK_RECOVERYCTL_RX1_ON 0x0002 +#define SK_RECOVERYCTL_RX2_OFF 0x0004 +#define SK_RECOVERYCTL_RX2_ON 0x0008 +#define SK_RECOVERYCTL_TX1_OFF 0x0010 +#define SK_RECOVERYCTL_TX1_ON 0x0020 +#define SK_RECOVERYCTL_TX2_OFF 0x0040 +#define SK_RECOVERYCTL_TX2_ON 0x0080 + +#define SK_RECOVERY_XMAC_B2 \ + (SK_RECOVERYCTL_RX1_ON|SK_RECOVERYCTL_RX2_ON| \ + SK_RECOVERYCTL_TX1_ON|SK_RECOVERYCTL_TX2_ON) + +#define SK_RECOVERY_XMAC_C1 \ + (SK_RECOVERYCTL_RX1_OFF|SK_RECOVERYCTL_RX2_OFF| \ + SK_RECOVERYCTL_TX1_OFF|SK_RECOVERYCTL_TX2_OFF) + +/* Block 4 -- TX Arbiter MAC 1 */ +#define SK_TXAR1_TIMERINIT 0x0200 +#define SK_TXAR1_TIMERVAL 0x0204 +#define SK_TXAR1_LIMITINIT 0x0208 +#define SK_TXAR1_LIMITCNT 0x020C +#define SK_TXAR1_COUNTERCTL 0x0210 +#define SK_TXAR1_COUNTERTST 0x0212 +#define SK_TXAR1_COUNTERSTS 0x0212 + +/* Block 5 -- TX Arbiter MAC 2 */ +#define SK_TXAR2_TIMERINIT 0x0280 +#define SK_TXAR2_TIMERVAL 0x0284 +#define SK_TXAR2_LIMITINIT 0x0288 +#define SK_TXAR2_LIMITCNT 0x028C +#define SK_TXAR2_COUNTERCTL 0x0290 +#define SK_TXAR2_COUNTERTST 0x0291 +#define SK_TXAR2_COUNTERSTS 0x0292 + +#define SK_TXARCTL_OFF 0x01 +#define SK_TXARCTL_ON 0x02 +#define SK_TXARCTL_RATECTL_OFF 0x04 +#define SK_TXARCTL_RATECTL_ON 0x08 +#define SK_TXARCTL_ALLOC_OFF 0x10 +#define SK_TXARCTL_ALLOC_ON 0x20 +#define SK_TXARCTL_FSYNC_OFF 0x40 +#define SK_TXARCTL_FSYNC_ON 0x80 + +/* Block 6 -- External registers */ +#define SK_EXTREG_BASE 0x300 +#define SK_EXTREG_END 0x37C + +/* Block 7 -- PCI config registers */ +#define SK_PCI_BASE 0x0380 +#define SK_PCI_END 0x03FC + +/* Compute offset of mirrored PCI register */ +#define SK_PCI_REG(reg) ((reg) + SK_PCI_BASE) + +/* Block 8 -- RX queue 1 */ +#define SK_RXQ1_BUFCNT 0x0400 +#define SK_RXQ1_BUFCTL 0x0402 +#define SK_RXQ1_NEXTDESC 0x0404 +#define SK_RXQ1_RXBUF_LO 0x0408 +#define SK_RXQ1_RXBUF_HI 0x040C +#define SK_RXQ1_RXSTAT 0x0410 +#define SK_RXQ1_TIMESTAMP 0x0414 +#define SK_RXQ1_CSUM1 0x0418 +#define SK_RXQ1_CSUM2 0x041A +#define SK_RXQ1_CSUM1_START 0x041C +#define SK_RXQ1_CSUM2_START 0x041E +#define SK_RXQ1_CURADDR_LO 0x0420 +#define SK_RXQ1_CURADDR_HI 0x0424 +#define SK_RXQ1_CURCNT_LO 0x0428 +#define SK_RXQ1_CURCNT_HI 0x042C +#define SK_RXQ1_CURBYTES 0x0430 +#define SK_RXQ1_BMU_CSR 0x0434 +#define SK_RXQ1_WATERMARK 0x0438 +#define SK_RXQ1_FLAG 0x043A +#define SK_RXQ1_TEST1 0x043C +#define SK_RXQ1_TEST2 0x0440 +#define SK_RXQ1_TEST3 0x0444 + +/* Block 9 -- RX queue 2 */ +#define SK_RXQ2_BUFCNT 0x0480 +#define SK_RXQ2_BUFCTL 0x0482 +#define SK_RXQ2_NEXTDESC 0x0484 +#define SK_RXQ2_RXBUF_LO 0x0488 +#define SK_RXQ2_RXBUF_HI 0x048C +#define SK_RXQ2_RXSTAT 0x0490 +#define SK_RXQ2_TIMESTAMP 0x0494 +#define SK_RXQ2_CSUM1 0x0498 +#define SK_RXQ2_CSUM2 0x049A +#define SK_RXQ2_CSUM1_START 0x049C +#define SK_RXQ2_CSUM2_START 0x049E +#define SK_RXQ2_CURADDR_LO 0x04A0 +#define SK_RXQ2_CURADDR_HI 0x04A4 +#define SK_RXQ2_CURCNT_LO 0x04A8 +#define SK_RXQ2_CURCNT_HI 0x04AC +#define SK_RXQ2_CURBYTES 0x04B0 +#define SK_RXQ2_BMU_CSR 0x04B4 +#define SK_RXQ2_WATERMARK 0x04B8 +#define SK_RXQ2_FLAG 0x04BA +#define SK_RXQ2_TEST1 0x04BC +#define SK_RXQ2_TEST2 0x04C0 +#define SK_RXQ2_TEST3 0x04C4 + +#define SK_RXBMU_CLR_IRQ_ERR 0x00000001 +#define SK_RXBMU_CLR_IRQ_EOF 0x00000002 +#define SK_RXBMU_CLR_IRQ_EOB 0x00000004 +#define SK_RXBMU_CLR_IRQ_PAR 0x00000008 +#define SK_RXBMU_RX_START 0x00000010 +#define SK_RXBMU_RX_STOP 0x00000020 +#define SK_RXBMU_POLL_OFF 0x00000040 +#define SK_RXBMU_POLL_ON 0x00000080 +#define SK_RXBMU_TRANSFER_SM_RESET 0x00000100 +#define SK_RXBMU_TRANSFER_SM_UNRESET 0x00000200 +#define SK_RXBMU_DESCWR_SM_RESET 0x00000400 +#define SK_RXBMU_DESCWR_SM_UNRESET 0x00000800 +#define SK_RXBMU_DESCRD_SM_RESET 0x00001000 +#define SK_RXBMU_DESCRD_SM_UNRESET 0x00002000 +#define SK_RXBMU_SUPERVISOR_SM_RESET 0x00004000 +#define SK_RXBMU_SUPERVISOR_SM_UNRESET 0x00008000 +#define SK_RXBMU_PFI_SM_RESET 0x00010000 +#define SK_RXBMU_PFI_SM_UNRESET 0x00020000 +#define SK_RXBMU_FIFO_RESET 0x00040000 +#define SK_RXBMU_FIFO_UNRESET 0x00080000 +#define SK_RXBMU_DESC_RESET 0x00100000 +#define SK_RXBMU_DESC_UNRESET 0x00200000 +#define SK_RXBMU_SUPERVISOR_IDLE 0x01000000 + +#define SK_RXBMU_ONLINE \ + (SK_RXBMU_TRANSFER_SM_UNRESET|SK_RXBMU_DESCWR_SM_UNRESET| \ + SK_RXBMU_DESCRD_SM_UNRESET|SK_RXBMU_SUPERVISOR_SM_UNRESET| \ + SK_RXBMU_PFI_SM_UNRESET|SK_RXBMU_FIFO_UNRESET| \ + SK_RXBMU_DESC_UNRESET) + +#define SK_RXBMU_OFFLINE \ + (SK_RXBMU_TRANSFER_SM_RESET|SK_RXBMU_DESCWR_SM_RESET| \ + SK_RXBMU_DESCRD_SM_RESET|SK_RXBMU_SUPERVISOR_SM_RESET| \ + SK_RXBMU_PFI_SM_RESET|SK_RXBMU_FIFO_RESET| \ + SK_RXBMU_DESC_RESET) + +/* Block 12 -- TX sync queue 1 */ +#define SK_TXQS1_BUFCNT 0x0600 +#define SK_TXQS1_BUFCTL 0x0602 +#define SK_TXQS1_NEXTDESC 0x0604 +#define SK_TXQS1_RXBUF_LO 0x0608 +#define SK_TXQS1_RXBUF_HI 0x060C +#define SK_TXQS1_RXSTAT 0x0610 +#define SK_TXQS1_CSUM_STARTVAL 0x0614 +#define SK_TXQS1_CSUM_STARTPOS 0x0618 +#define SK_TXQS1_CSUM_WRITEPOS 0x061A +#define SK_TXQS1_CURADDR_LO 0x0620 +#define SK_TXQS1_CURADDR_HI 0x0624 +#define SK_TXQS1_CURCNT_LO 0x0628 +#define SK_TXQS1_CURCNT_HI 0x062C +#define SK_TXQS1_CURBYTES 0x0630 +#define SK_TXQS1_BMU_CSR 0x0634 +#define SK_TXQS1_WATERMARK 0x0638 +#define SK_TXQS1_FLAG 0x063A +#define SK_TXQS1_TEST1 0x063C +#define SK_TXQS1_TEST2 0x0640 +#define SK_TXQS1_TEST3 0x0644 + +/* Block 13 -- TX async queue 1 */ +#define SK_TXQA1_BUFCNT 0x0680 +#define SK_TXQA1_BUFCTL 0x0682 +#define SK_TXQA1_NEXTDESC 0x0684 +#define SK_TXQA1_RXBUF_LO 0x0688 +#define SK_TXQA1_RXBUF_HI 0x068C +#define SK_TXQA1_RXSTAT 0x0690 +#define SK_TXQA1_CSUM_STARTVAL 0x0694 +#define SK_TXQA1_CSUM_STARTPOS 0x0698 +#define SK_TXQA1_CSUM_WRITEPOS 0x069A +#define SK_TXQA1_CURADDR_LO 0x06A0 +#define SK_TXQA1_CURADDR_HI 0x06A4 +#define SK_TXQA1_CURCNT_LO 0x06A8 +#define SK_TXQA1_CURCNT_HI 0x06AC +#define SK_TXQA1_CURBYTES 0x06B0 +#define SK_TXQA1_BMU_CSR 0x06B4 +#define SK_TXQA1_WATERMARK 0x06B8 +#define SK_TXQA1_FLAG 0x06BA +#define SK_TXQA1_TEST1 0x06BC +#define SK_TXQA1_TEST2 0x06C0 +#define SK_TXQA1_TEST3 0x06C4 + +/* Block 14 -- TX sync queue 2 */ +#define SK_TXQS2_BUFCNT 0x0700 +#define SK_TXQS2_BUFCTL 0x0702 +#define SK_TXQS2_NEXTDESC 0x0704 +#define SK_TXQS2_RXBUF_LO 0x0708 +#define SK_TXQS2_RXBUF_HI 0x070C +#define SK_TXQS2_RXSTAT 0x0710 +#define SK_TXQS2_CSUM_STARTVAL 0x0714 +#define SK_TXQS2_CSUM_STARTPOS 0x0718 +#define SK_TXQS2_CSUM_WRITEPOS 0x071A +#define SK_TXQS2_CURADDR_LO 0x0720 +#define SK_TXQS2_CURADDR_HI 0x0724 +#define SK_TXQS2_CURCNT_LO 0x0728 +#define SK_TXQS2_CURCNT_HI 0x072C +#define SK_TXQS2_CURBYTES 0x0730 +#define SK_TXQS2_BMU_CSR 0x0734 +#define SK_TXQS2_WATERMARK 0x0738 +#define SK_TXQS2_FLAG 0x073A +#define SK_TXQS2_TEST1 0x073C +#define SK_TXQS2_TEST2 0x0740 +#define SK_TXQS2_TEST3 0x0744 + +/* Block 15 -- TX async queue 2 */ +#define SK_TXQA2_BUFCNT 0x0780 +#define SK_TXQA2_BUFCTL 0x0782 +#define SK_TXQA2_NEXTDESC 0x0784 +#define SK_TXQA2_RXBUF_LO 0x0788 +#define SK_TXQA2_RXBUF_HI 0x078C +#define SK_TXQA2_RXSTAT 0x0790 +#define SK_TXQA2_CSUM_STARTVAL 0x0794 +#define SK_TXQA2_CSUM_STARTPOS 0x0798 +#define SK_TXQA2_CSUM_WRITEPOS 0x079A +#define SK_TXQA2_CURADDR_LO 0x07A0 +#define SK_TXQA2_CURADDR_HI 0x07A4 +#define SK_TXQA2_CURCNT_LO 0x07A8 +#define SK_TXQA2_CURCNT_HI 0x07AC +#define SK_TXQA2_CURBYTES 0x07B0 +#define SK_TXQA2_BMU_CSR 0x07B4 +#define SK_TXQA2_WATERMARK 0x07B8 +#define SK_TXQA2_FLAG 0x07BA +#define SK_TXQA2_TEST1 0x07BC +#define SK_TXQA2_TEST2 0x07C0 +#define SK_TXQA2_TEST3 0x07C4 + +#define SK_TXBMU_CLR_IRQ_ERR 0x00000001 +#define SK_TXBMU_CLR_IRQ_EOF 0x00000002 +#define SK_TXBMU_CLR_IRQ_EOB 0x00000004 +#define SK_TXBMU_TX_START 0x00000010 +#define SK_TXBMU_TX_STOP 0x00000020 +#define SK_TXBMU_POLL_OFF 0x00000040 +#define SK_TXBMU_POLL_ON 0x00000080 +#define SK_TXBMU_TRANSFER_SM_RESET 0x00000100 +#define SK_TXBMU_TRANSFER_SM_UNRESET 0x00000200 +#define SK_TXBMU_DESCWR_SM_RESET 0x00000400 +#define SK_TXBMU_DESCWR_SM_UNRESET 0x00000800 +#define SK_TXBMU_DESCRD_SM_RESET 0x00001000 +#define SK_TXBMU_DESCRD_SM_UNRESET 0x00002000 +#define SK_TXBMU_SUPERVISOR_SM_RESET 0x00004000 +#define SK_TXBMU_SUPERVISOR_SM_UNRESET 0x00008000 +#define SK_TXBMU_PFI_SM_RESET 0x00010000 +#define SK_TXBMU_PFI_SM_UNRESET 0x00020000 +#define SK_TXBMU_FIFO_RESET 0x00040000 +#define SK_TXBMU_FIFO_UNRESET 0x00080000 +#define SK_TXBMU_DESC_RESET 0x00100000 +#define SK_TXBMU_DESC_UNRESET 0x00200000 +#define SK_TXBMU_SUPERVISOR_IDLE 0x01000000 + +#define SK_TXBMU_ONLINE \ + (SK_TXBMU_TRANSFER_SM_UNRESET|SK_TXBMU_DESCWR_SM_UNRESET| \ + SK_TXBMU_DESCRD_SM_UNRESET|SK_TXBMU_SUPERVISOR_SM_UNRESET| \ + SK_TXBMU_PFI_SM_UNRESET|SK_TXBMU_FIFO_UNRESET| \ + SK_TXBMU_DESC_UNRESET) + +#define SK_TXBMU_OFFLINE \ + (SK_TXBMU_TRANSFER_SM_RESET|SK_TXBMU_DESCWR_SM_RESET| \ + SK_TXBMU_DESCRD_SM_RESET|SK_TXBMU_SUPERVISOR_SM_RESET| \ + SK_TXBMU_PFI_SM_RESET|SK_TXBMU_FIFO_RESET| \ + SK_TXBMU_DESC_RESET) + +/* Block 16 -- Receive RAMbuffer 1 */ +#define SK_RXRB1_START 0x0800 +#define SK_RXRB1_END 0x0804 +#define SK_RXRB1_WR_PTR 0x0808 +#define SK_RXRB1_RD_PTR 0x080C +#define SK_RXRB1_UTHR_PAUSE 0x0810 +#define SK_RXRB1_LTHR_PAUSE 0x0814 +#define SK_RXRB1_UTHR_HIPRIO 0x0818 +#define SK_RXRB1_UTHR_LOPRIO 0x081C +#define SK_RXRB1_PKTCNT 0x0820 +#define SK_RXRB1_LVL 0x0824 +#define SK_RXRB1_CTLTST 0x0828 + +/* Block 17 -- Receive RAMbuffer 2 */ +#define SK_RXRB2_START 0x0880 +#define SK_RXRB2_END 0x0884 +#define SK_RXRB2_WR_PTR 0x0888 +#define SK_RXRB2_RD_PTR 0x088C +#define SK_RXRB2_UTHR_PAUSE 0x0890 +#define SK_RXRB2_LTHR_PAUSE 0x0894 +#define SK_RXRB2_UTHR_HIPRIO 0x0898 +#define SK_RXRB2_UTHR_LOPRIO 0x089C +#define SK_RXRB2_PKTCNT 0x08A0 +#define SK_RXRB2_LVL 0x08A4 +#define SK_RXRB2_CTLTST 0x08A8 + +/* Block 20 -- Sync. Transmit RAMbuffer 1 */ +#define SK_TXRBS1_START 0x0A00 +#define SK_TXRBS1_END 0x0A04 +#define SK_TXRBS1_WR_PTR 0x0A08 +#define SK_TXRBS1_RD_PTR 0x0A0C +#define SK_TXRBS1_PKTCNT 0x0A20 +#define SK_TXRBS1_LVL 0x0A24 +#define SK_TXRBS1_CTLTST 0x0A28 + +/* Block 21 -- Async. Transmit RAMbuffer 1 */ +#define SK_TXRBA1_START 0x0A80 +#define SK_TXRBA1_END 0x0A84 +#define SK_TXRBA1_WR_PTR 0x0A88 +#define SK_TXRBA1_RD_PTR 0x0A8C +#define SK_TXRBA1_PKTCNT 0x0AA0 +#define SK_TXRBA1_LVL 0x0AA4 +#define SK_TXRBA1_CTLTST 0x0AA8 + +/* Block 22 -- Sync. Transmit RAMbuffer 2 */ +#define SK_TXRBS2_START 0x0B00 +#define SK_TXRBS2_END 0x0B04 +#define SK_TXRBS2_WR_PTR 0x0B08 +#define SK_TXRBS2_RD_PTR 0x0B0C +#define SK_TXRBS2_PKTCNT 0x0B20 +#define SK_TXRBS2_LVL 0x0B24 +#define SK_TXRBS2_CTLTST 0x0B28 + +/* Block 23 -- Async. Transmit RAMbuffer 2 */ +#define SK_TXRBA2_START 0x0B80 +#define SK_TXRBA2_END 0x0B84 +#define SK_TXRBA2_WR_PTR 0x0B88 +#define SK_TXRBA2_RD_PTR 0x0B8C +#define SK_TXRBA2_PKTCNT 0x0BA0 +#define SK_TXRBA2_LVL 0x0BA4 +#define SK_TXRBA2_CTLTST 0x0BA8 + +#define SK_RBCTL_RESET 0x00000001 +#define SK_RBCTL_UNRESET 0x00000002 +#define SK_RBCTL_OFF 0x00000004 +#define SK_RBCTL_ON 0x00000008 +#define SK_RBCTL_STORENFWD_OFF 0x00000010 +#define SK_RBCTL_STORENFWD_ON 0x00000020 + +/* Block 24 -- RX MAC FIFO 1 regisrers and LINK_SYNC counter */ +#define SK_RXF1_END 0x0C00 +#define SK_RXF1_WPTR 0x0C04 +#define SK_RXF1_RPTR 0x0C0C +#define SK_RXF1_PKTCNT 0x0C10 +#define SK_RXF1_LVL 0x0C14 +#define SK_RXF1_MACCTL 0x0C18 +#define SK_RXF1_CTL 0x0C1C +#define SK_RXLED1_CNTINIT 0x0C20 +#define SK_RXLED1_COUNTER 0x0C24 +#define SK_RXLED1_CTL 0x0C28 +#define SK_RXLED1_TST 0x0C29 +#define SK_LINK_SYNC1_CINIT 0x0C30 +#define SK_LINK_SYNC1_COUNTER 0x0C34 +#define SK_LINK_SYNC1_CTL 0x0C38 +#define SK_LINK_SYNC1_TST 0x0C39 +#define SK_LINKLED1_CTL 0x0C3C + +#define SK_FIFO_END 0x3F + +/* Block 25 -- RX MAC FIFO 2 regisrers and LINK_SYNC counter */ +#define SK_RXF2_END 0x0C80 +#define SK_RXF2_WPTR 0x0C84 +#define SK_RXF2_RPTR 0x0C8C +#define SK_RXF2_PKTCNT 0x0C90 +#define SK_RXF2_LVL 0x0C94 +#define SK_RXF2_MACCTL 0x0C98 +#define SK_RXF2_CTL 0x0C9C +#define SK_RXLED2_CNTINIT 0x0CA0 +#define SK_RXLED2_COUNTER 0x0CA4 +#define SK_RXLED2_CTL 0x0CA8 +#define SK_RXLED2_TST 0x0CA9 +#define SK_LINK_SYNC2_CINIT 0x0CB0 +#define SK_LINK_SYNC2_COUNTER 0x0CB4 +#define SK_LINK_SYNC2_CTL 0x0CB8 +#define SK_LINK_SYNC2_TST 0x0CB9 +#define SK_LINKLED2_CTL 0x0CBC + +#define SK_RXMACCTL_CLR_IRQ_NOSTS 0x00000001 +#define SK_RXMACCTL_CLR_IRQ_NOTSTAMP 0x00000002 +#define SK_RXMACCTL_TSTAMP_OFF 0x00000004 +#define SK_RXMACCTL_RSTAMP_ON 0x00000008 +#define SK_RXMACCTL_FLUSH_OFF 0x00000010 +#define SK_RXMACCTL_FLUSH_ON 0x00000020 +#define SK_RXMACCTL_PAUSE_OFF 0x00000040 +#define SK_RXMACCTL_PAUSE_ON 0x00000080 +#define SK_RXMACCTL_AFULL_OFF 0x00000100 +#define SK_RXMACCTL_AFULL_ON 0x00000200 +#define SK_RXMACCTL_VALIDTIME_PATCH_OFF 0x00000400 +#define SK_RXMACCTL_VALIDTIME_PATCH_ON 0x00000800 +#define SK_RXMACCTL_RXRDY_PATCH_OFF 0x00001000 +#define SK_RXMACCTL_RXRDY_PATCH_ON 0x00002000 +#define SK_RXMACCTL_STS_TIMEO 0x00FF0000 +#define SK_RXMACCTL_TSTAMP_TIMEO 0xFF000000 + +#define SK_RXLEDCTL_ENABLE 0x0001 +#define SK_RXLEDCTL_COUNTER_STOP 0x0002 +#define SK_RXLEDCTL_COUNTER_START 0x0004 + +#define SK_LINKLED_OFF 0x0001 +#define SK_LINKLED_ON 0x0002 +#define SK_LINKLED_LINKSYNC_OFF 0x0004 +#define SK_LINKLED_LINKSYNC_ON 0x0008 +#define SK_LINKLED_BLINK_OFF 0x0010 +#define SK_LINKLED_BLINK_ON 0x0020 + +/* Block 26 -- TX MAC FIFO 1 regisrers */ +#define SK_TXF1_END 0x0D00 +#define SK_TXF1_WPTR 0x0D04 +#define SK_TXF1_RPTR 0x0D0C +#define SK_TXF1_PKTCNT 0x0D10 +#define SK_TXF1_LVL 0x0D14 +#define SK_TXF1_MACCTL 0x0D18 +#define SK_TXF1_CTL 0x0D1C +#define SK_TXLED1_CNTINIT 0x0D20 +#define SK_TXLED1_COUNTER 0x0D24 +#define SK_TXLED1_CTL 0x0D28 +#define SK_TXLED1_TST 0x0D29 + +/* Block 27 -- TX MAC FIFO 2 regisrers */ +#define SK_TXF2_END 0x0D80 +#define SK_TXF2_WPTR 0x0D84 +#define SK_TXF2_RPTR 0x0D8C +#define SK_TXF2_PKTCNT 0x0D90 +#define SK_TXF2_LVL 0x0D94 +#define SK_TXF2_MACCTL 0x0D98 +#define SK_TXF2_CTL 0x0D9C +#define SK_TXLED2_CNTINIT 0x0DA0 +#define SK_TXLED2_COUNTER 0x0DA4 +#define SK_TXLED2_CTL 0x0DA8 +#define SK_TXLED2_TST 0x0DA9 + +#define SK_TXMACCTL_XMAC_RESET 0x00000001 +#define SK_TXMACCTL_XMAC_UNRESET 0x00000002 +#define SK_TXMACCTL_LOOP_OFF 0x00000004 +#define SK_TXMACCTL_LOOP_ON 0x00000008 +#define SK_TXMACCTL_FLUSH_OFF 0x00000010 +#define SK_TXMACCTL_FLUSH_ON 0x00000020 +#define SK_TXMACCTL_WAITEMPTY_OFF 0x00000040 +#define SK_TXMACCTL_WAITEMPTY_ON 0x00000080 +#define SK_TXMACCTL_AFULL_OFF 0x00000100 +#define SK_TXMACCTL_AFULL_ON 0x00000200 +#define SK_TXMACCTL_TXRDY_PATCH_OFF 0x00000400 +#define SK_TXMACCTL_RXRDY_PATCH_ON 0x00000800 +#define SK_TXMACCTL_PKT_RECOVERY_OFF 0x00001000 +#define SK_TXMACCTL_PKT_RECOVERY_ON 0x00002000 +#define SK_TXMACCTL_CLR_IRQ_PERR 0x00008000 +#define SK_TXMACCTL_WAITAFTERFLUSH 0x00010000 + +#define SK_TXLEDCTL_ENABLE 0x0001 +#define SK_TXLEDCTL_COUNTER_STOP 0x0002 +#define SK_TXLEDCTL_COUNTER_START 0x0004 + +#define SK_FIFO_RESET 0x00000001 +#define SK_FIFO_UNRESET 0x00000002 +#define SK_FIFO_OFF 0x00000004 +#define SK_FIFO_ON 0x00000008 + +/* Block 0x40 to 0x4F -- XMAC 1 registers */ +#define SK_XMAC1_BASE 0x2000 +#define SK_XMAC1_END 0x23FF + +/* Block 0x60 to 0x6F -- XMAC 2 registers */ +#define SK_XMAC2_BASE 0x3000 +#define SK_XMAC2_END 0x33FF + +/* Compute relative offset of an XMAC register in the XMAC window(s). */ +#define SK_XMAC_REG(reg, mac) (((reg) * 2) + SK_XMAC1_BASE + \ + (mac * (SK_XMAC2_BASE - SK_XMAC1_BASE))) + +#define SK_XM_READ_4(sc, reg) \ + (sk_win_read_2(sc->sk_softc, \ + SK_XMAC_REG(reg, sc->sk_port)) & 0xFFFF) | \ + ((sk_win_read_2(sc->sk_softc, \ + SK_XMAC_REG(reg + 2, sc->sk_port)) << 16) & 0xFFFF0000) + +#define SK_XM_WRITE_4(sc, reg, val) \ + sk_win_write_2(sc->sk_softc, \ + SK_XMAC_REG(reg, sc->sk_port), ((val) & 0xFFFF)); \ + sk_win_write_2(sc->sk_softc, \ + SK_XMAC_REG(reg + 2, sc->sk_port), ((val) >> 16) & 0xFFFF); + +#define SK_XM_READ_2(sc, reg) \ + sk_win_read_2(sc->sk_softc, SK_XMAC_REG(reg, sc->sk_port)) + +#define SK_XM_WRITE_2(sc, reg, val) \ + sk_win_write_2(sc->sk_softc, SK_XMAC_REG(reg, sc->sk_port), val) + +#define SK_XM_SETBIT_4(sc, reg, x) \ + SK_XM_WRITE_4(sc, reg, (SK_XM_READ_4(sc, reg)) | (x)) + +#define SK_XM_CLRBIT_4(sc, reg, x) \ + SK_XM_WRITE_4(sc, reg, (SK_XM_READ_4(sc, reg)) & ~(x)) + +#define SK_XM_SETBIT_2(sc, reg, x) \ + SK_XM_WRITE_2(sc, reg, (SK_XM_READ_2(sc, reg)) | (x)) + +#define SK_XM_CLRBIT_2(sc, reg, x) \ + SK_XM_WRITE_2(sc, reg, (SK_XM_READ_2(sc, reg)) & ~(x)) + + +/* + * The default FIFO threshold on the XMAC II is 4 bytes. On + * dual port NICs, this often leats to transmit underruns, so we + * bump the threshold a little. + */ +#define SK_XM_TX_FIFOTHRESH 512 + +#define SK_PCI_VENDOR_ID 0x0000 +#define SK_PCI_DEVICE_ID 0x0002 +#define SK_PCI_COMMAND 0x0004 +#define SK_PCI_STATUS 0x0006 +#define SK_PCI_REVID 0x0008 +#define SK_PCI_CLASSCODE 0x0009 +#define SK_PCI_CACHELEN 0x000C +#define SK_PCI_LATENCY_TIMER 0x000D +#define SK_PCI_HEADER_TYPE 0x000E +#define SK_PCI_LOMEM 0x0010 +#define SK_PCI_LOIO 0x0014 +#define SK_PCI_SUBVEN_ID 0x002C +#define SK_PCI_SYBSYS_ID 0x002E +#define SK_PCI_BIOSROM 0x0030 +#define SK_PCI_INTLINE 0x003C +#define SK_PCI_INTPIN 0x003D +#define SK_PCI_MINGNT 0x003E +#define SK_PCI_MINLAT 0x003F + +/* device specific PCI registers */ +#define SK_PCI_OURREG1 0x0040 +#define SK_PCI_OURREG2 0x0044 +#define SK_PCI_ +#define SK_PCI_CAPID 0x0048 /* 8 bits */ +#define SK_PCI_NEXTPTR 0x0049 /* 8 bits */ +#define SK_PCI_PWRMGMTCAP 0x004A /* 16 bits */ +#define SK_PCI_PWRMGMTCTRL 0x004C /* 16 bits */ +#define SK_PCI_PME_EVENT 0x004F +#define SK_PCI_VPD_CAPID 0x0050 +#define SK_PCI_VPD_NEXTPTR 0x0051 +#define SK_PCI_VPD_ADDR 0x0052 +#define SK_PCI_VPD_DATA 0x0054 + +#define SK_PSTATE_MASK 0x0003 +#define SK_PSTATE_D0 0x0000 +#define SK_PSTATE_D1 0x0001 +#define SK_PSTATE_D2 0x0002 +#define SK_PSTATE_D3 0x0003 +#define SK_PME_EN 0x0010 +#define SK_PME_STATUS 0x8000 + +/* + * VPD flag bit. Set to 0 to initiate a read, will become 1 when + * read is complete. Set to 1 to initiate a write, will become 0 + * when write is finished. + */ +#define SK_VPD_FLAG 0x8000 + +/* VPD structures */ +struct vpd_res { + u_int8_t vr_id; + u_int8_t vr_len; + u_int8_t vr_pad; +}; + +struct vpd_key { + char vk_key[2]; + u_int8_t vk_len; +}; + +#define VPD_RES_ID 0x82 /* ID string */ +#define VPD_RES_READ 0x90 /* start of read only area */ +#define VPD_RES_WRITE 0x81 /* start of read/write area */ +#define VPD_RES_END 0x78 /* end tag */ + +#define CSR_WRITE_4(sc, reg, val) \ + bus_space_write_4(sc->sk_btag, sc->sk_bhandle, reg, val) +#define CSR_WRITE_2(sc, reg, val) \ + bus_space_write_2(sc->sk_btag, sc->sk_bhandle, reg, val) +#define CSR_WRITE_1(sc, reg, val) \ + bus_space_write_1(sc->sk_btag, sc->sk_bhandle, reg, val) + +#define CSR_READ_4(sc, reg) \ + bus_space_read_4(sc->sk_btag, sc->sk_bhandle, reg) +#define CSR_READ_2(sc, reg) \ + bus_space_read_2(sc->sk_btag, sc->sk_bhandle, reg) +#define CSR_READ_1(sc, reg) \ + bus_space_read_1(sc->sk_btag, sc->sk_bhandle, reg) + +struct sk_type { + u_int16_t sk_vid; + u_int16_t sk_did; + char *sk_name; +}; + +/* RX queue descriptor data structure */ +struct sk_rx_desc { + u_int32_t sk_ctl; + u_int32_t sk_next; + u_int32_t sk_data_lo; + u_int32_t sk_data_hi; + u_int32_t sk_xmac_rxstat; + u_int32_t sk_timestamp; + u_int16_t sk_csum2; + u_int16_t sk_csum1; + u_int16_t sk_csum2_start; + u_int16_t sk_csum1_start; +}; + +#define SK_OPCODE_DEFAULT 0x00550000 +#define SK_OPCODE_CSUM 0x00560000 + +#define SK_RXCTL_LEN 0x0000FFFF +#define SK_RXCTL_OPCODE 0x00FF0000 +#define SK_RXCTL_TSTAMP_VALID 0x01000000 +#define SK_RXCTL_STATUS_VALID 0x02000000 +#define SK_RXCTL_DEV0 0x04000000 +#define SK_RXCTL_EOF_INTR 0x08000000 +#define SK_RXCTL_EOB_INTR 0x10000000 +#define SK_RXCTL_LASTFRAG 0x20000000 +#define SK_RXCTL_FIRSTFRAG 0x40000000 +#define SK_RXCTL_OWN 0x80000000 + +#define SK_RXSTAT \ + (SK_OPCODE_DEFAULT|SK_RXCTL_EOF_INTR|SK_RXCTL_LASTFRAG| \ + SK_RXCTL_FIRSTFRAG|SK_RXCTL_OWN) + +struct sk_tx_desc { + u_int32_t sk_ctl; + u_int32_t sk_next; + u_int32_t sk_data_lo; + u_int32_t sk_data_hi; + u_int32_t sk_xmac_txstat; + u_int16_t sk_rsvd0; + u_int16_t sk_csum_startval; + u_int16_t sk_csum_startpos; + u_int16_t sk_csum_writepos; + u_int32_t sk_rsvd1; +}; + +#define SK_TXCTL_LEN 0x0000FFFF +#define SK_TXCTL_OPCODE 0x00FF0000 +#define SK_TXCTL_SW 0x01000000 +#define SK_TXCTL_NOCRC 0x02000000 +#define SK_TXCTL_STORENFWD 0x04000000 +#define SK_TXCTL_EOF_INTR 0x08000000 +#define SK_TXCTL_EOB_INTR 0x10000000 +#define SK_TXCTL_LASTFRAG 0x20000000 +#define SK_TXCTL_FIRSTFRAG 0x40000000 +#define SK_TXCTL_OWN 0x80000000 + +#define SK_TXSTAT \ + (SK_OPCODE_DEFAULT|SK_TXCTL_EOF_INTR|SK_TXCTL_LASTFRAG|SK_TXCTL_OWN) + +#define SK_RXBYTES(x) (x) & 0x0000FFFF; +#define SK_TXBYTES SK_RXBYTES + +#define SK_TX_RING_CNT 512 +#define SK_RX_RING_CNT 256 + +/* + * Jumbo buffer stuff. Note that we must allocate more jumbo + * buffers than there are descriptors in the receive ring. This + * is because we don't know how long it will take for a packet + * to be released after we hand it off to the upper protocol + * layers. To be safe, we allocate 1.5 times the number of + * receive descriptors. + */ +#define SK_JUMBO_FRAMELEN 9018 +#define SK_JUMBO_MTU (SK_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN) +#define SK_JSLOTS 384 + +#define SK_JRAWLEN (SK_JUMBO_FRAMELEN + ETHER_ALIGN + sizeof(u_int64_t)) +#define SK_JLEN (SK_JRAWLEN + (sizeof(u_int64_t) - \ + (SK_JRAWLEN % sizeof(u_int64_t)))) +#define SK_MCLBYTES (SK_JLEN - sizeof(u_int64_t)) +#define SK_JPAGESZ PAGE_SIZE +#define SK_RESID (SK_JPAGESZ - (SK_JLEN * SK_JSLOTS) % SK_JPAGESZ) +#define SK_JMEM ((SK_JLEN * SK_JSLOTS) + SK_RESID) + +struct sk_jslot { + caddr_t sk_buf; + int sk_inuse; +}; + +struct sk_jpool_entry { + int slot; + SLIST_ENTRY(sk_jpool_entry) jpool_entries; +}; + +struct sk_chain { + void *sk_desc; + struct mbuf *sk_mbuf; + struct sk_chain *sk_next; +}; + +struct sk_chain_data { + struct sk_chain sk_tx_chain[SK_TX_RING_CNT]; + struct sk_chain sk_rx_chain[SK_RX_RING_CNT]; + int sk_tx_prod; + int sk_tx_cons; + int sk_tx_cnt; + int sk_rx_prod; + int sk_rx_cons; + int sk_rx_cnt; + /* Stick the jumbo mem management stuff here too. */ + struct sk_jslot sk_jslots[SK_JSLOTS]; + void *sk_jumbo_buf; + +}; + +struct sk_ring_data { + struct sk_tx_desc sk_tx_ring[SK_TX_RING_CNT]; + struct sk_rx_desc sk_rx_ring[SK_RX_RING_CNT]; +}; + +#define SK_INC(x, y) (x) = (x + 1) % y + +/* Forward decl. */ +struct sk_if_softc; + +/* Softc for the GEnesis controller. */ +struct sk_softc { + bus_space_handle_t sk_bhandle; /* bus space handle */ + bus_space_tag_t sk_btag; /* bus space tag */ + struct sk_type *sk_info; /* Starfire adapter info */ + u_int8_t sk_unit; /* controller number */ + u_int8_t sk_type; + u_int8_t sk_cachesize; + char *sk_vpd_prodname; + char *sk_vpd_readonly; + u_int32_t sk_rboff; /* RAMbuffer offset */ + u_int32_t sk_ramsize; /* amount of RAM on NIC */ + u_int32_t sk_pmd; /* physical media type */ + u_int32_t sk_intrmask; + struct sk_if_softc *sk_if[2]; +}; + +/* Softc for each logical interface */ +struct sk_if_softc { + struct arpcom arpcom; /* interface info */ + struct ifmedia ifmedia; /* media info */ + u_int8_t sk_unit; /* interface number */ + u_int8_t sk_port; /* port # on controller */ + u_int8_t sk_xmac_rev; /* XMAC chip rev (B2 or C1) */ + u_int8_t sk_link; + u_int32_t sk_rx_ramstart; + u_int32_t sk_rx_ramend; + u_int32_t sk_tx_ramstart; + u_int32_t sk_tx_ramend; + struct sk_chain_data sk_cdata; + struct sk_ring_data *sk_rdata; + struct sk_softc *sk_softc; /* parent controller */ + int sk_tx_bmu; /* TX BMU register */ + int sk_if_flags; + SLIST_HEAD(__sk_jfreehead, sk_jpool_entry) sk_jfree_listhead; + SLIST_HEAD(__sk_jinusehead, sk_jpool_entry) sk_jinuse_listhead; +}; + +#define SK_TIMEOUT 1000 +#define ETHER_ALIGN 2 + +#ifdef __alpha__ +#undef vtophys +#define vtophys(va) (pmap_kextract(((vm_offset_t) (va))) \ + + 1*1024*1024*1024) +#endif diff --git a/sys/pci/xmaciireg.h b/sys/pci/xmaciireg.h new file mode 100644 index 0000000..fe8946b --- /dev/null +++ b/sys/pci/xmaciireg.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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: xmaciireg.h,v 1.10 1999/07/09 03:35:12 wpaul Exp $ + */ + +/* + * Registers and data structures for the XaQti Corporation XMAC II + * Gigabit Ethernet MAC. Datasheet is available from http://www.xaqti.com. + * The XMAC can be programmed for 16-bit or 32-bit register access modes. + * The SysKonnect gigabit ethernet adapters use 16-bit mode, so that's + * how the registers are laid out here. + */ + +#define XM_DEVICEID 0x00E0AE20 +#define XM_XAQTI_OUI 0x00E0AE + +#define XM_XMAC_REV(x) (((x) & 0x000000E0) >> 5) + +#define XM_XMAC_REV_B2 0x0 +#define XM_XMAC_REV_C1 0x1 + +#define XM_MMUCMD 0x0000 +#define XM_POFF 0x0008 +#define XM_BURST 0x000C +#define XM_VLAN_TAGLEV1 0x0010 +#define XM_VLAN_TAGLEV2 0x0014 +#define XM_TXCMD 0x0020 +#define XM_TX_RETRYLIMIT 0x0024 +#define XM_TX_SLOTTIME 0x0028 +#define XM_TX_IPG 0x003C +#define XM_RXCMD 0x0030 +#define XM_PHY_ADDR 0x0034 +#define XM_PHY_DATA 0x0038 +#define XM_GPIO 0x0040 +#define XM_IMR 0x0044 +#define XM_ISR 0x0048 +#define XM_HWCFG 0x004C +#define XM_TX_LOWAT 0x0060 +#define XM_TX_HIWAT 0x0062 +#define XM_TX_REQTHRESH_LO 0x0064 +#define XM_TX_REQTHRESH_HI 0x0066 +#define XM_TX_REQTHRESH XM_TX_REQTHRESH_LO +#define XM_PAUSEDST0 0x0068 +#define XM_PAUSEDST1 0x006A +#define XM_PAUSEDST2 0x006C +#define XM_CTLPARM_LO 0x0070 +#define XM_CTLPARM_HI 0x0072 +#define XM_CTLPARM XM_CTLPARM_LO +#define XM_OPCODE_PAUSE_TIMER 0x0074 +#define XM_TXSTAT_LIFO 0x0078 + +/* + * Perfect filter registers. The XMAC has a table of 16 perfect + * filter entries, spaced 8 bytes apart. This is in addition to + * the station address registers, which appear below. + */ +#define XM_RXFILT_BASE 0x0080 +#define XM_RXFILT_END 0x0107 +#define XM_RXFILT_MAX 16 +#define XM_RXFILT_ENTRY(ent) (XM_RXFILT_BASE + ((ent * 8))) + +/* Primary station address. */ +#define XM_PAR0 0x0108 +#define XM_PAR1 0x010A +#define XM_PAR2 0x010C + +/* 64-bit multicast hash table registers */ +#define XM_MAR0 0x0110 +#define XM_MAR1 0x0112 +#define XM_MAR2 0x0114 +#define XM_MAR3 0x0116 +#define XM_RX_LOWAT 0x0118 +#define XM_RX_HIWAT 0x011A +#define XM_RX_REQTHRESH_LO 0x011C +#define XM_RX_REQTHRESH_HI 0x011E +#define XM_RX_REQTHRESH XM_RX_REQTHRESH_LO +#define XM_DEVID_LO 0x0120 +#define XM_DEVID_HI 0x0122 +#define XM_DEVID XM_DEVID_LO +#define XM_MODE_LO 0x0124 +#define XM_MODE_HI 0x0126 +#define XM_MODE XM_MODE_LO +#define XM_LASTSRC0 0x0128 +#define XM_LASTSRC1 0x012A +#define XM_LASTSRC2 0x012C +#define XM_TSTAMP_READ 0x0130 +#define XM_TSTAMP_LOAD 0x0134 +#define XM_STATS_CMD 0x0200 +#define XM_RXCNT_EVENT_LO 0x0204 +#define XM_RXCNT_EVENT_HI 0x0206 +#define XM_RXCNT_EVENT XM_RXCNT_EVENT_LO +#define XM_TXCNT_EVENT_LO 0x0208 +#define XM_TXCNT_EVENT_HI 0x020A +#define XM_TXCNT_EVENT XM_TXCNT_EVENT_LO +#define XM_RXCNT_EVMASK_LO 0x020C +#define XM_RXCNT_EVMASK_HI 0x020E +#define XM_RXCNT_EVMASK XM_RXCNT_EVMASK_LO +#define XM_TXCNT_EVMASK_LO 0x0210 +#define XM_TXCNT_EVMASK_HI 0x0212 +#define XM_TXCNT_EVMASK XM_TXCNT_EVMASK_LO + +/* Statistics command register */ +#define XM_STATCMD_CLR_TX 0x0001 +#define XM_STATCMD_CLR_RX 0x0002 +#define XM_STATCMD_COPY_TX 0x0004 +#define XM_STATCMD_COPY_RX 0x0008 +#define XM_STATCMD_SNAP_TX 0x0010 +#define XM_STATCMD_SNAP_RX 0x0020 + +/* TX statistics registers */ +#define XM_TXSTATS_PKTSOK 0x280 +#define XM_TXSTATS_BYTESOK_HI 0x284 +#define XM_TXSTATS_BYTESOK_LO 0x288 +#define XM_TXSTATS_BCASTSOK 0x28C +#define XM_TXSTATS_MCASTSOK 0x290 +#define XM_TXSTATS_UCASTSOK 0x294 +#define XM_TXSTATS_GIANTS 0x298 +#define XM_TXSTATS_BURSTCNT 0x29C +#define XM_TXSTATS_PAUSEPKTS 0x2A0 +#define XM_TXSTATS_MACCTLPKTS 0x2A4 +#define XM_TXSTATS_SINGLECOLS 0x2A8 +#define XM_TXSTATS_MULTICOLS 0x2AC +#define XM_TXSTATS_EXCESSCOLS 0x2B0 +#define XM_TXSTATS_LATECOLS 0x2B4 +#define XM_TXSTATS_DEFER 0x2B8 +#define XM_TXSTATS_EXCESSDEFER 0x2BC +#define XM_TXSTATS_UNDERRUN 0x2C0 +#define XM_TXSTATS_CARRIERSENSE 0x2C4 +#define XM_TXSTATS_UTILIZATION 0x2C8 +#define XM_TXSTATS_64 0x2D0 +#define XM_TXSTATS_65_127 0x2D4 +#define XM_TXSTATS_128_255 0x2D8 +#define XM_TXSTATS_256_511 0x2DC +#define XM_TXSTATS_512_1023 0x2E0 +#define XM_TXSTATS_1024_MAX 0x2E4 + +/* RX statistics registers */ +#define XM_RXSTATS_PKTSOK 0x300 +#define XM_RXSTATS_BYTESOK_HI 0x304 +#define XM_RXSTATS_BYTESOK_LO 0x308 +#define XM_RXSTATS_BCASTSOK 0x30C +#define XM_RXSTATS_MCASTSOK 0x310 +#define XM_RXSTATS_UCASTSOK 0x314 +#define XM_RXSTATS_PAUSEPKTS 0x318 +#define XM_RXSTATS_MACCTLPKTS 0x31C +#define XM_RXSTATS_BADPAUSEPKTS 0x320 +#define XM_RXSTATS_BADMACCTLPKTS 0x324 +#define XM_RXSTATS_BURSTCNT 0x328 +#define XM_RXSTATS_MISSEDPKTS 0x32C +#define XM_RXSTATS_FRAMEERRS 0x330 +#define XM_RXSTATS_OVERRUN 0x334 +#define XM_RXSTATS_JABBER 0x338 +#define XM_RXSTATS_CARRLOSS 0x33C +#define XM_RXSTATS_INRNGLENERR 0x340 +#define XM_RXSTATS_SYMERR 0x344 +#define XM_RXSTATS_SHORTEVENT 0x348 +#define XM_RXSTATS_RUNTS 0x34C +#define XM_RXSTATS_GIANTS 0x350 +#define XM_RXSTATS_CRCERRS 0x354 +#define XM_RXSTATS_CEXTERRS 0x35C +#define XM_RXSTATS_UTILIZATION 0x360 +#define XM_RXSTATS_64 0x368 +#define XM_RXSTATS_65_127 0x36C +#define XM_RXSTATS_128_255 0x370 +#define XM_RXSTATS_256_511 0x374 +#define XM_RXSTATS_512_1023 0x378 +#define XM_RXSTATS_1024_MAX 0x37C + +#define XM_MMUCMD_TX_ENB 0x0001 +#define XM_MMUCMD_RX_ENB 0x0002 +#define XM_MMUCMD_GMIILOOP 0x0004 +#define XM_MMUCMD_RATECTL 0x0008 +#define XM_MMUCMD_GMIIFDX 0x0010 +#define XM_MMUCMD_NO_MGMT_PRMB 0x0020 +#define XM_MMUCMD_SIMCOL 0x0040 +#define XM_MMUCMD_FORCETX 0x0080 +#define XM_MMUCMD_LOOPENB 0x0200 +#define XM_MMUCMD_IGNPAUSE 0x0400 +#define XM_MMUCMD_PHYBUSY 0x0800 +#define XM_MMUCMD_PHYDATARDY 0x1000 + +#define XM_TXCMD_AUTOPAD 0x0001 +#define XM_TXCMD_NOCRC 0x0002 +#define XM_TXCMD_NOPREAMBLE 0x0004 +#define XM_TXCMD_NOGIGAMODE 0x0008 +#define XM_TXCMD_SAMPLELINE 0x0010 +#define XM_TXCMD_ENCBYPASS 0x0020 +#define XM_TXCMD_XMITBK2BK 0x0040 +#define XM_TXCMD_FAIRSHARE 0x0080 + +#define XM_RXCMD_DISABLE_CEXT 0x0001 +#define XM_RXCMD_STRIPPAD 0x0002 +#define XM_RXCMD_SAMPLELINE 0x0004 +#define XM_RXCMD_SELFRX 0x0008 +#define XM_RXCMD_STRIPFCS 0x0010 +#define XM_RXCMD_TRANSPARENT 0x0020 +#define XM_RXCMD_IPGCAPTURE 0x0040 +#define XM_RXCMD_BIGPKTOK 0x0080 +#define XM_RXCMD_LENERROK 0x0100 + +#define XM_IMR_RX_EOF 0x0001 +#define XM_IMR_TX_EOF 0x0002 +#define XM_IMR_TX_UNDERRUN 0x0004 +#define XM_IMR_RX_OVERRUN 0x0008 +#define XM_IMR_TX_STATS_OFLOW 0x0010 +#define XM_IMR_RX_STATS_OFLOW 0x0020 +#define XM_IMR_TSTAMP_OFLOW 0x0040 +#define XM_IMR_AUTONEG_DONE 0x0080 +#define XM_IMR_NEXTPAGE_RDY 0x0100 +#define XM_IMR_PAGE_RECEIVED 0x0200 +#define XM_IMR_LP_REQCFG 0x0400 +#define XM_IMR_GP0_SET 0x0800 +#define XM_IMR_FORCEINTR 0x1000 +#define XM_IMR_TX_ABORT 0x2000 +#define XM_IMR_LINKEVENT 0x4000 + +#define XM_INTRS \ + (~(XM_IMR_LINKEVENT|XM_IMR_AUTONEG_DONE|XM_IMR_TX_UNDERRUN)) + +#define XM_ISR_RX_EOF 0x0001 +#define XM_ISR_TX_EOF 0x0002 +#define XM_ISR_TX_UNDERRUN 0x0004 +#define XM_ISR_RX_OVERRUN 0x0008 +#define XM_ISR_TX_STATS_OFLOW 0x0010 +#define XM_ISR_RX_STATS_OFLOW 0x0020 +#define XM_ISR_TSTAMP_OFLOW 0x0040 +#define XM_ISR_AUTONEG_DONE 0x0080 +#define XM_ISR_NEXTPAGE_RDY 0x0100 +#define XM_ISR_PAGE_RECEIVED 0x0200 +#define XM_ISR_LP_REQCFG 0x0400 +#define XM_ISR_GP0_SET 0x0800 +#define XM_ISR_FORCEINTR 0x1000 +#define XM_ISR_TX_ABORT 0x2000 +#define XM_ISR_LINKEVENT 0x4000 + +#define XM_MODE_FLUSH_RXFIFO 0x00000001 +#define XM_MODE_FLUSH_TXFIFO 0x00000002 +#define XM_MODE_BIGENDIAN 0x00000004 +#define XM_MODE_RX_PROMISC 0x00000008 +#define XM_MODE_RX_NOBROAD 0x00000010 +#define XM_MODE_RX_NOMULTI 0x00000020 +#define XM_MODE_RX_NOUNI 0x00000040 +#define XM_MODE_RX_BADFRAMES 0x00000080 +#define XM_MODE_RX_CRCERRS 0x00000100 +#define XM_MODE_RX_GIANTS 0x00000200 +#define XM_MODE_RX_INRANGELEN 0x00000400 +#define XM_MODE_RX_RUNTS 0x00000800 +#define XM_MODE_RX_MACCTL 0x00001000 +#define XM_MODE_RX_USE_PERFECT 0x00002000 +#define XM_MODE_RX_USE_STATION 0x00004000 +#define XM_MODE_RX_USE_HASH 0x00008000 +#define XM_MODE_RX_ADDRPAIR 0x00010000 +#define XM_MODE_PAUSEONHI 0x00020000 +#define XM_MODE_PAUSEONLO 0x00040000 +#define XM_MODE_TIMESTAMP 0x00080000 +#define XM_MODE_SENDPAUSE 0x00100000 +#define XM_MODE_SENDCONTINUOUS 0x00200000 +#define XM_MODE_LE_STATUSWORD 0x00400000 +#define XM_MODE_AUTOFIFOPAUSE 0x00800000 +#define XM_MODE_EXPAUSEGEN 0x02000000 +#define XM_MODE_RX_INVERSE 0x04000000 + +#define XM_RXSTAT_MACCTL 0x00000001 +#define XM_RXSTAT_ERRFRAME 0x00000002 +#define XM_RXSTAT_CRCERR 0x00000004 +#define XM_RXSTAT_GIANT 0x00000008 +#define XM_RXSTAT_RUNT 0x00000010 +#define XM_RXSTAT_FRAMEERR 0x00000020 +#define XM_RXSTAT_INRANGEERR 0x00000040 +#define XM_RXSTAT_CARRIERERR 0x00000080 +#define XM_RXSTAT_COLLERR 0x00000100 +#define XM_RXSTAT_802_3 0x00000200 +#define XM_RXSTAT_CARREXTERR 0x00000400 +#define XM_RXSTAT_BURSTMODE 0x00000800 +#define XM_RXSTAT_UNICAST 0x00002000 +#define XM_RXSTAT_MULTICAST 0x00004000 +#define XM_RXSTAT_BROADCAST 0x00008000 +#define XM_RXSTAT_VLAN_LEV1 0x00010000 +#define XM_RXSTAT_VLAN_LEV2 0x00020000 +#define XM_RXSTAT_LEN 0xFFFC0000 + +/* + * XMAC PHY registers, indirectly accessed through + * XM_PHY_ADDR and XM_PHY_REG. + */ + +#define XM_PHY_BMCR 0x0000 /* control */ +#define XM_PHY_BMSR 0x0001 /* status */ +#define XM_PHY_VENID 0x0002 /* vendor id */ +#define XM_PHY_DEVID 0x0003 /* device id */ +#define XM_PHY_ANAR 0x0004 /* autoneg advertisenemt */ +#define XM_PHY_LPAR 0x0005 /* link partner ability */ +#define XM_PHY_ANEXP 0x0006 /* autoneg expansion */ +#define XM_PHY_NEXTP 0x0007 /* nextpage */ +#define XM_PHY_LPNEXTP 0x0008 /* link partner's nextpage */ +#define XM_PHY_EXTSTS 0x000F /* extented status */ +#define XM_PHY_RESAB 0x0010 /* resolved ability */ + +#define XM_BMCR_DUPLEX 0x0100 +#define XM_BMCR_RENEGOTIATE 0x0200 +#define XM_BMCR_AUTONEGENBL 0x1000 +#define XM_BMCR_LOOPBACK 0x4000 +#define XM_BMCR_RESET 0x8000 + +#define XM_BMSR_EXTCAP 0x0001 +#define XM_BMSR_LINKSTAT 0x0004 +#define XM_BMSR_AUTONEGABLE 0x0008 +#define XM_BMSR_REMFAULT 0x0010 +#define XM_BMSR_AUTONEGDONE 0x0020 +#define XM_BMSR_EXTSTAT 0x0100 + +#define XM_VENID_XAQTI 0xD14C +#define XM_DEVID_XMAC 0x0002 + +#define XM_ANAR_FULLDUPLEX 0x0020 +#define XM_ANAR_HALFDUPLEX 0x0040 +#define XM_ANAR_PAUSEBITS 0x0180 +#define XM_ANAR_REMFAULTBITS 0x1800 +#define XM_ANAR_ACK 0x4000 +#define XM_ANAR_NEXTPAGE 0x8000 + +#define XM_LPAR_FULLDUPLEX 0x0020 +#define XM_LPAR_HALFDUPLEX 0x0040 +#define XM_LPAR_PAUSEBITS 0x0180 +#define XM_LPAR_REMFAULTBITS 0x1800 +#define XM_LPAR_ACK 0x4000 +#define XM_LPAR_NEXTPAGE 0x8000 + +#define XM_PAUSE_NOPAUSE 0x0000 +#define XM_PAUSE_SYMPAUSE 0x0080 +#define XM_PAUSE_ASYMPAUSE 0x0100 +#define XM_PAUSE_BOTH 0x0180 + +#define XM_REMFAULT_LINKOK 0x0000 +#define XM_REMFAULT_LINKFAIL 0x0800 +#define XM_REMFAULT_OFFLINE 0x1000 +#define XM_REMFAULT_ANEGERR 0x1800 + +#define XM_ANEXP_GOTPAGE 0x0002 +#define XM_ANEXP_NEXTPAGE_SELF 0x0004 +#define XM_ANEXP_NEXTPAGE_LP 0x0008 + +#define XM_NEXTP_MESSAGE 0x07FF +#define XM_NEXTP_TOGGLE 0x0800 +#define XM_NEXTP_ACK2 0x1000 +#define XM_NEXTP_MPAGE 0x2000 +#define XM_NEXTP_ACK1 0x4000 +#define XM_NEXTP_NPAGE 0x8000 + +#define XM_LPNEXTP_MESSAGE 0x07FF +#define XM_LPNEXTP_TOGGLE 0x0800 +#define XM_LPNEXTP_ACK2 0x1000 +#define XM_LPNEXTP_MPAGE 0x2000 +#define XM_LPNEXTP_ACK1 0x4000 +#define XM_LPNEXTP_NPAGE 0x8000 + +#define XM_EXTSTS_HALFDUPLEX 0x4000 +#define XM_EXTSTS_FULLDUPLEX 0x8000 + +#define XM_RESAB_PAUSEMISMATCH 0x0008 +#define XM_RESAB_ABLMISMATCH 0x0010 +#define XM_RESAB_FDMODESEL 0x0020 +#define XM_RESAB_HDMODESEL 0x0040 +#define XM_RESAB_PAUSEBITS 0x0180 diff --git a/usr.sbin/sade/devices.c b/usr.sbin/sade/devices.c index 1439cbb..e12ad06 100644 --- a/usr.sbin/sade/devices.c +++ b/usr.sbin/sade/devices.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: devices.c,v 1.94 1999/07/03 05:41:21 mharo Exp $ + * $Id: devices.c,v 1.95 1999/07/06 20:40:22 phk Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -100,6 +100,7 @@ static struct _devname { { DEVICE_TYPE_NETWORK, "mx", "Macronix 98713/98715/98725 PCI ethernet card" }, { DEVICE_TYPE_NETWORK, "pn", "Lite-On 82168/82169 PNIC PCI ethernet card" }, { DEVICE_TYPE_NETWORK, "rl", "RealTek 8129/8139 PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "sk", "SysKonnect PCI gigabit ethernet card" }, { DEVICE_TYPE_NETWORK, "tx", "SMC 9432TX ethernet card" }, { DEVICE_TYPE_NETWORK, "ti", "Alteon Networks PCI gigabit ethernet card" }, { DEVICE_TYPE_NETWORK, "tl", "Texas Instruments ThunderLAN PCI ethernet card" }, diff --git a/usr.sbin/sysinstall/devices.c b/usr.sbin/sysinstall/devices.c index 1439cbb..e12ad06 100644 --- a/usr.sbin/sysinstall/devices.c +++ b/usr.sbin/sysinstall/devices.c @@ -4,7 +4,7 @@ * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: devices.c,v 1.94 1999/07/03 05:41:21 mharo Exp $ + * $Id: devices.c,v 1.95 1999/07/06 20:40:22 phk Exp $ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. @@ -100,6 +100,7 @@ static struct _devname { { DEVICE_TYPE_NETWORK, "mx", "Macronix 98713/98715/98725 PCI ethernet card" }, { DEVICE_TYPE_NETWORK, "pn", "Lite-On 82168/82169 PNIC PCI ethernet card" }, { DEVICE_TYPE_NETWORK, "rl", "RealTek 8129/8139 PCI ethernet card" }, + { DEVICE_TYPE_NETWORK, "sk", "SysKonnect PCI gigabit ethernet card" }, { DEVICE_TYPE_NETWORK, "tx", "SMC 9432TX ethernet card" }, { DEVICE_TYPE_NETWORK, "ti", "Alteon Networks PCI gigabit ethernet card" }, { DEVICE_TYPE_NETWORK, "tl", "Texas Instruments ThunderLAN PCI ethernet card" }, |