Add an experimental driver for NICs using Silan Microelectronics' SC92301
authorSascha Wildner <swildner@dragonflybsd.org>
Thu, 28 Feb 2008 18:39:20 +0000 (18:39 +0000)
committerSascha Wildner <swildner@dragonflybsd.org>
Thu, 28 Feb 2008 18:39:20 +0000 (18:39 +0000)
chip, some of which seem to be known as Rsltek [sic] 8139D. This is a port
of Silan's own FreeBSD 4.7 driver which was written by one 'gaoyonghong'.

It's up to the point where it works with the "Noganet KN-8139D" product,
but it still gives occasional errors/warnings on the console. Also, some
areas need to be brought more up to date.

Therefore, the if_sln.ko module is built, but the driver is not yet in
GENERIC.

Tested-by: Damian Vicino <dvicino@dc.uba.ar>
share/man/man4/Makefile
share/man/man4/sln.4 [new file with mode: 0644]
sys/conf/files
sys/config/LINT
sys/dev/netif/Makefile
sys/dev/netif/sln/Makefile [new file with mode: 0644]
sys/dev/netif/sln/if_sln.c [new file with mode: 0644]
sys/dev/netif/sln/if_slnreg.h [new file with mode: 0644]
sys/dev/netif/sln/if_slnvar.h [new file with mode: 0644]

index 081368a..740233f 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/18/93
 # $FreeBSD: src/share/man/man4/Makefile,v 1.83.2.66 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/share/man/man4/Makefile,v 1.77 2008/02/11 18:13:58 hasso Exp $
+# $DragonFly: src/share/man/man4/Makefile,v 1.78 2008/02/28 18:39:20 swildner Exp $
 
 MAN=   aac.4 \
        acpi.4 \
@@ -206,6 +206,7 @@ MAN=        aac.4 \
        sis.4 \
        sk.4 \
        sl.4 \
+       sln.4 \
        smb.4 \
        smbus.4 \
        smp.4 \
diff --git a/share/man/man4/sln.4 b/share/man/man4/sln.4
new file mode 100644 (file)
index 0000000..19ba939
--- /dev/null
@@ -0,0 +1,137 @@
+.\"
+.\" Copyright (c) 2008
+.\"    The DragonFly Project.  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. Neither the name of The DragonFly Project nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific, prior written permission.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $DragonFly: src/share/man/man4/sln.4,v 1.1 2008/02/28 18:39:20 swildner Exp $
+.\"
+.Dd February 28, 2008
+.Dt SLN 4
+.Os
+.Sh NAME
+.Nm sln
+.Nd Silan SC92031 10/100 Ethernet device
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device sln"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+if_sln_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for Ethernet adapters based on Silan's SC92031 chip.
+.Pp
+The
+.Nm
+driver supports the following
+.Cm media
+types:
+.Pp
+.Bl -tag -width ".Ar 10baseT/UTP" -compact
+.It Ar autoselect
+Enable autoselection of the media types and options.
+.Pp
+.It Ar 10baseT/UTP
+Set 10Mbps operation.
+The
+.Cm mediaopt
+option can also be used to select either
+.Ar full-duplex
+or
+.Ar half-duplex
+modes.
+.Pp
+.It Ar 100baseTX
+Set 100Mbps (Fast Ethernet) operation.
+The
+.Cm mediaopt
+option can also be used to select either
+.Ar full-duplex
+or
+.Ar half-duplex
+modes.
+.El
+.Pp
+The
+.Nm
+driver supports the following
+.Cm media
+options:
+.Pp
+.Bl -tag -width full-duplex -compact
+.It Cm full-duplex
+Force full duplex operation.
+.Pp
+.It Cm half-duplex
+Force half duplex operation.
+.El
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh HARDWARE
+The following cards are among those supported by the
+.Nm
+driver:
+.Pp
+.Bl -bullet -compact
+.It
+Noganet KN-8139D
+.El
+.Sh SEE ALSO
+.Xr arp 4 ,
+.\".Xr ifmedia 4 ,
+.Xr pci 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Dx 1.13
+as a port of a
+.Fx 4.7
+driver provided by Silan.
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was originally written by
+.An gaoyonghong
+and ported to
+.Dx
+by
+.An Sascha Wildner .
index 6eff2af..03865a2 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/sys/conf/files,v 1.205 2008/02/11 19:57:30 swildner Exp $
+# $DragonFly: src/sys/conf/files,v 1.206 2008/02/28 18:39:20 swildner Exp $
 #
 # The long compile-with and dependency lines are required because of
 # limitations in config: backslash-newline doesn't work in strings, and
@@ -351,6 +351,7 @@ dev/serial/si/si3_t225.c    optional si
 dev/serial/si/si_eisa.c        optional si eisa
 dev/serial/si/si_isa.c         optional si isa
 dev/serial/si/si_pci.c         optional si pci
+dev/netif/sln/if_sln.c         optional sln pci
 dev/netif/sn/if_sn.c           optional sn
 dev/netif/sn/if_sn_isa.c       optional sn isa
 dev/netif/sn/if_sn_pccard.c    optional sn pccard
index 5339adb..a65a46a 100644 (file)
@@ -3,7 +3,7 @@
 #      as much of the source tree as it can.
 #
 # $FreeBSD: src/sys/i386/conf/LINT,v 1.749.2.144 2003/06/04 17:56:59 sam Exp $
-# $DragonFly: src/sys/config/LINT,v 1.149 2008/02/11 19:57:30 swildner Exp $
+# $DragonFly: src/sys/config/LINT,v 1.150 2008/02/28 18:39:20 swildner 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
@@ -1408,6 +1408,7 @@ device le0 at isa? port 0x300 irq 5 iomem 0xd0000
 device lnc0 at isa? port 0x280 irq 10 drq 0
 device rdp0 at isa? port 0x378 irq 7 flags 2
 device sbni0 at isa? port 0x210 irq 5 flags 0xefdead
+device sln
 device sr0 at isa? port 0x300 irq 5 iomem 0xd0000
 device sn0 at isa? port 0x300 irq 10
 
index a775295..3988b1c 100644 (file)
@@ -1,9 +1,9 @@
-# $DragonFly: src/sys/dev/netif/Makefile,v 1.30 2008/02/01 13:18:48 sephe Exp $
+# $DragonFly: src/sys/dev/netif/Makefile,v 1.31 2008/02/28 18:39:20 swildner Exp $
 #
 
 SUBDIR= an acx ar ath aue axe bce bfe bge bwi cue dc ed em ep et fwe fxp \
        ipw iwi kue lge lnc mii_layer my msk nfe nge pcn ral re rl rtw rue \
-       rum sbni sbsh sf sis sk sr ste stge ti tl tx txp ural vge vr vx wb wi \
-       xe xl
+       rum sbni sbsh sf sis sk sln sr ste stge \
+       ti tl tx txp ural vge vr vx wb wi xe xl
 
 .include <bsd.subdir.mk>
