1210040Scognet/*- 2210040Scognet * Copyright (c) 2010 Yohanes Nugroho <yohanes@gmail.com> 3210040Scognet * All rights reserved. 4210040Scognet * 5210040Scognet * Redistribution and use in source and binary forms, with or without 6210040Scognet * modification, are permitted provided that the following conditions 7210040Scognet * are met: 8210040Scognet * 1. Redistributions of source code must retain the above copyright 9210040Scognet * notice, this list of conditions and the following disclaimer. 10210040Scognet * 2. Redistributions in binary form must reproduce the above copyright 11210040Scognet * notice, this list of conditions and the following disclaimer in the 12210040Scognet * documentation and/or other materials provided with the distribution. 13210040Scognet * 14210040Scognet * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15210040Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16210040Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17210040Scognet * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18210040Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19210040Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20210040Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21210040Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22210040Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23210040Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24210040Scognet * SUCH DAMAGE. 25210040Scognet */ 26210040Scognet 27210040Scognet#include <sys/cdefs.h> 28210040Scognet__FBSDID("$FreeBSD$"); 29210040Scognet 30210040Scognet#include <sys/param.h> 31210040Scognet#include <sys/systm.h> 32210040Scognet#include <sys/bus.h> 33210040Scognet#include <sys/kernel.h> 34210040Scognet#include <sys/lock.h> 35210040Scognet#include <sys/mbuf.h> 36210040Scognet#include <sys/malloc.h> 37210040Scognet#include <sys/module.h> 38210040Scognet#include <sys/rman.h> 39210040Scognet#include <sys/socket.h> 40210040Scognet#include <sys/sockio.h> 41210040Scognet#include <sys/sysctl.h> 42210040Scognet#include <sys/taskqueue.h> 43210040Scognet 44210040Scognet#include <net/ethernet.h> 45210040Scognet#include <net/if.h> 46210040Scognet#include <net/if_arp.h> 47210040Scognet#include <net/if_dl.h> 48210040Scognet#include <net/if_media.h> 49210040Scognet#include <net/if_types.h> 50210040Scognet#include <net/if_vlan_var.h> 51210040Scognet 52210040Scognet#ifdef INET 53210040Scognet#include <netinet/in.h> 54210040Scognet#include <netinet/in_systm.h> 55210040Scognet#include <netinet/in_var.h> 56210040Scognet#include <netinet/ip.h> 57210040Scognet#endif 58210040Scognet 59210040Scognet#include <net/bpf.h> 60210040Scognet#include <net/bpfdesc.h> 61210040Scognet 62210040Scognet#include <dev/mii/mii.h> 63210040Scognet#include <dev/mii/miivar.h> 64210040Scognet 65210040Scognet#include <arm/at91/at91_pmcvar.h> 66210040Scognet#include <arm/at91/if_macbreg.h> 67210040Scognet#include <arm/at91/if_macbvar.h> 68210040Scognet#include <arm/at91/at91_piovar.h> 69210040Scognet 70210040Scognet#include <arm/at91/at91sam9g20reg.h> 71210040Scognet 72210040Scognet#include <machine/bus.h> 73210040Scognet#include <machine/intr.h> 74210040Scognet 75210040Scognet/* "device miibus" required. See GENERIC if you get errors here. */ 76210040Scognet#include "miibus_if.h" 77210040Scognet 78210040Scognet 79210040Scognet#define MACB_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 80210040Scognet#define MACB_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 81210040Scognet#define MACB_LOCK_INIT(_sc) \ 82210040Scognet mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 83210040Scognet MTX_NETWORK_LOCK, MTX_DEF) 84210040Scognet#define MACB_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 85210040Scognet#define MACB_LOCK_ASSERT(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 86210040Scognet#define MACB_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 87210040Scognet 88210040Scognet 89210040Scognetstatic inline uint32_t 90210040Scognetread_4(struct macb_softc *sc, bus_size_t off) 91210040Scognet{ 92210040Scognet 93210040Scognet return (bus_read_4(sc->mem_res, off)); 94210040Scognet} 95210040Scognet 96210040Scognetstatic inline void 97210040Scognetwrite_4(struct macb_softc *sc, bus_size_t off, uint32_t val) 98210040Scognet{ 99210040Scognet 100210040Scognet bus_write_4(sc->mem_res, off, val); 101210040Scognet} 102210040Scognet 103210040Scognet 104210040Scognetstatic devclass_t macb_devclass; 105210040Scognet 106210040Scognet/* ifnet entry points */ 107210040Scognet 108210040Scognetstatic void macbinit_locked(void *); 109210040Scognetstatic void macbstart_locked(struct ifnet *); 110210040Scognet 111210040Scognetstatic void macbinit(void *); 112210040Scognetstatic void macbstart(struct ifnet *); 113210040Scognetstatic void macbstop(struct macb_softc *); 114210040Scognetstatic int macbioctl(struct ifnet * ifp, u_long, caddr_t); 115210040Scognet 116210040Scognet/* bus entry points */ 117210040Scognet 118210040Scognetstatic int macb_probe(device_t dev); 119210040Scognetstatic int macb_attach(device_t dev); 120210040Scognetstatic int macb_detach(device_t dev); 121210040Scognet 122210040Scognet/* helper functions */ 123210040Scognetstatic int 124210040Scognetmacb_new_rxbuf(struct macb_softc *sc, int index); 125210040Scognet 126210040Scognetstatic void 127210040Scognetmacb_free_desc_dma_tx(struct macb_softc *sc); 128210040Scognet 129210040Scognetstatic void 130210040Scognetmacb_free_desc_dma_rx(struct macb_softc *sc); 131210040Scognet 132210040Scognetstatic void 133210040Scognetmacb_init_desc_dma_tx(struct macb_softc *sc); 134210040Scognet 135210040Scognetstatic void 136210040Scognetmacb_watchdog(struct macb_softc *sc); 137210040Scognet 138210040Scognetstatic int macb_intr_rx_locked(struct macb_softc *sc, int count); 139210040Scognetstatic void macb_intr_task(void *arg, int pending __unused); 140210040Scognetstatic void macb_intr(void *xsc); 141210040Scognet 142210040Scognetstatic void 143210040Scognetmacb_tx_cleanup(struct macb_softc *sc); 144210040Scognet 145210040Scognetstatic inline int 146210040Scognetphy_write(struct macb_softc *sc, int phy, int reg, int data); 147210040Scognet 148210040Scognetstatic void macb_reset(struct macb_softc *sc); 149210040Scognet 150210040Scognetstatic void 151210040Scognetmacb_deactivate(device_t dev) 152210040Scognet{ 153210040Scognet struct macb_softc *sc; 154210040Scognet 155210040Scognet sc = device_get_softc(dev); 156210040Scognet 157210040Scognet macb_free_desc_dma_tx(sc); 158210040Scognet macb_free_desc_dma_rx(sc); 159210040Scognet 160210040Scognet} 161210040Scognet 162210040Scognetstatic void 163210040Scognetmacb_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 164210040Scognet{ 165210040Scognet bus_addr_t *paddr; 166210040Scognet 167210040Scognet KASSERT(nsegs == 1, ("wrong number of segments, should be 1")); 168210040Scognet paddr = arg; 169210040Scognet *paddr = segs->ds_addr; 170210040Scognet} 171210040Scognet 172210040Scognetstatic int 173210040Scognetmacb_alloc_desc_dma_tx(struct macb_softc *sc) 174210040Scognet{ 175210040Scognet int error, i; 176210040Scognet 177210040Scognet /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ 178210040Scognet error = bus_dma_tag_create(sc->sc_parent_tag, /* parent */ 179210040Scognet 16, 0, /* alignment, boundary */ 180210040Scognet BUS_SPACE_MAXADDR, /* lowaddr */ 181210040Scognet BUS_SPACE_MAXADDR, /* highaddr */ 182210040Scognet NULL, NULL, /* filtfunc, filtfuncarg */ 183210040Scognet sizeof(struct eth_tx_desc) * MACB_MAX_TX_BUFFERS, /* max size */ 184210040Scognet 1, /* nsegments */ 185210040Scognet sizeof(struct eth_tx_desc) * MACB_MAX_TX_BUFFERS, 186210040Scognet 0, /* flags */ 187210040Scognet NULL, NULL, /* lockfunc, lockfuncarg */ 188210040Scognet &sc->dmatag_data_tx); /* dmat */ 189210040Scognet if (error != 0) { 190210040Scognet device_printf(sc->dev, 191210040Scognet "Couldn't create TX descriptor dma tag\n"); 192210040Scognet return (error); 193210040Scognet } 194210040Scognet /* Allocate memory for TX ring. */ 195210040Scognet error = bus_dmamem_alloc(sc->dmatag_data_tx, 196210040Scognet (void**)&(sc->desc_tx), BUS_DMA_NOWAIT | BUS_DMA_ZERO | 197210040Scognet BUS_DMA_COHERENT, &sc->dmamap_ring_tx); 198210040Scognet if (error != 0) { 199210040Scognet device_printf(sc->dev, "failed to allocate TX dma memory\n"); 200210040Scognet return (error); 201210040Scognet } 202210040Scognet /* Load Ring DMA. */ 203210040Scognet error = bus_dmamap_load(sc->dmatag_data_tx, sc->dmamap_ring_tx, 204210040Scognet sc->desc_tx, sizeof(struct eth_tx_desc) * MACB_MAX_TX_BUFFERS, 205210040Scognet macb_getaddr, &sc->ring_paddr_tx, BUS_DMA_NOWAIT); 206210040Scognet if (error != 0) { 207210040Scognet device_printf(sc->dev, "can't load TX descriptor dma map\n"); 208210040Scognet return (error); 209210040Scognet } 210210040Scognet /* Allocate a busdma tag for mbufs. No alignment restriction applys. */ 211210040Scognet error = bus_dma_tag_create(sc->sc_parent_tag, /* parent */ 212210040Scognet 1, 0, /* alignment, boundary */ 213210040Scognet BUS_SPACE_MAXADDR, /* lowaddr */ 214210040Scognet BUS_SPACE_MAXADDR, /* highaddr */ 215210040Scognet NULL, NULL, /* filtfunc, filtfuncarg */ 216210040Scognet MCLBYTES * MAX_FRAGMENT, /* maxsize */ 217210040Scognet MAX_FRAGMENT, /* nsegments */ 218210040Scognet MCLBYTES, 0, /* maxsegsz, flags */ 219210040Scognet NULL, NULL, /* lockfunc, lockfuncarg */ 220210040Scognet &sc->dmatag_ring_tx); /* dmat */ 221210040Scognet if (error != 0) { 222210040Scognet device_printf(sc->dev, "failed to create TX mbuf dma tag\n"); 223210040Scognet return (error); 224210040Scognet } 225210040Scognet 226210040Scognet for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { 227210040Scognet /* Create dma map for each descriptor. */ 228210040Scognet error = bus_dmamap_create(sc->dmatag_ring_tx, 0, 229210040Scognet &sc->tx_desc[i].dmamap); 230210040Scognet if (error != 0) { 231210040Scognet device_printf(sc->dev, 232210040Scognet "failed to create TX mbuf dma map\n"); 233210040Scognet return (error); 234210040Scognet } 235210040Scognet } 236210040Scognet return (0); 237210040Scognet} 238210040Scognet 239210040Scognetstatic void 240210040Scognetmacb_free_desc_dma_tx(struct macb_softc *sc) 241210040Scognet{ 242210040Scognet struct tx_desc_info *td; 243210040Scognet int i; 244210040Scognet 245210040Scognet /* TX buffers. */ 246210040Scognet if (sc->dmatag_ring_tx != NULL) { 247210040Scognet for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { 248210040Scognet td = &sc->tx_desc[i]; 249210040Scognet if (td->dmamap != NULL) { 250210040Scognet bus_dmamap_destroy(sc->dmatag_ring_tx, 251210040Scognet td->dmamap); 252210040Scognet td->dmamap = NULL; 253210040Scognet } 254210040Scognet } 255210040Scognet bus_dma_tag_destroy(sc->dmatag_ring_tx); 256210040Scognet sc->dmatag_ring_tx = NULL; 257210040Scognet } 258210040Scognet 259210040Scognet /* TX descriptor ring. */ 260210040Scognet if (sc->dmatag_data_tx != NULL) { 261210040Scognet if (sc->dmamap_ring_tx != NULL) 262210040Scognet bus_dmamap_unload(sc->dmatag_data_tx, 263210040Scognet sc->dmamap_ring_tx); 264210040Scognet if (sc->dmamap_ring_tx != NULL && sc->desc_tx != NULL) 265210040Scognet bus_dmamem_free(sc->dmatag_data_tx, sc->desc_tx, 266210040Scognet sc->dmamap_ring_tx); 267210040Scognet sc->dmamap_ring_tx = NULL; 268210040Scognet sc->dmamap_ring_tx = NULL; 269210040Scognet bus_dma_tag_destroy(sc->dmatag_data_tx); 270210040Scognet sc->dmatag_data_tx = NULL; 271210040Scognet } 272210040Scognet} 273210040Scognet 274210040Scognetstatic void 275210040Scognetmacb_init_desc_dma_tx(struct macb_softc *sc) 276210040Scognet{ 277210040Scognet struct eth_tx_desc *desc; 278210040Scognet int i; 279210040Scognet 280210040Scognet MACB_LOCK_ASSERT(sc); 281210040Scognet 282210040Scognet sc->tx_prod = 0; 283210040Scognet sc->tx_cons = 0; 284210040Scognet sc->tx_cnt = 0; 285210040Scognet 286210040Scognet desc = &sc->desc_tx[0]; 287210040Scognet bzero(desc, sizeof(struct eth_tx_desc) * MACB_MAX_TX_BUFFERS); 288210040Scognet 289210040Scognet for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { 290210040Scognet desc = &sc->desc_tx[i]; 291210040Scognet if (i == MACB_MAX_TX_BUFFERS - 1) 292210040Scognet desc->flags = TD_OWN | TD_WRAP_MASK; 293210040Scognet else 294210040Scognet desc->flags = TD_OWN; 295210040Scognet } 296210040Scognet 297210040Scognet bus_dmamap_sync(sc->dmatag_data_tx, sc->dmamap_ring_tx, 298210040Scognet BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 299210040Scognet} 300210040Scognet 301210040Scognetstatic int 302210040Scognetmacb_alloc_desc_dma_rx(struct macb_softc *sc) 303210040Scognet{ 304210040Scognet int error, i; 305210040Scognet 306210040Scognet /* Allocate a busdma tag and DMA safe memory for RX descriptors. */ 307210040Scognet error = bus_dma_tag_create(sc->sc_parent_tag, /* parent */ 308210040Scognet 16, 0, /* alignment, boundary */ 309210040Scognet BUS_SPACE_MAXADDR, /* lowaddr */ 310210040Scognet BUS_SPACE_MAXADDR, /* highaddr */ 311210040Scognet NULL, NULL, /* filtfunc, filtfuncarg */ 312210040Scognet /* maxsize, nsegments */ 313210040Scognet sizeof(struct eth_rx_desc) * MACB_MAX_RX_BUFFERS, 1, 314210040Scognet /* maxsegsz, flags */ 315210040Scognet sizeof(struct eth_rx_desc) * MACB_MAX_RX_BUFFERS, 0, 316210040Scognet NULL, NULL, /* lockfunc, lockfuncarg */ 317210040Scognet &sc->dmatag_data_rx); /* dmat */ 318210040Scognet if (error != 0) { 319210040Scognet device_printf(sc->dev, 320210040Scognet "Couldn't create RX descriptor dma tag\n"); 321210040Scognet return (error); 322210040Scognet } 323210040Scognet /* Allocate RX ring. */ 324210040Scognet error = bus_dmamem_alloc(sc->dmatag_data_rx, (void**)&(sc->desc_rx), 325210040Scognet BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 326210040Scognet &sc->dmamap_ring_rx); 327210040Scognet if (error != 0) { 328210040Scognet device_printf(sc->dev, 329210040Scognet "failed to allocate RX descriptor dma memory\n"); 330210040Scognet return (error); 331210040Scognet } 332210040Scognet 333210040Scognet /* Load dmamap. */ 334210040Scognet error = bus_dmamap_load(sc->dmatag_data_rx, sc->dmamap_ring_rx, 335210040Scognet sc->desc_rx, sizeof(struct eth_rx_desc) * MACB_MAX_RX_BUFFERS, 336210040Scognet macb_getaddr, &sc->ring_paddr_rx, BUS_DMA_NOWAIT); 337210040Scognet if (error != 0) { 338210040Scognet device_printf(sc->dev, "can't load RX descriptor dma map\n"); 339210040Scognet return (error); 340210040Scognet } 341210040Scognet 342210040Scognet /* Allocate a busdma tag for mbufs. */ 343210040Scognet error = bus_dma_tag_create(sc->sc_parent_tag,/* parent */ 344210040Scognet 16, 0, /* alignment, boundary */ 345210040Scognet BUS_SPACE_MAXADDR, /* lowaddr */ 346210040Scognet BUS_SPACE_MAXADDR, /* highaddr */ 347210040Scognet NULL, NULL, /* filtfunc, filtfuncarg */ 348210040Scognet MCLBYTES, 1, /* maxsize, nsegments */ 349210040Scognet MCLBYTES, 0, /* maxsegsz, flags */ 350210040Scognet NULL, NULL, /* lockfunc, lockfuncarg */ 351210040Scognet &sc->dmatag_ring_rx); /* dmat */ 352210040Scognet 353210040Scognet if (error != 0) { 354210040Scognet device_printf(sc->dev, "failed to create RX mbuf dma tag\n"); 355210040Scognet return (error); 356210040Scognet } 357210040Scognet 358210040Scognet for (i = 0; i < MACB_MAX_RX_BUFFERS; i++) { 359210040Scognet error = bus_dmamap_create(sc->dmatag_ring_rx, 0, 360210040Scognet &sc->rx_desc[i].dmamap); 361210040Scognet if (error != 0) { 362210040Scognet device_printf(sc->dev, 363210040Scognet "failed to create RX mbuf dmamap\n"); 364210040Scognet return (error); 365210040Scognet } 366210040Scognet } 367210040Scognet 368210040Scognet return (0); 369210040Scognet} 370210040Scognet 371210040Scognetstatic void 372210040Scognetmacb_free_desc_dma_rx(struct macb_softc *sc) 373210040Scognet{ 374210040Scognet struct rx_desc_info *rd; 375210040Scognet int i; 376210040Scognet 377210040Scognet /* RX buffers. */ 378210040Scognet if (sc->dmatag_ring_rx != NULL) { 379210040Scognet for (i = 0; i < MACB_MAX_RX_BUFFERS; i++) { 380210040Scognet rd = &sc->rx_desc[i]; 381210040Scognet if (rd->dmamap != NULL) { 382210040Scognet bus_dmamap_destroy(sc->dmatag_ring_rx, 383210040Scognet rd->dmamap); 384210040Scognet rd->dmamap = NULL; 385210040Scognet } 386210040Scognet } 387210040Scognet bus_dma_tag_destroy(sc->dmatag_ring_rx); 388210040Scognet sc->dmatag_ring_rx = NULL; 389210040Scognet } 390210040Scognet /* RX descriptor ring. */ 391210040Scognet if (sc->dmatag_data_rx != NULL) { 392210040Scognet if (sc->dmamap_ring_rx != NULL) 393210040Scognet bus_dmamap_unload(sc->dmatag_data_rx, 394210040Scognet sc->dmamap_ring_rx); 395210040Scognet if (sc->dmamap_ring_rx != NULL && 396210040Scognet sc->desc_rx != NULL) 397210040Scognet bus_dmamem_free(sc->dmatag_data_rx, sc->desc_rx, 398210040Scognet sc->dmamap_ring_rx); 399210040Scognet sc->desc_rx = NULL; 400210040Scognet sc->dmamap_ring_rx = NULL; 401210040Scognet bus_dma_tag_destroy(sc->dmatag_data_rx); 402210040Scognet sc->dmatag_data_rx = NULL; 403210040Scognet } 404210040Scognet} 405210040Scognet 406210040Scognetstatic int 407210040Scognetmacb_init_desc_dma_rx(struct macb_softc *sc) 408210040Scognet{ 409210040Scognet struct eth_rx_desc *desc; 410210040Scognet struct rx_desc_info *rd; 411210040Scognet int i; 412210040Scognet 413210040Scognet MACB_LOCK_ASSERT(sc); 414210040Scognet 415210040Scognet sc->rx_cons = 0; 416210040Scognet desc = &sc->desc_rx[0]; 417210040Scognet bzero(desc, sizeof(struct eth_rx_desc) * MACB_MAX_RX_BUFFERS); 418210040Scognet for (i = 0; i < MACB_MAX_RX_BUFFERS; i++) { 419210040Scognet rd = &sc->rx_desc[i]; 420210040Scognet rd->buff = NULL; 421210040Scognet if (macb_new_rxbuf(sc, i) != 0) 422210040Scognet return (ENOBUFS); 423210040Scognet } 424210040Scognet bus_dmamap_sync(sc->dmatag_ring_rx, sc->dmamap_ring_rx, 425210040Scognet BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 426210040Scognet return (0); 427210040Scognet} 428210040Scognet 429210040Scognetstatic int 430210040Scognetmacb_new_rxbuf(struct macb_softc *sc, int index) 431210040Scognet{ 432210040Scognet struct rx_desc_info *rd; 433210040Scognet struct eth_rx_desc *desc; 434210040Scognet struct mbuf *m; 435210040Scognet bus_dma_segment_t seg[1]; 436210040Scognet int error, nsegs; 437210040Scognet 438243882Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 439210040Scognet if (m == NULL) 440210040Scognet return (ENOBUFS); 441210040Scognet m->m_len = m->m_pkthdr.len = MCLBYTES - ETHER_ALIGN; 442210040Scognet rd = &sc->rx_desc[index]; 443210040Scognet bus_dmamap_unload(sc->dmatag_ring_rx, rd->dmamap); 444210040Scognet error = bus_dmamap_load_mbuf_sg(sc->dmatag_ring_rx, rd->dmamap, m, 445210040Scognet seg, &nsegs, 0); 446210040Scognet KASSERT(nsegs == 1, ("Too many segments returned!")); 447210040Scognet if (error != 0) { 448210040Scognet m_free(m); 449210040Scognet return (error); 450210040Scognet } 451210040Scognet 452210040Scognet bus_dmamap_sync(sc->dmatag_ring_rx, rd->dmamap, BUS_DMASYNC_PREREAD); 453210040Scognet rd->buff = m; 454210040Scognet 455210040Scognet desc = &sc->desc_rx[index]; 456210040Scognet desc->addr = seg[0].ds_addr; 457210040Scognet 458210040Scognet desc->flags = DATA_SIZE; 459210040Scognet 460210040Scognet if (index == MACB_MAX_RX_BUFFERS - 1) 461210040Scognet desc->addr |= RD_WRAP_MASK; 462210040Scognet 463210040Scognet return (0); 464210040Scognet} 465210040Scognet 466210040Scognetstatic int 467210040Scognetmacb_allocate_dma(struct macb_softc *sc) 468210040Scognet{ 469210040Scognet int error; 470210040Scognet 471210040Scognet /* Create parent tag for tx and rx */ 472210040Scognet error = bus_dma_tag_create( 473210040Scognet bus_get_dma_tag(sc->dev), /* parent */ 474210040Scognet 1, 0, /* alignment, boundary */ 475210040Scognet BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 476210040Scognet BUS_SPACE_MAXADDR, /* highaddr */ 477210040Scognet NULL, NULL, /* filter, filterarg */ 478210040Scognet BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 479210040Scognet BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 480210040Scognet 0, /* flags */ 481210040Scognet NULL, NULL, /* lockfunc, lockarg */ 482210040Scognet &sc->sc_parent_tag); 483210040Scognet if (error != 0) { 484210040Scognet device_printf(sc->dev, "Couldn't create parent DMA tag\n"); 485210040Scognet return (error); 486210040Scognet } 487210040Scognet 488210040Scognet if ((error = macb_alloc_desc_dma_tx(sc)) != 0) 489210040Scognet return (error); 490210040Scognet if ((error = macb_alloc_desc_dma_rx(sc)) != 0) 491210040Scognet return (error); 492210040Scognet return (0); 493210040Scognet} 494210040Scognet 495210040Scognet 496210040Scognetstatic void 497210040Scognetmacb_tick(void *xsc) 498210040Scognet{ 499210040Scognet struct macb_softc *sc; 500210040Scognet struct mii_data *mii; 501210040Scognet 502210040Scognet sc = xsc; 503210040Scognet mii = device_get_softc(sc->miibus); 504210040Scognet mii_tick(mii); 505210040Scognet macb_watchdog(sc); 506210040Scognet /* 507210040Scognet * Schedule another timeout one second from now. 508210040Scognet */ 509210040Scognet callout_reset(&sc->tick_ch, hz, macb_tick, sc); 510210040Scognet} 511210040Scognet 512210040Scognet 513210040Scognetstatic void 514210040Scognetmacb_watchdog(struct macb_softc *sc) 515210040Scognet{ 516210040Scognet struct ifnet *ifp; 517210040Scognet 518210040Scognet MACB_LOCK_ASSERT(sc); 519210040Scognet 520210040Scognet if (sc->macb_watchdog_timer == 0 || --sc->macb_watchdog_timer) 521210040Scognet return; 522210040Scognet 523210040Scognet ifp = sc->ifp; 524210040Scognet if ((sc->flags & MACB_FLAG_LINK) == 0) { 525210040Scognet if_printf(ifp, "watchdog timeout (missed link)\n"); 526210040Scognet ifp->if_oerrors++; 527210040Scognet return; 528210040Scognet } 529210040Scognet 530210040Scognet if_printf(ifp, "watchdog timeout\n"); 531210040Scognet ifp->if_oerrors++; 532210040Scognet ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 533210040Scognet macbinit_locked(sc); 534210040Scognet if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 535217062Sjhb macbstart_locked(ifp); 536210040Scognet} 537210040Scognet 538210040Scognet 539210040Scognet 540210040Scognetstatic void 541210040Scognetmacbinit_locked(void *xsc) 542210040Scognet{ 543210040Scognet struct macb_softc *sc; 544210040Scognet struct ifnet *ifp; 545210040Scognet int err; 546210040Scognet uint32_t config; 547210040Scognet struct mii_data *mii; 548210040Scognet 549210040Scognet sc = xsc; 550210040Scognet ifp = sc->ifp; 551210040Scognet 552210040Scognet MACB_LOCK_ASSERT(sc); 553210040Scognet 554210040Scognet if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 555210040Scognet return; 556210040Scognet 557210040Scognet if ((err = macb_init_desc_dma_rx(sc)) != 0) { 558210040Scognet device_printf(sc->dev, "no memory for RX buffers\n"); 559210040Scognet //ecestop(sc); 560210040Scognet return; 561210040Scognet } 562210040Scognet macb_init_desc_dma_tx(sc); 563210040Scognet 564210040Scognet config = read_4(sc, EMAC_NCFGR) | (sc->clock << 10); /*set clock*/ 565210040Scognet config |= CFG_PAE; /* PAuse Enable */ 566210040Scognet config |= CFG_DRFCS; /* Discard Rx FCS */ 567210040Scognet config |= CFG_SPD; /* 100 mbps*/ 568210040Scognet //config |= CFG_CAF; 569210040Scognet config |= CFG_FD; 570210040Scognet 571210040Scognet config |= CFG_RBOF_2; /*offset +2*/ 572210040Scognet 573210040Scognet write_4(sc, EMAC_NCFGR, config); 574210040Scognet 575210040Scognet /* Initialize TX and RX buffers */ 576210040Scognet write_4(sc, EMAC_RBQP, sc->ring_paddr_rx); 577210040Scognet write_4(sc, EMAC_TBQP, sc->ring_paddr_tx); 578210040Scognet 579210040Scognet /* Enable TX and RX */ 580210040Scognet write_4(sc, EMAC_NCR, RX_ENABLE | TX_ENABLE | MPE_ENABLE); 581210040Scognet 582210040Scognet 583210040Scognet /* Enable interrupts */ 584210040Scognet write_4(sc, EMAC_IER, (RCOMP_INTERRUPT | 585210040Scognet RXUBR_INTERRUPT | 586210040Scognet TUND_INTERRUPT | 587210040Scognet RLE_INTERRUPT | 588210040Scognet TXERR_INTERRUPT | 589210040Scognet ROVR_INTERRUPT | 590210040Scognet HRESP_INTERRUPT| 591210040Scognet TCOMP_INTERRUPT 592210040Scognet )); 593210040Scognet 594210040Scognet /* 595210040Scognet * Set 'running' flag, and clear output active flag 596210040Scognet * and attempt to start the output 597210040Scognet */ 598210040Scognet ifp->if_drv_flags |= IFF_DRV_RUNNING; 599210040Scognet ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 600210040Scognet 601210040Scognet mii = device_get_softc(sc->miibus); 602210040Scognet 603210040Scognet sc->flags |= MACB_FLAG_LINK; 604210040Scognet 605210040Scognet mii_mediachg(mii); 606210040Scognet 607210040Scognet callout_reset(&sc->tick_ch, hz, macb_tick, sc); 608210040Scognet} 609210040Scognet 610210040Scognet 611210040Scognetstatic void 612210040Scognetmacb_tx_cleanup(struct macb_softc *sc) 613210040Scognet{ 614210040Scognet struct ifnet *ifp; 615210040Scognet struct eth_tx_desc *desc; 616210040Scognet struct tx_desc_info *td; 617210040Scognet int flags; 618210040Scognet int status; 619210040Scognet int i; 620210040Scognet 621210040Scognet MACB_LOCK_ASSERT(sc); 622210040Scognet 623210040Scognet status = read_4(sc, EMAC_TSR); 624210040Scognet 625210040Scognet write_4(sc, EMAC_TSR, status); 626210040Scognet 627210040Scognet /*buffer underrun*/ 628210040Scognet if ((status & TSR_UND) != 0) { 629210040Scognet /*reset buffers*/ 630210040Scognet printf("underrun\n"); 631210040Scognet bus_dmamap_sync(sc->dmatag_data_tx, sc->dmamap_ring_tx, 632210040Scognet BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 633210040Scognet sc->tx_cons = sc->tx_prod = 0; 634210040Scognet for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { 635210040Scognet desc = &sc->desc_tx[i]; 636210040Scognet desc->flags = TD_OWN; 637210040Scognet } 638210040Scognet 639210040Scognet for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { 640210040Scognet td = &sc->tx_desc[i]; 641210040Scognet if (td->buff != NULL) { 642210040Scognet /* We are finished with this descriptor. */ 643210040Scognet bus_dmamap_sync(sc->dmatag_ring_tx, td->dmamap, 644210040Scognet BUS_DMASYNC_POSTWRITE); 645210040Scognet /* ... and unload, so we can reuse. */ 646210040Scognet bus_dmamap_unload(sc->dmatag_data_tx, 647210040Scognet td->dmamap); 648210040Scognet m_freem(td->buff); 649210040Scognet td->buff = NULL; 650210040Scognet } 651210040Scognet } 652210040Scognet } 653210040Scognet 654210040Scognet if ((status & TSR_COMP) == 0) 655210040Scognet return; 656210040Scognet 657210040Scognet 658210040Scognet if (sc->tx_cons == sc->tx_prod) 659210040Scognet return; 660210040Scognet 661210040Scognet ifp = sc->ifp; 662210040Scognet 663210040Scognet /* Prepare to read the ring (owner bit). */ 664210040Scognet bus_dmamap_sync(sc->dmatag_data_tx, sc->dmamap_ring_tx, 665210040Scognet BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 666210040Scognet while (sc->tx_cons != sc->tx_prod) { 667210040Scognet desc = &sc->desc_tx[sc->tx_cons]; 668210040Scognet if ((desc->flags & TD_OWN) == 0) 669210040Scognet break; 670210040Scognet 671210040Scognet td = &sc->tx_desc[sc->tx_cons]; 672210040Scognet if (td->buff != NULL) { 673210040Scognet /* We are finished with this descriptor. */ 674210040Scognet bus_dmamap_sync(sc->dmatag_ring_tx, td->dmamap, 675210040Scognet BUS_DMASYNC_POSTWRITE); 676210040Scognet /* ... and unload, so we can reuse. */ 677210040Scognet bus_dmamap_unload(sc->dmatag_data_tx, 678210040Scognet td->dmamap); 679210040Scognet m_freem(td->buff); 680210040Scognet td->buff = NULL; 681210040Scognet ifp->if_opackets++; 682210040Scognet } 683210040Scognet 684210040Scognet do { 685210040Scognet sc->tx_cnt--; 686210040Scognet MACB_DESC_INC(sc->tx_cons, MACB_MAX_TX_BUFFERS); 687210040Scognet ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 688210040Scognet flags = desc->flags; 689210040Scognet desc->flags = TD_OWN; 690210040Scognet desc = &sc->desc_tx[sc->tx_cons]; 691210040Scognet if (flags & TD_LAST) { 692210040Scognet break; 693210040Scognet } 694210040Scognet } while (sc->tx_cons != sc->tx_prod); 695210040Scognet } 696210040Scognet 697210040Scognet /* Unarm watchog timer when there is no pending descriptors in queue. */ 698210040Scognet if (sc->tx_cnt == 0) 699210040Scognet sc->macb_watchdog_timer = 0; 700210040Scognet} 701210040Scognet 702210040Scognetstatic void 703210040Scognetmacb_rx(struct macb_softc *sc) 704210040Scognet{ 705210040Scognet struct eth_rx_desc *rxdesc; 706210040Scognet struct ifnet *ifp; 707210040Scognet struct mbuf *m; 708210040Scognet int rxbytes; 709210040Scognet int flags; 710210040Scognet int nsegs; 711210040Scognet int first; 712210040Scognet 713210040Scognet rxdesc = &(sc->desc_rx[sc->rx_cons]); 714210040Scognet 715210040Scognet ifp = sc->ifp; 716210040Scognet 717210040Scognet bus_dmamap_sync(sc->dmatag_ring_rx, sc->dmamap_ring_rx, 718210040Scognet BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 719210040Scognet 720210040Scognet 721210040Scognet nsegs = 0; 722210040Scognet while (rxdesc->addr & RD_OWN) { 723210040Scognet 724210040Scognet if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 725210040Scognet break; 726210040Scognet 727210040Scognet flags = rxdesc->flags; 728210040Scognet 729210040Scognet rxbytes = flags & RD_LEN_MASK; 730210040Scognet 731210040Scognet m = sc->rx_desc[sc->rx_cons].buff; 732210040Scognet 733236989Simp bus_dmamap_sync(sc->dmatag_ring_rx, 734210040Scognet sc->rx_desc[sc->rx_cons].dmamap, BUS_DMASYNC_POSTREAD); 735210040Scognet if (macb_new_rxbuf(sc, sc->rx_cons) != 0) { 736210040Scognet ifp->if_iqdrops++; 737210040Scognet first = sc->rx_cons; 738210040Scognet 739210040Scognet do { 740210040Scognet rxdesc->flags = DATA_SIZE; 741210040Scognet MACB_DESC_INC(sc->rx_cons, MACB_MAX_RX_BUFFERS); 742236989Simp if ((rxdesc->flags & RD_EOF) != 0) 743210040Scognet break; 744210040Scognet rxdesc = &(sc->desc_rx[sc->rx_cons]); 745210040Scognet } while (sc->rx_cons != first); 746210040Scognet 747210040Scognet if (sc->macb_cdata.rxhead != NULL) { 748210040Scognet m_freem(sc->macb_cdata.rxhead); 749210040Scognet sc->macb_cdata.rxhead = NULL; 750210040Scognet sc->macb_cdata.rxtail = NULL; 751210040Scognet } 752210040Scognet 753210040Scognet break; 754210040Scognet } 755210040Scognet 756210040Scognet nsegs++; 757210040Scognet 758210040Scognet /* Chain received mbufs. */ 759210040Scognet if (sc->macb_cdata.rxhead == NULL) { 760210040Scognet m->m_data += 2; 761210040Scognet sc->macb_cdata.rxhead = m; 762210040Scognet sc->macb_cdata.rxtail = m; 763210040Scognet if (flags & RD_EOF) 764210040Scognet m->m_len = rxbytes; 765210040Scognet else 766210040Scognet m->m_len = DATA_SIZE - 2; 767210040Scognet } else { 768210040Scognet m->m_flags &= ~M_PKTHDR; 769210040Scognet m->m_len = DATA_SIZE; 770210040Scognet sc->macb_cdata.rxtail->m_next = m; 771210040Scognet sc->macb_cdata.rxtail = m; 772210040Scognet } 773210040Scognet 774210040Scognet if (flags & RD_EOF) { 775210040Scognet 776210040Scognet if (nsegs > 1) { 777210040Scognet sc->macb_cdata.rxtail->m_len = (rxbytes - 778210040Scognet ((nsegs - 1) * DATA_SIZE)) + 2; 779236989Simp } 780210040Scognet 781210040Scognet m = sc->macb_cdata.rxhead; 782210040Scognet m->m_flags |= M_PKTHDR; 783210040Scognet m->m_pkthdr.len = rxbytes; 784210040Scognet m->m_pkthdr.rcvif = ifp; 785210040Scognet ifp->if_ipackets++; 786210040Scognet 787210040Scognet nsegs = 0; 788210040Scognet MACB_UNLOCK(sc); 789210040Scognet (*ifp->if_input)(ifp, m); 790210040Scognet MACB_LOCK(sc); 791210040Scognet sc->macb_cdata.rxhead = NULL; 792210040Scognet sc->macb_cdata.rxtail = NULL; 793210040Scognet 794210040Scognet } 795210040Scognet 796210040Scognet rxdesc->addr &= ~RD_OWN; 797210040Scognet 798210040Scognet MACB_DESC_INC(sc->rx_cons, MACB_MAX_RX_BUFFERS); 799210040Scognet 800210040Scognet rxdesc = &(sc->desc_rx[sc->rx_cons]); 801210040Scognet } 802210040Scognet 803210040Scognet write_4(sc, EMAC_IER, (RCOMP_INTERRUPT|RXUBR_INTERRUPT)); 804210040Scognet 805210040Scognet} 806210040Scognet 807210040Scognetstatic int 808210040Scognetmacb_intr_rx_locked(struct macb_softc *sc, int count) 809210040Scognet{ 810210040Scognet macb_rx(sc); 811210040Scognet return (0); 812210040Scognet} 813210040Scognet 814210040Scognetstatic void 815210040Scognetmacb_intr_task(void *arg, int pending __unused) 816210040Scognet{ 817210040Scognet struct macb_softc *sc; 818210040Scognet 819210040Scognet sc = arg; 820210040Scognet MACB_LOCK(sc); 821210040Scognet macb_intr_rx_locked(sc, -1); 822210040Scognet MACB_UNLOCK(sc); 823210040Scognet} 824210040Scognet 825210040Scognetstatic void 826210040Scognetmacb_intr(void *xsc) 827210040Scognet{ 828210040Scognet struct macb_softc *sc; 829210040Scognet struct ifnet *ifp; 830210040Scognet uint32_t status; 831210040Scognet 832210040Scognet sc = xsc; 833210040Scognet ifp = sc->ifp; 834210040Scognet if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 835210040Scognet printf("not running\n"); 836210040Scognet return; 837210040Scognet } 838210040Scognet 839217062Sjhb MACB_LOCK(sc); 840210040Scognet status = read_4(sc, EMAC_ISR); 841210040Scognet 842210040Scognet while (status) { 843210040Scognet if (status & RCOMP_INTERRUPT) { 844210040Scognet write_4(sc, EMAC_IDR, (RCOMP_INTERRUPT|RXUBR_INTERRUPT)); 845210040Scognet taskqueue_enqueue(sc->sc_tq, &sc->sc_intr_task); 846210040Scognet } 847210040Scognet 848210040Scognet if (status & TCOMP_INTERRUPT) { 849210040Scognet macb_tx_cleanup(sc); 850210040Scognet } 851210040Scognet 852210040Scognet status = read_4(sc, EMAC_ISR); 853210040Scognet } 854210040Scognet 855210040Scognet if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 856217062Sjhb macbstart_locked(ifp); 857217062Sjhb MACB_UNLOCK(sc); 858210040Scognet} 859210040Scognet 860210040Scognetstatic inline int 861210040Scognetmacb_encap(struct macb_softc *sc, struct mbuf **m_head) 862210040Scognet{ 863210040Scognet struct eth_tx_desc *desc; 864210040Scognet struct tx_desc_info *txd, *txd_last; 865210040Scognet struct mbuf *m; 866210040Scognet bus_dma_segment_t segs[MAX_FRAGMENT]; 867210040Scognet bus_dmamap_t map; 868210040Scognet uint32_t csum_flags; 869210040Scognet int error, i, nsegs, prod, si; 870210040Scognet 871210040Scognet M_ASSERTPKTHDR((*m_head)); 872210040Scognet 873210040Scognet prod = sc->tx_prod; 874210040Scognet 875210040Scognet m = *m_head; 876210040Scognet 877210040Scognet txd = txd_last = &sc->tx_desc[prod]; 878210040Scognet error = bus_dmamap_load_mbuf_sg(sc->dmatag_ring_tx, txd->dmamap, 879210040Scognet *m_head, segs, &nsegs, 0); 880210040Scognet if (error == EFBIG) { 881243882Sglebius m = m_collapse(*m_head, M_NOWAIT, MAX_FRAGMENT); 882210040Scognet if (m == NULL) { 883210040Scognet m_freem(*m_head); 884210040Scognet *m_head = NULL; 885210040Scognet return (ENOMEM); 886210040Scognet } 887210040Scognet *m_head = m; 888210040Scognet error = bus_dmamap_load_mbuf_sg(sc->dmatag_ring_tx, txd->dmamap, 889210040Scognet *m_head, segs, &nsegs, 0); 890210040Scognet if (error != 0) { 891210040Scognet m_freem(*m_head); 892210040Scognet *m_head = NULL; 893210040Scognet return (error); 894210040Scognet } 895210040Scognet } else if (error != 0) { 896210040Scognet return (error); 897210040Scognet } 898210040Scognet /* Check for TX descriptor overruns. */ 899210040Scognet if (sc->tx_cnt + nsegs > MACB_MAX_TX_BUFFERS - 1) { 900210040Scognet bus_dmamap_unload(sc->dmatag_ring_tx, txd->dmamap); 901210040Scognet return (ENOBUFS); 902210040Scognet } 903210040Scognet bus_dmamap_sync(sc->dmatag_ring_tx, txd->dmamap, BUS_DMASYNC_PREWRITE); 904210040Scognet m = *m_head; 905210040Scognet 906210040Scognet /* TODO: VLAN hardware tag insertion. */ 907210040Scognet 908210040Scognet csum_flags = 0; 909210040Scognet si = prod; 910210040Scognet desc = NULL; 911210040Scognet 912210040Scognet for (i = 0; i < nsegs; i++) { 913210040Scognet desc = &sc->desc_tx[prod]; 914210040Scognet desc->addr = segs[i].ds_addr; 915210040Scognet 916210040Scognet if (i == 0 ) { 917210040Scognet desc->flags = segs[i].ds_len | TD_OWN; 918210040Scognet } else { 919210040Scognet desc->flags = segs[i].ds_len; 920210040Scognet } 921210040Scognet 922210040Scognet if (prod == MACB_MAX_TX_BUFFERS - 1) 923210040Scognet desc->flags |= TD_WRAP_MASK; 924210040Scognet 925210040Scognet sc->tx_cnt++; 926210040Scognet MACB_DESC_INC(prod, MACB_MAX_TX_BUFFERS); 927210040Scognet } 928210040Scognet /* 929210040Scognet * Set EOP on the last fragment. 930210040Scognet */ 931210040Scognet 932210040Scognet desc->flags |= TD_LAST; 933210040Scognet desc = &sc->desc_tx[si]; 934210040Scognet desc->flags &= ~TD_OWN; 935210040Scognet 936210040Scognet sc->tx_prod = prod; 937210040Scognet 938210040Scognet /* Swap the first dma map and the last. */ 939210040Scognet map = txd_last->dmamap; 940210040Scognet txd_last->dmamap = txd->dmamap; 941210040Scognet txd->dmamap = map; 942210040Scognet txd->buff = m; 943210040Scognet 944210040Scognet return (0); 945210040Scognet} 946210040Scognet 947210040Scognet 948210040Scognetstatic void 949210040Scognetmacbstart_locked(struct ifnet *ifp) 950210040Scognet{ 951210040Scognet 952210040Scognet 953210040Scognet 954210040Scognet struct macb_softc *sc; 955210040Scognet struct mbuf *m0; 956210040Scognet#if 0 957210040Scognet struct mbuf *m_new; 958210040Scognet#endif 959210040Scognet int queued = 0; 960210040Scognet 961210040Scognet sc = ifp->if_softc; 962210040Scognet 963210040Scognet if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 964210040Scognet IFF_DRV_RUNNING || (sc->flags & MACB_FLAG_LINK) == 0) { 965210040Scognet return; 966210040Scognet } 967210040Scognet 968210040Scognet while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 969210040Scognet /* Get packet from the queue */ 970210040Scognet IF_DEQUEUE(&ifp->if_snd, m0); 971210040Scognet if (m0 == NULL) 972210040Scognet break; 973210040Scognet#if 0 974210040Scognet if (m0->m_next != NULL) { 975210040Scognet /* Fragmented mbuf chain, collapse it. */ 976243882Sglebius m_new = m_defrag(m0, M_NOWAIT); 977210040Scognet if (m_new != NULL) { 978210040Scognet /* Original frame freed. */ 979210040Scognet m0 = m_new; 980210040Scognet } else { 981210040Scognet /* Defragmentation failed, just use the chain. */ 982210040Scognet } 983210040Scognet } 984210040Scognet#endif 985210040Scognet if (macb_encap(sc, &m0)) { 986210040Scognet if (m0 == NULL) 987210040Scognet break; 988210040Scognet IF_PREPEND(&ifp->if_snd, m0); 989210040Scognet ifp->if_drv_flags |= IFF_DRV_OACTIVE; 990210040Scognet break; 991210040Scognet } 992210040Scognet queued++; 993210040Scognet BPF_MTAP(ifp, m0); 994210040Scognet } 995210040Scognet if (IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 996210040Scognet ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 997210040Scognet if (queued) { 998210040Scognet bus_dmamap_sync(sc->dmatag_data_tx, sc->dmamap_ring_tx, 999210040Scognet BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1000210040Scognet write_4(sc, EMAC_NCR, read_4(sc, EMAC_NCR) | TRANSMIT_START); 1001210040Scognet sc->macb_watchdog_timer = MACB_TIMEOUT; 1002210040Scognet } 1003210040Scognet} 1004210040Scognet 1005210040Scognetstatic void 1006210040Scognetmacbinit(void *xsc) 1007210040Scognet{ 1008210040Scognet struct macb_softc *sc = xsc; 1009210040Scognet 1010210040Scognet MACB_LOCK(sc); 1011210040Scognet macbinit_locked(sc); 1012210040Scognet MACB_UNLOCK(sc); 1013210040Scognet} 1014210040Scognet 1015210040Scognetstatic void 1016210040Scognetmacbstart(struct ifnet *ifp) 1017210040Scognet{ 1018210040Scognet struct macb_softc *sc = ifp->if_softc; 1019210040Scognet MACB_ASSERT_UNLOCKED(sc); 1020210040Scognet MACB_LOCK(sc); 1021210040Scognet macbstart_locked(ifp); 1022210040Scognet MACB_UNLOCK(sc); 1023210040Scognet 1024210040Scognet} 1025210040Scognet 1026210040Scognet 1027210040Scognetstatic void 1028210040Scognetmacbstop(struct macb_softc *sc) 1029210040Scognet{ 1030210040Scognet struct ifnet *ifp = sc->ifp; 1031210040Scognet struct rx_desc_info *rd; 1032210040Scognet struct tx_desc_info *td; 1033210040Scognet int i; 1034210040Scognet 1035210040Scognet ifp = sc->ifp; 1036210040Scognet 1037210040Scognet ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1038210040Scognet 1039210040Scognet macb_reset(sc); 1040210040Scognet 1041210040Scognet sc->flags &= ~MACB_FLAG_LINK; 1042210040Scognet callout_stop(&sc->tick_ch); 1043210040Scognet sc->macb_watchdog_timer = 0; 1044210040Scognet 1045210040Scognet /* Free TX/RX mbufs still in the queues. */ 1046210040Scognet for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { 1047210040Scognet td = &sc->tx_desc[i]; 1048210040Scognet if (td->buff != NULL) { 1049210040Scognet bus_dmamap_sync(sc->dmatag_ring_tx, td->dmamap, 1050210040Scognet BUS_DMASYNC_POSTWRITE); 1051210040Scognet bus_dmamap_unload(sc->dmatag_data_tx, td->dmamap); 1052210040Scognet m_freem(td->buff); 1053210040Scognet td->buff = NULL; 1054210040Scognet } 1055210040Scognet } 1056210040Scognet for (i = 0; i < MACB_MAX_RX_BUFFERS; i++) { 1057210040Scognet rd = &sc->rx_desc[i]; 1058210040Scognet if (rd->buff != NULL) { 1059210040Scognet bus_dmamap_sync(sc->dmatag_ring_rx, rd->dmamap, 1060210040Scognet BUS_DMASYNC_POSTREAD); 1061210040Scognet bus_dmamap_unload(sc->dmatag_data_rx, rd->dmamap); 1062210040Scognet m_freem(rd->buff); 1063210040Scognet rd->buff = NULL; 1064210040Scognet } 1065210040Scognet } 1066210040Scognet} 1067210040Scognet 1068210040Scognetstatic int 1069210040Scognetget_hash_index(uint8_t *mac) 1070210040Scognet{ 1071210040Scognet int i, j, k; 1072210040Scognet int result; 1073210040Scognet int bit; 1074210040Scognet 1075210040Scognet result = 0; 1076210040Scognet for (i = 0; i < 6; i++) { 1077210040Scognet bit = 0; 1078210040Scognet for (j = 0; j < 8; j++) { 1079210040Scognet k = j * 6 + i; 1080210040Scognet bit ^= (mac[k/8] & (1 << (k % 8)) ) != 0; 1081210040Scognet } 1082210040Scognet result |= bit; 1083210040Scognet } 1084210040Scognet return result; 1085210040Scognet} 1086210040Scognet 1087210040Scognetstatic void 1088210040Scognetset_mac_filter(uint32_t *filter, uint8_t *mac) 1089210040Scognet{ 1090210040Scognet int bits; 1091210040Scognet 1092210040Scognet bits = get_hash_index(mac); 1093210040Scognet filter[bits >> 5] |= 1 << (bits & 31); 1094210040Scognet} 1095210040Scognet 1096210040Scognetstatic void 1097210040Scognetset_filter(struct macb_softc *sc) 1098210040Scognet{ 1099210040Scognet struct ifnet *ifp; 1100210040Scognet struct ifmultiaddr *ifma; 1101210040Scognet int config; 1102210040Scognet int count; 1103210040Scognet uint32_t multicast_filter[2]; 1104210040Scognet 1105236989Simp ifp = sc->ifp; 1106210040Scognet 1107210040Scognet config = read_4(sc, EMAC_NCFGR); 1108210040Scognet 1109210040Scognet config &= ~(CFG_CAF | CFG_MTI); 1110210040Scognet write_4(sc, EMAC_HRB, 0); 1111210040Scognet write_4(sc, EMAC_HRT, 0); 1112210040Scognet 1113210040Scognet if ((ifp->if_flags & (IFF_ALLMULTI |IFF_PROMISC)) != 0){ 1114210040Scognet if ((ifp->if_flags & IFF_ALLMULTI) != 0) { 1115210040Scognet write_4(sc, EMAC_HRB, ~0); 1116210040Scognet write_4(sc, EMAC_HRT, ~0); 1117210040Scognet config |= CFG_MTI; 1118210040Scognet } 1119210040Scognet if ((ifp->if_flags & IFF_PROMISC) != 0) { 1120210040Scognet config |= CFG_CAF; 1121210040Scognet } 1122210040Scognet write_4(sc, EMAC_NCFGR, config); 1123210040Scognet return; 1124210040Scognet } 1125210040Scognet 1126210040Scognet if_maddr_rlock(ifp); 1127210040Scognet count = 0; 1128210040Scognet multicast_filter[0] = 0; 1129210040Scognet multicast_filter[1] = 0; 1130210040Scognet 1131210040Scognet TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1132210040Scognet if (ifma->ifma_addr->sa_family != AF_LINK) 1133210040Scognet continue; 1134210040Scognet count++; 1135236989Simp set_mac_filter(multicast_filter, 1136210040Scognet LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 1137210040Scognet } 1138210040Scognet if (count) { 1139210040Scognet write_4(sc, EMAC_HRB, multicast_filter[0]); 1140210040Scognet write_4(sc, EMAC_HRT, multicast_filter[1]); 1141210040Scognet write_4(sc, EMAC_NCFGR, config|CFG_MTI); 1142210040Scognet } 1143210040Scognet if_maddr_runlock(ifp); 1144210040Scognet} 1145210040Scognet 1146210040Scognetstatic int 1147210040Scognetmacbioctl(struct ifnet * ifp, u_long cmd, caddr_t data) 1148210040Scognet{ 1149210040Scognet 1150210040Scognet struct macb_softc *sc = ifp->if_softc; 1151210040Scognet struct mii_data *mii; 1152210040Scognet struct ifreq *ifr = (struct ifreq *)data; 1153210040Scognet 1154210040Scognet int error = 0; 1155210040Scognet 1156210040Scognet switch (cmd) { 1157210040Scognet case SIOCSIFFLAGS: 1158210040Scognet MACB_LOCK(sc); 1159210040Scognet 1160210040Scognet if ((ifp->if_flags & IFF_UP) != 0) { 1161210040Scognet if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1162210040Scognet if (((ifp->if_flags ^ sc->if_flags) 1163210040Scognet & (IFF_PROMISC | IFF_ALLMULTI)) != 0) 1164210040Scognet set_filter(sc); 1165210040Scognet } else { 1166210040Scognet macbinit_locked(sc); 1167210040Scognet } 1168210040Scognet } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1169210040Scognet macbstop(sc); 1170210040Scognet } 1171210040Scognet sc->if_flags = ifp->if_flags; 1172210040Scognet MACB_UNLOCK(sc); 1173210040Scognet break; 1174210040Scognet case SIOCADDMULTI: 1175210040Scognet case SIOCDELMULTI: 1176210040Scognet MACB_LOCK(sc); 1177210040Scognet if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1178210040Scognet set_filter(sc); 1179210040Scognet 1180210040Scognet MACB_UNLOCK(sc); 1181210040Scognet break; 1182210040Scognet case SIOCSIFMEDIA: 1183210040Scognet case SIOCGIFMEDIA: 1184210040Scognet mii = device_get_softc(sc->miibus); 1185210040Scognet error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1186210040Scognet break; 1187210040Scognet default: 1188210040Scognet error = ether_ioctl(ifp, cmd, data); 1189210040Scognet break; 1190210040Scognet } 1191210040Scognet return (error); 1192210040Scognet 1193210040Scognet} 1194210040Scognet 1195210040Scognet/* bus entry points */ 1196210040Scognet 1197210040Scognetstatic int 1198210040Scognetmacb_probe(device_t dev) 1199210040Scognet{ 1200210040Scognet device_set_desc(dev, "macb"); 1201210040Scognet return (0); 1202210040Scognet} 1203210040Scognet 1204210040Scognet/* 1205210040Scognet * Change media according to request. 1206210040Scognet */ 1207210040Scognetstatic int 1208210040Scognetmacb_ifmedia_upd(struct ifnet *ifp) 1209210040Scognet{ 1210210040Scognet struct macb_softc *sc = ifp->if_softc; 1211210040Scognet struct mii_data *mii; 1212210040Scognet 1213210040Scognet mii = device_get_softc(sc->miibus); 1214210040Scognet MACB_LOCK(sc); 1215210040Scognet mii_mediachg(mii); 1216210040Scognet MACB_UNLOCK(sc); 1217210040Scognet return (0); 1218210040Scognet} 1219210040Scognet 1220210040Scognet/* 1221210040Scognet * Notify the world which media we're using. 1222210040Scognet */ 1223210040Scognetstatic void 1224210040Scognetmacb_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1225210040Scognet{ 1226210040Scognet struct macb_softc *sc = ifp->if_softc; 1227210040Scognet struct mii_data *mii; 1228210040Scognet 1229210040Scognet mii = device_get_softc(sc->miibus); 1230210040Scognet 1231210040Scognet MACB_LOCK(sc); 1232210040Scognet /* Don't report link state if driver is not running. */ 1233210040Scognet if ((ifp->if_flags & IFF_UP) == 0) { 1234210040Scognet MACB_UNLOCK(sc); 1235210040Scognet return; 1236210040Scognet } 1237210040Scognet mii_pollstat(mii); 1238210040Scognet ifmr->ifm_active = mii->mii_media_active; 1239210040Scognet ifmr->ifm_status = mii->mii_media_status; 1240210040Scognet MACB_UNLOCK(sc); 1241210040Scognet} 1242210040Scognet 1243210040Scognetstatic void 1244210040Scognetmacb_reset(struct macb_softc *sc) 1245210040Scognet{ 1246210040Scognet /* 1247210040Scognet * Disable RX and TX 1248210040Scognet */ 1249210040Scognet write_4(sc, EMAC_NCR, 0); 1250210040Scognet 1251210040Scognet write_4(sc, EMAC_NCR, CLEAR_STAT); 1252210040Scognet 1253210040Scognet /* Clear all status flags */ 1254210040Scognet write_4(sc, EMAC_TSR, ~0UL); 1255210040Scognet write_4(sc, EMAC_RSR, ~0UL); 1256210040Scognet 1257210040Scognet /* Disable all interrupts */ 1258210040Scognet write_4(sc, EMAC_IDR, ~0UL); 1259210040Scognet read_4(sc, EMAC_ISR); 1260210040Scognet 1261210040Scognet} 1262210040Scognet 1263210040Scognet 1264210040Scognetstatic int 1265210040Scognetmacb_get_mac(struct macb_softc *sc, u_char *eaddr) 1266210040Scognet{ 1267210040Scognet uint32_t bottom; 1268210040Scognet uint16_t top; 1269210040Scognet 1270210040Scognet bottom = read_4(sc, EMAC_SA1B); 1271210040Scognet top = read_4(sc, EMAC_SA1T); 1272210040Scognet 1273210040Scognet eaddr[0] = bottom & 0xff; 1274210040Scognet eaddr[1] = (bottom >> 8) & 0xff; 1275210040Scognet eaddr[2] = (bottom >> 16) & 0xff; 1276210040Scognet eaddr[3] = (bottom >> 24) & 0xff; 1277210040Scognet eaddr[4] = top & 0xff; 1278210040Scognet eaddr[5] = (top >> 8) & 0xff; 1279210040Scognet 1280210040Scognet return (0); 1281210040Scognet} 1282210040Scognet 1283210040Scognet 1284210040Scognetstatic int 1285210040Scognetmacb_attach(device_t dev) 1286210040Scognet{ 1287210040Scognet struct macb_softc *sc; 1288210040Scognet struct ifnet *ifp = NULL; 1289210040Scognet struct sysctl_ctx_list *sctx; 1290210040Scognet struct sysctl_oid *soid; 1291210040Scognet int pclk_hz; 1292210040Scognet u_char eaddr[ETHER_ADDR_LEN]; 1293210040Scognet int rid; 1294210040Scognet int err; 1295210040Scognet struct at91_pmc_clock *master; 1296210040Scognet 1297210040Scognet 1298210040Scognet err = 0; 1299210040Scognet 1300210040Scognet sc = device_get_softc(dev); 1301210040Scognet sc->dev = dev; 1302210040Scognet 1303210040Scognet MACB_LOCK_INIT(sc); 1304210040Scognet 1305210040Scognet callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0); 1306210040Scognet 1307210040Scognet /* 1308210040Scognet * Allocate resources. 1309210040Scognet */ 1310210040Scognet rid = 0; 1311210040Scognet sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1312210040Scognet RF_ACTIVE); 1313210040Scognet if (sc->mem_res == NULL) { 1314210040Scognet device_printf(dev, "could not allocate memory resources.\n"); 1315210040Scognet err = ENOMEM; 1316210040Scognet goto out; 1317210040Scognet } 1318210040Scognet rid = 0; 1319210040Scognet sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1320210040Scognet RF_ACTIVE); 1321210040Scognet if (sc->irq_res == NULL) { 1322210040Scognet device_printf(dev, "could not allocate interrupt resources.\n"); 1323210040Scognet err = ENOMEM; 1324210040Scognet goto out; 1325210040Scognet } 1326210040Scognet 1327210040Scognet /*setup clock*/ 1328213496Scognet sc->clk = at91_pmc_clock_ref(device_get_nameunit(sc->dev)); 1329210040Scognet at91_pmc_clock_enable(sc->clk); 1330210040Scognet 1331210040Scognet macb_reset(sc); 1332210040Scognet macb_get_mac(sc, eaddr); 1333210040Scognet 1334210040Scognet master = at91_pmc_clock_ref("mck"); 1335210040Scognet 1336210040Scognet pclk_hz = master->hz; 1337210040Scognet 1338210040Scognet sc->clock = CFG_CLK_8; 1339210040Scognet if (pclk_hz <= 20000000) 1340210040Scognet sc->clock = CFG_CLK_8; 1341210040Scognet else if (pclk_hz <= 40000000) 1342210040Scognet sc->clock = CFG_CLK_16; 1343210040Scognet else if (pclk_hz <= 80000000) 1344210040Scognet sc->clock = CFG_CLK_32; 1345210040Scognet else 1346210040Scognet sc->clock = CFG_CLK_64; 1347210040Scognet 1348210040Scognet sc->clock = sc->clock << 10; 1349210040Scognet 1350210040Scognet write_4(sc, EMAC_NCFGR, sc->clock); 1351210040Scognet write_4(sc, EMAC_USRIO, USRIO_CLOCK); //enable clock 1352210040Scognet 1353210040Scognet write_4(sc, EMAC_NCR, MPE_ENABLE); //enable MPE 1354210040Scognet 1355210040Scognet sc->ifp = ifp = if_alloc(IFT_ETHER); 1356213894Smarius err = mii_attach(dev, &sc->miibus, ifp, macb_ifmedia_upd, 1357213894Smarius macb_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 1358213894Smarius if (err != 0) { 1359213894Smarius device_printf(dev, "attaching PHYs failed\n"); 1360210040Scognet goto out; 1361210040Scognet } 1362210040Scognet 1363210040Scognet if (macb_allocate_dma(sc) != 0) 1364210040Scognet goto out; 1365210040Scognet 1366210040Scognet /* Sysctls */ 1367210040Scognet sctx = device_get_sysctl_ctx(dev); 1368210040Scognet soid = device_get_sysctl_tree(dev); 1369210040Scognet 1370210040Scognet ifp->if_softc = sc; 1371210040Scognet if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1372210040Scognet ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1373210040Scognet ifp->if_capabilities |= IFCAP_VLAN_MTU; 1374210040Scognet ifp->if_capenable |= IFCAP_VLAN_MTU; /* The hw bits already set. */ 1375210040Scognet ifp->if_start = macbstart; 1376210040Scognet ifp->if_ioctl = macbioctl; 1377210040Scognet ifp->if_init = macbinit; 1378210040Scognet IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 1379210040Scognet ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 1380210040Scognet IFQ_SET_READY(&ifp->if_snd); 1381210040Scognet sc->if_flags = ifp->if_flags; 1382210040Scognet 1383210040Scognet TASK_INIT(&sc->sc_intr_task, 0, macb_intr_task, sc); 1384210040Scognet 1385210040Scognet sc->sc_tq = taskqueue_create_fast("macb_taskq", M_WAITOK, 1386210040Scognet taskqueue_thread_enqueue, &sc->sc_tq); 1387210040Scognet if (sc->sc_tq == NULL) { 1388210040Scognet device_printf(sc->dev, "could not create taskqueue\n"); 1389210040Scognet goto out; 1390210040Scognet } 1391210040Scognet 1392210040Scognet ether_ifattach(ifp, eaddr); 1393210040Scognet 1394210040Scognet /* 1395210040Scognet * Activate the interrupt. 1396210040Scognet */ 1397210040Scognet err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, 1398210040Scognet NULL, macb_intr, sc, &sc->intrhand); 1399210040Scognet if (err) { 1400210040Scognet device_printf(dev, "could not establish interrupt handler.\n"); 1401210040Scognet ether_ifdetach(ifp); 1402210040Scognet goto out; 1403210040Scognet } 1404210040Scognet 1405210040Scognet taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", 1406210040Scognet device_get_nameunit(sc->dev)); 1407210040Scognet 1408210040Scognet sc->macb_cdata.rxhead = 0; 1409210040Scognet sc->macb_cdata.rxtail = 0; 1410210040Scognet 1411210040Scognet phy_write(sc, 0, 0, 0x3300); //force autoneg 1412210040Scognet 1413210040Scognet return (0); 1414210040Scognetout: 1415210040Scognet 1416210040Scognet return (err); 1417210040Scognet} 1418210040Scognet 1419210040Scognetstatic int 1420210040Scognetmacb_detach(device_t dev) 1421210040Scognet{ 1422210040Scognet struct macb_softc *sc; 1423210040Scognet 1424210040Scognet sc = device_get_softc(dev); 1425217062Sjhb ether_ifdetach(sc->ifp); 1426217062Sjhb MACB_LOCK(sc); 1427210040Scognet macbstop(sc); 1428217062Sjhb MACB_UNLOCK(sc); 1429217062Sjhb callout_drain(&sc->tick_ch); 1430217062Sjhb bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 1431217062Sjhb taskqueue_drain(sc->sc_tq, &sc->sc_intr_task); 1432217062Sjhb taskqueue_free(sc->sc_tq); 1433210040Scognet macb_deactivate(dev); 1434217062Sjhb bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 1435217062Sjhb bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 1436217062Sjhb MACB_LOCK_DESTROY(sc); 1437210040Scognet 1438210040Scognet return (0); 1439210040Scognet} 1440210040Scognet 1441210040Scognet/*PHY related functions*/ 1442210040Scognetstatic inline int 1443210040Scognetphy_read(struct macb_softc *sc, int phy, int reg) 1444210040Scognet{ 1445210040Scognet int val; 1446210040Scognet 1447210040Scognet write_4(sc, EMAC_MAN, EMAC_MAN_REG_RD(phy, reg)); 1448210040Scognet while ((read_4(sc, EMAC_SR) & EMAC_SR_IDLE) == 0) 1449210040Scognet continue; 1450210040Scognet val = read_4(sc, EMAC_MAN) & EMAC_MAN_VALUE_MASK; 1451210040Scognet 1452210040Scognet return (val); 1453210040Scognet} 1454210040Scognet 1455210040Scognetstatic inline int 1456210040Scognetphy_write(struct macb_softc *sc, int phy, int reg, int data) 1457210040Scognet{ 1458210040Scognet 1459210040Scognet write_4(sc, EMAC_MAN, EMAC_MAN_REG_WR(phy, reg, data)); 1460210040Scognet while ((read_4(sc, EMAC_SR) & EMAC_SR_IDLE) == 0) 1461210040Scognet continue; 1462210040Scognet 1463210040Scognet return (0); 1464210040Scognet} 1465210040Scognet 1466210040Scognet/* 1467210040Scognet * MII bus support routines. 1468210040Scognet */ 1469210040Scognetstatic int 1470210040Scognetmacb_miibus_readreg(device_t dev, int phy, int reg) 1471210040Scognet{ 1472210040Scognet struct macb_softc *sc; 1473210040Scognet sc = device_get_softc(dev); 1474210040Scognet return (phy_read(sc, phy, reg)); 1475210040Scognet} 1476210040Scognet 1477210040Scognetstatic int 1478210040Scognetmacb_miibus_writereg(device_t dev, int phy, int reg, int data) 1479210040Scognet{ 1480210040Scognet struct macb_softc *sc; 1481210040Scognet sc = device_get_softc(dev); 1482210040Scognet return (phy_write(sc, phy, reg, data)); 1483210040Scognet} 1484210040Scognet 1485210040Scognetstatic void 1486210040Scognetmacb_child_detached(device_t dev, device_t child) 1487210040Scognet{ 1488210040Scognet struct macb_softc *sc; 1489210040Scognet sc = device_get_softc(dev); 1490210040Scognet 1491210040Scognet} 1492210040Scognet 1493210040Scognetstatic void 1494210040Scognetmacb_miibus_statchg(device_t dev) 1495210040Scognet{ 1496210040Scognet struct macb_softc *sc; 1497210040Scognet struct mii_data *mii; 1498210040Scognet int config; 1499210040Scognet 1500210040Scognet sc = device_get_softc(dev); 1501210040Scognet 1502210040Scognet mii = device_get_softc(sc->miibus); 1503210040Scognet 1504236989Simp sc->flags &= ~MACB_FLAG_LINK; 1505210040Scognet 1506210040Scognet config = read_4(sc, EMAC_NCFGR); 1507210040Scognet 1508210040Scognet if ((mii->mii_media_status & IFM_AVALID) != 0) { 1509210040Scognet switch (IFM_SUBTYPE(mii->mii_media_active)) { 1510210040Scognet case IFM_10_T: 1511210040Scognet config &= ~(CFG_SPD); 1512210040Scognet sc->flags |= MACB_FLAG_LINK; 1513210040Scognet break; 1514210040Scognet case IFM_100_TX: 1515210040Scognet config |= CFG_SPD; 1516210040Scognet sc->flags |= MACB_FLAG_LINK; 1517210040Scognet break; 1518210040Scognet default: 1519210040Scognet break; 1520210040Scognet } 1521210040Scognet } 1522210040Scognet 1523210040Scognet config |= CFG_FD; 1524210040Scognet write_4(sc, EMAC_NCFGR, config); 1525210040Scognet} 1526210040Scognet 1527210040Scognetstatic device_method_t macb_methods[] = { 1528210040Scognet /* Device interface */ 1529210040Scognet DEVMETHOD(device_probe, macb_probe), 1530210040Scognet DEVMETHOD(device_attach, macb_attach), 1531210040Scognet DEVMETHOD(device_detach, macb_detach), 1532210040Scognet 1533210040Scognet /* Bus interface */ 1534210040Scognet DEVMETHOD(bus_child_detached, macb_child_detached), 1535210040Scognet 1536210040Scognet /* MII interface */ 1537210040Scognet DEVMETHOD(miibus_readreg, macb_miibus_readreg), 1538210040Scognet DEVMETHOD(miibus_writereg, macb_miibus_writereg), 1539210040Scognet DEVMETHOD(miibus_statchg, macb_miibus_statchg), 1540210040Scognet { 0, 0 } 1541210040Scognet}; 1542210040Scognet 1543210040Scognetstatic driver_t macb_driver = { 1544210040Scognet "macb", 1545210040Scognet macb_methods, 1546210040Scognet sizeof(struct macb_softc), 1547210040Scognet}; 1548210040Scognet 1549210040Scognet 1550210040ScognetDRIVER_MODULE(macb, atmelarm, macb_driver, macb_devclass, 0, 0); 1551210040ScognetDRIVER_MODULE(miibus, macb, miibus_driver, miibus_devclass, 0, 0); 1552210040ScognetMODULE_DEPEND(macb, miibus, 1, 1, 1); 1553210040ScognetMODULE_DEPEND(macb, ether, 1, 1, 1); 1554