diff options
| author | kiyohara <kiyohara@NetBSD.org> | 2009-08-09 06:40:09 +0000 |
|---|---|---|
| committer | kiyohara <kiyohara@NetBSD.org> | 2009-08-09 06:40:09 +0000 |
| commit | 5bb9b7a6efa9566e656f7fbb9d7e8dd73d40ba25 (patch) | |
| tree | 072ac65e7830c24c5242011f6dc7eb2f8834352b /sys/dev | |
| parent | b76e3b1e19e7717294aa7282131eec673cf5fa80 (diff) | |
Support SMSC LAN9118 Family Ethernet interfaces device driver.
It tested on GUMSTIX only.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/DEVNAMES | 3 | ||||
| -rw-r--r-- | sys/dev/ic/lan9118.c | 1106 | ||||
| -rw-r--r-- | sys/dev/ic/lan9118reg.h | 293 | ||||
| -rw-r--r-- | sys/dev/ic/lan9118var.h | 86 |
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_ */ |
