if_lpe.c revision 243882
1239278Sgonzo/*- 2239278Sgonzo * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org> 3239278Sgonzo * All rights reserved. 4239278Sgonzo * 5239278Sgonzo * Redistribution and use in source and binary forms, with or without 6239278Sgonzo * modification, are permitted provided that the following conditions 7239278Sgonzo * are met: 8239278Sgonzo * 1. Redistributions of source code must retain the above copyright 9239278Sgonzo * notice, this list of conditions and the following disclaimer. 10239278Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11239278Sgonzo * notice, this list of conditions and the following disclaimer in the 12239278Sgonzo * documentation and/or other materials provided with the distribution. 13239278Sgonzo * 14239278Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15239278Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16239278Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17239278Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18239278Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19239278Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20239278Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21239278Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22239278Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23239278Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24239278Sgonzo * SUCH DAMAGE. 25239278Sgonzo * 26239278Sgonzo */ 27239278Sgonzo#include <sys/cdefs.h> 28239278Sgonzo__FBSDID("$FreeBSD: head/sys/arm/lpc/if_lpe.c 243882 2012-12-05 08:04:20Z glebius $"); 29239278Sgonzo 30239278Sgonzo#include <sys/param.h> 31239278Sgonzo#include <sys/endian.h> 32239278Sgonzo#include <sys/systm.h> 33239278Sgonzo#include <sys/sockio.h> 34239278Sgonzo#include <sys/mbuf.h> 35239278Sgonzo#include <sys/malloc.h> 36239278Sgonzo#include <sys/kernel.h> 37239278Sgonzo#include <sys/module.h> 38239278Sgonzo#include <sys/lock.h> 39239278Sgonzo#include <sys/mutex.h> 40239278Sgonzo#include <sys/rman.h> 41239278Sgonzo#include <sys/bus.h> 42239278Sgonzo#include <sys/socket.h> 43239278Sgonzo#include <machine/bus.h> 44239278Sgonzo#include <machine/intr.h> 45239278Sgonzo 46239278Sgonzo#include <net/if.h> 47239278Sgonzo#include <net/if_arp.h> 48239278Sgonzo#include <net/ethernet.h> 49239278Sgonzo#include <net/if_dl.h> 50239278Sgonzo#include <net/if_media.h> 51239278Sgonzo#include <net/if_types.h> 52239278Sgonzo 53239278Sgonzo#include <net/bpf.h> 54239278Sgonzo 55239278Sgonzo#include <dev/ofw/ofw_bus.h> 56239278Sgonzo#include <dev/ofw/ofw_bus_subr.h> 57239278Sgonzo 58239278Sgonzo#include <dev/mii/mii.h> 59239278Sgonzo#include <dev/mii/miivar.h> 60239278Sgonzo 61239278Sgonzo#include <arm/lpc/lpcreg.h> 62239278Sgonzo#include <arm/lpc/lpcvar.h> 63239278Sgonzo#include <arm/lpc/if_lpereg.h> 64239278Sgonzo 65239278Sgonzo#include "miibus_if.h" 66239278Sgonzo 67239278Sgonzo#define DEBUG 68239278Sgonzo#undef DEBUG 69239278Sgonzo 70239278Sgonzo#ifdef DEBUG 71239278Sgonzo#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 72239278Sgonzo printf(fmt,##args); } while (0) 73239278Sgonzo#else 74239278Sgonzo#define debugf(fmt, args...) 75239278Sgonzo#endif 76239278Sgonzo 77239278Sgonzostruct lpe_dmamap_arg { 78239278Sgonzo bus_addr_t lpe_dma_busaddr; 79239278Sgonzo}; 80239278Sgonzo 81239278Sgonzostruct lpe_rxdesc { 82239278Sgonzo struct mbuf * lpe_rxdesc_mbuf; 83239278Sgonzo bus_dmamap_t lpe_rxdesc_dmamap; 84239278Sgonzo}; 85239278Sgonzo 86239278Sgonzostruct lpe_txdesc { 87239278Sgonzo int lpe_txdesc_first; 88239278Sgonzo struct mbuf * lpe_txdesc_mbuf; 89239278Sgonzo bus_dmamap_t lpe_txdesc_dmamap; 90239278Sgonzo}; 91239278Sgonzo 92239278Sgonzostruct lpe_chain_data { 93239278Sgonzo bus_dma_tag_t lpe_parent_tag; 94239278Sgonzo bus_dma_tag_t lpe_tx_ring_tag; 95239278Sgonzo bus_dmamap_t lpe_tx_ring_map; 96239278Sgonzo bus_dma_tag_t lpe_tx_status_tag; 97239278Sgonzo bus_dmamap_t lpe_tx_status_map; 98239278Sgonzo bus_dma_tag_t lpe_tx_buf_tag; 99239278Sgonzo bus_dma_tag_t lpe_rx_ring_tag; 100239278Sgonzo bus_dmamap_t lpe_rx_ring_map; 101239278Sgonzo bus_dma_tag_t lpe_rx_status_tag; 102239278Sgonzo bus_dmamap_t lpe_rx_status_map; 103239278Sgonzo bus_dma_tag_t lpe_rx_buf_tag; 104239278Sgonzo struct lpe_rxdesc lpe_rx_desc[LPE_RXDESC_NUM]; 105239278Sgonzo struct lpe_txdesc lpe_tx_desc[LPE_TXDESC_NUM]; 106239278Sgonzo int lpe_tx_prod; 107239278Sgonzo int lpe_tx_last; 108239278Sgonzo int lpe_tx_used; 109239278Sgonzo}; 110239278Sgonzo 111239278Sgonzostruct lpe_ring_data { 112239278Sgonzo struct lpe_hwdesc * lpe_rx_ring; 113239278Sgonzo struct lpe_hwstatus * lpe_rx_status; 114239278Sgonzo bus_addr_t lpe_rx_ring_phys; 115239278Sgonzo bus_addr_t lpe_rx_status_phys; 116239278Sgonzo struct lpe_hwdesc * lpe_tx_ring; 117239278Sgonzo struct lpe_hwstatus * lpe_tx_status; 118239278Sgonzo bus_addr_t lpe_tx_ring_phys; 119239278Sgonzo bus_addr_t lpe_tx_status_phys; 120239278Sgonzo}; 121239278Sgonzo 122239278Sgonzostruct lpe_softc { 123239278Sgonzo struct ifnet * lpe_ifp; 124239278Sgonzo struct mtx lpe_mtx; 125239278Sgonzo phandle_t lpe_ofw; 126239278Sgonzo device_t lpe_dev; 127239278Sgonzo device_t lpe_miibus; 128239278Sgonzo uint8_t lpe_enaddr[6]; 129239278Sgonzo struct resource * lpe_mem_res; 130239278Sgonzo struct resource * lpe_irq_res; 131239278Sgonzo void * lpe_intrhand; 132239278Sgonzo bus_space_tag_t lpe_bst; 133239278Sgonzo bus_space_handle_t lpe_bsh; 134239278Sgonzo#define LPE_FLAG_LINK (1 << 0) 135239278Sgonzo uint32_t lpe_flags; 136239278Sgonzo int lpe_watchdog_timer; 137239278Sgonzo struct callout lpe_tick; 138239278Sgonzo struct lpe_chain_data lpe_cdata; 139239278Sgonzo struct lpe_ring_data lpe_rdata; 140239278Sgonzo}; 141239278Sgonzo 142239278Sgonzostatic int lpe_probe(device_t); 143239278Sgonzostatic int lpe_attach(device_t); 144239278Sgonzostatic int lpe_detach(device_t); 145239278Sgonzostatic int lpe_miibus_readreg(device_t, int, int); 146239278Sgonzostatic int lpe_miibus_writereg(device_t, int, int, int); 147239278Sgonzostatic void lpe_miibus_statchg(device_t); 148239278Sgonzo 149239278Sgonzostatic void lpe_reset(struct lpe_softc *); 150239278Sgonzostatic void lpe_init(void *); 151239278Sgonzostatic void lpe_init_locked(struct lpe_softc *); 152239278Sgonzostatic void lpe_start(struct ifnet *); 153239278Sgonzostatic void lpe_start_locked(struct ifnet *); 154239278Sgonzostatic void lpe_stop(struct lpe_softc *); 155239278Sgonzostatic void lpe_stop_locked(struct lpe_softc *); 156239278Sgonzostatic int lpe_ioctl(struct ifnet *, u_long, caddr_t); 157239278Sgonzostatic void lpe_set_rxmode(struct lpe_softc *); 158239278Sgonzostatic void lpe_set_rxfilter(struct lpe_softc *); 159239278Sgonzostatic void lpe_intr(void *); 160239278Sgonzostatic void lpe_rxintr(struct lpe_softc *); 161239278Sgonzostatic void lpe_txintr(struct lpe_softc *); 162239278Sgonzostatic void lpe_tick(void *); 163239278Sgonzostatic void lpe_watchdog(struct lpe_softc *); 164239278Sgonzostatic int lpe_encap(struct lpe_softc *, struct mbuf **); 165239278Sgonzostatic int lpe_dma_alloc(struct lpe_softc *); 166239278Sgonzostatic int lpe_dma_alloc_rx(struct lpe_softc *); 167239278Sgonzostatic int lpe_dma_alloc_tx(struct lpe_softc *); 168239278Sgonzostatic int lpe_init_rx(struct lpe_softc *); 169239278Sgonzostatic int lpe_init_rxbuf(struct lpe_softc *, int); 170239278Sgonzostatic void lpe_discard_rxbuf(struct lpe_softc *, int); 171239278Sgonzostatic void lpe_dmamap_cb(void *, bus_dma_segment_t *, int, int); 172239278Sgonzostatic int lpe_ifmedia_upd(struct ifnet *); 173239278Sgonzostatic void lpe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 174239278Sgonzo 175239278Sgonzo#define lpe_lock(_sc) mtx_lock(&(_sc)->lpe_mtx) 176239278Sgonzo#define lpe_unlock(_sc) mtx_unlock(&(_sc)->lpe_mtx) 177239278Sgonzo#define lpe_lock_assert(sc) mtx_assert(&(_sc)->lpe_mtx, MA_OWNED) 178239278Sgonzo 179239278Sgonzo#define lpe_read_4(_sc, _reg) \ 180239278Sgonzo bus_space_read_4((_sc)->lpe_bst, (_sc)->lpe_bsh, (_reg)) 181239278Sgonzo#define lpe_write_4(_sc, _reg, _val) \ 182239278Sgonzo bus_space_write_4((_sc)->lpe_bst, (_sc)->lpe_bsh, (_reg), (_val)) 183239278Sgonzo 184239278Sgonzo#define LPE_HWDESC_RXERRS (LPE_HWDESC_CRCERROR | LPE_HWDESC_SYMBOLERROR | \ 185239278Sgonzo LPE_HWDESC_LENGTHERROR | LPE_HWDESC_ALIGNERROR | LPE_HWDESC_OVERRUN | \ 186239278Sgonzo LPE_HWDESC_RXNODESCR) 187239278Sgonzo 188239278Sgonzo#define LPE_HWDESC_TXERRS (LPE_HWDESC_EXCDEFER | LPE_HWDESC_EXCCOLL | \ 189239278Sgonzo LPE_HWDESC_LATECOLL | LPE_HWDESC_UNDERRUN | LPE_HWDESC_TXNODESCR) 190239278Sgonzo 191239278Sgonzostatic int 192239278Sgonzolpe_probe(device_t dev) 193239278Sgonzo{ 194239278Sgonzo 195239278Sgonzo if (!ofw_bus_is_compatible(dev, "lpc,ethernet")) 196239278Sgonzo return (ENXIO); 197239278Sgonzo 198239278Sgonzo device_set_desc(dev, "LPC32x0 10/100 Ethernet"); 199239278Sgonzo return (BUS_PROBE_DEFAULT); 200239278Sgonzo} 201239278Sgonzo 202239278Sgonzostatic int 203239278Sgonzolpe_attach(device_t dev) 204239278Sgonzo{ 205239278Sgonzo struct lpe_softc *sc = device_get_softc(dev); 206239278Sgonzo struct ifnet *ifp; 207239278Sgonzo int rid, i; 208239278Sgonzo uint32_t val; 209239278Sgonzo 210239278Sgonzo sc->lpe_dev = dev; 211239278Sgonzo sc->lpe_ofw = ofw_bus_get_node(dev); 212239278Sgonzo 213239278Sgonzo i = OF_getprop(sc->lpe_ofw, "local-mac-address", (void *)&sc->lpe_enaddr, 6); 214239278Sgonzo if (i != 6) { 215239278Sgonzo sc->lpe_enaddr[0] = 0x00; 216239278Sgonzo sc->lpe_enaddr[1] = 0x11; 217239278Sgonzo sc->lpe_enaddr[2] = 0x22; 218239278Sgonzo sc->lpe_enaddr[3] = 0x33; 219239278Sgonzo sc->lpe_enaddr[4] = 0x44; 220239278Sgonzo sc->lpe_enaddr[5] = 0x55; 221239278Sgonzo } 222239278Sgonzo 223239278Sgonzo mtx_init(&sc->lpe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 224239278Sgonzo MTX_DEF); 225239278Sgonzo 226239278Sgonzo callout_init_mtx(&sc->lpe_tick, &sc->lpe_mtx, 0); 227239278Sgonzo 228239278Sgonzo rid = 0; 229239278Sgonzo sc->lpe_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 230239278Sgonzo RF_ACTIVE); 231239278Sgonzo if (!sc->lpe_mem_res) { 232239278Sgonzo device_printf(dev, "cannot allocate memory window\n"); 233239278Sgonzo goto fail; 234239278Sgonzo } 235239278Sgonzo 236239278Sgonzo sc->lpe_bst = rman_get_bustag(sc->lpe_mem_res); 237239278Sgonzo sc->lpe_bsh = rman_get_bushandle(sc->lpe_mem_res); 238239278Sgonzo 239239278Sgonzo rid = 0; 240239278Sgonzo sc->lpe_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 241239278Sgonzo RF_ACTIVE); 242239278Sgonzo if (!sc->lpe_irq_res) { 243239278Sgonzo device_printf(dev, "cannot allocate interrupt\n"); 244239278Sgonzo goto fail; 245239278Sgonzo } 246239278Sgonzo 247239278Sgonzo sc->lpe_ifp = if_alloc(IFT_ETHER); 248239278Sgonzo if (!sc->lpe_ifp) { 249239278Sgonzo device_printf(dev, "cannot allocated ifnet\n"); 250239278Sgonzo goto fail; 251239278Sgonzo } 252239278Sgonzo 253239278Sgonzo ifp = sc->lpe_ifp; 254239278Sgonzo 255239278Sgonzo if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 256239278Sgonzo ifp->if_softc = sc; 257239278Sgonzo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 258239278Sgonzo ifp->if_start = lpe_start; 259239278Sgonzo ifp->if_ioctl = lpe_ioctl; 260239278Sgonzo ifp->if_init = lpe_init; 261239278Sgonzo IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 262239278Sgonzo ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 263239278Sgonzo IFQ_SET_READY(&ifp->if_snd); 264239278Sgonzo 265239278Sgonzo ether_ifattach(ifp, sc->lpe_enaddr); 266239278Sgonzo 267239278Sgonzo if (bus_setup_intr(dev, sc->lpe_irq_res, INTR_TYPE_NET, NULL, 268239278Sgonzo lpe_intr, sc, &sc->lpe_intrhand)) { 269239278Sgonzo device_printf(dev, "cannot establish interrupt handler\n"); 270239278Sgonzo ether_ifdetach(ifp); 271239278Sgonzo goto fail; 272239278Sgonzo } 273239278Sgonzo 274239278Sgonzo /* Enable Ethernet clock */ 275239278Sgonzo lpc_pwr_write(dev, LPC_CLKPWR_MACCLK_CTRL, 276239278Sgonzo LPC_CLKPWR_MACCLK_CTRL_REG | 277239278Sgonzo LPC_CLKPWR_MACCLK_CTRL_SLAVE | 278239278Sgonzo LPC_CLKPWR_MACCLK_CTRL_MASTER | 279239278Sgonzo LPC_CLKPWR_MACCLK_CTRL_HDWINF(3)); 280239278Sgonzo 281239278Sgonzo /* Reset chip */ 282239278Sgonzo lpe_reset(sc); 283239278Sgonzo 284239278Sgonzo /* Initialize MII */ 285239278Sgonzo val = lpe_read_4(sc, LPE_COMMAND); 286239278Sgonzo lpe_write_4(sc, LPE_COMMAND, val | LPE_COMMAND_RMII); 287239278Sgonzo 288239278Sgonzo if (mii_attach(dev, &sc->lpe_miibus, ifp, lpe_ifmedia_upd, 289239278Sgonzo lpe_ifmedia_sts, BMSR_DEFCAPMASK, 0x01, 290239278Sgonzo MII_OFFSET_ANY, 0)) { 291239278Sgonzo device_printf(dev, "cannot find PHY\n"); 292239278Sgonzo goto fail; 293239278Sgonzo } 294239278Sgonzo 295239278Sgonzo lpe_dma_alloc(sc); 296239278Sgonzo 297239278Sgonzo return (0); 298239278Sgonzo 299239278Sgonzofail: 300239278Sgonzo if (sc->lpe_ifp) 301239278Sgonzo if_free(sc->lpe_ifp); 302239278Sgonzo if (sc->lpe_intrhand) 303239278Sgonzo bus_teardown_intr(dev, sc->lpe_irq_res, sc->lpe_intrhand); 304239278Sgonzo if (sc->lpe_irq_res) 305239278Sgonzo bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lpe_irq_res); 306239278Sgonzo if (sc->lpe_mem_res) 307239278Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lpe_mem_res); 308239278Sgonzo return (ENXIO); 309239278Sgonzo} 310239278Sgonzo 311239278Sgonzostatic int 312239278Sgonzolpe_detach(device_t dev) 313239278Sgonzo{ 314239278Sgonzo struct lpe_softc *sc = device_get_softc(dev); 315239278Sgonzo 316239278Sgonzo lpe_stop(sc); 317239278Sgonzo 318239278Sgonzo if_free(sc->lpe_ifp); 319239278Sgonzo bus_teardown_intr(dev, sc->lpe_irq_res, sc->lpe_intrhand); 320239278Sgonzo bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lpe_irq_res); 321239278Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lpe_mem_res); 322239278Sgonzo 323239278Sgonzo return (0); 324239278Sgonzo} 325239278Sgonzo 326239278Sgonzostatic int 327239278Sgonzolpe_miibus_readreg(device_t dev, int phy, int reg) 328239278Sgonzo{ 329239278Sgonzo struct lpe_softc *sc = device_get_softc(dev); 330239278Sgonzo uint32_t val; 331239278Sgonzo int result; 332239278Sgonzo 333239278Sgonzo lpe_write_4(sc, LPE_MCMD, LPE_MCMD_READ); 334239278Sgonzo lpe_write_4(sc, LPE_MADR, 335239278Sgonzo (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT | 336239278Sgonzo (phy & LPE_MADR_PHYMASK) << LPE_MADR_PHYSHIFT); 337239278Sgonzo 338239278Sgonzo val = lpe_read_4(sc, LPE_MIND); 339239278Sgonzo 340239278Sgonzo /* Wait until request is completed */ 341239278Sgonzo while (val & LPE_MIND_BUSY) { 342239278Sgonzo val = lpe_read_4(sc, LPE_MIND); 343239278Sgonzo DELAY(10); 344239278Sgonzo } 345239278Sgonzo 346239278Sgonzo if (val & LPE_MIND_INVALID) 347239278Sgonzo return (0); 348239278Sgonzo 349239278Sgonzo lpe_write_4(sc, LPE_MCMD, 0); 350239278Sgonzo result = (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK); 351239278Sgonzo debugf("phy=%d reg=%d result=0x%04x\n", phy, reg, result); 352239278Sgonzo 353239278Sgonzo return (result); 354239278Sgonzo} 355239278Sgonzo 356239278Sgonzostatic int 357239278Sgonzolpe_miibus_writereg(device_t dev, int phy, int reg, int data) 358239278Sgonzo{ 359239278Sgonzo struct lpe_softc *sc = device_get_softc(dev); 360239278Sgonzo uint32_t val; 361239278Sgonzo 362239278Sgonzo debugf("phy=%d reg=%d data=0x%04x\n", phy, reg, data); 363239278Sgonzo 364239278Sgonzo lpe_write_4(sc, LPE_MCMD, LPE_MCMD_WRITE); 365239278Sgonzo lpe_write_4(sc, LPE_MADR, 366239278Sgonzo (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT | 367239278Sgonzo (phy & LPE_MADR_PHYMASK) << LPE_MADR_PHYSHIFT); 368239278Sgonzo 369239278Sgonzo lpe_write_4(sc, LPE_MWTD, (data & LPE_MWTD_DATAMASK)); 370239278Sgonzo 371239278Sgonzo val = lpe_read_4(sc, LPE_MIND); 372239278Sgonzo 373239278Sgonzo /* Wait until request is completed */ 374239278Sgonzo while (val & LPE_MIND_BUSY) { 375239278Sgonzo val = lpe_read_4(sc, LPE_MIND); 376239278Sgonzo DELAY(10); 377239278Sgonzo } 378239278Sgonzo 379239278Sgonzo return (0); 380239278Sgonzo} 381239278Sgonzo 382239278Sgonzostatic void 383239278Sgonzolpe_miibus_statchg(device_t dev) 384239278Sgonzo{ 385239278Sgonzo struct lpe_softc *sc = device_get_softc(dev); 386239278Sgonzo struct mii_data *mii = device_get_softc(sc->lpe_miibus); 387239278Sgonzo 388239278Sgonzo lpe_lock(sc); 389239278Sgonzo 390239278Sgonzo if ((mii->mii_media_status & IFM_ACTIVE) && 391239278Sgonzo (mii->mii_media_status & IFM_AVALID)) 392239278Sgonzo sc->lpe_flags |= LPE_FLAG_LINK; 393239278Sgonzo else 394239278Sgonzo sc->lpe_flags &= ~LPE_FLAG_LINK; 395239278Sgonzo 396239278Sgonzo lpe_unlock(sc); 397239278Sgonzo} 398239278Sgonzo 399239278Sgonzostatic void 400239278Sgonzolpe_reset(struct lpe_softc *sc) 401239278Sgonzo{ 402239278Sgonzo uint32_t mac1; 403239278Sgonzo 404239278Sgonzo /* Enter soft reset mode */ 405239278Sgonzo mac1 = lpe_read_4(sc, LPE_MAC1); 406239278Sgonzo lpe_write_4(sc, LPE_MAC1, mac1 | LPE_MAC1_SOFTRESET | LPE_MAC1_RESETTX | 407239278Sgonzo LPE_MAC1_RESETMCSTX | LPE_MAC1_RESETRX | LPE_MAC1_RESETMCSRX); 408239278Sgonzo 409239278Sgonzo /* Reset registers, Tx path and Rx path */ 410239278Sgonzo lpe_write_4(sc, LPE_COMMAND, LPE_COMMAND_REGRESET | 411239278Sgonzo LPE_COMMAND_TXRESET | LPE_COMMAND_RXRESET); 412239278Sgonzo 413239278Sgonzo /* Set station address */ 414239278Sgonzo lpe_write_4(sc, LPE_SA2, sc->lpe_enaddr[1] << 8 | sc->lpe_enaddr[0]); 415239278Sgonzo lpe_write_4(sc, LPE_SA1, sc->lpe_enaddr[3] << 8 | sc->lpe_enaddr[2]); 416239278Sgonzo lpe_write_4(sc, LPE_SA0, sc->lpe_enaddr[5] << 8 | sc->lpe_enaddr[4]); 417239278Sgonzo 418239278Sgonzo /* Leave soft reset mode */ 419239278Sgonzo mac1 = lpe_read_4(sc, LPE_MAC1); 420239278Sgonzo lpe_write_4(sc, LPE_MAC1, mac1 & ~(LPE_MAC1_SOFTRESET | LPE_MAC1_RESETTX | 421239278Sgonzo LPE_MAC1_RESETMCSTX | LPE_MAC1_RESETRX | LPE_MAC1_RESETMCSRX)); 422239278Sgonzo} 423239278Sgonzo 424239278Sgonzostatic void 425239278Sgonzolpe_init(void *arg) 426239278Sgonzo{ 427239278Sgonzo struct lpe_softc *sc = (struct lpe_softc *)arg; 428239278Sgonzo 429239278Sgonzo lpe_lock(sc); 430239278Sgonzo lpe_init_locked(sc); 431239278Sgonzo lpe_unlock(sc); 432239278Sgonzo} 433239278Sgonzo 434239278Sgonzostatic void 435239278Sgonzolpe_init_locked(struct lpe_softc *sc) 436239278Sgonzo{ 437239278Sgonzo struct ifnet *ifp = sc->lpe_ifp; 438239278Sgonzo uint32_t cmd, mac1; 439239278Sgonzo 440239278Sgonzo lpe_lock_assert(sc); 441239278Sgonzo 442239278Sgonzo if (ifp->if_drv_flags & IFF_DRV_RUNNING) 443239278Sgonzo return; 444239278Sgonzo 445239278Sgonzo /* Enable Tx and Rx */ 446239278Sgonzo cmd = lpe_read_4(sc, LPE_COMMAND); 447239278Sgonzo lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE | 448239278Sgonzo LPE_COMMAND_TXENABLE | LPE_COMMAND_PASSRUNTFRAME); 449239278Sgonzo 450239278Sgonzo /* Enable receive */ 451239278Sgonzo mac1 = lpe_read_4(sc, LPE_MAC1); 452239278Sgonzo lpe_write_4(sc, LPE_MAC1, /*mac1 |*/ LPE_MAC1_RXENABLE | LPE_MAC1_PASSALL); 453239278Sgonzo 454239278Sgonzo lpe_write_4(sc, LPE_MAC2, LPE_MAC2_CRCENABLE | LPE_MAC2_PADCRCENABLE | 455239278Sgonzo LPE_MAC2_FULLDUPLEX); 456239278Sgonzo 457239278Sgonzo lpe_write_4(sc, LPE_MCFG, LPE_MCFG_CLKSEL(7)); 458239278Sgonzo 459239278Sgonzo /* Set up Rx filter */ 460239278Sgonzo lpe_set_rxmode(sc); 461239278Sgonzo 462239278Sgonzo /* Enable interrupts */ 463239278Sgonzo lpe_write_4(sc, LPE_INTENABLE, LPE_INT_RXOVERRUN | LPE_INT_RXERROR | 464239278Sgonzo LPE_INT_RXFINISH | LPE_INT_RXDONE | LPE_INT_TXUNDERRUN | 465239278Sgonzo LPE_INT_TXERROR | LPE_INT_TXFINISH | LPE_INT_TXDONE); 466239278Sgonzo 467239278Sgonzo sc->lpe_cdata.lpe_tx_prod = 0; 468239278Sgonzo sc->lpe_cdata.lpe_tx_last = 0; 469239278Sgonzo sc->lpe_cdata.lpe_tx_used = 0; 470239278Sgonzo 471239278Sgonzo lpe_init_rx(sc); 472239278Sgonzo 473239278Sgonzo /* Initialize Rx packet and status descriptor heads */ 474239278Sgonzo lpe_write_4(sc, LPE_RXDESC, sc->lpe_rdata.lpe_rx_ring_phys); 475239278Sgonzo lpe_write_4(sc, LPE_RXSTATUS, sc->lpe_rdata.lpe_rx_status_phys); 476239278Sgonzo lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM - 1); 477239278Sgonzo lpe_write_4(sc, LPE_RXDESC_CONS, 0); 478239278Sgonzo 479239278Sgonzo /* Initialize Tx packet and status descriptor heads */ 480239278Sgonzo lpe_write_4(sc, LPE_TXDESC, sc->lpe_rdata.lpe_tx_ring_phys); 481239278Sgonzo lpe_write_4(sc, LPE_TXSTATUS, sc->lpe_rdata.lpe_tx_status_phys); 482239278Sgonzo lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM - 1); 483239278Sgonzo lpe_write_4(sc, LPE_TXDESC_PROD, 0); 484239278Sgonzo 485239278Sgonzo ifp->if_drv_flags |= IFF_DRV_RUNNING; 486239278Sgonzo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 487239278Sgonzo 488239278Sgonzo callout_reset(&sc->lpe_tick, hz, lpe_tick, sc); 489239278Sgonzo} 490239278Sgonzo 491239278Sgonzostatic void 492239278Sgonzolpe_start(struct ifnet *ifp) 493239278Sgonzo{ 494239278Sgonzo struct lpe_softc *sc = (struct lpe_softc *)ifp->if_softc; 495239278Sgonzo 496239278Sgonzo lpe_lock(sc); 497239278Sgonzo lpe_start_locked(ifp); 498239278Sgonzo lpe_unlock(sc); 499239278Sgonzo} 500239278Sgonzo 501239278Sgonzostatic void 502239278Sgonzolpe_start_locked(struct ifnet *ifp) 503239278Sgonzo{ 504239278Sgonzo struct lpe_softc *sc = (struct lpe_softc *)ifp->if_softc; 505239278Sgonzo struct mbuf *m_head; 506239278Sgonzo int encap = 0; 507239278Sgonzo 508239278Sgonzo lpe_lock_assert(sc); 509239278Sgonzo 510239278Sgonzo while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 511239278Sgonzo if (lpe_read_4(sc, LPE_TXDESC_PROD) == 512239278Sgonzo lpe_read_4(sc, LPE_TXDESC_CONS) - 5) 513239278Sgonzo break; 514239278Sgonzo 515239278Sgonzo /* Dequeue first packet */ 516239278Sgonzo IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 517239278Sgonzo if (!m_head) 518239278Sgonzo break; 519239278Sgonzo 520239278Sgonzo lpe_encap(sc, &m_head); 521239278Sgonzo 522239278Sgonzo encap++; 523239278Sgonzo } 524239278Sgonzo 525239278Sgonzo /* Submit new descriptor list */ 526239278Sgonzo if (encap) { 527239278Sgonzo lpe_write_4(sc, LPE_TXDESC_PROD, sc->lpe_cdata.lpe_tx_prod); 528239278Sgonzo sc->lpe_watchdog_timer = 5; 529239278Sgonzo } 530239278Sgonzo 531239278Sgonzo} 532239278Sgonzo 533239278Sgonzostatic int 534239278Sgonzolpe_encap(struct lpe_softc *sc, struct mbuf **m_head) 535239278Sgonzo{ 536239278Sgonzo struct lpe_txdesc *txd; 537239278Sgonzo struct lpe_hwdesc *hwd; 538239278Sgonzo bus_dma_segment_t segs[LPE_MAXFRAGS]; 539239278Sgonzo int i, err, nsegs, prod; 540239278Sgonzo 541239278Sgonzo lpe_lock_assert(sc); 542239278Sgonzo M_ASSERTPKTHDR((*m_head)); 543239278Sgonzo 544239278Sgonzo prod = sc->lpe_cdata.lpe_tx_prod; 545239278Sgonzo txd = &sc->lpe_cdata.lpe_tx_desc[prod]; 546239278Sgonzo 547239278Sgonzo debugf("starting with prod=%d\n", prod); 548239278Sgonzo 549239278Sgonzo err = bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_tx_buf_tag, 550239278Sgonzo txd->lpe_txdesc_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 551239278Sgonzo 552239278Sgonzo if (err) 553239278Sgonzo return (err); 554239278Sgonzo 555239278Sgonzo if (nsegs == 0) { 556239278Sgonzo m_freem(*m_head); 557239278Sgonzo *m_head = NULL; 558239278Sgonzo return (EIO); 559239278Sgonzo } 560239278Sgonzo 561239278Sgonzo bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap, 562239278Sgonzo BUS_DMASYNC_PREREAD); 563239278Sgonzo bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map, 564239278Sgonzo BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 565239278Sgonzo 566239278Sgonzo txd->lpe_txdesc_first = 1; 567239278Sgonzo txd->lpe_txdesc_mbuf = *m_head; 568239278Sgonzo 569239278Sgonzo for (i = 0; i < nsegs; i++) { 570239278Sgonzo hwd = &sc->lpe_rdata.lpe_tx_ring[prod]; 571239278Sgonzo hwd->lhr_data = segs[i].ds_addr; 572239278Sgonzo hwd->lhr_control = segs[i].ds_len - 1; 573239278Sgonzo 574239278Sgonzo if (i == nsegs - 1) { 575239278Sgonzo hwd->lhr_control |= LPE_HWDESC_LASTFLAG; 576239278Sgonzo hwd->lhr_control |= LPE_HWDESC_INTERRUPT; 577239278Sgonzo hwd->lhr_control |= LPE_HWDESC_CRC; 578239278Sgonzo hwd->lhr_control |= LPE_HWDESC_PAD; 579239278Sgonzo } 580239278Sgonzo 581239278Sgonzo LPE_INC(prod, LPE_TXDESC_NUM); 582239278Sgonzo } 583239278Sgonzo 584239278Sgonzo bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map, 585239278Sgonzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 586239278Sgonzo 587239278Sgonzo sc->lpe_cdata.lpe_tx_used += nsegs; 588239278Sgonzo sc->lpe_cdata.lpe_tx_prod = prod; 589239278Sgonzo 590239278Sgonzo return (0); 591239278Sgonzo} 592239278Sgonzo 593239278Sgonzostatic void 594239278Sgonzolpe_stop(struct lpe_softc *sc) 595239278Sgonzo{ 596239278Sgonzo lpe_lock(sc); 597239278Sgonzo lpe_stop_locked(sc); 598239278Sgonzo lpe_unlock(sc); 599239278Sgonzo} 600239278Sgonzo 601239278Sgonzostatic void 602239278Sgonzolpe_stop_locked(struct lpe_softc *sc) 603239278Sgonzo{ 604239278Sgonzo lpe_lock_assert(sc); 605239278Sgonzo 606239278Sgonzo callout_stop(&sc->lpe_tick); 607239278Sgonzo 608239278Sgonzo /* Disable interrupts */ 609239278Sgonzo lpe_write_4(sc, LPE_INTCLEAR, 0xffffffff); 610239278Sgonzo 611239278Sgonzo /* Stop EMAC */ 612239278Sgonzo lpe_write_4(sc, LPE_MAC1, 0); 613239278Sgonzo lpe_write_4(sc, LPE_MAC2, 0); 614239278Sgonzo lpe_write_4(sc, LPE_COMMAND, 0); 615239278Sgonzo 616239278Sgonzo sc->lpe_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 617239278Sgonzo sc->lpe_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 618239278Sgonzo} 619239278Sgonzo 620239278Sgonzostatic int 621239278Sgonzolpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 622239278Sgonzo{ 623239278Sgonzo struct lpe_softc *sc = ifp->if_softc; 624239278Sgonzo struct mii_data *mii = device_get_softc(sc->lpe_miibus); 625239278Sgonzo struct ifreq *ifr = (struct ifreq *)data; 626239278Sgonzo int err = 0; 627239278Sgonzo 628239278Sgonzo switch (cmd) { 629239278Sgonzo case SIOCSIFFLAGS: 630239278Sgonzo lpe_lock(sc); 631239278Sgonzo if (ifp->if_flags & IFF_UP) { 632239278Sgonzo if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 633239278Sgonzo lpe_set_rxmode(sc); 634239278Sgonzo lpe_set_rxfilter(sc); 635239278Sgonzo } else 636239278Sgonzo lpe_init_locked(sc); 637239278Sgonzo } else 638239278Sgonzo lpe_stop(sc); 639239278Sgonzo lpe_unlock(sc); 640239278Sgonzo break; 641239278Sgonzo case SIOCADDMULTI: 642239278Sgonzo case SIOCDELMULTI: 643239278Sgonzo if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 644239278Sgonzo lpe_lock(sc); 645239278Sgonzo lpe_set_rxfilter(sc); 646239278Sgonzo lpe_unlock(sc); 647239278Sgonzo } 648239278Sgonzo break; 649239278Sgonzo case SIOCGIFMEDIA: 650239278Sgonzo case SIOCSIFMEDIA: 651239278Sgonzo err = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 652239278Sgonzo break; 653239278Sgonzo default: 654239278Sgonzo err = ether_ioctl(ifp, cmd, data); 655239278Sgonzo break; 656239278Sgonzo } 657239278Sgonzo 658239278Sgonzo return (err); 659239278Sgonzo} 660239278Sgonzo 661239278Sgonzostatic void lpe_set_rxmode(struct lpe_softc *sc) 662239278Sgonzo{ 663239278Sgonzo struct ifnet *ifp = sc->lpe_ifp; 664239278Sgonzo uint32_t rxfilt; 665239278Sgonzo 666239278Sgonzo rxfilt = LPE_RXFILTER_UNIHASH | LPE_RXFILTER_MULTIHASH | LPE_RXFILTER_PERFECT; 667239278Sgonzo 668239278Sgonzo if (ifp->if_flags & IFF_BROADCAST) 669239278Sgonzo rxfilt |= LPE_RXFILTER_BROADCAST; 670239278Sgonzo 671239278Sgonzo if (ifp->if_flags & IFF_PROMISC) 672239278Sgonzo rxfilt |= LPE_RXFILTER_UNICAST | LPE_RXFILTER_MULTICAST; 673239278Sgonzo 674239278Sgonzo if (ifp->if_flags & IFF_ALLMULTI) 675239278Sgonzo rxfilt |= LPE_RXFILTER_MULTICAST; 676239278Sgonzo 677239278Sgonzo lpe_write_4(sc, LPE_RXFILTER_CTRL, rxfilt); 678239278Sgonzo} 679239278Sgonzo 680239278Sgonzostatic void lpe_set_rxfilter(struct lpe_softc *sc) 681239278Sgonzo{ 682239278Sgonzo struct ifnet *ifp = sc->lpe_ifp; 683239278Sgonzo struct ifmultiaddr *ifma; 684239278Sgonzo int index; 685239278Sgonzo uint32_t hashl, hashh; 686239278Sgonzo 687239278Sgonzo hashl = 0; 688239278Sgonzo hashh = 0; 689239278Sgonzo 690239278Sgonzo if_maddr_rlock(ifp); 691239278Sgonzo TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 692239278Sgonzo if (ifma->ifma_addr->sa_family != AF_LINK) 693239278Sgonzo continue; 694239278Sgonzo 695239278Sgonzo index = ether_crc32_be(LLADDR((struct sockaddr_dl *) 696239278Sgonzo ifma->ifma_addr), ETHER_ADDR_LEN) >> 23 & 0x3f; 697239278Sgonzo 698239278Sgonzo if (index > 31) 699239278Sgonzo hashh |= (1 << (index - 32)); 700239278Sgonzo else 701239278Sgonzo hashl |= (1 << index); 702239278Sgonzo } 703239278Sgonzo if_maddr_runlock(ifp); 704239278Sgonzo 705239278Sgonzo /* Program new hash filter */ 706239278Sgonzo lpe_write_4(sc, LPE_HASHFILTER_L, hashl); 707239278Sgonzo lpe_write_4(sc, LPE_HASHFILTER_H, hashh); 708239278Sgonzo} 709239278Sgonzo 710239278Sgonzostatic void 711239278Sgonzolpe_intr(void *arg) 712239278Sgonzo{ 713239278Sgonzo struct lpe_softc *sc = (struct lpe_softc *)arg; 714239278Sgonzo uint32_t intstatus; 715239278Sgonzo 716239278Sgonzo debugf("status=0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS)); 717239278Sgonzo 718239278Sgonzo lpe_lock(sc); 719239278Sgonzo 720239278Sgonzo while ((intstatus = lpe_read_4(sc, LPE_INTSTATUS))) { 721239278Sgonzo if (intstatus & LPE_INT_RXDONE) 722239278Sgonzo lpe_rxintr(sc); 723239278Sgonzo 724239278Sgonzo if (intstatus & LPE_INT_TXDONE) 725239278Sgonzo lpe_txintr(sc); 726239278Sgonzo 727239278Sgonzo lpe_write_4(sc, LPE_INTCLEAR, 0xffff); 728239278Sgonzo } 729239278Sgonzo 730239278Sgonzo lpe_unlock(sc); 731239278Sgonzo} 732239278Sgonzo 733239278Sgonzostatic void 734239278Sgonzolpe_rxintr(struct lpe_softc *sc) 735239278Sgonzo{ 736239278Sgonzo struct ifnet *ifp = sc->lpe_ifp; 737239278Sgonzo struct lpe_hwdesc *hwd; 738239278Sgonzo struct lpe_hwstatus *hws; 739239278Sgonzo struct lpe_rxdesc *rxd; 740239278Sgonzo struct mbuf *m; 741239278Sgonzo int prod, cons; 742239278Sgonzo 743239278Sgonzo for (;;) { 744239278Sgonzo prod = lpe_read_4(sc, LPE_RXDESC_PROD); 745239278Sgonzo cons = lpe_read_4(sc, LPE_RXDESC_CONS); 746239278Sgonzo 747239278Sgonzo if (prod == cons) 748239278Sgonzo break; 749239278Sgonzo 750239278Sgonzo rxd = &sc->lpe_cdata.lpe_rx_desc[cons]; 751239278Sgonzo hwd = &sc->lpe_rdata.lpe_rx_ring[cons]; 752239278Sgonzo hws = &sc->lpe_rdata.lpe_rx_status[cons]; 753239278Sgonzo 754239278Sgonzo /* Check received frame for errors */ 755239278Sgonzo if (hws->lhs_info & LPE_HWDESC_RXERRS) { 756239278Sgonzo ifp->if_ierrors++; 757239278Sgonzo lpe_discard_rxbuf(sc, cons); 758239278Sgonzo lpe_init_rxbuf(sc, cons); 759239278Sgonzo goto skip; 760239278Sgonzo } 761239278Sgonzo 762239278Sgonzo m = rxd->lpe_rxdesc_mbuf; 763239278Sgonzo m->m_pkthdr.rcvif = ifp; 764239278Sgonzo m->m_data += 2; 765239278Sgonzo 766239278Sgonzo ifp->if_ipackets++; 767239278Sgonzo 768239278Sgonzo lpe_unlock(sc); 769239278Sgonzo (*ifp->if_input)(ifp, m); 770239278Sgonzo lpe_lock(sc); 771239278Sgonzo 772239278Sgonzo lpe_init_rxbuf(sc, cons); 773239278Sgonzoskip: 774239278Sgonzo LPE_INC(cons, LPE_RXDESC_NUM); 775239278Sgonzo lpe_write_4(sc, LPE_RXDESC_CONS, cons); 776239278Sgonzo } 777239278Sgonzo} 778239278Sgonzo 779239278Sgonzostatic void 780239278Sgonzolpe_txintr(struct lpe_softc *sc) 781239278Sgonzo{ 782239278Sgonzo struct ifnet *ifp = sc->lpe_ifp; 783239278Sgonzo struct lpe_hwdesc *hwd; 784239278Sgonzo struct lpe_hwstatus *hws; 785239278Sgonzo struct lpe_txdesc *txd; 786239278Sgonzo int cons, last; 787239278Sgonzo 788239278Sgonzo for (;;) { 789239278Sgonzo cons = lpe_read_4(sc, LPE_TXDESC_CONS); 790239278Sgonzo last = sc->lpe_cdata.lpe_tx_last; 791239278Sgonzo 792239278Sgonzo if (cons == last) 793239278Sgonzo break; 794239278Sgonzo 795239278Sgonzo txd = &sc->lpe_cdata.lpe_tx_desc[last]; 796239278Sgonzo hwd = &sc->lpe_rdata.lpe_tx_ring[last]; 797239278Sgonzo hws = &sc->lpe_rdata.lpe_tx_status[last]; 798239278Sgonzo 799239278Sgonzo bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, 800239278Sgonzo txd->lpe_txdesc_dmamap, BUS_DMASYNC_POSTWRITE); 801239278Sgonzo 802239278Sgonzo ifp->if_collisions += LPE_HWDESC_COLLISIONS(hws->lhs_info); 803239278Sgonzo 804239278Sgonzo if (hws->lhs_info & LPE_HWDESC_TXERRS) 805239278Sgonzo ifp->if_oerrors++; 806239278Sgonzo else 807239278Sgonzo ifp->if_opackets++; 808239278Sgonzo 809239278Sgonzo if (txd->lpe_txdesc_first) { 810239278Sgonzo bus_dmamap_unload(sc->lpe_cdata.lpe_tx_buf_tag, 811239278Sgonzo txd->lpe_txdesc_dmamap); 812239278Sgonzo 813239278Sgonzo m_freem(txd->lpe_txdesc_mbuf); 814239278Sgonzo txd->lpe_txdesc_mbuf = NULL; 815239278Sgonzo txd->lpe_txdesc_first = 0; 816239278Sgonzo } 817239278Sgonzo 818239278Sgonzo sc->lpe_cdata.lpe_tx_used--; 819239278Sgonzo LPE_INC(sc->lpe_cdata.lpe_tx_last, LPE_TXDESC_NUM); 820239278Sgonzo } 821239278Sgonzo 822239278Sgonzo if (!sc->lpe_cdata.lpe_tx_used) 823239278Sgonzo sc->lpe_watchdog_timer = 0; 824239278Sgonzo} 825239278Sgonzo 826239278Sgonzostatic void 827239278Sgonzolpe_tick(void *arg) 828239278Sgonzo{ 829239278Sgonzo struct lpe_softc *sc = (struct lpe_softc *)arg; 830239278Sgonzo struct mii_data *mii = device_get_softc(sc->lpe_miibus); 831239278Sgonzo 832239278Sgonzo lpe_lock_assert(sc); 833239278Sgonzo 834239278Sgonzo mii_tick(mii); 835239278Sgonzo lpe_watchdog(sc); 836239278Sgonzo 837239278Sgonzo callout_reset(&sc->lpe_tick, hz, lpe_tick, sc); 838239278Sgonzo} 839239278Sgonzo 840239278Sgonzostatic void 841239278Sgonzolpe_watchdog(struct lpe_softc *sc) 842239278Sgonzo{ 843239278Sgonzo struct ifnet *ifp = sc->lpe_ifp; 844239278Sgonzo 845239278Sgonzo lpe_lock_assert(sc); 846239278Sgonzo 847239278Sgonzo if (sc->lpe_watchdog_timer == 0 || sc->lpe_watchdog_timer--) 848239278Sgonzo return; 849239278Sgonzo 850239278Sgonzo /* Chip has stopped responding */ 851239278Sgonzo device_printf(sc->lpe_dev, "WARNING: chip hangup, restarting...\n"); 852239278Sgonzo lpe_stop_locked(sc); 853239278Sgonzo lpe_init_locked(sc); 854239278Sgonzo 855239278Sgonzo /* Try to resend packets */ 856239278Sgonzo if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 857239278Sgonzo lpe_start_locked(ifp); 858239278Sgonzo} 859239278Sgonzo 860239278Sgonzostatic int 861239278Sgonzolpe_dma_alloc(struct lpe_softc *sc) 862239278Sgonzo{ 863239278Sgonzo int err; 864239278Sgonzo 865239278Sgonzo /* Create parent DMA tag */ 866239278Sgonzo err = bus_dma_tag_create( 867239278Sgonzo bus_get_dma_tag(sc->lpe_dev), 868239278Sgonzo 1, 0, /* alignment, boundary */ 869239278Sgonzo BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 870239278Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 871239278Sgonzo NULL, NULL, /* filter, filterarg */ 872239278Sgonzo BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 873239278Sgonzo BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsegsize, flags */ 874239278Sgonzo NULL, NULL, /* lockfunc, lockarg */ 875239278Sgonzo &sc->lpe_cdata.lpe_parent_tag); 876239278Sgonzo 877239278Sgonzo if (err) { 878239278Sgonzo device_printf(sc->lpe_dev, "cannot create parent DMA tag\n"); 879239278Sgonzo return (err); 880239278Sgonzo } 881239278Sgonzo 882239278Sgonzo err = lpe_dma_alloc_rx(sc); 883239278Sgonzo if (err) 884239278Sgonzo return (err); 885239278Sgonzo 886239278Sgonzo err = lpe_dma_alloc_tx(sc); 887239278Sgonzo if (err) 888239278Sgonzo return (err); 889239278Sgonzo 890239278Sgonzo return (0); 891239278Sgonzo} 892239278Sgonzo 893239278Sgonzostatic int 894239278Sgonzolpe_dma_alloc_rx(struct lpe_softc *sc) 895239278Sgonzo{ 896239278Sgonzo struct lpe_rxdesc *rxd; 897239278Sgonzo struct lpe_dmamap_arg ctx; 898239278Sgonzo int err, i; 899239278Sgonzo 900239278Sgonzo /* Create tag for Rx ring */ 901239278Sgonzo err = bus_dma_tag_create( 902239278Sgonzo sc->lpe_cdata.lpe_parent_tag, 903239278Sgonzo LPE_DESC_ALIGN, 0, /* alignment, boundary */ 904239278Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 905239278Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 906239278Sgonzo NULL, NULL, /* filter, filterarg */ 907239278Sgonzo LPE_RXDESC_SIZE, 1, /* maxsize, nsegments */ 908239278Sgonzo LPE_RXDESC_SIZE, 0, /* maxsegsize, flags */ 909239278Sgonzo NULL, NULL, /* lockfunc, lockarg */ 910239278Sgonzo &sc->lpe_cdata.lpe_rx_ring_tag); 911239278Sgonzo 912239278Sgonzo if (err) { 913239278Sgonzo device_printf(sc->lpe_dev, "cannot create Rx ring DMA tag\n"); 914239278Sgonzo goto fail; 915239278Sgonzo } 916239278Sgonzo 917239278Sgonzo /* Create tag for Rx status ring */ 918239278Sgonzo err = bus_dma_tag_create( 919239278Sgonzo sc->lpe_cdata.lpe_parent_tag, 920239278Sgonzo LPE_DESC_ALIGN, 0, /* alignment, boundary */ 921239278Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 922239278Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 923239278Sgonzo NULL, NULL, /* filter, filterarg */ 924239278Sgonzo LPE_RXSTATUS_SIZE, 1, /* maxsize, nsegments */ 925239278Sgonzo LPE_RXSTATUS_SIZE, 0, /* maxsegsize, flags */ 926239278Sgonzo NULL, NULL, /* lockfunc, lockarg */ 927239278Sgonzo &sc->lpe_cdata.lpe_rx_status_tag); 928239278Sgonzo 929239278Sgonzo if (err) { 930239278Sgonzo device_printf(sc->lpe_dev, "cannot create Rx status ring DMA tag\n"); 931239278Sgonzo goto fail; 932239278Sgonzo } 933239278Sgonzo 934239278Sgonzo /* Create tag for Rx buffers */ 935239278Sgonzo err = bus_dma_tag_create( 936239278Sgonzo sc->lpe_cdata.lpe_parent_tag, 937239278Sgonzo LPE_DESC_ALIGN, 0, /* alignment, boundary */ 938239278Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 939239278Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 940239278Sgonzo NULL, NULL, /* filter, filterarg */ 941239278Sgonzo MCLBYTES * LPE_RXDESC_NUM, /* maxsize */ 942239278Sgonzo LPE_RXDESC_NUM, /* segments */ 943239278Sgonzo MCLBYTES, 0, /* maxsegsize, flags */ 944239278Sgonzo NULL, NULL, /* lockfunc, lockarg */ 945239278Sgonzo &sc->lpe_cdata.lpe_rx_buf_tag); 946239278Sgonzo 947239278Sgonzo if (err) { 948239278Sgonzo device_printf(sc->lpe_dev, "cannot create Rx buffers DMA tag\n"); 949239278Sgonzo goto fail; 950239278Sgonzo } 951239278Sgonzo 952239278Sgonzo /* Allocate Rx DMA ring */ 953239278Sgonzo err = bus_dmamem_alloc(sc->lpe_cdata.lpe_rx_ring_tag, 954239278Sgonzo (void **)&sc->lpe_rdata.lpe_rx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT | 955239278Sgonzo BUS_DMA_ZERO, &sc->lpe_cdata.lpe_rx_ring_map); 956239278Sgonzo 957239278Sgonzo err = bus_dmamap_load(sc->lpe_cdata.lpe_rx_ring_tag, 958239278Sgonzo sc->lpe_cdata.lpe_rx_ring_map, sc->lpe_rdata.lpe_rx_ring, 959239278Sgonzo LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0); 960239278Sgonzo 961239278Sgonzo sc->lpe_rdata.lpe_rx_ring_phys = ctx.lpe_dma_busaddr; 962239278Sgonzo 963239278Sgonzo /* Allocate Rx status ring */ 964239278Sgonzo err = bus_dmamem_alloc(sc->lpe_cdata.lpe_rx_status_tag, 965239278Sgonzo (void **)&sc->lpe_rdata.lpe_rx_status, BUS_DMA_WAITOK | BUS_DMA_COHERENT | 966239278Sgonzo BUS_DMA_ZERO, &sc->lpe_cdata.lpe_rx_status_map); 967239278Sgonzo 968239278Sgonzo err = bus_dmamap_load(sc->lpe_cdata.lpe_rx_status_tag, 969239278Sgonzo sc->lpe_cdata.lpe_rx_status_map, sc->lpe_rdata.lpe_rx_status, 970239278Sgonzo LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0); 971239278Sgonzo 972239278Sgonzo sc->lpe_rdata.lpe_rx_status_phys = ctx.lpe_dma_busaddr; 973239278Sgonzo 974239278Sgonzo 975239278Sgonzo /* Create Rx buffers DMA map */ 976239278Sgonzo for (i = 0; i < LPE_RXDESC_NUM; i++) { 977239278Sgonzo rxd = &sc->lpe_cdata.lpe_rx_desc[i]; 978239278Sgonzo rxd->lpe_rxdesc_mbuf = NULL; 979239278Sgonzo rxd->lpe_rxdesc_dmamap = NULL; 980239278Sgonzo 981239278Sgonzo err = bus_dmamap_create(sc->lpe_cdata.lpe_rx_buf_tag, 0, 982239278Sgonzo &rxd->lpe_rxdesc_dmamap); 983239278Sgonzo 984239278Sgonzo if (err) { 985239278Sgonzo device_printf(sc->lpe_dev, "cannot create Rx DMA map\n"); 986239278Sgonzo return (err); 987239278Sgonzo } 988239278Sgonzo } 989239278Sgonzo 990239278Sgonzo return (0); 991239278Sgonzofail: 992239278Sgonzo return (err); 993239278Sgonzo} 994239278Sgonzo 995239278Sgonzostatic int 996239278Sgonzolpe_dma_alloc_tx(struct lpe_softc *sc) 997239278Sgonzo{ 998239278Sgonzo struct lpe_txdesc *txd; 999239278Sgonzo struct lpe_dmamap_arg ctx; 1000239278Sgonzo int err, i; 1001239278Sgonzo 1002239278Sgonzo /* Create tag for Tx ring */ 1003239278Sgonzo err = bus_dma_tag_create( 1004239278Sgonzo sc->lpe_cdata.lpe_parent_tag, 1005239278Sgonzo LPE_DESC_ALIGN, 0, /* alignment, boundary */ 1006239278Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1007239278Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1008239278Sgonzo NULL, NULL, /* filter, filterarg */ 1009239278Sgonzo LPE_TXDESC_SIZE, 1, /* maxsize, nsegments */ 1010239278Sgonzo LPE_TXDESC_SIZE, 0, /* maxsegsize, flags */ 1011239278Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1012239278Sgonzo &sc->lpe_cdata.lpe_tx_ring_tag); 1013239278Sgonzo 1014239278Sgonzo if (err) { 1015239278Sgonzo device_printf(sc->lpe_dev, "cannot create Tx ring DMA tag\n"); 1016239278Sgonzo goto fail; 1017239278Sgonzo } 1018239278Sgonzo 1019239278Sgonzo /* Create tag for Tx status ring */ 1020239278Sgonzo err = bus_dma_tag_create( 1021239278Sgonzo sc->lpe_cdata.lpe_parent_tag, 1022239278Sgonzo LPE_DESC_ALIGN, 0, /* alignment, boundary */ 1023239278Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1024239278Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1025239278Sgonzo NULL, NULL, /* filter, filterarg */ 1026239278Sgonzo LPE_TXSTATUS_SIZE, 1, /* maxsize, nsegments */ 1027239278Sgonzo LPE_TXSTATUS_SIZE, 0, /* maxsegsize, flags */ 1028239278Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1029239278Sgonzo &sc->lpe_cdata.lpe_tx_status_tag); 1030239278Sgonzo 1031239278Sgonzo if (err) { 1032239278Sgonzo device_printf(sc->lpe_dev, "cannot create Tx status ring DMA tag\n"); 1033239278Sgonzo goto fail; 1034239278Sgonzo } 1035239278Sgonzo 1036239278Sgonzo /* Create tag for Tx buffers */ 1037239278Sgonzo err = bus_dma_tag_create( 1038239278Sgonzo sc->lpe_cdata.lpe_parent_tag, 1039239278Sgonzo LPE_DESC_ALIGN, 0, /* alignment, boundary */ 1040239278Sgonzo BUS_SPACE_MAXADDR, /* lowaddr */ 1041239278Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 1042239278Sgonzo NULL, NULL, /* filter, filterarg */ 1043239278Sgonzo MCLBYTES * LPE_TXDESC_NUM, /* maxsize */ 1044239278Sgonzo LPE_TXDESC_NUM, /* segments */ 1045239278Sgonzo MCLBYTES, 0, /* maxsegsize, flags */ 1046239278Sgonzo NULL, NULL, /* lockfunc, lockarg */ 1047239278Sgonzo &sc->lpe_cdata.lpe_tx_buf_tag); 1048239278Sgonzo 1049239278Sgonzo if (err) { 1050239278Sgonzo device_printf(sc->lpe_dev, "cannot create Tx buffers DMA tag\n"); 1051239278Sgonzo goto fail; 1052239278Sgonzo } 1053239278Sgonzo 1054239278Sgonzo /* Allocate Tx DMA ring */ 1055239278Sgonzo err = bus_dmamem_alloc(sc->lpe_cdata.lpe_tx_ring_tag, 1056239278Sgonzo (void **)&sc->lpe_rdata.lpe_tx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT | 1057239278Sgonzo BUS_DMA_ZERO, &sc->lpe_cdata.lpe_tx_ring_map); 1058239278Sgonzo 1059239278Sgonzo err = bus_dmamap_load(sc->lpe_cdata.lpe_tx_ring_tag, 1060239278Sgonzo sc->lpe_cdata.lpe_tx_ring_map, sc->lpe_rdata.lpe_tx_ring, 1061239278Sgonzo LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0); 1062239278Sgonzo 1063239278Sgonzo sc->lpe_rdata.lpe_tx_ring_phys = ctx.lpe_dma_busaddr; 1064239278Sgonzo 1065239278Sgonzo /* Allocate Tx status ring */ 1066239278Sgonzo err = bus_dmamem_alloc(sc->lpe_cdata.lpe_tx_status_tag, 1067239278Sgonzo (void **)&sc->lpe_rdata.lpe_tx_status, BUS_DMA_WAITOK | BUS_DMA_COHERENT | 1068239278Sgonzo BUS_DMA_ZERO, &sc->lpe_cdata.lpe_tx_status_map); 1069239278Sgonzo 1070239278Sgonzo err = bus_dmamap_load(sc->lpe_cdata.lpe_tx_status_tag, 1071239278Sgonzo sc->lpe_cdata.lpe_tx_status_map, sc->lpe_rdata.lpe_tx_status, 1072239278Sgonzo LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0); 1073239278Sgonzo 1074239278Sgonzo sc->lpe_rdata.lpe_tx_status_phys = ctx.lpe_dma_busaddr; 1075239278Sgonzo 1076239278Sgonzo 1077239278Sgonzo /* Create Tx buffers DMA map */ 1078239278Sgonzo for (i = 0; i < LPE_TXDESC_NUM; i++) { 1079239278Sgonzo txd = &sc->lpe_cdata.lpe_tx_desc[i]; 1080239278Sgonzo txd->lpe_txdesc_mbuf = NULL; 1081239278Sgonzo txd->lpe_txdesc_dmamap = NULL; 1082239278Sgonzo txd->lpe_txdesc_first = 0; 1083239278Sgonzo 1084239278Sgonzo err = bus_dmamap_create(sc->lpe_cdata.lpe_tx_buf_tag, 0, 1085239278Sgonzo &txd->lpe_txdesc_dmamap); 1086239278Sgonzo 1087239278Sgonzo if (err) { 1088239278Sgonzo device_printf(sc->lpe_dev, "cannot create Tx DMA map\n"); 1089239278Sgonzo return (err); 1090239278Sgonzo } 1091239278Sgonzo } 1092239278Sgonzo 1093239278Sgonzo return (0); 1094239278Sgonzofail: 1095239278Sgonzo return (err); 1096239278Sgonzo} 1097239278Sgonzo 1098239278Sgonzostatic int 1099239278Sgonzolpe_init_rx(struct lpe_softc *sc) 1100239278Sgonzo{ 1101239278Sgonzo int i, err; 1102239278Sgonzo 1103239278Sgonzo for (i = 0; i < LPE_RXDESC_NUM; i++) { 1104239278Sgonzo err = lpe_init_rxbuf(sc, i); 1105239278Sgonzo if (err) 1106239278Sgonzo return (err); 1107239278Sgonzo } 1108239278Sgonzo 1109239278Sgonzo return (0); 1110239278Sgonzo} 1111239278Sgonzo 1112239278Sgonzostatic int 1113239278Sgonzolpe_init_rxbuf(struct lpe_softc *sc, int n) 1114239278Sgonzo{ 1115239278Sgonzo struct lpe_rxdesc *rxd; 1116239278Sgonzo struct lpe_hwdesc *hwd; 1117239278Sgonzo struct lpe_hwstatus *hws; 1118239278Sgonzo struct mbuf *m; 1119239278Sgonzo bus_dma_segment_t segs[1]; 1120239278Sgonzo int nsegs; 1121239278Sgonzo 1122239278Sgonzo rxd = &sc->lpe_cdata.lpe_rx_desc[n]; 1123239278Sgonzo hwd = &sc->lpe_rdata.lpe_rx_ring[n]; 1124239278Sgonzo hws = &sc->lpe_rdata.lpe_rx_status[n]; 1125243882Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1126239278Sgonzo 1127239278Sgonzo if (!m) { 1128239278Sgonzo device_printf(sc->lpe_dev, "WARNING: mbufs exhausted!\n"); 1129239278Sgonzo return (ENOBUFS); 1130239278Sgonzo } 1131239278Sgonzo 1132239278Sgonzo m->m_len = m->m_pkthdr.len = MCLBYTES; 1133239278Sgonzo 1134239278Sgonzo bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap); 1135239278Sgonzo 1136239278Sgonzo if (bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_rx_buf_tag, 1137239278Sgonzo rxd->lpe_rxdesc_dmamap, m, segs, &nsegs, 0)) { 1138239278Sgonzo m_freem(m); 1139239278Sgonzo return (ENOBUFS); 1140239278Sgonzo } 1141239278Sgonzo 1142239278Sgonzo bus_dmamap_sync(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap, 1143239278Sgonzo BUS_DMASYNC_PREREAD); 1144239278Sgonzo 1145239278Sgonzo rxd->lpe_rxdesc_mbuf = m; 1146239278Sgonzo hwd->lhr_data = segs[0].ds_addr + 2; 1147239278Sgonzo hwd->lhr_control = (segs[0].ds_len - 1) | LPE_HWDESC_INTERRUPT; 1148239278Sgonzo 1149239278Sgonzo return (0); 1150239278Sgonzo} 1151239278Sgonzo 1152239278Sgonzostatic void 1153239278Sgonzolpe_discard_rxbuf(struct lpe_softc *sc, int n) 1154239278Sgonzo{ 1155239278Sgonzo struct lpe_rxdesc *rxd; 1156239278Sgonzo struct lpe_hwdesc *hwd; 1157239278Sgonzo 1158239278Sgonzo rxd = &sc->lpe_cdata.lpe_rx_desc[n]; 1159239278Sgonzo hwd = &sc->lpe_rdata.lpe_rx_ring[n]; 1160239278Sgonzo 1161239278Sgonzo bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap); 1162239278Sgonzo 1163239278Sgonzo hwd->lhr_data = 0; 1164239278Sgonzo hwd->lhr_control = 0; 1165239278Sgonzo 1166239278Sgonzo if (rxd->lpe_rxdesc_mbuf) { 1167239278Sgonzo m_freem(rxd->lpe_rxdesc_mbuf); 1168239278Sgonzo rxd->lpe_rxdesc_mbuf = NULL; 1169239278Sgonzo } 1170239278Sgonzo} 1171239278Sgonzo 1172239278Sgonzostatic void 1173239278Sgonzolpe_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1174239278Sgonzo{ 1175239278Sgonzo struct lpe_dmamap_arg *ctx; 1176239278Sgonzo 1177239278Sgonzo if (error) 1178239278Sgonzo return; 1179239278Sgonzo 1180239278Sgonzo ctx = (struct lpe_dmamap_arg *)arg; 1181239278Sgonzo ctx->lpe_dma_busaddr = segs[0].ds_addr; 1182239278Sgonzo} 1183239278Sgonzo 1184239278Sgonzostatic int 1185239278Sgonzolpe_ifmedia_upd(struct ifnet *ifp) 1186239278Sgonzo{ 1187239278Sgonzo return (0); 1188239278Sgonzo} 1189239278Sgonzo 1190239278Sgonzostatic void 1191239278Sgonzolpe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1192239278Sgonzo{ 1193239278Sgonzo struct lpe_softc *sc = ifp->if_softc; 1194239278Sgonzo struct mii_data *mii = device_get_softc(sc->lpe_miibus); 1195239278Sgonzo 1196239278Sgonzo lpe_lock(sc); 1197239278Sgonzo mii_pollstat(mii); 1198239278Sgonzo ifmr->ifm_active = mii->mii_media_active; 1199239278Sgonzo ifmr->ifm_status = mii->mii_media_status; 1200239278Sgonzo lpe_unlock(sc); 1201239278Sgonzo} 1202239278Sgonzo 1203239278Sgonzostatic device_method_t lpe_methods[] = { 1204239278Sgonzo /* Device interface */ 1205239278Sgonzo DEVMETHOD(device_probe, lpe_probe), 1206239278Sgonzo DEVMETHOD(device_attach, lpe_attach), 1207239278Sgonzo DEVMETHOD(device_detach, lpe_detach), 1208239278Sgonzo 1209239278Sgonzo /* Bus interface */ 1210239278Sgonzo DEVMETHOD(bus_print_child, bus_generic_print_child), 1211239278Sgonzo 1212239278Sgonzo /* MII interface */ 1213239278Sgonzo DEVMETHOD(miibus_readreg, lpe_miibus_readreg), 1214239278Sgonzo DEVMETHOD(miibus_writereg, lpe_miibus_writereg), 1215239278Sgonzo DEVMETHOD(miibus_statchg, lpe_miibus_statchg), 1216239278Sgonzo { 0, 0 } 1217239278Sgonzo}; 1218239278Sgonzo 1219239278Sgonzostatic driver_t lpe_driver = { 1220239278Sgonzo "lpe", 1221239278Sgonzo lpe_methods, 1222239278Sgonzo sizeof(struct lpe_softc), 1223239278Sgonzo}; 1224239278Sgonzo 1225239278Sgonzostatic devclass_t lpe_devclass; 1226239278Sgonzo 1227239278SgonzoDRIVER_MODULE(lpe, simplebus, lpe_driver, lpe_devclass, 0, 0); 1228239278SgonzoDRIVER_MODULE(miibus, lpe, miibus_driver, miibus_devclass, 0, 0); 1229239278SgonzoMODULE_DEPEND(lpe, obio, 1, 1, 1); 1230239278SgonzoMODULE_DEPEND(lpe, miibus, 1, 1, 1); 1231239278SgonzoMODULE_DEPEND(lpe, ether, 1, 1, 1); 1232