diff --git a/sys/dev/netif/sln/Makefile b/sys/dev/netif/sln/Makefile
new file mode 100644 (file)
index 0000000..cca1033
--- /dev/null
@@ -0,0 +1,7 @@
+# $DragonFly: src/sys/dev/netif/sln/Makefile,v 1.1 2008/02/28 18:39:20 swildner Exp $
+
+KMOD=  if_sln
+SRCS=  if_sln.c
+SRCS+= device_if.h bus_if.h pci_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/dev/netif/sln/if_sln.c b/sys/dev/netif/sln/if_sln.c
new file mode 100644 (file)
index 0000000..040ce0a
--- /dev/null
@@ -0,0 +1,1196 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project.  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. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * $FreeBSD-4.7: /usr/src/sys/pci/silan.c,v 1.0 2003/01/10 gaoyonghong $
+ * $DragonFly: src/sys/dev/netif/sln/if_sln.c,v 1.1 2008/02/28 18:39:20 swildner Exp $
+ */
+
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/systm.h>
+
+#include <bus/pci/pcidevs.h>
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+
+#include <machine/clock.h>
+
+#include <net/bpf.h>
+#include <net/ethernet.h>
+#include <net/ifq_var.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_var.h>
+
+#include <vm/pmap.h>
+#include <vm/vm.h>
+
+#include "if_slnreg.h"
+#include "if_slnvar.h"
+
+/* Default to using PIO access for netcard driver */
+#define SL_USEIOSPACE
+
+#ifdef SLN_DEBUG
+#define PDEBUG(fmt, args...)   kprintf("%s: " fmt "\n" , __func__ , ## args)
+#else
+#define PDEBUG(fmt, args...)
+#endif
+
+static const struct sln_dev {
+       uint16_t vid;
+       uint16_t did;
+       const char *desc;
+} sln_devs[] = {
+       {PCI_VENDOR_SILAN, PCI_PRODUCT_SILAN_SC92301,
+        "Silan SC92031 Fast Ethernet" },
+       {PCI_VENDOR_SILAN, PCI_PRODUCT_SILAN_8139D,
+        "Silan Rsltek 8139D Fast Ethernet" },
+       {0, 0, NULL}
+};
+
+static int     sln_probe(device_t);
+static int     sln_attach(device_t);
+static int     sln_detach(device_t);
+static int     sln_shutdown(device_t);
+static int     sln_suspend(device_t);
+static int     sln_resume(device_t);
+
+static void    sln_reset(struct sln_softc *);
+static void    sln_init(void *);
+
+static void    sln_tx(struct ifnet *);
+static void    sln_rx(struct sln_softc *);
+static void    sln_tx_intr(struct sln_softc *);
+static void    sln_media_intr(struct sln_softc *);
+static void    sln_interrupt(void *);
+static int     sln_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
+static void    sln_stop(struct sln_softc *);
+static void    sln_watchdog(struct ifnet *);
+
+static int     sln_media_upd(struct ifnet *);
+
+static void    sln_media_stat(struct ifnet *, struct ifmediareq *);
+static void    sln_mii_cmd(struct sln_softc *, uint32_t, u_long *);
+static void    sln_media_cfg(struct sln_softc *);
+static void    sln_mac_cfg(struct sln_softc *);
+static uint32_t        sln_ether_crc32(caddr_t);
+static void    sln_set_multi(struct sln_softc *);
+static void    sln_init_tx(struct sln_softc *);
+static void    sln_tick(void *);
+
+#ifdef SL_USEIOSPACE
+#define SL_RID SL_PCI_IOAD
+#define SL_RES SYS_RES_IOPORT
+#else
+#define SL_RID SL_PCI_MEMAD
+#define SL_RES SYS_RES_MEMORY
+#endif
+
+static device_method_t sln_methods[] = {
+       DEVMETHOD(device_probe,         sln_probe),
+       DEVMETHOD(device_attach,        sln_attach),
+       DEVMETHOD(device_detach,        sln_detach),
+       DEVMETHOD(device_shutdown,      sln_shutdown),
+       DEVMETHOD(device_suspend,       sln_suspend),
+       DEVMETHOD(device_resume,        sln_resume),
+
+       DEVMETHOD(bus_print_child,      bus_generic_print_child),
+       DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
+
+       {0, 0}
+};
+
+static driver_t sln_driver = {
+       "sln",
+       sln_methods,
+       sizeof(struct sln_softc)
+};
+
+static devclass_t sln_devclass;
+
+DRIVER_MODULE(sln, pci, sln_driver, sln_devclass, 0, 0);
+
+static int
+sln_probe(struct device *dev)
+{
+       const struct sln_dev *d;
+       uint16_t did, vid;
+
+       vid = pci_get_vendor(dev);
+       did = pci_get_device(dev);
+
+       for (d = sln_devs; d->desc != NULL; d++) {
+               if (vid == d->vid && did == d->did) {
+                       device_set_desc(dev, d->desc);
+                       return 0;
+               }
+       }
+       return ENXIO;
+}
+
+/* the chip reset */
+static void
+sln_reset(struct sln_softc *sc)
+{
+       SLN_WRITE_4(sc, SL_CFG0, SL_SOFT_RESET);
+       DELAY(200000);
+       SLN_WRITE_4(sc, SL_CFG0, 0x0);
+       DELAY(10000);
+}
+
+/* Attach the interface. Allocate softc structures */
+static int
+sln_attach(device_t dev)
+{
+       struct sln_softc *sc = device_get_softc(dev);
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       unsigned char eaddr[ETHER_ADDR_LEN];
+       int rid;
+       int error = 0;
+
+       if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+
+       /* TODO: power state change */
+
+       pci_enable_busmaster(dev);
+
+       rid = SL_RID;
+       sc->sln_res = bus_alloc_resource_any(dev, SL_RES, &rid, RF_ACTIVE);
+       if (sc->sln_res == NULL) {
+               device_printf(dev, "couldn't map ports/memory\n");
+               error = ENXIO;
+               goto fail;
+       }
+       sc->sln_bustag = rman_get_bustag(sc->sln_res);
+       sc->sln_bushandle = rman_get_bushandle(sc->sln_res);
+
+       /* alloc pci irq */
+       rid = 0;
+       sc->sln_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+           RF_SHAREABLE | RF_ACTIVE);
+       if (sc->sln_irq == NULL) {
+               device_printf(dev, "couldn't map interrupt\n");
+               bus_release_resource(dev, SL_RES, SL_RID, sc->sln_res);
+               error = ENXIO;
+               goto fail;
+       }
+
+       /* Get MAC address */
+       ((uint32_t *)(&eaddr))[0] = be32toh(SLN_READ_4(sc, SL_MAC_ADDR0));
+       ((uint16_t *)(&eaddr))[2] = be16toh(SLN_READ_4(sc, SL_MAC_ADDR1));
+
+       /* alloc rx buffer space */
+       sc->sln_bufdata.sln_rx_buf = contigmalloc(SL_RX_BUFLEN,
+           M_DEVBUF, M_WAITOK, 0, 0xffffffff, PAGE_SIZE, 0);
+       if (sc->sln_bufdata.sln_rx_buf == NULL) {
+               device_printf(dev, "no memory for rx buffers!\n");
+               bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sln_irq);
+               bus_release_resource(dev, SL_RES, SL_RID, sc->sln_res);
+               error = ENXIO;
+               goto fail;
+       }
+       callout_init(&sc->sln_state);
+
+       ifp->if_softc = sc;
+       ifp->if_mtu = ETHERMTU;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_init = sln_init;
+       ifp->if_start = sln_tx;
+       ifp->if_ioctl = sln_ioctl;
+       ifp->if_watchdog = sln_watchdog;
+       ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
+       ifq_set_ready(&ifp->if_snd);
+
+       /* initial media */
+       ifmedia_init(&sc->ifmedia, 0, sln_media_upd, sln_media_stat);
+
+       /* supported media types */
+       ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
+       ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
+       ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_HDX, 0, NULL);
+       ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
+       ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL);
+       ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_HDX, 0, NULL);
+       ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
+
+       /* Choose a default media. */
+       ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_AUTO);
+
+       ether_ifattach(ifp, eaddr, NULL);
+
+       error = bus_setup_intr(dev, sc->sln_irq, INTR_MPSAFE, sln_interrupt, sc,
+                              &sc->sln_intrhand, ifp->if_serializer);
+       if (error) {
+               bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sln_irq);
+               bus_release_resource(dev, SL_RES, SL_RID, sc->sln_res);
+               ether_ifdetach(ifp);
+               device_printf(dev, "couldn't set up irq\n");
+               goto fail;
+       }
+       return 0;
+fail:
+       return error;
+}
+
+/* Stop the adapter and free any mbufs allocated to the RX and TX buffers */
+static void
+sln_stop(struct sln_softc *sc)
+{
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       uint32_t intr_status;
+       int i;
+
+       ASSERT_SERIALIZED(ifp->if_serializer);
+
+       ifp->if_timer = 0;
+       callout_stop(&sc->sln_state);
+
+       /* disable Tx/Rx */
+       sc->txcfg &= ~SL_TXCFG_EN;
+       sc->rxcfg &= ~SL_RXCFG_EN;
+       SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
+       SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
+
+       /* Clear interrupt */
+       SLN_WRITE_4(sc, SL_INT_MASK, 0);
+       intr_status = SLN_READ_4(sc, SL_INT_STATUS);
+
+       /* Free the TX list buffers */
+       for (i = 0; i < SL_TXD_CNT; i++) {
+               if (sc->sln_bufdata.sln_tx_buf[i] != NULL) {
+                       m_freem(sc->sln_bufdata.sln_tx_buf[i]);
+                       sc->sln_bufdata.sln_tx_buf[i] = NULL;
+                       SLN_WRITE_4(sc, SL_TSAD0 + i * 4, 0);
+               }
+       }
+
+       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+}
+
+static int
+sln_detach(device_t dev)
+{
+       struct sln_softc *sc = device_get_softc(dev);
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+
+       lwkt_serialize_enter(ifp->if_serializer);
+       sln_stop(sc);
+       bus_teardown_intr(dev, sc->sln_irq, sc->sln_intrhand);
+       lwkt_serialize_exit(ifp->if_serializer);
+
+       ether_ifdetach(ifp);
+
+       bus_generic_detach(dev);
+
+       bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sln_irq);
+       bus_release_resource(dev, SL_RES, SL_RID, sc->sln_res);
+       
+       contigfree(sc->sln_bufdata.sln_rx_buf, SL_RX_BUFLEN, M_DEVBUF);
+
+       return 0;
+}
+
+static int
+sln_media_upd(struct ifnet *ifp)
+{
+       struct sln_softc *sc = ifp->if_softc;
+       struct ifmedia *ifm = &sc->ifmedia;
+
+       if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+               return EINVAL;
+
+       if (ifp->if_flags & IFF_UP)
+               sln_init(sc);
+
+       return 0;
+}
+
+static void
+sln_media_stat(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+       struct sln_softc *sc = ifp->if_softc;
+       u_long phys[2];
+       uint32_t temp;
+
+       ifmr->ifm_status = IFM_AVALID;
+       ifmr->ifm_active = IFM_ETHER;
+
+       phys[0] = SL_MII_STAT;
+       sln_mii_cmd(sc, SL_MII0_READ, phys);
+
+       if (phys[1] & SL_MIISTAT_LINK)
+               ifmr->ifm_status |= IFM_ACTIVE;
+
+       temp = SLN_READ_4(sc, SL_PHY_CTRL);
+
+       if ((temp & (SL_PHYCTL_DUX | SL_PHYCTL_SPD100 | SL_PHYCTL_SPD10)) == 0x60800000)
+               ifmr->ifm_active |= IFM_AUTO;
+       else if ((temp & (SL_PHYCTL_DUX | SL_PHYCTL_SPD100)) == 0x40800000)
+               ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
+       else if ((temp & SL_PHYCTL_SPD100) == 0x40000000)
+               ifmr->ifm_active |= IFM_100_TX | IFM_HDX;
+       else if ((temp & (SL_PHYCTL_DUX | SL_PHYCTL_SPD10)) == 0x20800000)
+               ifmr->ifm_active |= IFM_10_T | IFM_FDX;
+       else if ((temp & SL_PHYCTL_SPD10) == 0x20000000)
+               ifmr->ifm_active |= IFM_10_T | IFM_HDX;
+
+       sln_mii_cmd(sc, SL_MII0_SCAN, phys);
+}
+
+/* command selected in MII command register  */
+static void
+sln_mii_cmd(struct sln_softc *sc, uint32_t cmd, u_long *phys)
+{
+       uint32_t mii_status;
+
+       SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER);
+
+       do {
+               mii_status = 0;
+               DELAY(10);
+               mii_status = SLN_READ_4(sc, SL_MII_STATUS);
+       } while (mii_status & SL_MIISTAT_BUSY);
+
+       switch (cmd) {
+       case SL_MII0_SCAN:
+               SLN_WRITE_4(sc, SL_MII_CMD1, 0x1 << 6);
+               SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER | SL_MII0_SCAN);
+               break;
+
+       case SL_MII0_READ:
+               SLN_WRITE_4(sc, SL_MII_CMD1, phys[0] << 6);
+               SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER | SL_MII0_READ);
+               break;
+
+       default:                /* WRITE */
+               SLN_WRITE_4(sc, SL_MII_CMD1, phys[0] << 6 | phys[1] << 11);
+               SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER | SL_MII0_WRITE);
+               break;
+       }
+
+       do {
+               DELAY(10);
+               mii_status = SLN_READ_4(sc, SL_MII_STATUS);
+       } while (mii_status & SL_MIISTAT_BUSY);
+
+       if (SL_MII0_READ == cmd)
+               phys[1] = (mii_status >> 13) & 0xffff;
+}
+
+/* Set media speed and duplex mode */
+static void
+sln_media_cfg(struct sln_softc *sc)
+{
+       u_long phys[2];
+       uint32_t mediatype;
+       uint32_t temp;
+
+       mediatype = (&sc->ifmedia)->ifm_cur->ifm_media;
+
+       temp = SLN_READ_4(sc, SL_PHY_CTRL);
+       temp &= ~(SL_PHYCTL_DUX | SL_PHYCTL_SPD100 | SL_PHYCTL_SPD10);
+       temp |= (SL_PHYCTL_ANE | SL_PHYCTL_RESET);
+
+       /************************************************/
+       /* currently set media word by selected media   */
+       /*                                              */
+       /* IFM_ETHER = 0x00000020                       */
+       /* IFM_AUTO=0, IFM_10_T=3,  IFM_100_TX=6        */
+       /* IFM_FDX=0x00100000    IFM_HDX=0x00200000     */
+       /************************************************/
+       switch (mediatype) {
+       case 0x00000020:
+               PDEBUG(" autoselet supported\n");
+               temp |= (SL_PHYCTL_DUX | SL_PHYCTL_SPD100 | SL_PHYCTL_SPD10);
+               sc->ifmedia.ifm_media = IFM_ETHER | IFM_AUTO;
+               ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_AUTO);
+               break;
+       case 0x23:
+       case 0x00200023:
+               PDEBUG(" 10Mbps half_duplex supported\n");
+               temp |= SL_PHYCTL_SPD10;
+               sc->ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX;
+               ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_HDX);
+               break;
+
+       case 0x00100023:
+               PDEBUG("10Mbps full_duplex supported\n");
+               temp |= (SL_PHYCTL_SPD10 | SL_PHYCTL_DUX);
+               sc->ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_FDX;
+               ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX);
+               break;
+
+       case 0x26:
+       case 0x00200026:
+               PDEBUG("100Mbps half_duplex supported\n");
+               temp |= SL_PHYCTL_SPD100;
+               sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_HDX;
+               ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_HDX);
+               break;
+
+       case 0x00100026:
+               PDEBUG("100Mbps full_duplex supported\n");
+               temp |= (SL_PHYCTL_SPD100 | SL_PHYCTL_DUX);
+               sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_FDX;
+               ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX);
+               break;
+
+       default:
+               break;
+       }
+
+       SLN_WRITE_4(sc, SL_PHY_CTRL, temp);
+
+       DELAY(10000);
+       temp &= ~SL_PHYCTL_RESET;
+       SLN_WRITE_4(sc, SL_PHY_CTRL, temp);
+
+       DELAY(1000);
+       phys[0] = SL_MII_JAB;
+       phys[1] = SL_PHY_16_JAB_ENB | SL_PHY_16_PORT_ENB;
+       sln_mii_cmd(sc, SL_MII0_WRITE, phys);
+
+       sc->connect = 0;
+       sln_mii_cmd(sc, SL_MII0_SCAN, phys);
+}
+
+static void
+sln_mac_cfg(struct sln_softc *sc)
+{
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       u_long flowcfg = 0;
+
+       /* Set the initial TX/RX/Flow Control configuration */
+       sc->rxcfg = SL_RXCFG_LOW_THRESHOLD | SL_RXCFG_HIGH_THRESHOLD;
+       sc->txcfg = TX_CFG_DEFAULT;
+
+       if (sc->txenablepad)
+               sc->txcfg |= 0x20000000;
+
+       if (sc->media_speed == IFM_10_T)
+               sc->txcfg |= SL_TXCFG_DATARATE;
+
+       if (sc->media_duplex == IFM_FDX) {
+               sc->rxcfg |= SL_RXCFG_FULLDX;
+               sc->txcfg |= SL_TXCFG_FULLDX;
+               flowcfg = SL_FLOWCTL_FULLDX | SL_FLOWCTL_EN;
+       } else {
+               sc->rxcfg &= ~SL_RXCFG_FULLDX;
+               sc->txcfg &= ~SL_TXCFG_FULLDX;
+       }
+
+       /* if promiscuous mode, set the allframes bit. */
+       if (ifp->if_flags & IFF_PROMISC)
+               sc->rxcfg |= (SL_RXCFG_EN | SL_RXCFG_RCV_SMALL | SL_RXCFG_RCV_HUGE | SL_RXCFG_RCV_ERR | SL_RXCFG_RCV_BROAD | SL_RXCFG_RCV_MULTI | SL_RXCFG_RCV_ALL);
+       else
+               sc->rxcfg &= ~(SL_RXCFG_EN | SL_RXCFG_RCV_SMALL | SL_RXCFG_RCV_HUGE | SL_RXCFG_RCV_ERR | SL_RXCFG_RCV_BROAD | SL_RXCFG_RCV_MULTI | SL_RXCFG_RCV_ALL);
+
+       /* Set capture broadcast bit to capture broadcast frames */
+       if (ifp->if_flags & IFF_BROADCAST)
+               sc->rxcfg |= SL_RXCFG_EN | SL_RXCFG_RCV_BROAD;
+       else
+               sc->rxcfg &= ~(SL_RXCFG_EN | SL_RXCFG_RCV_BROAD);
+
+       /* Program the multicast filter, if necessary */
+       sln_set_multi(sc);
+
+       SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
+       SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
+       SLN_WRITE_4(sc, SL_FLOW_CTRL, flowcfg);
+}
+
+static u_char shade_map[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
+                             0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
+
+/* Calculate CRC32 of a multicast group address */
+static uint32_t
+sln_ether_crc32(caddr_t addr)
+{
+       uint32_t crc, crcr;
+       int i, j;
+       unsigned char data = 0;
+       /* Compute CRC for the address value. */
+
+       crc = 0xFFFFFFFF;       /* initial value */
+
+       for (i = ETHER_ADDR_LEN; i > 0; i--) {
+               data = *addr++;
+
+               for (j = 0; j < 8; j++) {
+                       if (((data & 0x1) ^ (crc & 0x1)) != 0) {
+                               crc >>= 1;
+                               crc ^= 0xEDB88320;
+                       } else {
+                               crc >>= 1;
+                       }
+                       data >>= 1;
+               }
+       }
+
+       crcr = shade_map[crc >> 28];
+       crcr |= (shade_map[(crc >> 24) & 0xf] << 4);
+       crcr |= (shade_map[(crc >> 20) & 0xf] << 8);
+       crcr |= (shade_map[(crc >> 16) & 0xf] << 12);
+       crcr |= (shade_map[(crc >> 12) & 0xf] << 16);
+       crcr |= (shade_map[(crc >> 8) & 0xf] << 20);
+       crcr |= (shade_map[(crc >> 4) & 0xf] << 24);
+       crcr |= (shade_map[crc & 0xf] << 28);
+
+       return crcr;
+}
+
+/* Program the 64-bit multicast hash filter */
+static void
+sln_set_multi(struct sln_softc *sc)
+{
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       uint32_t crc = 0;
+       uint32_t mc_g[2] = {0, 0};
+       struct ifmultiaddr *ifma;
+       int i, j;
+
+       if (ifp->if_flags & IFF_PROMISC) {
+               kprintf("Promisc mode is enabled\n");
+               sc->rxcfg |= SL_RXCFG_EN | SL_RXCFG_RCV_MULTI;
+               mc_g[0] = mc_g[1] = 0xFFFFFFFF;
+       } else if (ifp->if_flags & IFF_ALLMULTI) {
+               kprintf("Allmulti mode is enabled\n");
+               sc->rxcfg |= SL_RXCFG_EN | SL_RXCFG_RCV_MULTI;
+               mc_g[0] = mc_g[1] = 0xFFFFFFFF;
+       } else if (ifp->if_flags & IFF_MULTICAST) {
+               kprintf("Multicast mode is enabled\n");
+               sc->rxcfg |= SL_RXCFG_EN | SL_RXCFG_RCV_MULTI;
+
+               /* first, zero all the existing hash bits */
+               mc_g[0] = mc_g[1] = 0;
+
+               for (i = 0, ifma = (ifp->if_multiaddrs.lh_first);
+                    ifma != NULL && (i < ifma->ifma_refcount);
+                    i++, ifma = (ifma->ifma_link.le_next)) {
+                       j = 0;
+
+                       if ((ifma->ifma_addr->sa_family) != AF_LINK)
+                               continue;
+
+                       crc = ~sln_ether_crc32(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+                       crc >>= 24;
+
+                       if (crc & 0x1)
+                               j |= 0x2;
+                       if (crc & 0x2)
+                               j |= 0x1;
+                       if (crc & 0x10)
+                               j |= 0x20;
+                       if (crc & 0x20)
+                               j |= 0x10;
+                       if (crc & 0x40)
+                               j |= 0x8;
+                       if (crc & 0x80)
+                               j |= 0x4;
+
+                       if (j > 31)
+                               mc_g[0] |= (0x1 << (j - 32));
+                       else
+                               mc_g[1] |= (0x1 << j);
+               }
+       } else {
+               sc->rxcfg &= ~(SL_RXCFG_EN | SL_RXCFG_RCV_MULTI);
+       }
+
+       SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
+       SLN_WRITE_4(sc, SL_MULTI_GROUP0, mc_g[0]);
+       SLN_WRITE_4(sc, SL_MULTI_GROUP1, mc_g[1]);
+}
+
+/* Initialize the TX/Rx descriptors */
+static void
+sln_init_tx(struct sln_softc *sc)
+{
+       int i;
+
+       sc->sln_bufdata.cur_tx = 0;
+       sc->sln_bufdata.dirty_tx = 0;
+
+       for (i = 0; i < SL_TXD_CNT; i++) {
+               sc->sln_bufdata.sln_tx_buf[i] = NULL;
+               SLN_WRITE_4(sc, SL_TSAD0 + (i * 4), 0);
+       }
+}
+
+/* Software & Hardware Initialize */
+static void
+sln_init(void *x)
+{
+       struct sln_softc *sc = x;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+
+       PDEBUG("sln_init\n");
+
+       ASSERT_SERIALIZED(ifp->if_serializer);
+
+       sln_stop(sc);
+
+       /* soft reset the chip */
+       sln_reset(sc);
+
+       /* disable interrupt */
+       SLN_WRITE_4(sc, SL_INT_MASK, 0);
+
+       /* SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER); */
+
+       /* clear multicast address */
+       SLN_WRITE_4(sc, SL_MULTI_GROUP0, 0);
+       SLN_WRITE_4(sc, SL_MULTI_GROUP1, 0);
+
+       /* Init the RX buffer start address register. */
+       SLN_WRITE_4(sc, SL_RBSA, vtophys(sc->sln_bufdata.sln_rx_buf));
+       sc->sln_bufdata.dirty_rx = vtophys(sc->sln_bufdata.sln_rx_buf);
+
+       /* Init TX descriptors. */
+       sln_init_tx(sc);
+
+       /* configure RX buffer size */
+       if (sc->tx_early_ctrl && sc->rx_early_ctrl)
+               SLN_WRITE_4(sc, SL_CFG1, SL_EARLY_RX | SL_EARLY_TX | SL_RXBUF_64 | SL_RXFIFO_1024BYTES);
+       else if (sc->tx_early_ctrl)
+               SLN_WRITE_4(sc, SL_CFG1, SL_EARLY_TX | SL_RXBUF_64);
+       else if (sc->rx_early_ctrl)
+               SLN_WRITE_4(sc, SL_CFG1, SL_EARLY_RX | SL_RXBUF_64 | SL_RXFIFO_1024BYTES);
+       else
+               SLN_WRITE_4(sc, SL_CFG1, SL_RXBUF_64);
+
+       /* MII media configuration */
+       sln_media_cfg(sc);
+
+       if (sc->connect) {
+               /* Enable transmit and receive */
+               sc->rxcfg |= SL_RXCFG_EN;
+               sc->txcfg |= SL_TXCFG_EN;
+       } else {
+               sc->rxcfg &= ~SL_RXCFG_EN;
+               sc->txcfg &= ~SL_TXCFG_EN;
+       }
+
+       SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
+       SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
+
+       /* Enable interrupts */
+       SLN_WRITE_4(sc, SL_INT_MASK, SL_INRTS);
+
+       sc->suspended = 0;
+
+       ifp->if_flags |= IFF_RUNNING;
+       ifp->if_flags &= ~IFF_OACTIVE;
+
+       callout_reset(&sc->sln_state, hz, sln_tick, sc);
+}
+
+/* Transmit Packet */
+static void
+sln_tx(struct ifnet *ifp)
+{
+       struct sln_softc *sc = ifp->if_softc;
+       struct mbuf *m_head = NULL;
+       struct mbuf *m_new = NULL;
+       int entry;
+
+       ASSERT_SERIALIZED(ifp->if_serializer);
+
+       if (!sc->connect ||
+           (ifp->if_flags & (IFF_OACTIVE | IFF_RUNNING)) != IFF_RUNNING)
+               return;
+
+       while (SL_CUR_TXBUF(sc) == NULL) {      /* SL_CUR_TXBUF(x) = x->sln_bufdata.sln_tx_buf[x->sln_bufdata.cur_tx] */
+               entry = sc->sln_bufdata.cur_tx;
+
+               m_head = ifq_dequeue(&ifp->if_snd, NULL);
+               if (m_head == NULL)
+                       break;
+
+               MGETHDR(m_new, MB_DONTWAIT, MT_DATA);
+               if (m_new == NULL) {
+                       if_printf(ifp, "no memory for tx descriptor");
+                       m_freem(m_head);
+                       break;
+               }
+               if ((m_head->m_pkthdr.len > MHLEN) || (60 > MHLEN)) {
+                       MCLGET(m_new, MB_DONTWAIT);
+                       if (!(m_new->m_flags & M_EXT)) {
+                               m_freem(m_new);
+                               m_freem(m_head);
+                               if_printf(ifp, "no memory for tx descriptor");
+                               break;
+                       }
+               }
+               m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t));
+               m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
+               m_freem(m_head);
+               m_head = m_new;
+               SL_CUR_TXBUF(sc) = m_head;
+
+               /*
+                * if there's a BPF listener, bounce a copy of this frame to
+                * him
+                */
+               BPF_MTAP(ifp, SL_CUR_TXBUF(sc));
+
+               /* Transmit the frame */
+               SLN_WRITE_4(sc, ((entry * 4) + SL_TSAD0),
+                   vtophys(mtod(SL_CUR_TXBUF(sc), caddr_t)));
+
+               /* calculate length of the frame */
+               if ((SL_CUR_TXBUF(sc)->m_pkthdr.len < 60) && (!sc->txenablepad)) {
+                       memset(mtod(m_head, char *)+m_head->m_pkthdr.len, 0x20, 60 - m_head->m_pkthdr.len);
+                       SLN_WRITE_4(sc, (entry * 4) + SL_TSD0, 60);
+               } else if (SL_CUR_TXBUF(sc)->m_pkthdr.len < 100)
+                       SLN_WRITE_4(sc, (entry * 4) + SL_TSD0, SL_CUR_TXBUF(sc)->m_pkthdr.len);
+               else if (SL_CUR_TXBUF(sc)->m_pkthdr.len < 300)
+                       SLN_WRITE_4(sc, (entry * 4) + SL_TSD0, 0x30000 | SL_CUR_TXBUF(sc)->m_pkthdr.len);
+               else
+                       SLN_WRITE_4(sc, (entry * 4) + SL_TSD0, 0x50000 | SL_CUR_TXBUF(sc)->m_pkthdr.len);
+               sc->sln_bufdata.cur_tx = (entry + 1) % SL_TXD_CNT;
+
+               PDEBUG("Queue tx packet size %d to tx-descriptor %d.\n", m_head->m_pkthdr.len, entry);
+       }
+
+       /* Tx buffer chain full */
+       if (SL_CUR_TXBUF(sc) != NULL)
+               ifp->if_flags |= IFF_OACTIVE;
+
+       /* Set a timeout in case the chip goes out to lunch */
+       ifp->if_timer = 5;
+}
+
+/* Receive Data handler */
+static void
+sln_rx(struct sln_softc *sc)
+{
+       struct mbuf *m;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       uint32_t rxstat = 0;
+       uint32_t rx_offset;
+       caddr_t rx_bufpos = NULL;
+       uint32_t cur_rx = 0;
+       uint32_t dirty_rx;
+       long rx_len;
+       u_long rx_space;
+       u_long rx_size = 0;
+       u_long rx_size_align = 0;
+       uint32_t rx_bytes = 0;
+       u_long pkt_size = 0;
+
+       cur_rx = SLN_READ_4(sc, SL_RBW_PTR);
+       dirty_rx = sc->sln_bufdata.dirty_rx;
+
+       /*
+        * cur_rx is only 17 bits in the RxBufWPtr register. if cur_rx can be
+        * used in physical space, we need to change it to 32 bits physical
+        * address
+        */
+       cur_rx |= vtophys(sc->sln_bufdata.sln_rx_buf) & (~(u_long) (SL_RX_BUFLEN - 1));
+
+       if (cur_rx < vtophys(sc->sln_bufdata.sln_rx_buf))
+               cur_rx += SL_RX_BUFLEN;
+
+       if (cur_rx >= dirty_rx)
+               rx_len = (long)(cur_rx - dirty_rx);
+       else
+               rx_len = SL_RX_BUFLEN - (long)(dirty_rx - cur_rx);
+
+       if ((rx_len > SL_RX_BUFLEN) || (rx_len < 0)) {
+               if_printf(ifp, "rx len is fail\n");
+               return;
+       }
+       if (rx_len == 0)
+               return;
+
+       rx_offset = (dirty_rx - vtophys(sc->sln_bufdata.sln_rx_buf)) & (u_long) (SL_RX_BUFLEN - 1);
+
+       while (rx_len > 0) {
+               rx_bufpos = sc->sln_bufdata.sln_rx_buf + rx_offset;
+               rxstat = *(uint32_t *) rx_bufpos;
+               rx_size = (rxstat >> 20) & 0x0FFF;
+               rx_size_align = (rx_size + 3) & ~3;     /* for 4 bytes aligned */
+               pkt_size = rx_size - ETHER_CRC_LEN;     /* Omit the four octet
+                                                        * CRC from the length. */
+
+               PDEBUG("rx len: %ld  rx frame size:%ld  rx state:0x%x\n", rx_len, rx_size, rxstat);
+
+               /* errors receive packets caculatation */
+               if (rxstat == 0 || rx_size < 16 || !(rxstat & SL_RXSTAT_RXOK)) {
+                       ifp->if_ierrors++;
+
+                       if (!(rxstat & SL_RXSTAT_RXOK))
+                               if_printf(ifp, "receiver ok error\n");
+
+                       if (!(rxstat & SL_RXSTAT_CRCOK))
+                               if_printf(ifp, "crc error\n");
+
+                       if (rxstat & SL_RXSTAT_ALIGNERR)
+                               if_printf(ifp, "frame alignment error\n");
+
+                       if (rxstat & (SL_RXSTAT_HUGEFRM | SL_RXSTAT_SMALLFRM))
+                               if_printf(ifp, "received frame length is error\n");
+
+                       break;
+               }
+               rx_len -= (long)(rx_size_align + 4);    /* 4 bytes for receive
+                                                        * frame head */
+
+               if (rx_len < 0) {
+                       kprintf("rx packets len is too small\n");
+                       break;
+               }
+#ifdef SLN_PDEBUG
+               caddr_t p = NULL;
+
+               if_printf(ifp, "rx frame content\n");
+               p = rx_bufpos;
+               for (i = 0; i < 30; i++, p++) {
+                       if (i % 10 == 0)
+                               kprintf("\n");
+                       if_printf(ifp, "%x  ", (u_char)*p);
+               }
+               if_printf(ifp, "\n");
+#endif
+               /* No errors; receive the packet. */
+               rx_bytes = rx_bytes + rx_size + 4;      /* 4 bytes for receive
+                                                        * frame header */
+
+               if (rx_bufpos == (sc->sln_bufdata.sln_rx_buf + SL_RX_BUFLEN))
+                       rx_bufpos = sc->sln_bufdata.sln_rx_buf;
+
+               rx_bufpos = rx_bufpos + 4;      /* 4 bytes for receive frame
+                                                * header */
+               rx_space = (u_long)((sc->sln_bufdata.sln_rx_buf + SL_RX_BUFLEN) - rx_bufpos);
+
+               if (pkt_size > rx_space) {
+                       m = m_devget(rx_bufpos - 2, pkt_size + 2, 0, ifp, NULL);        /* 2 for etherer head
+                                                                                        * align */
+
+                       if (m == NULL) {
+                               ifp->if_ierrors++;
+                               if_printf(ifp,
+                                   "out of mbufs, tried to copy %ld bytes\n",
+                                   rx_space);
+                       } else {
+                               m_adj(m, 2);
+                               m_copyback(m, rx_space, pkt_size - rx_space, sc->sln_bufdata.sln_rx_buf);
+                       }
+               } else {
+                       m = m_devget(rx_bufpos - 2, pkt_size + 2, 0, ifp, NULL);
+
+                       if (m == NULL) {
+                               ifp->if_ierrors++;
+                               if_printf(ifp,
+                                   "out of mbufs, tried to copy %ld bytes\n",
+                                   pkt_size);
+                               if_printf(ifp, "ierrors = %ld\n", ifp->if_ierrors);
+
+                       } else {
+                               m_adj(m, 2);
+                       }
+               }
+
+               ifp->if_ipackets++;
+               PDEBUG("ipackets = %ld\n", ifp->if_ipackets);
+
+               ifp->if_input(ifp, m);
+
+               rx_offset = (rx_offset + rx_size + 4) & (u_long) (SL_RX_BUFLEN - 1);    /* 4 bytes for receive
+                                                                                        * frame head */
+       }
+
+       sc->sln_bufdata.dirty_rx = cur_rx;
+
+       SLN_WRITE_4(sc, SL_RBR_PTR, cur_rx);
+}
+
+/* Transmit OK/ERR handler */
+static void
+sln_tx_intr(struct sln_softc *sc)
+{
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       uint32_t txstat;
+       int entry;
+
+       do {
+               entry = sc->sln_bufdata.dirty_tx;
+               txstat = SLN_READ_4(sc, SL_TSD0 + entry * 4);
+
+               if (!(txstat & (SL_TXSD_TOK | SL_TXSD_TUN | SL_TXSD_TABT)))
+                       break;  /* It still hasn't been sent */
+
+               if (SL_DIRTY_TXBUF(sc) != NULL) {       /* SL_DIRTY_TXBUF(x) =
+                                                        * x->sln_bufdata.sln_tx_
+                                                        * buf[x->sln_bufdata.dir
+                                                        * ty_tx] */
+                       m_freem(SL_DIRTY_TXBUF(sc));
+                       SL_DIRTY_TXBUF(sc) = NULL;
+               }
+               if (txstat & SL_TXSD_TOK) {
+                       ifp->if_opackets++;
+                       ifp->if_obytes += txstat & SL_TXSD_LENMASK;
+                       PDEBUG("opackets = %ld\n", ifp->if_opackets);
+                       ifp->if_collisions += (txstat & SL_TXSD_NCC) >> 22;
+               } else {
+                       ifp->if_oerrors++;
+                       if ((txstat & (SL_TXSD_TABT | SL_TXSD_OWC))) {
+                               sc->txcfg = TX_CFG_DEFAULT;
+
+                               if (sc->txenablepad)
+                                       sc->txcfg |= 0x20000000;
+
+                               SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
+                       }
+               }
+               PDEBUG("tx done descriprtor %x\n", entry);
+               sc->sln_bufdata.dirty_tx = (entry + 1) % SL_TXD_CNT;
+
+               ifp->if_flags &= ~IFF_OACTIVE;
+       } while (sc->sln_bufdata.dirty_tx != sc->sln_bufdata.cur_tx);
+
+       if (sc->sln_bufdata.dirty_tx == sc->sln_bufdata.cur_tx)
+               ifp->if_timer = 0;
+       else
+               ifp->if_timer = 5;
+}
+
+static void
+sln_media_intr(struct sln_softc *sc)
+{
+       u_long phys[2];
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+
+       phys[0] = SL_MII_STAT;
+       sln_mii_cmd(sc, SL_MII0_READ, phys);
+
+       PDEBUG("mii_stat:0x%lx\n", phys[1]);
+
+       if (0 == (phys[1] & SL_MIISTAT_LINK)) {
+               kprintf("media is unconnect,linked down,or uncompatible\n");
+               sc->connect = 0;
+               sln_mii_cmd(sc, SL_MII0_SCAN, phys);
+               /* disable tx/rx */
+               sc->txcfg &= ~SL_TXCFG_EN;
+               sc->rxcfg &= ~SL_RXCFG_EN;
+               SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
+               SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
+
+               return;
+       }
+       /* Link is good. Report modes and set duplex mode. */
+       PDEBUG("media is connecting---> ");
+       sc->connect = 1;
+
+       phys[0] = SL_MII_STAT_OUTPUT;
+       sln_mii_cmd(sc, SL_MII0_READ, phys);
+       sc->media_duplex = ((phys[1] & 0x0004) == 0) ? IFM_HDX : IFM_FDX;
+       sc->media_speed = ((phys[1] & 0x0002) == 0) ? IFM_10_T : IFM_100_TX;
+
+       if_printf(ifp, "media option:%dM %s-duplex\n",
+           sc->media_speed == 0x6 ? 100 : 10,
+           sc->media_duplex == 0x100000 ? "full" : "half");
+
+       sln_mii_cmd(sc, SL_MII0_SCAN, phys);
+
+       sln_mac_cfg(sc);
+
+       /* Enable tx/rx */
+       sc->rxcfg |= SL_RXCFG_EN;
+       sc->txcfg |= SL_TXCFG_EN;
+       SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
+       SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
+}
+
+/* Interrupt Handler */
+static void
+sln_interrupt(void *arg)
+{
+       struct sln_softc *sc = arg;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       uint32_t int_status;
+
+       ASSERT_SERIALIZED(ifp->if_serializer);
+
+       if (sc->suspended || (ifp->if_flags & IFF_RUNNING) == 0)
+               return;
+
+       /* Disable interrupts. */
+       SLN_WRITE_4(sc, SL_INT_MASK, 0);
+
+       int_status = SLN_READ_4(sc, SL_INT_STATUS);
+
+       if ((int_status == 0xffffffff) || (int_status & SL_INRTS) == 0)
+               goto back;
+
+       int_status = int_status & SL_INRTS;
+       PDEBUG("int_status = 0x%x\n", int_status);
+
+       while (0 != int_status) {
+               if (int_status & SL_INT_ROK)
+                       sln_rx(sc);
+
+               if (int_status & SL_INT_TOK)
+                       sln_tx_intr(sc);
+
+               if (int_status & SL_INT_RBO) {
+                       ifp->if_ierrors++;
+                       PDEBUG("rx buffer is overflow\n");
+               }
+
+               if (int_status & (SL_INT_LINKFAIL | SL_INT_LINKOK))
+                       sln_media_intr(sc);
+
+               int_status = SLN_READ_4(sc, SL_INT_STATUS);
+       }
+
+       /* Data in Tx buffer waiting for transimission */
+       if (!ifq_is_empty(&ifp->if_snd))
+               sln_tx(ifp);
+back:
+       /* Re-enable interrupts. */
+       SLN_WRITE_4(sc, SL_INT_MASK, SL_INRTS);
+}
+
+static void
+sln_tick(void *x)
+{
+       struct sln_softc *sc = x;
+
+       callout_reset(&sc->sln_state, hz, sln_tick, sc);
+}
+
+static int
+sln_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
+{
+       struct sln_softc *sc = ifp->if_softc;
+       struct ifreq *ifr = (struct ifreq *)data;
+       int error = 0;
+
+       ASSERT_SERIALIZED(ifp->if_serializer);
+
+       switch (cmd) {
+       case SIOCSIFFLAGS:
+               if (ifp->if_flags & IFF_UP) {
+                       if ((ifp->if_flags & IFF_RUNNING) == 0)
+                               sln_init(sc);
+               } else {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               sln_stop(sc);
+               }
+               break;
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+               sln_set_multi(sc);
+               break;
+       case SIOCGIFMEDIA:
+       case SIOCSIFMEDIA:
+               error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd);
+               break;
+       default:
+               error = ether_ioctl(ifp, cmd, data);
+               break;
+       }
+       return error;
+}
+
+static void
+sln_watchdog(struct ifnet *ifp)
+{
+       struct sln_softc *sc = ifp->if_softc;
+
+       ASSERT_SERIALIZED(ifp->if_serializer);
+
+       if_printf(ifp, "watchdog timeout!\n");
+       ifp->if_oerrors++;
+
+       sln_tx_intr(sc);
+       sln_rx(sc);
+       sln_init(sc);
+
+       if (!ifq_is_empty(&ifp->if_snd))
+               sln_tx(ifp);
+}
+
+/* Stop all chip I/O */
+static int
+sln_shutdown(device_t dev)
+{
+       struct sln_softc *sc = device_get_softc(dev);
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+
+       lwkt_serialize_enter(ifp->if_serializer);
+       sln_stop(sc);
+       lwkt_serialize_exit(ifp->if_serializer);
+
+       return 0;
+}
+
+/* device suspend routine */
+static int
+sln_suspend(device_t dev)
+{
+       struct sln_softc *sc = device_get_softc(dev);
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+
+       lwkt_serialize_enter(ifp->if_serializer);
+       sln_stop(sc);
+       sc->suspended = 1;
+       lwkt_serialize_exit(ifp->if_serializer);
+
+       return 0;
+}
+
+/* device resume routine */
+static int
+sln_resume(device_t dev)
+{
+       struct sln_softc *sc = device_get_softc(dev);
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+
+       lwkt_serialize_enter(ifp->if_serializer);
+       if (ifp->if_flags & IFF_UP)
+               sln_init(sc);
+       sc->suspended = 0;
+       lwkt_serialize_exit(ifp->if_serializer);
+
+       return 0;
+}
diff --git a/sys/dev/netif/sln/if_slnreg.h b/sys/dev/netif/sln/if_slnreg.h
new file mode 100644 (file)
index 0000000..94adb5e
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project.  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. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * $DragonFly: src/sys/dev/netif/sln/if_slnreg.h,v 1.1 2008/02/28 18:39:20 swildner Exp $
+ */
+
+#ifndef  _IF_SLREG_H_
+#define  _IF_SLREG_H_
+
+/*
+ * Silan netcard register offsets
+ */
+
+#define SL_CFG0          0x00  /* software reset */
+#define SL_CFG1          0x04  /* select RX buffer size */
+#define SL_RBW_PTR       0x08  /* RX buffer write pointer */
+#define SL_INT_STATUS    0x0C  /* interrupt status register */
+#define SL_INT_MASK      0x10  /* interrupt mask register */
+#define SL_RBSA          0x14  /* RX buffer start address */
+#define SL_RBR_PTR       0x18  /* RX buffer read pointer */
+#define SL_TSALD0        0x1C  /* TX status of all descriptors */
+#define SL_TSD0          0x20  /* TX status of descriptor 0 */
+#define SL_TSD1          0x24  /* TX status of descriptor 1 */
+#define SL_TSD2          0x28  /* TX status of descriptor 2 */
+#define SL_TSD3          0x2C  /* TX status of descriptor 3 */
+#define SL_TSAD0         0x30  /* TX start address of descriptor 0 */
+#define SL_TSAD1         0x34  /* TX start address of descriptor 1 */
+#define SL_TSAD2         0x38  /* TX start address of descriptor 2 */
+#define SL_TSAD3         0x3C  /* TX start address of descriptor 3 */
+#define SL_RX_CONFIG     0x40  /* RX configuration register */
+#define SL_MAC_ADDR0     0x44  /* MAC address register 0 [47-16] */
+#define SL_MAC_ADDR1     0x48  /* MAC address register 1 [15-0] */
+#define SL_MULTI_GROUP0  0x4C  /* multicast address config regiser 0 [63-32] */
+#define SL_MULTI_GROUP1  0x50  /* multicast address config regiser 1 [31-0] */
+#define SL_RX_STATUS0    0x54  /* RX status register 0 */
+/* 0x58 reserved */
+#define SL_TX_CONFIG     0x5C  /* TX configuration register */
+#define SL_PHY_CTRL      0x60  /* Physical control */
+#define SL_FLOW_CTRL     0x64  /* flow control register */
+#define SL_MII_CMD0      0x68  /* MII command register 0 */
+#define SL_MII_CMD1      0x6C  /* MII command register 1 */
+#define SL_MII_STATUS    0x70  /* MII status register */
+#define SL_TIMER_CNT     0x74  /* Timer counter register */
+#define SL_TIMER_INTR    0x78  /* TImer interrupt register */
+#define SL_PM_CFG        0x7C  /* power managerment configuration register */
+
+/* config register 0 */
+#define SL_SOFT_RESET           0x80000000
+#define SL_ANAOFF               0x40000000
+#define SL_LDPS                 0x20000000
+
+/* config register 1 */
+#define SL_EARLY_RX             0x80000000
+#define SL_EARLY_TX             0x40000000
+
+#define SL_RXFIFO_16BYTES      0x00000000
+#define SL_RXFIFO_32BYTES      0x00200000
+#define SL_RXFIFO_64BYTES      0x00400000
+#define SL_RXFIFO_128BYTES     0x00600000
+#define SL_RXFIFO_256BYTES     0x00800000
+#define SL_RXFIFO_512BYTES     0x00A00000
+#define SL_RXFIFO_1024BYTES    0x00C00000
+#define SL_RXFIFO_NOTHRESH     0x00E00000
+
+#define SL_RXBUF_8             0x00000000
+#define SL_RXBUF_16            0x00000001
+#define SL_RXBUF_32            0x00000003
+#define SL_RXBUF_64            0x00000007
+#define SL_RXBUF_128            0x0000000F
+
+/* interrupt status register bits */
+#define SL_INT_LINKFAIL         0x80000000
+#define SL_INT_LINKOK           0x40000000
+#define SL_INT_TIMEOUT          0x20000000
+#define SL_INT_DMARD_ST         0x00080000
+#define SL_INT_DMARD_FIN        0x00040000
+#define SL_INT_STB_Pl           0x00020000
+#define SL_INT_TXFIN_P          0x00010000
+#define SL_INT_RXFIN_P          0x00008000
+#define SL_INT_DMAWR_ST         0x00004000
+#define SL_INT_DMAWR_FIN        0x00002000
+#define SL_INT_RBO              0x00000040
+#define SL_INT_ROK              0x00000020
+#define SL_INT_TOK              0x00000001
+
+#define  SL_INRTS     (SL_INT_LINKFAIL | SL_INT_LINKOK | SL_INT_TIMEOUT | SL_INT_RBO | SL_INT_ROK | SL_INT_TOK)
+
+/* TX status of silan descriptors */
+#define SL_TXSAD_TOK3        0x00008000
+#define SL_TXSAD_TOK2        0x00004000
+#define SL_TXSAD_TOK1        0x00002000
+#define SL_TXSAD_TOK0        0x00001000
+#define SL_TXSAD_TUN3        0x00000800
+#define SL_TXSAD_TUN2        0x00000400
+#define SL_TXSAD_TUN1        0x00000200
+#define SL_TXSAD_TUN0        0x00000100
+#define SL_TXSAD_TABT3       0x00000080
+#define SL_TXSAD_TABT2       0x00000040
+#define SL_TXSAD_TABT1              0x00000020
+#define SL_TXSAD_TABT0      0x00000010
+#define SL_TXSAD_OWN3        0x00000008
+#define SL_TXSAD_OWN2        0x00000004
+#define SL_TXSAD_OWN1        0x00000002
+#define SL_TXSAD_OWN0       0x00000001
+
+/* Transmit descriptor status register bits */
+#define SL_TXSD_CRS           0x20000000
+#define SL_TXSD_TABT          0x10000000
+#define SL_TXSD_OWC           0x08000000
+#define SL_TXSD_NCC           0x03C00000
+#define SL_TXSD_EARLY_THRESH  0x003F0000
+#define SL_TXSD_TOK           0x00008000
+#define SL_TXSD_TUN           0x00004000
+#define SL_TXSD_OWN           0x00002000
+#define SL_TXSD_LENMASK       0x00001FFF
+
+/* bits in TX configuration register */
+#define SL_TXCFG_FULLDX          0x80000000
+#define SL_TXCFG_EN              0x40000000
+#define SL_TXCFG_PAD             0x20000000
+#define SL_TXCFG_HUGE            0x10000000
+#define SL_TXCFG_FCS             0x08000000
+#define SL_TXCFG_NOBACKOFF       0x04000000
+#define SL_TXCFG_PREMBLE         0x02000000
+#define SL_TXCFG_LOSTCRS         0x01000000
+#define SL_TXCFG_EXDCOLLNUM      0x00F00000
+#define SL_TXCFG_DATARATE        0x00080000
+
+/* bits in RX configuration register */
+#define SL_RXCFG_FULLDX          0x80000000
+#define SL_RXCFG_EN              0x40000000
+#define SL_RXCFG_RCV_SMALL       0x20000000
+#define SL_RXCFG_RCV_HUGE        0x10000000
+#define SL_RXCFG_RCV_ERR         0x08000000
+#define SL_RXCFG_RCV_ALL         0x04000000
+#define SL_RXCFG_RCV_MULTI       0x02000000
+#define SL_RXCFG_RCV_BROAD       0x01000000
+#define SL_RXCFG_LP_BCK          0x00C00000
+#define SL_RXCFG_LOW_THRESHOLD   0x00040000
+#define SL_RXCFG_HIGH_THRESHOLD  0x00000700
+
+/* Bits in RX status header (in RX'ed packet) */
+#define SL_RXSTAT_LENMASK      0xFFF00000
+#define SL_RXSTAT_RXOK         0x00080000
+#define SL_RXSTAT_ALIGNERR      0x00040000
+#define SL_RXSTAT_HUGEFRM      0x00020000
+#define SL_RXSTAT_SMALLFRM     0x00010000
+#define SL_RXSTAT_CRCOK        0x00008000
+#define SL_RXSTAT_CRLFRM       0x00004000
+#define SL_RXSTAT_BROAD        0x00002000
+#define SL_RXSTAT_MULTI        0x00001000
+#define SL_RXSTAT_MATCH                0x00000800
+#define SL_RXSTAT_MIIERR       0x00000400
+
+/* Physical Control configuration register */
+#define SL_PHYCTL_ANE           0x80000000
+#define SL_PHYCTL_SPD100        0x40000000
+#define SL_PHYCTL_SPD10         0x20000000
+#define SL_PHYCTL_BASEADD       0x1F000000
+#define SL_PHYCTL_DUX           0x00800000
+#define SL_PHYCTL_RESET         0x00400000
+
+/* Flow Control configuration register */
+#define SL_FLOWCTL_FULLDX       0x80000000
+#define SL_FLOWCTL_EN           0x40000000
+#define SL_FLOWCTL_PASSALL      0x20000000
+#define SL_FLOWCTL_ENPAUSE      0x10000000
+#define SL_FLOWCTL_PAUSEF       0x08000000
+#define SL_FLOWCTL_PAUSE0       0x04000000
+
+/* MII command register 0 */
+#define SL_MII0_DIVEDER       0x20000000
+#define SL_MII0_NOPRE         0x00800000
+#define SL_MII0_WRITE         0x00400000
+#define SL_MII0_READ          0x00200000
+#define SL_MII0_SCAN          0x00100000
+#define SL_MII0_TXMODE        0x00080000
+#define SL_MII0_DRVMOD        0x00040000
+#define SL_MII0_MDC           0x00020000
+#define SL_MII0_MDOEN         0x00010000
+#define SL_MII0_MDO           0x00008000
+#define SL_MII0_MDI           0x00004000
+
+/* MII status register */
+#define SL_MIISTAT_BUSY       0x80000000
+
+/* register in 80225 */
+#define SL_MII_CTRL            0
+#define SL_MII_STAT            1
+#define SL_MII_ADV             4
+#define SL_MII_JAB             16
+#define SL_MII_STAT_OUTPUT     24
+
+/* bit value for 80225 */
+#define SL_MIICTRL_ANEGEN      0x1000
+#define SL_MIICTRL_SPEEDSEL     0x2000
+#define SL_MIICTRL_DUPSEL       0x0100
+#define SL_MIICTRL_ANEGRSTR     0x0200
+#define SL_MIISTAT_LINK                0x0004
+#define SL_MIISTAT_ANEGACK     0x0020
+#define SL_PHY_16_JAB_ENB       0x1000
+#define SL_PHY_16_PORT_ENB      0x1
+
+/*
+ * PCI low memory base and low I/O base register, and other PCI registers.
+ */
+#define SL_PCI_VENDORID        0x00
+#define SL_PCI_DEVICEID                0x02
+#define SL_PCI_COMMAND         0x04
+#define SL_PCI_STATUS          0x06
+#define SL_PCI_REVISIONID      0x08
+#define SL_PCI_MEMAD            0x10
+#define SL_PCI_IOAD             0x14
+#define SL_PCI_SUBVENDORID      0x2C
+#define SL_PCI_SUBDEVICEID      0x2E
+#define RL_PCI_INTLINE         0x3C
+
+#define SL_CMD_IO               0x0001
+#define SL_CMD_MEMORY           0x0002
+#define SL_CMD_BUSMASTER        0x0004
+
+#define  SL_TXD_CNT        4
+#define  SL_RX_BUF_SZ      SL_RXBUF_64
+#define  SL_RX_BUFLEN      (1 << (SL_RX_BUF_SZ + 9))
+#define  TX_CFG_DEFAULT    0x48800000
+
+/* register space access macros */
+#define SLN_WRITE_4(adapter, reg, val)   bus_space_write_4(adapter->sln_bustag, adapter->sln_bushandle, reg, val)
+#define SLN_WRITE_2(adapter, reg, val)   bus_space_write_2(adapter->sln_bustag, adapter->sln_bushandle, reg, val)
+#define SLN_WRITE_1(adapter, reg, val)   bus_space_write_1(adapter->sln_bustag, adapter->sln_bushandle, reg, val)
+
+#define SLN_READ_4(adapter, reg)     bus_space_read_4(adapter->sln_bustag, adapter->sln_bushandle, reg)
+#define SLN_READ_2(adapter, reg)     bus_space_read_2(adapter->sln_bustag, adapter->sln_bushandle, reg)
+#define SLN_READ_1(adapter, reg)     bus_space_read_1(adapter->sln_bustag, adapter->sln_bushandle, reg)
+
+#define SL_DIRTY_TXBUF(x)    x->sln_bufdata.sln_tx_buf[x->sln_bufdata.dirty_tx]
+#define SL_CUR_TXBUF(x)      x->sln_bufdata.sln_tx_buf[x->sln_bufdata.cur_tx]
+
+#endif /* !_IF_SLREG_H_ */
diff --git a/sys/dev/netif/sln/if_slnvar.h b/sys/dev/netif/sln/if_slnvar.h
new file mode 100644 (file)
index 0000000..ddc7450
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project.  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. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * $DragonFly: src/sys/dev/netif/sln/if_slnvar.h,v 1.1 2008/02/28 18:39:20 swildner Exp $
+ */
+
+#ifndef  _IF_SLVAR_H_
+#define  _IF_SLVAR_H_
+
+struct sln_buf_data {
+       uint32_t                dirty_rx;
+       caddr_t                 sln_rx_buf;
+       struct mbuf             *sln_tx_buf[SL_TXD_CNT];
+       uint32_t                dirty_tx;
+       uint32_t                cur_tx;
+};
+
+struct sln_softc {
+       struct arpcom           arpcom;         /* interface info */
+       struct ifmedia          ifmedia;        /* media info */
+       bus_space_handle_t      sln_bushandle;  /* bus space handle */
+       bus_space_tag_t         sln_bustag;     /* bus space tag */
+       struct resource         *sln_res;
+       struct resource         *sln_irq;
+       void                    *sln_intrhand;
+       uint8_t                 sln_type;
+       uint8_t                 sln_stats_no_timeout;
+       uint16_t                tx_early_ctrl;
+       uint16_t                rx_early_ctrl:1;
+       struct sln_buf_data     sln_bufdata;    /* Tx buffer descriptor */
+       struct callout          sln_state;
+       uint32_t                rxcfg;
+       uint32_t                txcfg;
+       int                     suspended;
+       int                     connect;
+       int                     media_duplex;
+       int                     media_speed;
+       int                     txenablepad;
+};
+
+#endif /* !_IF_SLVAR_H_ */