summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorkiyohara <kiyohara@NetBSD.org>2009-08-09 06:40:09 +0000
committerkiyohara <kiyohara@NetBSD.org>2009-08-09 06:40:09 +0000
commit5bb9b7a6efa9566e656f7fbb9d7e8dd73d40ba25 (patch)
tree072ac65e7830c24c5242011f6dc7eb2f8834352b /sys/dev
parentb76e3b1e19e7717294aa7282131eec673cf5fa80 (diff)
Support SMSC LAN9118 Family Ethernet interfaces device driver.
It tested on GUMSTIX only.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/DEVNAMES3
-rw-r--r--sys/dev/ic/lan9118.c1106
-rw-r--r--sys/dev/ic/lan9118reg.h293
-rw-r--r--sys/dev/ic/lan9118var.h86
4 files changed, 1487 insertions, 1 deletions
diff --git a/sys/dev/DEVNAMES b/sys/dev/DEVNAMES
index e534b29a656..c8003c317e3 100644
--- a/sys/dev/DEVNAMES
+++ b/sys/dev/DEVNAMES
@@ -1,4 +1,4 @@
-# $NetBSD: DEVNAMES,v 1.246 2009/07/27 12:34:13 kiyohara Exp $
+# $NetBSD: DEVNAMES,v 1.247 2009/08/09 06:40:10 kiyohara Exp $
#
# This file contains all used device names and defined attributes in
# alphabetical order. New devices added to the system somewhere should first
@@ -1201,6 +1201,7 @@ sm MI
smap playstation2
smc93cx6 MI Attribute
smg vax
+smsh MI
sn arc
sn mac68k
sn newsmips
diff --git a/sys/dev/ic/lan9118.c b/sys/dev/ic/lan9118.c
new file mode 100644
index 00000000000..fed8bc1a79f
--- /dev/null
+++ b/sys/dev/ic/lan9118.c
@@ -0,0 +1,1106 @@
+/* $NetBSD: lan9118.c,v 1.1 2009/08/09 06:40:10 kiyohara Exp $ */
+/*
+ * Copyright (c) 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: lan9118.c,v 1.1 2009/08/09 06:40:10 kiyohara Exp $");
+
+/*
+ * The LAN9118 Family
+ *
+ * * The LAN9118 is targeted for 32-bit applications requiring high
+ * performance, and provides the highest level of performance possible for
+ * a non-PCI 10/100 Ethernet controller.
+ *
+ * * The LAN9117 is designed to provide the highest level of performance
+ * possible for 16-bit applications. It also has an external MII interface,
+ * which can be used to attach an external PHY.
+ *
+ * * The LAN9116 and LAN9115 are designed for performance-sensitive
+ * applications with less intensive performance requirements. The LAN9116
+ * is for 32-bit host processors, while the LAN9115 is for 16-bit
+ * applications, which may also require an external PHY. Both devices
+ * deliver superior levels of performance.
+ */
+
+#include "bpfilter.h"
+#include "rnd.h"
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/bus.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+#if NRND > 0
+#include <sys/rnd.h>
+#endif
+
+#include <dev/ic/lan9118reg.h>
+#include <dev/ic/lan9118var.h>
+
+
+#ifdef SMSH_DEBUG
+#define DPRINTF(x) if (smsh_debug) printf x
+#define DPRINTFN(n,x) if (smsh_debug >= (n)) printf x
+int smsh_debug = SMSH_DEBUG;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+
+static void lan9118_start(struct ifnet *);
+static int lan9118_ioctl(struct ifnet *, u_long, void *);
+static int lan9118_init(struct ifnet *);
+static void lan9118_stop(struct ifnet *, int);
+static void lan9118_watchdog(struct ifnet *);
+
+static int lan9118_ifm_change(struct ifnet *);
+static void lan9118_ifm_status(struct ifnet *, struct ifmediareq *);
+
+static int lan9118_miibus_readreg(device_t, int, int);
+static void lan9118_miibus_writereg(device_t, int, int, int);
+static void lan9118_miibus_statchg(device_t);
+
+static uint16_t lan9118_mii_readreg(struct lan9118_softc *, int, int);
+static void lan9118_mii_writereg(struct lan9118_softc *, int, int, uint16_t);
+static uint32_t lan9118_mac_readreg(struct lan9118_softc *, int);
+static void lan9118_mac_writereg(struct lan9118_softc *, int, uint32_t);
+
+static void lan9118_set_filter(struct lan9118_softc *);
+static void lan9118_rxintr(struct lan9118_softc *);
+static void lan9118_txintr(struct lan9118_softc *);
+
+/* This values refer from Linux's smc911x.c */
+static uint32_t afc_cfg[] = {
+ /* 0 */ 0x00000000,
+ /* 1 */ 0x00000000,
+ /* 2 */ 0x008c4600 | LAN9118_AFC_CFG_BACK_DUR(10) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* 3 */ 0x00824100 | LAN9118_AFC_CFG_BACK_DUR(9) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* 4 */ 0x00783c00 | LAN9118_AFC_CFG_BACK_DUR(9) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* 5 */ 0x006e3700 | LAN9118_AFC_CFG_BACK_DUR(8) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* 6 */ 0x00643200 | LAN9118_AFC_CFG_BACK_DUR(8) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* 7 */ 0x005a2d00 | LAN9118_AFC_CFG_BACK_DUR(7) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* 8 */ 0x00502800 | LAN9118_AFC_CFG_BACK_DUR(7) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* 9 */ 0x00462300 | LAN9118_AFC_CFG_BACK_DUR(6) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* a */ 0x003c1e00 | LAN9118_AFC_CFG_BACK_DUR(6) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* b */ 0x00321900 | LAN9118_AFC_CFG_BACK_DUR(5) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* c */ 0x00241200 | LAN9118_AFC_CFG_BACK_DUR(4) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* d */ 0x00150700 | LAN9118_AFC_CFG_BACK_DUR(3) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* e */ 0x00060300 | LAN9118_AFC_CFG_BACK_DUR(2) |
+ LAN9118_AFC_CFG_FCMULT | LAN9118_AFC_CFG_FCBRD |
+ LAN9118_AFC_CFG_FCADD | LAN9118_AFC_CFG_FCANY,
+ /* f */ 0x00000000,
+};
+
+
+int
+lan9118_attach(struct lan9118_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ uint32_t val;
+ int timo, i;
+
+ if (sc->sc_flags & LAN9118_FLAGS_SWAP) {
+ /* need byte swap */
+ DPRINTFN(1, ("%s: need byte swap\n", __func__));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_WORD_SWAP,
+ 0xffffffff);
+ }
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_BYTE_TEST);
+ if (val != LAN9118_BYTE_TEST_VALUE) {
+ aprint_error_dev(sc->sc_dev, "failed to detect chip\n");
+ return EINVAL;
+ }
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_ID_REV);
+ sc->sc_id = LAN9118_ID_REV_ID(val);
+ sc->sc_rev = LAN9118_ID_REV_REV(val);
+
+ aprint_normal_dev(sc->sc_dev, "SMSC LAN9%03x Rev %d\n",
+ sc->sc_id, sc->sc_rev);
+
+ timo = 3 * 1000 * 1000; /* XXXX 3sec */
+ do {
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_MAC_CSR_CMD);
+ if (!(val & LAN9118_MAC_CSR_CMD_BUSY))
+ break;
+ delay(100);
+ } while (timo -= 100);
+ if (timo <= 0)
+ aprint_error_dev(sc->sc_dev, "%s: command busy\n", __func__);
+ if (!(sc->sc_flags & LAN9118_FLAGS_NO_EEPROM)) {
+ /* Read auto-loaded MAC address */
+ val = lan9118_mac_readreg(sc, LAN9118_ADDRL);
+ sc->sc_enaddr[3] = (val >> 24) & 0xff;
+ sc->sc_enaddr[2] = (val >> 16) & 0xff;
+ sc->sc_enaddr[1] = (val >> 8) & 0xff;
+ sc->sc_enaddr[0] = val & 0xff;
+ val = lan9118_mac_readreg(sc, LAN9118_ADDRH);
+ sc->sc_enaddr[5] = (val >> 8) & 0xff;
+ sc->sc_enaddr[4] = val & 0xff;
+ }
+ aprint_normal_dev(sc->sc_dev, "MAC address %s\n",
+ ether_sprintf(sc->sc_enaddr));
+
+ KASSERT(LAN9118_TX_FIF_SZ >= 2 && LAN9118_TX_FIF_SZ < 15);
+ sc->sc_afc_cfg = afc_cfg[LAN9118_TX_FIF_SZ];
+
+ /* Initialize the ifnet structure. */
+ strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_start = lan9118_start;
+ ifp->if_ioctl = lan9118_ioctl;
+ ifp->if_init = lan9118_init;
+ ifp->if_stop = lan9118_stop;
+ ifp->if_watchdog = lan9118_watchdog;
+ IFQ_SET_READY(&ifp->if_snd);
+
+#if 0 /* Not support 802.1Q VLAN-sized frames yet. */
+ sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
+#endif
+
+ ifmedia_init(&sc->sc_mii.mii_media, 0,
+ lan9118_ifm_change, lan9118_ifm_status);
+ /*
+ * Number of instance of Internal PHY is always 0. External PHY
+ * number that above.
+ */
+ sc->sc_mii.mii_instance++;
+ if (sc->sc_id == LAN9118_ID_9115 || sc->sc_id == LAN9118_ID_9117) {
+ if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_HW_CFG) &
+ LAN9118_HW_CFG_EXT_PHY_DET) {
+ /*
+ * We always have a internal PHY at phy1.
+ * In addition, external PHY is attached.
+ */
+ DPRINTFN(1, ("%s: detect External PHY\n", __func__));
+
+ sc->sc_mii.mii_readreg = lan9118_miibus_readreg;
+ sc->sc_mii.mii_writereg = lan9118_miibus_writereg;
+ sc->sc_mii.mii_statchg = lan9118_miibus_statchg;
+
+ /* Switch MII and SMI */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_HW_CFG,
+ LAN9118_HW_CFG_MBO |
+ LAN9118_HW_CFG_PHY_CLK_SEL_CD);
+ delay(1); /* Wait 5 cycle */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_HW_CFG,
+ LAN9118_HW_CFG_MBO |
+ LAN9118_HW_CFG_PHY_CLK_SEL_EMII |
+ LAN9118_HW_CFG_SMI_SEL |
+ LAN9118_HW_CFG_EXT_PHY_EN);
+ delay(1); /* Once wait more 5 cycle */
+
+ /* Call mii_attach, avoid at phy1. */
+ mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff,
+ 0, MII_OFFSET_ANY, 0);
+ for (i = 2; i < MII_NPHY; i++)
+ mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff,
+ i, MII_OFFSET_ANY, 0);
+ }
+ }
+ ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
+ ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_10_T, 0, NULL);
+ ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0,
+ NULL);
+ ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_100_TX, 0, NULL);
+ ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0,
+ NULL);
+ ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO, 0, NULL);
+
+ aprint_normal_dev(sc->sc_dev,
+ "10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto\n");
+ ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
+
+ /* Attach the interface. */
+ if_attach(ifp);
+ ether_ifattach(ifp, sc->sc_enaddr);
+
+#if NRND > 0
+ rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
+ RND_TYPE_NET, 0);
+#endif
+ return 0;
+}
+
+int
+lan9118_intr(void *arg)
+{
+ struct lan9118_softc *sc = (struct lan9118_softc *)arg;
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ uint32_t int_sts, int_en, datum = 0;
+ int handled = 0;
+
+ for (;;) {
+ int_sts =
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_INT_STS);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_INT_STS,
+ int_sts);
+ int_en =
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_INT_EN);
+
+ DPRINTFN(3, ("%s: int_sts=0x%x, int_en=0x%x\n",
+ __func__, int_sts, int_en));
+
+ if (!(int_sts & int_en))
+ break;
+ datum = int_sts;
+
+ if (int_sts & LAN9118_INT_PHY_INT) { /* PHY */
+ /* Shall we need? */
+ }
+ if (int_sts & LAN9118_INT_PME_INT) { /*Power Management Event*/
+ /* not yet... */
+ }
+ if (int_sts & LAN9118_INT_RXE) {
+ ifp->if_ierrors++;
+ aprint_error_ifnet(ifp, "Receive Error\n");
+ }
+ if (int_sts & LAN9118_INT_TSFL) /* TX Status FIFO Level */
+ lan9118_txintr(sc);
+ if (int_sts & LAN9118_INT_RXDF_INT) {
+ ifp->if_ierrors++;
+ aprint_error_ifnet(ifp, "RX Dropped Frame Interrupt\n");
+ }
+ if (int_sts & LAN9118_INT_RSFF) {
+ ifp->if_ierrors++;
+ aprint_error_ifnet(ifp, "RX Status FIFO Full\n");
+ }
+ if (int_sts & LAN9118_INT_RSFL) /* RX Status FIFO Level */
+ lan9118_rxintr(sc);
+ }
+
+ if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ lan9118_start(ifp);
+
+#if NRND > 0
+ if (RND_ENABLED(&sc->rnd_source))
+ rnd_add_uint32(&sc->rnd_source, datum);
+#endif
+
+ return handled;
+}
+
+
+static void
+lan9118_start(struct ifnet *ifp)
+{
+ struct lan9118_softc *sc = ifp->if_softc;
+ struct mbuf *m0, *m;
+ unsigned tdfree, totlen, dso;
+ uint32_t txa, txb;
+ uint8_t *p;
+
+ DPRINTFN(3, ("%s\n", __func__));
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ totlen = 0;
+ for (;;) {
+ IFQ_POLL(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+
+ tdfree = LAN9118_TX_FIFO_INF_TDFREE(bus_space_read_4(sc->sc_iot,
+ sc->sc_ioh, LAN9118_TX_FIFO_INF));
+ if (tdfree < 2036) {
+ /*
+ * 2036 is the possible maximum FIFO consumption
+ * for the most fragmented frame.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+
+ /*
+ * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
+ */
+
+ m = m0;
+ totlen = m->m_pkthdr.len;
+ p = mtod(m, uint8_t *);
+ dso = (unsigned)p & 0x3;
+ txa =
+ LAN9118_TXC_A_BEA_4B |
+ LAN9118_TXC_A_DSO(dso) |
+ LAN9118_TXC_A_FS |
+ LAN9118_TXC_A_BS(m->m_len);
+ txb = LAN9118_TXC_B_PL(totlen);
+ while (m->m_next != NULL) {
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_TXDFIFOP, txa);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_TXDFIFOP, txb);
+ /*
+ * XXXX:
+ * We are assuming that the size of mbus always align
+ * in 4 bytes.
+ */
+ bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_TXDFIFOP, (uint32_t *)(p - dso),
+ (m->m_len + dso + 3) >> 2);
+
+ m = m->m_next;
+ p = mtod(m, uint8_t *);
+ dso = (unsigned)p & 0x3;
+ txa =
+ LAN9118_TXC_A_BEA_4B |
+ LAN9118_TXC_A_DSO(dso) |
+ LAN9118_TXC_A_BS(m->m_len);
+ }
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_TXDFIFOP,
+ txa | LAN9118_TXC_A_LS);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_TXDFIFOP,
+ txb);
+ bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_TXDFIFOP, (uint32_t *)(p - dso),
+ (m->m_len + dso + 3) >> 2);
+#if NBPFILTER > 0
+ /*
+ * Pass the packet to any BPF listeners.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0);
+#endif /* NBPFILTER > 0 */
+
+ m_freem(m0);
+ }
+ if (totlen > 0)
+ ifp->if_timer = 5;
+}
+
+static int
+lan9118_ioctl(struct ifnet *ifp, u_long command, void *data)
+{
+ struct lan9118_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = data;
+ struct mii_data *mii = &sc->sc_mii;
+ int s, error = 0;
+
+ s = splnet();
+
+ switch (command) {
+ case SIOCSIFFLAGS:
+ DPRINTFN(2, ("%s: IFFLAGS\n", __func__));
+ if ((error = ifioctl_common(ifp, command, data)) != 0)
+ break;
+ switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
+ case IFF_RUNNING:
+ lan9118_stop(ifp, 0);
+ break;
+ case IFF_UP:
+ lan9118_init(ifp);
+ break;
+ default:
+ break;
+ }
+ error = 0;
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ DPRINTFN(2, ("%s: MEDIA\n", __func__));
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+
+ default:
+ DPRINTFN(2, ("%s: ETHER\n", __func__));
+ error = ether_ioctl(ifp, command, data);
+ if (error == ENETRESET) {
+ if (ifp->if_flags & IFF_RUNNING) {
+ lan9118_set_filter(sc);
+ DPRINTFN(2, ("%s set_filter called\n",
+ __func__));
+ }
+ error = 0;
+ }
+ break;
+ }
+
+ splx(s);
+
+ return error;
+}
+
+static int
+lan9118_init(struct ifnet *ifp)
+{
+ struct lan9118_softc *sc = ifp->if_softc;
+ struct ifmedia *ifm = &sc->sc_mii.mii_media;
+ uint32_t reg, hw_cfg, mac_cr;
+ int timo, s;
+
+ DPRINTFN(2, ("%s\n", __func__));
+
+ s = splnet();
+
+ /* wait for PMT_CTRL[READY] */
+ timo = mstohz(5); /* XXXX 5sec */
+ while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_PMT_CTRL) &
+ LAN9118_PMT_CTRL_READY)) {
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_BYTE_TEST,
+ 0xbad0c0de);
+ tsleep(&sc, PRIBIO, "lan9118_pmt_ready", 1);
+ if (--timo <= 0) {
+ splx(s);
+ return EBUSY;
+ }
+ }
+
+ /* Soft Reset */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_HW_CFG,
+ LAN9118_HW_CFG_SRST);
+ do {
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_HW_CFG);
+ if (reg & LAN9118_HW_CFG_SRST_TO) {
+ aprint_error_dev(sc->sc_dev,
+ "soft reset timeouted out\n");
+ splx(s);
+ return ETIMEDOUT;
+ }
+ } while (reg & LAN9118_HW_CFG_SRST);
+
+ /* Set MAC and PHY CSRs */
+
+ if (sc->sc_flags & LAN9118_FLAGS_SWAP)
+ /* need byte swap */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_WORD_SWAP,
+ 0xffffffff);
+
+ while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_E2P_CMD) &
+ LAN9118_E2P_CMD_EPCB);
+ if (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_E2P_CMD) &
+ LAN9118_E2P_CMD_MACAL)) {
+ lan9118_mac_writereg(sc, LAN9118_ADDRL,
+ sc->sc_enaddr[0] |
+ sc->sc_enaddr[1] << 8 |
+ sc->sc_enaddr[2] << 16 |
+ sc->sc_enaddr[3] << 24);
+ lan9118_mac_writereg(sc, LAN9118_ADDRH,
+ sc->sc_enaddr[4] | sc->sc_enaddr[5] << 8);
+ }
+
+ if (ifm->ifm_media & IFM_FLOW) {
+ lan9118_mac_writereg(sc, LAN9118_FLOW,
+ LAN9118_FLOW_FCPT(1) | LAN9118_FLOW_FCEN);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_AFC_CFG,
+ sc->sc_afc_cfg);
+ }
+
+ lan9118_ifm_change(ifp);
+ hw_cfg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_HW_CFG);
+ hw_cfg &= ~LAN9118_HW_CFG_TX_FIF_MASK;
+ hw_cfg |= LAN9118_HW_CFG_TX_FIF_SZ(LAN9118_TX_FIF_SZ);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_HW_CFG, hw_cfg);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_GPIO_CFG,
+ LAN9118_GPIO_CFG_LEDX_EN(2) |
+ LAN9118_GPIO_CFG_LEDX_EN(1) |
+ LAN9118_GPIO_CFG_LEDX_EN(0) |
+ LAN9118_GPIO_CFG_GPIOBUFN(2) |
+ LAN9118_GPIO_CFG_GPIOBUFN(1) |
+ LAN9118_GPIO_CFG_GPIOBUFN(0));
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_IRQ_CFG,
+ LAN9118_IRQ_CFG_IRQ_EN);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_INT_STS,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_INT_STS));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_FIFO_INT,
+ LAN9118_FIFO_INT_TXSL(0) | LAN9118_FIFO_INT_RXSL(0));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_INT_EN,
+ LAN9118_INT_PHY_INT | /* PHY */
+ LAN9118_INT_PME_INT | /* Power Management Event */
+ LAN9118_INT_RXE | /* Receive Error */
+ LAN9118_INT_TSFL | /* TX Status FIFO Level */
+ LAN9118_INT_RXDF_INT| /* RX Dropped Frame Interrupt */
+ LAN9118_INT_RSFF | /* RX Status FIFO Full */
+ LAN9118_INT_RSFL); /* RX Status FIFO Level */
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_RX_CFG,
+ LAN9118_RX_CFG_RXDOFF(2));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_TX_CFG,
+ LAN9118_TX_CFG_TX_ON);
+ mac_cr = lan9118_mac_readreg(sc, LAN9118_MAC_CR);
+ lan9118_mac_writereg(sc, LAN9118_MAC_CR,
+ mac_cr | LAN9118_MAC_CR_TXEN | LAN9118_MAC_CR_RXEN);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ splx(s);
+
+ return 0;
+}
+
+static void
+lan9118_stop(struct ifnet *ifp, int disable)
+{
+ struct lan9118_softc *sc = ifp->if_softc;
+ uint32_t cr;
+
+ DPRINTFN(2, ("%s\n", __func__));
+
+ /* Disable IRQ */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_INT_EN, 0);
+
+ /* Stopping transmitter */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_TX_CFG,
+ LAN9118_TX_CFG_STOP_TX);
+ while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_TX_CFG) &
+ (LAN9118_TX_CFG_TX_ON | LAN9118_TX_CFG_STOP_TX));
+
+ /* Purge TX Status/Data FIFOs */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_TX_CFG,
+ LAN9118_TX_CFG_TXS_DUMP | LAN9118_TX_CFG_TXD_DUMP);
+
+ /* Stopping receiver, also clear TXEN */
+ cr = lan9118_mac_readreg(sc, LAN9118_MAC_CR);
+ cr &= ~(LAN9118_MAC_CR_TXEN | LAN9118_MAC_CR_RXEN);
+ lan9118_mac_writereg(sc, LAN9118_MAC_CR, cr);
+ while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_INT_STS) &
+ LAN9118_INT_RXSTOP_INT));
+
+ /* Clear RX Status/Data FIFOs */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_RX_CFG,
+ LAN9118_RX_CFG_RX_DUMP);
+}
+
+static void
+lan9118_watchdog(struct ifnet *ifp)
+{
+ struct lan9118_softc *sc = ifp->if_softc;
+
+ /*
+ * Reclaim first as there is a possibility of losing Tx completion
+ * interrupts.
+ */
+ lan9118_txintr(sc);
+
+ aprint_error_ifnet(ifp, "watchdog timeout\n");
+ ifp->if_oerrors++;
+
+ lan9118_init(ifp);
+}
+
+
+static int
+lan9118_ifm_change(struct ifnet *ifp)
+{
+ struct lan9118_softc *sc = ifp->if_softc;
+ struct ifmedia *ifm = &sc->sc_mii.mii_media;
+ struct ifmedia_entry *ife = ifm->ifm_cur;
+ uint32_t pmt_ctrl, cr, bmc, bms, ana, anlpa;
+
+ DPRINTFN(3, ("%s: ifm inst %d\n", __func__, IFM_INST(ife->ifm_media)));
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_HW_CFG,
+ LAN9118_HW_CFG_MBO | LAN9118_HW_CFG_PHY_CLK_SEL_CD);
+ delay(1); /* Wait 5 cycle */
+
+ if (IFM_INST(ife->ifm_media) != 0) {
+ /* Use External PHY */
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_HW_CFG,
+ LAN9118_HW_CFG_MBO |
+ LAN9118_HW_CFG_PHY_CLK_SEL_EMII |
+ LAN9118_HW_CFG_SMI_SEL |
+ LAN9118_HW_CFG_EXT_PHY_EN);
+ delay(1);
+ return mii_mediachg(&sc->sc_mii);
+ }
+
+ /* Setup Internal PHY */
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_HW_CFG,
+ LAN9118_HW_CFG_MBO |
+ LAN9118_HW_CFG_PHY_CLK_SEL_IPHY);
+ delay(1);
+
+ /* Reset PHY */
+ pmt_ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_PMT_CTRL);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_PMT_CTRL,
+ pmt_ctrl | LAN9118_PMT_CTRL_PHY_RST);
+ while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_PMT_CTRL) &
+ LAN9118_PMT_CTRL_PHY_RST);
+
+ if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
+ bmc = BMCR_AUTOEN | BMCR_STARTNEG;
+ bms = lan9118_mii_readreg(sc, LAN9118_IPHY_ADDR, MII_BMSR);
+ ana = ANAR_FC | BMSR_MEDIA_TO_ANAR(bms) | ANAR_CSMA;
+ } else {
+ switch (IFM_SUBTYPE(ifm->ifm_media)) {
+ case IFM_10_T:
+ bmc = BMCR_S10;
+ ana = ANAR_CSMA | ANAR_10;
+ break;
+
+ case IFM_100_TX:
+ bmc = BMCR_S100;
+ if (ifm->ifm_media & IFM_FDX)
+ bmc |= BMCR_FDX;
+ ana = ANAR_CSMA | ANAR_TX;
+ break;
+
+ case IFM_NONE:
+ bmc = BMCR_PDOWN;
+ break;
+
+ default:
+ return EINVAL;
+ }
+ if (ifm->ifm_media & IFM_FDX)
+ bmc |= BMCR_FDX;
+ if (ifm->ifm_media & IFM_FLOW)
+ ana |= ANAR_FC;
+ }
+ lan9118_mii_writereg(sc, LAN9118_IPHY_ADDR, MII_ANAR, ana);
+ lan9118_mii_writereg(sc, LAN9118_IPHY_ADDR, MII_BMCR, bmc);
+
+ bms = lan9118_mii_readreg(sc, LAN9118_IPHY_ADDR, MII_BMSR);
+ if (bms & BMSR_LINK) {
+ anlpa = lan9118_mii_readreg(sc, LAN9118_IPHY_ADDR, MII_ANLPAR);
+
+ bmc = lan9118_mii_readreg(sc, LAN9118_IPHY_ADDR, MII_BMCR);
+ cr = lan9118_mac_readreg(sc, LAN9118_MAC_CR);
+ if (anlpa & (ANLPAR_TX_FD | ANLPAR_10_FD)) {
+ bmc |= BMCR_FDX;
+ cr |= LAN9118_MAC_CR_RCVOWN;
+ } else {
+ bmc &= ~BMCR_FDX;
+ cr &= ~LAN9118_MAC_CR_RCVOWN;
+ }
+ lan9118_mii_writereg(sc, LAN9118_IPHY_ADDR, MII_BMCR, bmc);
+ lan9118_mac_writereg(sc, LAN9118_MAC_CR, cr);
+ }
+ return 0;
+}
+
+static void
+lan9118_ifm_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct lan9118_softc *sc = ifp->if_softc;
+ struct mii_data *mii = &sc->sc_mii;
+ struct ifmedia *ifm = &mii->mii_media;
+ struct ifmedia_entry *ife = ifm->ifm_cur;
+ uint32_t bms, physcs;
+
+ DPRINTFN(3, ("%s\n", __func__));
+
+ if (IFM_INST(ife->ifm_media) != 0) {
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ return;
+ }
+
+ ifmr->ifm_active = IFM_ETHER;
+ ifmr->ifm_status = IFM_AVALID;
+
+ bms = lan9118_mii_readreg(sc, LAN9118_IPHY_ADDR, MII_BMSR);
+ if (!(bms & BMSR_LINK)) {
+ /* link is down */
+ ifmr->ifm_active |= IFM_NONE;
+ return;
+ }
+ ifmr->ifm_active |= IFM_ACTIVE;
+ physcs = lan9118_mii_readreg(sc, LAN9118_IPHY_ADDR, LAN9118_PHYSCSR);
+ if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
+ if (!(physcs & LAN9118_PHYSCSR_AUTODONE)) {
+ /* negotiation in progress */
+ ifmr->ifm_active |= IFM_NONE;
+ return;
+ }
+ }
+ if (physcs & LAN9118_PHYSCSR_SI_10)
+ ifmr->ifm_active |= IFM_10_T;
+ if (physcs & LAN9118_PHYSCSR_SI_100)
+ ifmr->ifm_active |= IFM_100_TX;
+ if (physcs & LAN9118_PHYSCSR_SI_FDX)
+ ifmr->ifm_active |= IFM_FDX;
+}
+
+
+static int
+lan9118_miibus_readreg(device_t dev, int phy, int reg)
+{
+
+ return lan9118_mii_readreg(device_private(dev), phy, reg);
+}
+static void
+lan9118_miibus_writereg(device_t dev, int phy, int reg, int val)
+{
+
+ lan9118_mii_writereg(device_private(dev), phy, reg, val);
+}
+
+static void
+lan9118_miibus_statchg(device_t dev)
+{
+
+ /* nothing to do */
+}
+
+
+static uint16_t
+lan9118_mii_readreg(struct lan9118_softc *sc, int phy, int reg)
+{
+ uint32_t acc;
+
+ while (lan9118_mac_readreg(sc, LAN9118_MII_ACC) &
+ LAN9118_MII_ACC_MIIBZY);
+ acc = LAN9118_MII_ACC_MIIRINDA(phy) | LAN9118_MII_ACC_PHYA(reg);
+ lan9118_mac_writereg(sc, LAN9118_MII_ACC, acc);
+ while (lan9118_mac_readreg(sc, LAN9118_MII_ACC) &
+ LAN9118_MII_ACC_MIIBZY);
+ return lan9118_mac_readreg(sc, LAN9118_MII_DATA);
+}
+
+static void
+lan9118_mii_writereg(struct lan9118_softc *sc, int phy, int reg, uint16_t val)
+{
+ uint32_t acc;
+
+ while (lan9118_mac_readreg(sc, LAN9118_MII_ACC) &
+ LAN9118_MII_ACC_MIIBZY);
+ acc = LAN9118_MII_ACC_MIIRINDA(phy) | LAN9118_MII_ACC_PHYA(reg) |
+ LAN9118_MII_ACC_MIIWNR;
+ lan9118_mac_writereg(sc, LAN9118_MII_DATA, val);
+ while (lan9118_mac_readreg(sc, LAN9118_MII_ACC) &
+ LAN9118_MII_ACC_MIIBZY);
+}
+
+static uint32_t
+lan9118_mac_readreg(struct lan9118_softc *sc, int reg)
+{
+ uint32_t cmd;
+ int timo = 3 * 1000 * 1000; /* XXXX: 3sec */
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_MAC_CSR_CMD,
+ LAN9118_MAC_CSR_CMD_BUSY | LAN9118_MAC_CSR_CMD_R | reg);
+ do {
+ cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_MAC_CSR_CMD);
+ if (!(cmd & LAN9118_MAC_CSR_CMD_BUSY))
+ break;
+ delay(100);
+ } while (timo -= 100);
+ if (timo <= 0)
+ aprint_error_dev(sc->sc_dev, "%s: command busy\n", __func__);
+ return bus_space_read_4(sc->sc_iot, sc->sc_ioh, LAN9118_MAC_CSR_DATA);
+}
+
+static void
+lan9118_mac_writereg(struct lan9118_softc *sc, int reg, uint32_t val)
+{
+ uint32_t cmd;
+ int timo = 3 * 1000 * 1000; /* XXXX: 3sec */
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_MAC_CSR_DATA, val);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_MAC_CSR_CMD,
+ LAN9118_MAC_CSR_CMD_BUSY | LAN9118_MAC_CSR_CMD_W | reg);
+ do {
+ cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_MAC_CSR_CMD);
+ if (!(cmd & LAN9118_MAC_CSR_CMD_BUSY))
+ break;
+ delay(100);
+ } while (timo -= 100);
+ if (timo <= 0)
+ aprint_error_dev(sc->sc_dev, "%s: command busy\n", __func__);
+}
+
+
+static void
+lan9118_set_filter(struct lan9118_softc *sc)
+{
+ struct ether_multistep step;
+ struct ether_multi *enm;
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ uint32_t mac_cr, h, hashes[2] = { 0, 0 };
+
+ mac_cr = lan9118_mac_readreg(sc, LAN9118_MAC_CR);
+ if (ifp->if_flags & IFF_PROMISC) {
+ lan9118_mac_writereg(sc, LAN9118_MAC_CR,
+ mac_cr | LAN9118_MAC_CR_PRMS);
+ return;
+ }
+
+ mac_cr &= ~(LAN9118_MAC_CR_PRMS | LAN9118_MAC_CR_MCPAS |
+ LAN9118_MAC_CR_BCAST | LAN9118_MAC_CR_HPFILT);
+ if (!(ifp->if_flags & IFF_BROADCAST))
+ mac_cr |= LAN9118_MAC_CR_BCAST;
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ mac_cr |= LAN9118_MAC_CR_MCPAS;
+ else {
+ ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
+ while (enm != NULL) {
+ if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
+ ETHER_ADDR_LEN) != 0) {
+ /*
+ * We must listen to a range of multicast
+ * addresses. For now, just accept all
+ * multicasts, rather than trying to set
+ * only those filter bits needed to match
+ * the range. (At this time, the only use
+ * of address ranges is for IP multicast
+ * routing, for which the range is big enough
+ * to require all bits set.)
+ */
+ ifp->if_flags |= IFF_ALLMULTI;
+ mac_cr |= LAN9118_MAC_CR_MCPAS;
+ break;
+ }
+ h = ether_crc32_le(enm->enm_addrlo,
+ ETHER_ADDR_LEN) >> 26;
+ hashes[h >> 5] |= 1 << (h & 0x1f);
+
+ mac_cr |= LAN9118_MAC_CR_HPFILT;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+ if (mac_cr & LAN9118_MAC_CR_HPFILT) {
+ lan9118_mac_writereg(sc, LAN9118_HASHH, hashes[1]);
+ lan9118_mac_writereg(sc, LAN9118_HASHL, hashes[0]);
+ }
+ }
+ lan9118_mac_writereg(sc, LAN9118_MAC_CR, mac_cr);
+ return;
+}
+
+static void
+lan9118_rxintr(struct lan9118_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ struct mbuf *m;
+ uint32_t rx_fifo_inf, rx_status;
+ int pktlen;
+ const int pad = ETHER_HDR_LEN % sizeof(uint32_t);
+
+ DPRINTFN(3, ("%s\n", __func__));
+
+ for (;;) {
+ rx_fifo_inf = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_RX_FIFO_INF);
+ if (LAN9118_RX_FIFO_INF_RXSUSED(rx_fifo_inf) == 0)
+ break;
+
+ rx_status = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_RXSFIFOP);
+ pktlen = LAN9118_RXS_PKTLEN(rx_status);
+ DPRINTFN(3, ("%s: rx_status=0x%x(pktlen %d)\n",
+ __func__, rx_status, pktlen));
+ if (rx_status & (LAN9118_RXS_ES | LAN9118_RXS_LENERR |
+ LAN9118_RXS_RWTO | LAN9118_RXS_MIIERR | LAN9118_RXS_DBIT)) {
+ if (rx_status & LAN9118_RXS_LENERR)
+ aprint_error_dev(sc->sc_dev, "Length Error\n");
+ if (rx_status & LAN9118_RXS_RUNTF)
+ aprint_error_dev(sc->sc_dev, "Runt Frame\n");
+ if (rx_status & LAN9118_RXS_FTL)
+ aprint_error_dev(sc->sc_dev,
+ "Frame Too Long\n");
+ if (rx_status & LAN9118_RXS_RWTO)
+ aprint_error_dev(sc->sc_dev,
+ "Receive Watchdog time-out\n");
+ if (rx_status & LAN9118_RXS_MIIERR)
+ aprint_error_dev(sc->sc_dev, "MII Error\n");
+ if (rx_status & LAN9118_RXS_DBIT)
+ aprint_error_dev(sc->sc_dev, "Drabbling Bit\n");
+ if (rx_status & LAN9118_RXS_COLS)
+ aprint_error_dev(sc->sc_dev,
+ "Collision Seen\n");
+ if (rx_status & LAN9118_RXS_CRCERR)
+ aprint_error_dev(sc->sc_dev, "CRC Error\n");
+
+dropit:
+ ifp->if_ierrors++;
+ /*
+ * Receive Data FIFO Fast Forward
+ * When performing a fast-forward, there must be at
+ * least 4 DWORDs of data in the RX data FIFO for the
+ * packet being discarded.
+ */
+ if (pktlen >= 4 * sizeof(uint32_t)) {
+ uint32_t rx_dp_ctl;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_RX_DP_CTL,
+ LAN9118_RX_DP_CTL_RX_FFWD);
+ /* DP_FFWD bit is self clearing */
+ do {
+ rx_dp_ctl = bus_space_read_4(sc->sc_iot,
+ sc->sc_ioh, LAN9118_RX_DP_CTL);
+ } while (rx_dp_ctl & LAN9118_RX_DP_CTL_RX_FFWD);
+ } else {
+ /* For less than 4 DWORDs do not use RX_FFWD. */
+ uint32_t garbage[4];
+
+ bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_RXDFIFOP, garbage,
+ roundup(pktlen, 4) >> 2);
+ }
+ continue;
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ goto dropit;
+ if (pktlen > (MHLEN - pad)) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ goto dropit;
+ }
+ }
+
+ /* STRICT_ALIGNMENT */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LAN9118_RX_CFG,
+ LAN9118_RX_CFG_RXEA_4B | LAN9118_RX_CFG_RXDOFF(pad));
+ bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh, LAN9118_RXDFIFOP,
+ mtod(m, uint32_t *),
+ roundup(pad + pktlen, sizeof(uint32_t)) >> 2);
+ m->m_data += pad;
+
+ ifp->if_ipackets++;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = (pktlen - ETHER_CRC_LEN);
+
+#if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass if up the stack if it's for us.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif /* NBPFILTER > 0 */
+
+ /* Pass it on. */
+ (*ifp->if_input)(ifp, m);
+ }
+}
+
+static void
+lan9118_txintr(struct lan9118_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ uint32_t tx_fifo_inf, tx_status;
+ int tdfree;
+
+ DPRINTFN(3, ("%s\n", __func__));
+
+ for (;;) {
+ tx_fifo_inf = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_TX_FIFO_INF);
+ if (LAN9118_TX_FIFO_INF_TXSUSED(tx_fifo_inf) == 0)
+ break;
+
+ tx_status = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ LAN9118_TXSFIFOP);
+ DPRINTFN(3, ("%s: tx_status=0x%x\n", __func__, tx_status));
+ if (tx_status & LAN9118_TXS_ES) {
+ if (tx_status & LAN9118_TXS_LOC)
+ aprint_error_dev(sc->sc_dev,
+ "Loss Of Carrier\n");
+ if (tx_status & LAN9118_TXS_NC)
+ aprint_error_dev(sc->sc_dev, "No Carrier\n");
+ if (tx_status & LAN9118_TXS_LCOL)
+ aprint_error_dev(sc->sc_dev,
+ "Late Collision\n");
+ if (tx_status & LAN9118_TXS_ECOL) {
+ /* Rearch 16 collision */
+ ifp->if_collisions += 16;
+ aprint_error_dev(sc->sc_dev,
+ "Excessive Collision\n");
+ }
+ if (LAN9118_TXS_COLCNT(tx_status) != 0)
+ aprint_error_dev(sc->sc_dev,
+ "Collision Count: %d\n",
+ LAN9118_TXS_COLCNT(tx_status));
+ if (tx_status & LAN9118_TXS_ED)
+ aprint_error_dev(sc->sc_dev,
+ "Excessive Deferral\n");
+ if (tx_status & LAN9118_TXS_DEFERRED)
+ aprint_error_dev(sc->sc_dev, "Deferred\n");
+ ifp->if_oerrors++;
+ } else
+ ifp->if_opackets++;
+ }
+
+ tdfree = LAN9118_TX_FIFO_INF_TDFREE(tx_fifo_inf);
+ if (tdfree == LAN9118_TX_DATA_FIFO_SIZE)
+ /* FIFO empty */
+ ifp->if_timer = 0;
+ if (tdfree >= 2036)
+ /*
+ * 2036 is the possible maximum FIFO consumption
+ * for the most fragmented frame.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+}
diff --git a/sys/dev/ic/lan9118reg.h b/sys/dev/ic/lan9118reg.h
new file mode 100644
index 00000000000..6e3ac5f1dee
--- /dev/null
+++ b/sys/dev/ic/lan9118reg.h
@@ -0,0 +1,293 @@
+/* $NetBSD: lan9118reg.h,v 1.1 2009/08/09 06:40:10 kiyohara Exp $ */
+/*
+ * Copyright (c) 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LAN9118REG_H_
+#define _LAN9118REG_H_
+
+#define LAN9118_IOSIZE 0x100
+
+#define LAN9118_ID_9115 0x115
+#define LAN9118_ID_9116 0x116
+#define LAN9118_ID_9117 0x117
+#define LAN9118_ID_9118 0x118
+
+#define LAN9118_IPHY_ADDR 0x01 /* Internal PHY Address */
+
+
+#define LAN9118_RXDFIFOP 0x00 /* RX Data FIFO Port */
+#define LAN9118_RXDFIFOAP 0x04 /* RX Data FIFO Alias Ports */
+#define LAN9118_TXDFIFOP 0x20 /* TX Data FIFO Port */
+#define LAN9118_TXDFIFOAP 0x24 /* TX Data FIFO Alias Ports */
+#define LAN9118_RXSFIFOP 0x40 /* RX Status FIFO Port */
+#define LAN9118_RXSFIFOPEEK 0x44 /* RX Status FIFO PEEK */
+#define LAN9118_TXSFIFOP 0x48 /* TX Status FIFO Port */
+#define LAN9118_TXSFIFOPEEK 0x4c /* TX Status FIFO PEEK */
+
+/* System Control and Status Registers */
+#define LAN9118_ID_REV 0x50 /* Chip ID and Revision */
+#define LAN9118_ID_REV_ID(x) (((x) >> 16) & 0xffff)
+#define LAN9118_ID_REV_REV(x) ((x) & 0xffff)
+#define LAN9118_IRQ_CFG 0x54 /* Main Interrupt Configuration */
+#define LAN9118_IRQ_CFG_INT_DEAS(t) ((t) << 24) /* Intr Deassert Interval */
+#define LAN9118_IRQ_CFG_INT_DEAS_CLR (1 << 14) /* Intr Deass Intrval clr */
+#define LAN9118_IRQ_CFG_INT_DEAS_STS (1 << 13) /* Intr Deassert Status */
+#define LAN9118_IRQ_CFG_IRQ_INT (1 << 12) /* Master Interrupt */
+#define LAN9118_IRQ_CFG_IRQ_EN (1 << 8) /* IRQ Enable */
+#define LAN9118_IRQ_CFG_IRQ_POL (1 << 4) /* IRQ Polarity */
+#define LAN9118_IRQ_CFG_IRQ_TYPE (1 << 0) /* IRQ Buffer Type */
+#define LAN9118_INT_STS 0x58 /* Interrupt Status */
+#define LAN9118_INT_EN 0x5c /* Interrupt Enable Register */
+#define LAN9118_INT_SW_INT (1 << 31) /* Software Interrupt */
+#define LAN9118_INT_TXSTOP_INT (1 << 25) /* TX Stopped */
+#define LAN9118_INT_RXSTOP_INT (1 << 24) /* RX Stopped */
+#define LAN9118_INT_RXDFH_INT (1 << 23) /* RX Drppd Frm Cnt Halfway */
+#define LAN9118_INT_TX_IOC (1 << 21) /* TX IOC Interrupt */
+#define LAN9118_INT_RXD_INT (1 << 20) /* RX DMA Interrupt */
+#define LAN9118_INT_GPT_INT (1 << 19) /* GP Timer */
+#define LAN9118_INT_PHY_INT (1 << 18) /* PHY */
+#define LAN9118_INT_PME_INT (1 << 17) /* Power Management Event */
+#define LAN9118_INT_TXSO (1 << 16) /* TX Status FIFO Overflow */
+#define LAN9118_INT_RWT (1 << 15) /* Rcv Watchdog Time-out */
+#define LAN9118_INT_RXE (1 << 14) /* Receive Error */
+#define LAN9118_INT_TXE (1 << 13) /* Transmitter Error */
+#define LAN9118_INT_TDFO (1 << 10) /* TX Data FIFO Overrun */
+#define LAN9118_INT_TDFA (1 << 9) /* TX Data FIFO Available */
+#define LAN9118_INT_TSFF (1 << 8) /* TX Status FIFO Full */
+#define LAN9118_INT_TSFL (1 << 7) /* TX Status FIFO Level */
+#define LAN9118_INT_RXDF_INT (1 << 6) /* RX Dropped Frame Intr */
+#define LAN9118_INT_RSFF (1 << 4) /* RX Status FIFO Full */
+#define LAN9118_INT_RSFL (1 << 3) /* RX Status FIFO Level */
+#define LAN9118_INT_GPIOX_INT(x) (1 << (x)) /* GPIO[2:0] */
+/* 0x60 Reserved for future use */
+#define LAN9118_BYTE_TEST 0x64 /* Read-only byte order testing reg */
+#define LAN9118_BYTE_TEST_VALUE 0x87654321
+#define LAN9118_FIFO_INT 0x68 /* FIFO Level Interrupt */
+#define LAN9118_FIFO_INT_TXDAL(x) ((x) << 24) /* TX Data Available Lvl */
+#define LAN9118_FIFO_INT_TXSL(x) ((x) << 16) /* TX Status Level */
+#define LAN9118_FIFO_INT_RXSL(x) ((x) << 0) /* RX Status Level */
+#define LAN9118_RX_CFG 0x6c /* Receive Configuration */
+#define LAN9118_RX_CFG_RXEA_4B (0 << 30) /* RX End Alignment: 4 Byte */
+#define LAN9118_RX_CFG_RXEA_16B (1 << 30) /* 16 Byte */
+#define LAN9118_RX_CFG_RXEA_32B (2 << 30) /* 32 Byte */
+#define LAN9118_RX_CFG_RX_DMA_CNT(x) ((x) << 16) /* RX DMA Count */
+#define LAN9118_RX_CFG_RX_DUMP (1 << 15) /* Force RX Discard */
+#define LAN9118_RX_CFG_RXDOFF(x) ((x) << 8) /* RX Data Offset */
+#define LAN9118_TX_CFG 0x70 /* Transmit Configuration */
+#define LAN9118_TX_CFG_TXS_DUMP (1 << 15) /* Force TX Status Discard */
+#define LAN9118_TX_CFG_TXD_DUMP (1 << 14) /* Force TX Data Discard */
+#define LAN9118_TX_CFG_TXSAO (1 << 2) /* TX Status Allow Overrun */
+#define LAN9118_TX_CFG_TX_ON (1 << 1) /* Transmitter Enable */
+#define LAN9118_TX_CFG_STOP_TX (1 << 0) /* Stop Transmitter */
+#define LAN9118_HW_CFG 0x74 /* Hardware Configuration */
+#define LAN9118_HW_CFG_MBO (1 << 20)/* Must Be One */
+#define LAN9118_HW_CFG_TX_FIF_MASK (0xf << 16) /* TX FIFO Size */
+#define LAN9118_HW_CFG_TX_FIF_SZ(sz) ((sz) << 16)
+#define LAN9118_HW_CFG_PHY_CLK_SEL_MASK (3 << 5) /* PHY Clock Select */
+#define LAN9118_HW_CFG_PHY_CLK_SEL_IPHY (0 << 5) /* Internal PHY */
+#define LAN9118_HW_CFG_PHY_CLK_SEL_EMII (1 << 5) /* External MII Port */
+#define LAN9118_HW_CFG_PHY_CLK_SEL_CD (2 << 5) /* Clock Disabled */
+#define LAN9118_HW_CFG_SMI_SEL (1 << 4) /* Serial Mgmt Interface Sel */
+#define LAN9118_HW_CFG_EXT_PHY_DET (1 << 3) /* External PHY Detect */
+#define LAN9118_HW_CFG_EXT_PHY_EN (1 << 2) /* External PHY Enable */
+#define LAN9118_HW_CFG_SRST_TO (1 << 1) /* Soft Reset Timeout */
+#define LAN9118_HW_CFG_SRST (1 << 0) /* Soft Reset */
+#define LAN9118_RX_DP_CTL 0x78 /* RX Datapath Control */
+#define LAN9118_RX_DP_CTL_RX_FFWD (1 << 31)/* RX Data FIFO Fast Forward */
+#define LAN9118_RX_FIFO_INF 0x7c /* Receive FIFO Information */
+#define LAN9118_RX_FIFO_INF_RXSUSED(x) (((x) >> 16) & 0xff) /*Sts Used Space*/
+#define LAN9118_RX_FIFO_INF_RXDUSED(x) ((x) & 0xffff) /*Data FIFO Used Space*/
+#define LAN9118_TX_FIFO_INF 0x80 /* Transmit FIFO Information */
+#define LAN9118_TX_FIFO_INF_TXSUSED(x) (((x) >> 16) & 0xff) /*Sts Used Space*/
+#define LAN9118_TX_FIFO_INF_TDFREE(x) ((x) & 0xffff) /*Data FIFO Free Space*/
+#define LAN9118_PMT_CTRL 0x84 /* Power Management Control */
+#define LAN9118_PMT_CTRL_PM_MODE_MASK (3 << 12)
+#define LAN9118_PMT_CTRL_PM_MODE_D0 (0 << 12)
+#define LAN9118_PMT_CTRL_PM_MODE_D1 (1 << 12)
+#define LAN9118_PMT_CTRL_PM_MODE_D2 (2 << 12)
+#define LAN9118_PMT_CTRL_PHY_RST (1 << 10) /* PHY Reset */
+#define LAN9118_PMT_CTRL_WOL_EN (1 << 9) /* Wake-On-LAN Enable */
+#define LAN9118_PMT_CTRL_ED_EN (1 << 8) /* Energy-Detect Enable */
+#define LAN9118_PMT_CTRL_PME_TYPE (1 << 6) /* PME Buffer Type */
+#define LAN9118_PMT_CTRL_WUPS_NWUED (0 << 4) /* WAKE-UP Status: No Event */
+#define LAN9118_PMT_CTRL_WUPS_ED (1 << 4) /* WAKE-UP Status: Energy */
+#define LAN9118_PMT_CTRL_WUPS_WUD (2 << 4) /* WAKE-UP Status: Wake-up */
+#define LAN9118_PMT_CTRL_PME_IND (1 << 3) /* PME indication */
+#define LAN9118_PMT_CTRL_PME_POL (1 << 2) /* PME Polarity */
+#define LAN9118_PMT_CTRL_PME_EN (1 << 1) /* PME Enable */
+#define LAN9118_PMT_CTRL_READY (1 << 0) /* Device Ready */
+#define LAN9118_GPIO_CFG 0x88 /* General Purpose IO Configuration */
+#define LAN9118_GPIO_CFG_LEDX_EN(x) (1 << ((x) + 28)) /* LED[3:1] enable */
+#define LAN9118_GPIO_CFG_GPIO_INT_POL(p) (1 << ((p) + 24)) /* Intr Polarity */
+#define LAN9118_GPIO_CFG_EEPR_EN (7 << 20) /* EEPROM Enable */
+#define LAN9118_GPIO_CFG_GPIOBUFN(n) (1 << ((n) + 16)) /* Buffer Type */
+#define LAN9118_GPIO_CFG_GPDIRN(n) (1 << ((n) + 8)) /* Direction */
+#define LAN9118_GPIO_CFG_GPODN(n) (1 << (n)) /* GPIO Data (3,4 is WO) */
+#define LAN9118_GPT_CFG 0x8c /* General Purpose Timer Config */
+#define LAN9118_GPT_CNT 0x90 /* General Purpose Timer Count */
+/* 0x94 Reserved for future use */
+#define LAN9118_WORD_SWAP 0x98 /* WORD SWAP Register */
+#define LAN9118_FREE_RUN 0x9c /* Free Run Counter */
+#define LAN9118_RX_DROP 0xa0 /* RX Drop Frame Counter */
+#define LAN9118_MAC_CSR_CMD 0xa4 /* MAC CSR Synchronizer Command */
+#define LAN9118_MAC_CSR_CMD_BUSY (1 << 31)
+#define LAN9118_MAC_CSR_CMD_W (0 << 30)
+#define LAN9118_MAC_CSR_CMD_R (1 << 30)
+#define LAN9118_MAC_CSR_CMD_ADDRESS(a) ((a) & 0xff)
+#define LAN9118_MAC_CSR_DATA 0xa8 /* MAC CSR Synchronizer Data */
+#define LAN9118_AFC_CFG 0xac /* Automatic Flow Control Config */
+#define LAN9118_AFC_CFG_AFC_HI(x) ((x) << 16)
+#define LAN9118_AFC_CFG_AFC_LO(x) ((x) << 8)
+#define LAN9118_AFC_CFG_BACK_DUR(x) ((x) << 4)
+#define LAN9118_AFC_CFG_FCMULT (1 << 3) /* Flow Control on Multicast */
+#define LAN9118_AFC_CFG_FCBRD (1 << 2) /* Flow Control on Broadcast */
+#define LAN9118_AFC_CFG_FCADD (1 << 1) /* Flow Control on Addr Dec */
+#define LAN9118_AFC_CFG_FCANY (1 << 0) /* Flow Control on Any Frame */
+#define LAN9118_E2P_CMD 0xb0 /* EEPROM command */
+#define LAN9118_E2P_CMD_EPCB (1 << 31) /* EPC Busy */
+#define LAN9118_E2P_CMD_EPCC_READ (0 << 28) /* EPC Command: READ */
+#define LAN9118_E2P_CMD_EPCC_EWDS (1 << 28) /* EWDS */
+#define LAN9118_E2P_CMD_EPCC_EWEN (2 << 28) /* EWEN */
+#define LAN9118_E2P_CMD_EPCC_WRITE (3 << 28) /* WRITE */
+#define LAN9118_E2P_CMD_EPCC_WRAL (4 << 28) /* WRAL */
+#define LAN9118_E2P_CMD_EPCC_ERASE (5 << 28) /* ERASE */
+#define LAN9118_E2P_CMD_EPCC_ERAL (6 << 28) /* ERAL */
+#define LAN9118_E2P_CMD_EPCC_RELOAD (7 << 28) /* Reload */
+#define LAN9118_E2P_CMD_EPCTO (1 << 9) /* EPC Time-out */
+#define LAN9118_E2P_CMD_MACAL (1 << 8) /* MAC Address Loaded */
+#define LAN9118_E2P_CMD_EPCA(a) ((a) & 0xff) /* EPC Address */
+#define LAN9118_E2P_DATA 0xb4 /* EEPROM Data */
+/* 0xb8 - 0xfc Reserved for future use */
+
+/* MAC Control and Status Registers */
+#define LAN9118_MAC_CR 0x1 /* MAC Control Register */
+#define LAN9118_MAC_CR_RXALL (1 << 31) /* Receive All Mode */
+#define LAN9118_MAC_CR_RCVOWN (1 << 23) /* Disable Receive Own */
+#define LAN9118_MAC_CR_LOOPBK (1 << 21) /* Loopback operation Mode */
+#define LAN9118_MAC_CR_FDPX (1 << 20) /* Full Duplex Mode */
+#define LAN9118_MAC_CR_MCPAS (1 << 19) /* Pass All Multicast */
+#define LAN9118_MAC_CR_PRMS (1 << 18) /* Promiscuous Mode */
+#define LAN9118_MAC_CR_INVFILT (1 << 17) /* Inverse filtering */
+#define LAN9118_MAC_CR_PASSBAD (1 << 16) /* Pass Bad Frames */
+#define LAN9118_MAC_CR_HO (1 << 15) /* Hash Only Filtering mode */
+#define LAN9118_MAC_CR_HPFILT (1 << 13) /* Hash/Perfect Flt Mode */
+#define LAN9118_MAC_CR_LCOLL (1 << 12) /* Late Collision Control */
+#define LAN9118_MAC_CR_BCAST (1 << 11) /* Disable Broardcast Frms */
+#define LAN9118_MAC_CR_DISRTY (1 << 10) /* Disable Retry */
+#define LAN9118_MAC_CR_PADSTR (1 << 8) /* Automatic Pad String */
+#define LAN9118_MAC_CR_BOLMT (1 << 7) /* BackOff Limit */
+#define LAN9118_MAC_CR_DFCHK (1 << 5) /* Deferral Check */
+#define LAN9118_MAC_CR_TXEN (1 << 3) /* Transmitter enable */
+#define LAN9118_MAC_CR_RXEN (1 << 2) /* Receiver enable */
+#define LAN9118_ADDRH 0x2 /* MAC Address High */
+#define LAN9118_ADDRL 0x3 /* MAC Address Low */
+#define LAN9118_HASHH 0x4 /* Multicast Hash Table High */
+#define LAN9118_HASHL 0x5 /* Multicast Hash Table Low */
+#define LAN9118_MII_ACC 0x6 /* MII Access */
+#define LAN9118_MII_ACC_PHYA(a) ((a) << 11) /* PHY Address */
+#define LAN9118_MII_ACC_MIIRINDA(i) ((i) << 6) /* MII Register Index */
+#define LAN9118_MII_ACC_MIIWNR (1 << 1) /* MII Write */
+#define LAN9118_MII_ACC_MIIBZY (1 << 0) /* MII Busy */
+#define LAN9118_MII_DATA 0x7 /* MII Data */
+#define LAN9118_FLOW 0x8 /* Flow Control */
+#define LAN9118_FLOW_FCPT(t) ((t) << 16) /* Pause Time */
+#define LAN9118_FLOW_FCPASS (1 << 2) /* Pass Control Frame */
+#define LAN9118_FLOW_FCEN (1 << 1) /* Flow Control Enable */
+#define LAN9118_FLOW_FCBUSY (1 << 0) /* Flow Control Busy */
+#define LAN9118_VLAN1 0x9 /* VLAN1 Tag */
+#define LAN9118_VLAN2 0xa /* VLAN2 Tag */
+#define LAN9118_WUFF 0xb /* Wake-up Frame Filter */
+#define LAN9118_WUCSR 0xc /* Wake-up Control and Status */
+
+/* PHY Registers */
+#define LAN9118_MCSR 0x11 /* Mode Control/Status Register */
+#define LAN9118_MCSR_EDPWRDOWN (1 << 13) /* Energy Detect Power Down */
+#define LAN9118_MCSR_ENERGYON (1 << 1)
+#define LAN9118_SMR 0x12 /* Special Modes Register */
+#define LAN9118_SMR_PHYAD (0x01)
+#define LAN9118_SCSI 0x1b /* Special Control/Status Indications */
+#define LAN9118_SCSI_VCOOFF_LP (1 << 10)
+#define LAN9118_SCSI_XPOL (1 << 4) /* Polarity state */
+#define LAN9118_ISR 0x1d /* Interrupt Source Register */
+#define LAN9118_IMR 0x1e /* Interrupt Mask Register */
+#define LAN9118_I_ENERGYON (1 << 7)
+#define LAN9118_I_AUTONEGOCOMPL (1 << 6)
+#define LAN9118_I_REMOTEFAULT (1 << 5)
+#define LAN9118_I_LINKDOWN (1 << 4)
+#define LAN9118_I_AUTONEGOLPACK (1 << 3) /* AutoNego LP Acknowledge */
+#define LAN9118_I_PDF (1 << 2) /* Parallel Detection Fault */
+#define LAN9118_I_AUTONEGOPR (1 << 1) /* AutoNego Page Received */
+#define LAN9118_PHYSCSR 0x1f /* PHY Special Control/Status Reg */
+#define LAN9118_PHYSCSR_AUTODONE (1 << 12) /* AutoNego done indication */
+#define LAN9118_PHYSCSR_SI_10 (1 << 2) /* Speed Indication */
+#define LAN9118_PHYSCSR_SI_100 (2 << 2)
+#define LAN9118_PHYSCSR_SI_FDX (4 << 2)
+
+
+/* TX Command 'A' Format */
+#define LAN9118_TXC_A_IC (1 << 31) /* Interrupt on Completion */
+#define LAN9118_TXC_A_BEA_4B (0 << 24) /* Buffer End Alignment: 4B */
+#define LAN9118_TXC_A_BEA_16B (1 << 24) /* 16B */
+#define LAN9118_TXC_A_BEA_32B (2 << 24) /* 32B */
+#define LAN9118_TXC_A_DSO(x) ((x) << 16) /*Data Start Offset: bytes*/
+#define LAN9118_TXC_A_FS (1 << 13) /* First Segment */
+#define LAN9118_TXC_A_LS (1 << 12) /* Last Segment */
+#define LAN9118_TXC_A_BS(x) ((x) << 0) /* Buffer Size */
+
+/* TX Command 'B' Format */
+#define LAN9118_TXC_B_PT(x) ((x) << 16) /* Packet Tag */
+#define LAN9118_TXC_B_ACRCD (1 << 13) /* Add CRC Disable */
+#define LAN9118_TXC_B_DEFP (1 << 12) /* Dis Ether Frame Padding */
+#define LAN9118_TXC_B_PL(x) ((x) << 0) /* Packet Length */
+
+/* TX Status Format */
+#define LAN9118_TXS_PKTTAG(x) (((x) >> 16) & 0xff) /* Packet Tag */
+#define LAN9118_TXS_ES (1 << 15) /* Error Status */
+#define LAN9118_TXS_LOC (1 << 11) /* Loss Of Carrier */
+#define LAN9118_TXS_NC (1 << 10) /* No Carrier */
+#define LAN9118_TXS_LCOL (1 << 9) /* Late Collision */
+#define LAN9118_TXS_ECOL (1 << 8) /* Excessive Collision*/
+#define LAN9118_TXS_COLCNT(x) (((x) >> 3) & 0xf) /* Collision Count */
+#define LAN9118_TXS_ED (1 << 2) /* Excessive Deferral */
+#define LAN9118_TXS_DEFERRED (1 << 0) /* Deferred */
+
+/* RX Status Format */
+#define LAN9118_RXS_FILTFAIL (1 << 30) /* Filtering Fail */
+#define LAN9118_RXS_PKTLEN(x) (((x) >> 16) & 0x3fff) /* Packet Len */
+#define LAN9118_RXS_ES (1 << 15) /* Error Status */
+#define LAN9118_RXS_BCF (1 << 13) /* Broadcast Frame */
+#define LAN9118_RXS_LENERR (1 << 12) /* Length Error */
+#define LAN9118_RXS_RUNTF (1 << 11) /* Runt Frame */
+#define LAN9118_RXS_MCF (1 << 10) /* Multicast Frame */
+#define LAN9118_RXS_FTL (1 << 7) /* Frame Too Long */
+#define LAN9118_RXS_COLS (1 << 6) /* Collision Seen */
+#define LAN9118_RXS_FT (1 << 5) /* Frame Type */
+#define LAN9118_RXS_RWTO (1 << 4) /* Rcv Watchdog time-out */
+#define LAN9118_RXS_MIIERR (1 << 3) /* MII Error */
+#define LAN9118_RXS_DBIT (1 << 2) /* Drabbling Bit */
+#define LAN9118_RXS_CRCERR (1 << 1) /* CRC Error */
+
+#endif /* _LAN9118REG_H_ */
diff --git a/sys/dev/ic/lan9118var.h b/sys/dev/ic/lan9118var.h
new file mode 100644
index 00000000000..ef2d4469a86
--- /dev/null
+++ b/sys/dev/ic/lan9118var.h
@@ -0,0 +1,86 @@
+/* $NetBSD: lan9118var.h,v 1.1 2009/08/09 06:40:10 kiyohara Exp $ */
+/*
+ * Copyright (c) 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LAN9118VAR_H_
+#define _LAN9118VAR_H_
+
+#include "rnd.h"
+
+#if NRND > 0
+#include <sys/rnd.h>
+#endif
+
+#define LAN9118_DEFAULT_TX_FIF_SZ 5 /*kB*/
+
+#ifndef LAN9118_TX_FIF_SZ
+#define LAN9118_TX_FIF_SZ LAN9118_DEFAULT_TX_FIF_SZ
+#endif
+#define LAN9118_TX_DATA_FIFO_SIZE (LAN9118_TX_FIF_SZ * 1024 - 512)
+/*
+ * LAN9118 has FIFO buffer, total size is 16kB. That is using TX and RX
+ * buffers. We can set TX FIFO Size. Also TX Status FIFO size is fixed
+ * at 512 Bytes.
+ *
+ * TX FIFO Size : LAN9118_TX_FIF_SZ
+ * TX Status FIFO Size : 512 Bytes (fixed)
+ * TX Data FIFO Size : LAN9118_TX_FIF_SZ - TX Status FIFO Size
+ *
+ * RX FIFO Size : 16kB - LAN9118_TX_FIF_SZ
+ * RX Status FIFO Size : RX FIFO Size / 16
+ * RX Data FIFO Size : RX FIFO Size - RX Status FIFO Size
+ */
+
+
+struct lan9118_softc {
+ device_t sc_dev; /* generic device glue */
+ struct ethercom sc_ec; /* ethernet common glue */
+ struct mii_data sc_mii;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ uint16_t sc_id;
+ uint16_t sc_rev;
+ uint8_t sc_enaddr[ETHER_ADDR_LEN];
+
+ uint32_t sc_afc_cfg; /* AFC_CFG configuration */
+ int sc_use_extphy;
+
+ int sc_flags;
+#define LAN9118_FLAGS_SWAP 0x00000001
+#define LAN9118_FLAGS_NO_EEPROM 0x00000002
+
+#if NRND > 0
+ rndsource_element_t rnd_source;
+#endif
+};
+
+
+int lan9118_attach(struct lan9118_softc *);
+int lan9118_intr(void *);
+
+#endif /* _SMSC9118VAR_H_ */