if_bfe.c revision 181994
1139749Simp/*- 2119917Swpaul * Copyright (c) 2003 Stuart Walsh<stu@ipng.org.uk> 3119917Swpaul * and Duncan Barclay<dmlb@dmlb.org> 4139749Simp * 5119917Swpaul * Redistribution and use in source and binary forms, with or without 6119917Swpaul * modification, are permitted provided that the following conditions 7119917Swpaul * are met: 8119917Swpaul * 1. Redistributions of source code must retain the above copyright 9119917Swpaul * notice, this list of conditions and the following disclaimer. 10119917Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11119917Swpaul * notice, this list of conditions and the following disclaimer in the 12119917Swpaul * documentation and/or other materials provided with the distribution. 13119917Swpaul * 14119917Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND 15119917Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16119917Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17119917Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18119917Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19119917Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20119917Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21119917Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22119917Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23119917Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24119917Swpaul * SUCH DAMAGE. 25119917Swpaul */ 26119917Swpaul 27119917Swpaul 28119917Swpaul#include <sys/cdefs.h> 29119917Swpaul__FBSDID("$FreeBSD: head/sys/dev/bfe/if_bfe.c 181994 2008-08-22 06:46:55Z yongari $"); 30119917Swpaul 31119917Swpaul#include <sys/param.h> 32119917Swpaul#include <sys/systm.h> 33181953Syongari#include <sys/bus.h> 34181953Syongari#include <sys/endian.h> 35181953Syongari#include <sys/kernel.h> 36181953Syongari#include <sys/malloc.h> 37119917Swpaul#include <sys/mbuf.h> 38129879Sphk#include <sys/module.h> 39181953Syongari#include <sys/rman.h> 40119917Swpaul#include <sys/socket.h> 41181953Syongari#include <sys/sockio.h> 42181994Syongari#include <sys/sysctl.h> 43119917Swpaul 44181953Syongari#include <net/bpf.h> 45119917Swpaul#include <net/if.h> 46119917Swpaul#include <net/ethernet.h> 47119917Swpaul#include <net/if_dl.h> 48119917Swpaul#include <net/if_media.h> 49119917Swpaul#include <net/if_types.h> 50119917Swpaul#include <net/if_vlan_var.h> 51119917Swpaul 52119917Swpaul#include <dev/mii/mii.h> 53119917Swpaul#include <dev/mii/miivar.h> 54119917Swpaul 55119917Swpaul#include <dev/pci/pcireg.h> 56119917Swpaul#include <dev/pci/pcivar.h> 57119917Swpaul 58181953Syongari#include <machine/bus.h> 59181953Syongari 60119917Swpaul#include <dev/bfe/if_bfereg.h> 61119917Swpaul 62119917SwpaulMODULE_DEPEND(bfe, pci, 1, 1, 1); 63119917SwpaulMODULE_DEPEND(bfe, ether, 1, 1, 1); 64119917SwpaulMODULE_DEPEND(bfe, miibus, 1, 1, 1); 65119917Swpaul 66151545Simp/* "device miibus" required. See GENERIC if you get errors here. */ 67119917Swpaul#include "miibus_if.h" 68119917Swpaul 69119917Swpaul#define BFE_DEVDESC_MAX 64 /* Maximum device description length */ 70119917Swpaul 71119917Swpaulstatic struct bfe_type bfe_devs[] = { 72119917Swpaul { BCOM_VENDORID, BCOM_DEVICEID_BCM4401, 73119917Swpaul "Broadcom BCM4401 Fast Ethernet" }, 74134590Sdes { BCOM_VENDORID, BCOM_DEVICEID_BCM4401B0, 75134590Sdes "Broadcom BCM4401-B0 Fast Ethernet" }, 76119917Swpaul { 0, 0, NULL } 77119917Swpaul}; 78119917Swpaul 79119917Swpaulstatic int bfe_probe (device_t); 80119917Swpaulstatic int bfe_attach (device_t); 81119917Swpaulstatic int bfe_detach (device_t); 82164456Sjhbstatic int bfe_suspend (device_t); 83164456Sjhbstatic int bfe_resume (device_t); 84119917Swpaulstatic void bfe_release_resources (struct bfe_softc *); 85119917Swpaulstatic void bfe_intr (void *); 86181953Syongaristatic int bfe_encap (struct bfe_softc *, struct mbuf **); 87119917Swpaulstatic void bfe_start (struct ifnet *); 88136804Smtmstatic void bfe_start_locked (struct ifnet *); 89119917Swpaulstatic int bfe_ioctl (struct ifnet *, u_long, caddr_t); 90119917Swpaulstatic void bfe_init (void *); 91136804Smtmstatic void bfe_init_locked (void *); 92119917Swpaulstatic void bfe_stop (struct bfe_softc *); 93175787Syongaristatic void bfe_watchdog (struct bfe_softc *); 94173839Syongaristatic int bfe_shutdown (device_t); 95119917Swpaulstatic void bfe_tick (void *); 96119917Swpaulstatic void bfe_txeof (struct bfe_softc *); 97119917Swpaulstatic void bfe_rxeof (struct bfe_softc *); 98119917Swpaulstatic void bfe_set_rx_mode (struct bfe_softc *); 99119917Swpaulstatic int bfe_list_rx_init (struct bfe_softc *); 100181953Syongaristatic void bfe_list_tx_init (struct bfe_softc *); 101181953Syongaristatic void bfe_discard_buf (struct bfe_softc *, int); 102181953Syongaristatic int bfe_list_newbuf (struct bfe_softc *, int); 103119917Swpaulstatic void bfe_rx_ring_free (struct bfe_softc *); 104119917Swpaul 105119917Swpaulstatic void bfe_pci_setup (struct bfe_softc *, u_int32_t); 106119917Swpaulstatic int bfe_ifmedia_upd (struct ifnet *); 107119917Swpaulstatic void bfe_ifmedia_sts (struct ifnet *, struct ifmediareq *); 108119917Swpaulstatic int bfe_miibus_readreg (device_t, int, int); 109119917Swpaulstatic int bfe_miibus_writereg (device_t, int, int, int); 110119917Swpaulstatic void bfe_miibus_statchg (device_t); 111133282Sdesstatic int bfe_wait_bit (struct bfe_softc *, u_int32_t, u_int32_t, 112119917Swpaul u_long, const int); 113119917Swpaulstatic void bfe_get_config (struct bfe_softc *sc); 114119917Swpaulstatic void bfe_read_eeprom (struct bfe_softc *, u_int8_t *); 115119917Swpaulstatic void bfe_stats_update (struct bfe_softc *); 116119917Swpaulstatic void bfe_clear_stats (struct bfe_softc *); 117119917Swpaulstatic int bfe_readphy (struct bfe_softc *, u_int32_t, u_int32_t*); 118119917Swpaulstatic int bfe_writephy (struct bfe_softc *, u_int32_t, u_int32_t); 119119917Swpaulstatic int bfe_resetphy (struct bfe_softc *); 120119917Swpaulstatic int bfe_setupphy (struct bfe_softc *); 121119917Swpaulstatic void bfe_chip_reset (struct bfe_softc *); 122119917Swpaulstatic void bfe_chip_halt (struct bfe_softc *); 123119917Swpaulstatic void bfe_core_reset (struct bfe_softc *); 124119917Swpaulstatic void bfe_core_disable (struct bfe_softc *); 125181953Syongaristatic int bfe_dma_alloc (struct bfe_softc *); 126181953Syongaristatic void bfe_dma_free (struct bfe_softc *sc); 127119917Swpaulstatic void bfe_dma_map (void *, bus_dma_segment_t *, int, int); 128119917Swpaulstatic void bfe_cam_write (struct bfe_softc *, u_char *, int); 129181994Syongaristatic int sysctl_bfe_stats (SYSCTL_HANDLER_ARGS); 130119917Swpaul 131119917Swpaulstatic device_method_t bfe_methods[] = { 132119917Swpaul /* Device interface */ 133119917Swpaul DEVMETHOD(device_probe, bfe_probe), 134119917Swpaul DEVMETHOD(device_attach, bfe_attach), 135119917Swpaul DEVMETHOD(device_detach, bfe_detach), 136119917Swpaul DEVMETHOD(device_shutdown, bfe_shutdown), 137164456Sjhb DEVMETHOD(device_suspend, bfe_suspend), 138164456Sjhb DEVMETHOD(device_resume, bfe_resume), 139119917Swpaul 140119917Swpaul /* bus interface */ 141119917Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 142119917Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 143119917Swpaul 144119917Swpaul /* MII interface */ 145119917Swpaul DEVMETHOD(miibus_readreg, bfe_miibus_readreg), 146119917Swpaul DEVMETHOD(miibus_writereg, bfe_miibus_writereg), 147119917Swpaul DEVMETHOD(miibus_statchg, bfe_miibus_statchg), 148119917Swpaul 149119917Swpaul { 0, 0 } 150119917Swpaul}; 151119917Swpaul 152119917Swpaulstatic driver_t bfe_driver = { 153119917Swpaul "bfe", 154119917Swpaul bfe_methods, 155119917Swpaul sizeof(struct bfe_softc) 156119917Swpaul}; 157119917Swpaul 158119917Swpaulstatic devclass_t bfe_devclass; 159119917Swpaul 160119917SwpaulDRIVER_MODULE(bfe, pci, bfe_driver, bfe_devclass, 0, 0); 161119917SwpaulDRIVER_MODULE(miibus, bfe, miibus_driver, miibus_devclass, 0, 0); 162119917Swpaul 163119917Swpaul/* 164133282Sdes * Probe for a Broadcom 4401 chip. 165119917Swpaul */ 166119917Swpaulstatic int 167119917Swpaulbfe_probe(device_t dev) 168119917Swpaul{ 169119917Swpaul struct bfe_type *t; 170119917Swpaul 171119917Swpaul t = bfe_devs; 172119917Swpaul 173180954Syongari while (t->bfe_name != NULL) { 174181556Syongari if (pci_get_vendor(dev) == t->bfe_vid && 175181556Syongari pci_get_device(dev) == t->bfe_did) { 176181557Syongari device_set_desc(dev, t->bfe_name); 177143163Simp return (BUS_PROBE_DEFAULT); 178119917Swpaul } 179119917Swpaul t++; 180119917Swpaul } 181119917Swpaul 182133282Sdes return (ENXIO); 183119917Swpaul} 184119917Swpaul 185181953Syongaristruct bfe_dmamap_arg { 186181953Syongari bus_addr_t bfe_busaddr; 187181953Syongari}; 188181953Syongari 189119917Swpaulstatic int 190181953Syongaribfe_dma_alloc(struct bfe_softc *sc) 191119917Swpaul{ 192181953Syongari struct bfe_dmamap_arg ctx; 193181953Syongari struct bfe_rx_data *rd; 194181953Syongari struct bfe_tx_data *td; 195119917Swpaul int error, i; 196119917Swpaul 197158075Sscottl /* 198158075Sscottl * parent tag. Apparently the chip cannot handle any DMA address 199158075Sscottl * greater than 1GB. 200158075Sscottl */ 201181953Syongari error = bus_dma_tag_create(bus_get_dma_tag(sc->bfe_dev), /* parent */ 202181953Syongari 1, 0, /* alignment, boundary */ 203181953Syongari BFE_DMA_MAXADDR, /* lowaddr */ 204181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 205181953Syongari NULL, NULL, /* filter, filterarg */ 206181953Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 207181953Syongari 0, /* nsegments */ 208181953Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 209181953Syongari 0, /* flags */ 210181953Syongari NULL, NULL, /* lockfunc, lockarg */ 211181953Syongari &sc->bfe_parent_tag); 212181953Syongari if (error != 0) { 213181953Syongari device_printf(sc->bfe_dev, "cannot create parent DMA tag.\n"); 214181953Syongari goto fail; 215181953Syongari } 216119917Swpaul 217181953Syongari /* Create tag for Tx ring. */ 218181953Syongari error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 219181953Syongari BFE_TX_RING_ALIGN, 0, /* alignment, boundary */ 220181953Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 221181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 222181953Syongari NULL, NULL, /* filter, filterarg */ 223181953Syongari BFE_TX_LIST_SIZE, /* maxsize */ 224181953Syongari 1, /* nsegments */ 225181953Syongari BFE_TX_LIST_SIZE, /* maxsegsize */ 226181953Syongari 0, /* flags */ 227181953Syongari NULL, NULL, /* lockfunc, lockarg */ 228181953Syongari &sc->bfe_tx_tag); 229181953Syongari if (error != 0) { 230181953Syongari device_printf(sc->bfe_dev, "cannot create Tx ring DMA tag.\n"); 231181953Syongari goto fail; 232181953Syongari } 233119917Swpaul 234181953Syongari /* Create tag for Rx ring. */ 235181953Syongari error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 236181953Syongari BFE_RX_RING_ALIGN, 0, /* alignment, boundary */ 237181953Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 238181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 239181953Syongari NULL, NULL, /* filter, filterarg */ 240181953Syongari BFE_RX_LIST_SIZE, /* maxsize */ 241181953Syongari 1, /* nsegments */ 242181953Syongari BFE_RX_LIST_SIZE, /* maxsegsize */ 243181953Syongari 0, /* flags */ 244181953Syongari NULL, NULL, /* lockfunc, lockarg */ 245181953Syongari &sc->bfe_rx_tag); 246181953Syongari if (error != 0) { 247181953Syongari device_printf(sc->bfe_dev, "cannot create Rx ring DMA tag.\n"); 248181953Syongari goto fail; 249119917Swpaul } 250119917Swpaul 251181953Syongari /* Create tag for Tx buffers. */ 252181953Syongari error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 253181953Syongari 1, 0, /* alignment, boundary */ 254181953Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 255181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 256181953Syongari NULL, NULL, /* filter, filterarg */ 257181953Syongari MCLBYTES * BFE_MAXTXSEGS, /* maxsize */ 258181953Syongari BFE_MAXTXSEGS, /* nsegments */ 259181953Syongari MCLBYTES, /* maxsegsize */ 260181953Syongari 0, /* flags */ 261181953Syongari NULL, NULL, /* lockfunc, lockarg */ 262181953Syongari &sc->bfe_txmbuf_tag); 263181953Syongari if (error != 0) { 264181953Syongari device_printf(sc->bfe_dev, 265181953Syongari "cannot create Tx buffer DMA tag.\n"); 266181953Syongari goto fail; 267181953Syongari } 268119917Swpaul 269181953Syongari /* Create tag for Rx buffers. */ 270181953Syongari error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 271181953Syongari 1, 0, /* alignment, boundary */ 272181953Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 273181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 274181953Syongari NULL, NULL, /* filter, filterarg */ 275181953Syongari MCLBYTES, /* maxsize */ 276181953Syongari 1, /* nsegments */ 277181953Syongari MCLBYTES, /* maxsegsize */ 278181953Syongari 0, /* flags */ 279181953Syongari NULL, NULL, /* lockfunc, lockarg */ 280181953Syongari &sc->bfe_rxmbuf_tag); 281181953Syongari if (error != 0) { 282181953Syongari device_printf(sc->bfe_dev, 283181953Syongari "cannot create Rx buffer DMA tag.\n"); 284181953Syongari goto fail; 285119917Swpaul } 286119917Swpaul 287181953Syongari /* Allocate DMA'able memory and load DMA map. */ 288181953Syongari error = bus_dmamem_alloc(sc->bfe_tx_tag, (void *)&sc->bfe_tx_list, 289181953Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->bfe_tx_map); 290181953Syongari if (error != 0) { 291181953Syongari device_printf(sc->bfe_dev, 292181953Syongari "cannot allocate DMA'able memory for Tx ring.\n"); 293181953Syongari goto fail; 294181953Syongari } 295181953Syongari ctx.bfe_busaddr = 0; 296181953Syongari error = bus_dmamap_load(sc->bfe_tx_tag, sc->bfe_tx_map, 297181953Syongari sc->bfe_tx_list, BFE_TX_LIST_SIZE, bfe_dma_map, &ctx, 298181953Syongari BUS_DMA_NOWAIT); 299181953Syongari if (error != 0 || ctx.bfe_busaddr == 0) { 300181953Syongari device_printf(sc->bfe_dev, 301181953Syongari "cannot load DMA'able memory for Tx ring.\n"); 302181953Syongari goto fail; 303181953Syongari } 304181953Syongari sc->bfe_tx_dma = BFE_ADDR_LO(ctx.bfe_busaddr); 305119917Swpaul 306181953Syongari error = bus_dmamem_alloc(sc->bfe_rx_tag, (void *)&sc->bfe_rx_list, 307181953Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->bfe_rx_map); 308181953Syongari if (error != 0) { 309181953Syongari device_printf(sc->bfe_dev, 310181953Syongari "cannot allocate DMA'able memory for Rx ring.\n"); 311181953Syongari goto fail; 312119917Swpaul } 313181953Syongari ctx.bfe_busaddr = 0; 314181953Syongari error = bus_dmamap_load(sc->bfe_rx_tag, sc->bfe_rx_map, 315181953Syongari sc->bfe_rx_list, BFE_RX_LIST_SIZE, bfe_dma_map, &ctx, 316181953Syongari BUS_DMA_NOWAIT); 317181953Syongari if (error != 0 || ctx.bfe_busaddr == 0) { 318181953Syongari device_printf(sc->bfe_dev, 319181953Syongari "cannot load DMA'able memory for Rx ring.\n"); 320181953Syongari goto fail; 321181953Syongari } 322181953Syongari sc->bfe_rx_dma = BFE_ADDR_LO(ctx.bfe_busaddr); 323119917Swpaul 324181953Syongari /* Create DMA maps for Tx buffers. */ 325181953Syongari for (i = 0; i < BFE_TX_LIST_CNT; i++) { 326181953Syongari td = &sc->bfe_tx_ring[i]; 327181953Syongari td->bfe_mbuf = NULL; 328181953Syongari td->bfe_map = NULL; 329181953Syongari error = bus_dmamap_create(sc->bfe_txmbuf_tag, 0, &td->bfe_map); 330181953Syongari if (error != 0) { 331181953Syongari device_printf(sc->bfe_dev, 332181953Syongari "cannot create DMA map for Tx.\n"); 333181953Syongari goto fail; 334119917Swpaul } 335119917Swpaul } 336119917Swpaul 337181953Syongari /* Create spare DMA map for Rx buffers. */ 338181953Syongari error = bus_dmamap_create(sc->bfe_rxmbuf_tag, 0, &sc->bfe_rx_sparemap); 339181953Syongari if (error != 0) { 340181953Syongari device_printf(sc->bfe_dev, "cannot create spare DMA map for Rx.\n"); 341181953Syongari goto fail; 342181953Syongari } 343181953Syongari /* Create DMA maps for Rx buffers. */ 344181953Syongari for (i = 0; i < BFE_RX_LIST_CNT; i++) { 345181953Syongari rd = &sc->bfe_rx_ring[i]; 346181953Syongari rd->bfe_mbuf = NULL; 347181953Syongari rd->bfe_map = NULL; 348181953Syongari rd->bfe_ctrl = 0; 349181953Syongari error = bus_dmamap_create(sc->bfe_rxmbuf_tag, 0, &rd->bfe_map); 350181953Syongari if (error != 0) { 351181953Syongari device_printf(sc->bfe_dev, 352181953Syongari "cannot create DMA map for Rx.\n"); 353181953Syongari goto fail; 354119917Swpaul } 355119917Swpaul } 356119917Swpaul 357181953Syongarifail: 358181953Syongari return (error); 359181953Syongari} 360119917Swpaul 361181953Syongaristatic void 362181953Syongaribfe_dma_free(struct bfe_softc *sc) 363181953Syongari{ 364181953Syongari struct bfe_tx_data *td; 365181953Syongari struct bfe_rx_data *rd; 366181953Syongari int i; 367119917Swpaul 368181953Syongari /* Tx ring. */ 369181953Syongari if (sc->bfe_tx_tag != NULL) { 370181953Syongari if (sc->bfe_tx_map != NULL) 371181953Syongari bus_dmamap_unload(sc->bfe_tx_tag, sc->bfe_tx_map); 372181953Syongari if (sc->bfe_tx_map != NULL && sc->bfe_tx_list != NULL) 373181953Syongari bus_dmamem_free(sc->bfe_tx_tag, sc->bfe_tx_list, 374181953Syongari sc->bfe_tx_map); 375181953Syongari sc->bfe_tx_map = NULL; 376181953Syongari sc->bfe_tx_list = NULL; 377181953Syongari bus_dma_tag_destroy(sc->bfe_tx_tag); 378181953Syongari sc->bfe_tx_tag = NULL; 379181953Syongari } 380119917Swpaul 381181953Syongari /* Rx ring. */ 382181953Syongari if (sc->bfe_rx_tag != NULL) { 383181953Syongari if (sc->bfe_rx_map != NULL) 384181953Syongari bus_dmamap_unload(sc->bfe_rx_tag, sc->bfe_rx_map); 385181953Syongari if (sc->bfe_rx_map != NULL && sc->bfe_rx_list != NULL) 386181953Syongari bus_dmamem_free(sc->bfe_rx_tag, sc->bfe_rx_list, 387181953Syongari sc->bfe_rx_map); 388181953Syongari sc->bfe_rx_map = NULL; 389181953Syongari sc->bfe_rx_list = NULL; 390181953Syongari bus_dma_tag_destroy(sc->bfe_rx_tag); 391181953Syongari sc->bfe_rx_tag = NULL; 392181953Syongari } 393119917Swpaul 394181953Syongari /* Tx buffers. */ 395181953Syongari if (sc->bfe_txmbuf_tag != NULL) { 396181953Syongari for (i = 0; i < BFE_TX_LIST_CNT; i++) { 397181953Syongari td = &sc->bfe_tx_ring[i]; 398181953Syongari if (td->bfe_map != NULL) { 399181953Syongari bus_dmamap_destroy(sc->bfe_txmbuf_tag, 400181953Syongari td->bfe_map); 401181953Syongari td->bfe_map = NULL; 402181953Syongari } 403181953Syongari } 404181953Syongari bus_dma_tag_destroy(sc->bfe_txmbuf_tag); 405181953Syongari sc->bfe_txmbuf_tag = NULL; 406181953Syongari } 407119917Swpaul 408181953Syongari /* Rx buffers. */ 409181953Syongari if (sc->bfe_rxmbuf_tag != NULL) { 410181953Syongari for (i = 0; i < BFE_RX_LIST_CNT; i++) { 411181953Syongari rd = &sc->bfe_rx_ring[i]; 412181953Syongari if (rd->bfe_map != NULL) { 413181953Syongari bus_dmamap_destroy(sc->bfe_rxmbuf_tag, 414181953Syongari rd->bfe_map); 415181953Syongari rd->bfe_map = NULL; 416181953Syongari } 417181953Syongari } 418181953Syongari if (sc->bfe_rx_sparemap != NULL) { 419181953Syongari bus_dmamap_destroy(sc->bfe_rxmbuf_tag, 420181953Syongari sc->bfe_rx_sparemap); 421181953Syongari sc->bfe_rx_sparemap = NULL; 422181953Syongari } 423181953Syongari bus_dma_tag_destroy(sc->bfe_rxmbuf_tag); 424181953Syongari sc->bfe_rxmbuf_tag = NULL; 425181953Syongari } 426119917Swpaul 427181953Syongari if (sc->bfe_parent_tag != NULL) { 428181953Syongari bus_dma_tag_destroy(sc->bfe_parent_tag); 429181953Syongari sc->bfe_parent_tag = NULL; 430181953Syongari } 431119917Swpaul} 432119917Swpaul 433119917Swpaulstatic int 434119917Swpaulbfe_attach(device_t dev) 435119917Swpaul{ 436147256Sbrooks struct ifnet *ifp = NULL; 437119917Swpaul struct bfe_softc *sc; 438180950Syongari int error = 0, rid; 439119917Swpaul 440119917Swpaul sc = device_get_softc(dev); 441119917Swpaul mtx_init(&sc->bfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 442136804Smtm MTX_DEF); 443175787Syongari callout_init_mtx(&sc->bfe_stat_co, &sc->bfe_mtx, 0); 444119917Swpaul 445119917Swpaul sc->bfe_dev = dev; 446119917Swpaul 447119917Swpaul /* 448119917Swpaul * Map control/status registers. 449119917Swpaul */ 450119917Swpaul pci_enable_busmaster(dev); 451119917Swpaul 452181953Syongari rid = PCIR_BAR(0); 453127135Snjl sc->bfe_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 454119917Swpaul RF_ACTIVE); 455119917Swpaul if (sc->bfe_res == NULL) { 456180950Syongari device_printf(dev, "couldn't map memory\n"); 457119917Swpaul error = ENXIO; 458119917Swpaul goto fail; 459119917Swpaul } 460119917Swpaul 461119917Swpaul /* Allocate interrupt */ 462119917Swpaul rid = 0; 463119917Swpaul 464127135Snjl sc->bfe_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 465119917Swpaul RF_SHAREABLE | RF_ACTIVE); 466119917Swpaul if (sc->bfe_irq == NULL) { 467180950Syongari device_printf(dev, "couldn't map interrupt\n"); 468119917Swpaul error = ENXIO; 469119917Swpaul goto fail; 470119917Swpaul } 471119917Swpaul 472181953Syongari if (bfe_dma_alloc(sc) != 0) { 473180950Syongari device_printf(dev, "failed to allocate DMA resources\n"); 474119917Swpaul error = ENXIO; 475119917Swpaul goto fail; 476119917Swpaul } 477119917Swpaul 478181994Syongari SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 479181994Syongari SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 480181994Syongari "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, sysctl_bfe_stats, 481181994Syongari "I", "Statistics"); 482181994Syongari 483119917Swpaul /* Set up ifnet structure */ 484147256Sbrooks ifp = sc->bfe_ifp = if_alloc(IFT_ETHER); 485147256Sbrooks if (ifp == NULL) { 486180950Syongari device_printf(dev, "failed to if_alloc()\n"); 487147256Sbrooks error = ENOSPC; 488147256Sbrooks goto fail; 489147256Sbrooks } 490119917Swpaul ifp->if_softc = sc; 491121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 492119917Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 493119917Swpaul ifp->if_ioctl = bfe_ioctl; 494119917Swpaul ifp->if_start = bfe_start; 495119917Swpaul ifp->if_init = bfe_init; 496119917Swpaul ifp->if_mtu = ETHERMTU; 497131455Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, BFE_TX_QLEN); 498131455Smlaier ifp->if_snd.ifq_drv_maxlen = BFE_TX_QLEN; 499131455Smlaier IFQ_SET_READY(&ifp->if_snd); 500119917Swpaul 501119917Swpaul bfe_get_config(sc); 502119917Swpaul 503119917Swpaul /* Reset the chip and turn on the PHY */ 504136804Smtm BFE_LOCK(sc); 505119917Swpaul bfe_chip_reset(sc); 506136804Smtm BFE_UNLOCK(sc); 507119917Swpaul 508119917Swpaul if (mii_phy_probe(dev, &sc->bfe_miibus, 509119917Swpaul bfe_ifmedia_upd, bfe_ifmedia_sts)) { 510180950Syongari device_printf(dev, "MII without any PHY!\n"); 511119917Swpaul error = ENXIO; 512119917Swpaul goto fail; 513119917Swpaul } 514119917Swpaul 515147256Sbrooks ether_ifattach(ifp, sc->bfe_enaddr); 516119917Swpaul 517119917Swpaul /* 518129708Sdes * Tell the upper layer(s) we support long frames. 519129708Sdes */ 520129708Sdes ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 521129708Sdes ifp->if_capabilities |= IFCAP_VLAN_MTU; 522129709Sdes ifp->if_capenable |= IFCAP_VLAN_MTU; 523129708Sdes 524129708Sdes /* 525119917Swpaul * Hook interrupt last to avoid having to lock softc 526119917Swpaul */ 527136804Smtm error = bus_setup_intr(dev, sc->bfe_irq, INTR_TYPE_NET | INTR_MPSAFE, 528166901Spiso NULL, bfe_intr, sc, &sc->bfe_intrhand); 529119917Swpaul 530119917Swpaul if (error) { 531180950Syongari device_printf(dev, "couldn't set up irq\n"); 532119917Swpaul goto fail; 533119917Swpaul } 534119917Swpaulfail: 535181953Syongari if (error != 0) 536181953Syongari bfe_detach(dev); 537133282Sdes return (error); 538119917Swpaul} 539119917Swpaul 540119917Swpaulstatic int 541119917Swpaulbfe_detach(device_t dev) 542119917Swpaul{ 543119917Swpaul struct bfe_softc *sc; 544119917Swpaul struct ifnet *ifp; 545119917Swpaul 546119917Swpaul sc = device_get_softc(dev); 547119917Swpaul 548147256Sbrooks ifp = sc->bfe_ifp; 549119917Swpaul 550119917Swpaul if (device_is_attached(dev)) { 551175787Syongari BFE_LOCK(sc); 552181976Syongari sc->bfe_flags |= BFE_FLAG_DETACH; 553119917Swpaul bfe_stop(sc); 554175787Syongari BFE_UNLOCK(sc); 555175787Syongari callout_drain(&sc->bfe_stat_co); 556175787Syongari if (ifp != NULL) 557175787Syongari ether_ifdetach(ifp); 558119917Swpaul } 559119917Swpaul 560181953Syongari BFE_LOCK(sc); 561119917Swpaul bfe_chip_reset(sc); 562181953Syongari BFE_UNLOCK(sc); 563119917Swpaul 564119917Swpaul bus_generic_detach(dev); 565180954Syongari if (sc->bfe_miibus != NULL) 566119917Swpaul device_delete_child(dev, sc->bfe_miibus); 567119917Swpaul 568119917Swpaul bfe_release_resources(sc); 569181953Syongari bfe_dma_free(sc); 570119917Swpaul mtx_destroy(&sc->bfe_mtx); 571119917Swpaul 572133282Sdes return (0); 573119917Swpaul} 574119917Swpaul 575119917Swpaul/* 576119917Swpaul * Stop all chip I/O so that the kernel's probe routines don't 577119917Swpaul * get confused by errant DMAs when rebooting. 578119917Swpaul */ 579173839Syongaristatic int 580119917Swpaulbfe_shutdown(device_t dev) 581119917Swpaul{ 582119917Swpaul struct bfe_softc *sc; 583119917Swpaul 584119917Swpaul sc = device_get_softc(dev); 585119917Swpaul BFE_LOCK(sc); 586133282Sdes bfe_stop(sc); 587119917Swpaul 588119917Swpaul BFE_UNLOCK(sc); 589173839Syongari 590173839Syongari return (0); 591119917Swpaul} 592119917Swpaul 593119917Swpaulstatic int 594164456Sjhbbfe_suspend(device_t dev) 595164456Sjhb{ 596164456Sjhb struct bfe_softc *sc; 597164456Sjhb 598164456Sjhb sc = device_get_softc(dev); 599164456Sjhb BFE_LOCK(sc); 600164456Sjhb bfe_stop(sc); 601164456Sjhb BFE_UNLOCK(sc); 602164456Sjhb 603164456Sjhb return (0); 604164456Sjhb} 605164456Sjhb 606164456Sjhbstatic int 607164456Sjhbbfe_resume(device_t dev) 608164456Sjhb{ 609164456Sjhb struct bfe_softc *sc; 610164456Sjhb struct ifnet *ifp; 611164456Sjhb 612164456Sjhb sc = device_get_softc(dev); 613164456Sjhb ifp = sc->bfe_ifp; 614164456Sjhb BFE_LOCK(sc); 615164456Sjhb bfe_chip_reset(sc); 616164456Sjhb if (ifp->if_flags & IFF_UP) { 617164456Sjhb bfe_init_locked(sc); 618164456Sjhb if (ifp->if_drv_flags & IFF_DRV_RUNNING && 619164456Sjhb !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 620164456Sjhb bfe_start_locked(ifp); 621164456Sjhb } 622164456Sjhb BFE_UNLOCK(sc); 623164456Sjhb 624164456Sjhb return (0); 625164456Sjhb} 626164456Sjhb 627164456Sjhbstatic int 628119917Swpaulbfe_miibus_readreg(device_t dev, int phy, int reg) 629119917Swpaul{ 630119917Swpaul struct bfe_softc *sc; 631119917Swpaul u_int32_t ret; 632119917Swpaul 633119917Swpaul sc = device_get_softc(dev); 634180954Syongari if (phy != sc->bfe_phyaddr) 635133282Sdes return (0); 636119917Swpaul bfe_readphy(sc, reg, &ret); 637119917Swpaul 638133282Sdes return (ret); 639119917Swpaul} 640119917Swpaul 641119917Swpaulstatic int 642119917Swpaulbfe_miibus_writereg(device_t dev, int phy, int reg, int val) 643119917Swpaul{ 644119917Swpaul struct bfe_softc *sc; 645119917Swpaul 646119917Swpaul sc = device_get_softc(dev); 647180954Syongari if (phy != sc->bfe_phyaddr) 648133282Sdes return (0); 649133282Sdes bfe_writephy(sc, reg, val); 650119917Swpaul 651133282Sdes return (0); 652119917Swpaul} 653119917Swpaul 654119917Swpaulstatic void 655119917Swpaulbfe_miibus_statchg(device_t dev) 656119917Swpaul{ 657175787Syongari struct bfe_softc *sc; 658175787Syongari struct mii_data *mii; 659175787Syongari u_int32_t val, flow; 660175787Syongari 661175787Syongari sc = device_get_softc(dev); 662175787Syongari mii = device_get_softc(sc->bfe_miibus); 663175787Syongari 664181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 665181976Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 666181976Syongari (IFM_ACTIVE | IFM_AVALID)) { 667181976Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 668181976Syongari case IFM_10_T: 669181976Syongari case IFM_100_TX: 670181976Syongari sc->bfe_flags |= BFE_FLAG_LINK; 671181976Syongari break; 672181976Syongari default: 673181976Syongari break; 674181976Syongari } 675181976Syongari } 676175787Syongari 677175787Syongari /* XXX Should stop Rx/Tx engine prior to touching MAC. */ 678175787Syongari val = CSR_READ_4(sc, BFE_TX_CTRL); 679175787Syongari val &= ~BFE_TX_DUPLEX; 680175787Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 681175787Syongari val |= BFE_TX_DUPLEX; 682175787Syongari flow = 0; 683175787Syongari#ifdef notyet 684175787Syongari flow = CSR_READ_4(sc, BFE_RXCONF); 685175787Syongari flow &= ~BFE_RXCONF_FLOW; 686175787Syongari if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 687175787Syongari IFM_ETH_RXPAUSE) != 0) 688175787Syongari flow |= BFE_RXCONF_FLOW; 689175787Syongari CSR_WRITE_4(sc, BFE_RXCONF, flow); 690175787Syongari /* 691175787Syongari * It seems that the hardware has Tx pause issues 692175787Syongari * so enable only Rx pause. 693175787Syongari */ 694175787Syongari flow = CSR_READ_4(sc, BFE_MAC_FLOW); 695175787Syongari flow &= ~BFE_FLOW_PAUSE_ENAB; 696175787Syongari CSR_WRITE_4(sc, BFE_MAC_FLOW, flow); 697175787Syongari#endif 698175787Syongari } 699175787Syongari CSR_WRITE_4(sc, BFE_TX_CTRL, val); 700119917Swpaul} 701119917Swpaul 702119917Swpaulstatic void 703119917Swpaulbfe_tx_ring_free(struct bfe_softc *sc) 704119917Swpaul{ 705126470Sjulian int i; 706133282Sdes 707126470Sjulian for(i = 0; i < BFE_TX_LIST_CNT; i++) { 708180954Syongari if (sc->bfe_tx_ring[i].bfe_mbuf != NULL) { 709181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, 710181953Syongari sc->bfe_tx_ring[i].bfe_map, BUS_DMASYNC_POSTWRITE); 711181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, 712181953Syongari sc->bfe_tx_ring[i].bfe_map); 713126470Sjulian m_freem(sc->bfe_tx_ring[i].bfe_mbuf); 714126470Sjulian sc->bfe_tx_ring[i].bfe_mbuf = NULL; 715126470Sjulian } 716126470Sjulian } 717126470Sjulian bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE); 718181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 719181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 720119917Swpaul} 721119917Swpaul 722119917Swpaulstatic void 723119917Swpaulbfe_rx_ring_free(struct bfe_softc *sc) 724119917Swpaul{ 725119917Swpaul int i; 726119917Swpaul 727119917Swpaul for (i = 0; i < BFE_RX_LIST_CNT; i++) { 728119917Swpaul if (sc->bfe_rx_ring[i].bfe_mbuf != NULL) { 729181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, 730181953Syongari sc->bfe_rx_ring[i].bfe_map, BUS_DMASYNC_POSTREAD); 731181953Syongari bus_dmamap_unload(sc->bfe_rxmbuf_tag, 732181953Syongari sc->bfe_rx_ring[i].bfe_map); 733119917Swpaul m_freem(sc->bfe_rx_ring[i].bfe_mbuf); 734119917Swpaul sc->bfe_rx_ring[i].bfe_mbuf = NULL; 735119917Swpaul } 736119917Swpaul } 737119917Swpaul bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE); 738181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 739181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 740119917Swpaul} 741119917Swpaul 742133282Sdesstatic int 743119917Swpaulbfe_list_rx_init(struct bfe_softc *sc) 744119917Swpaul{ 745181953Syongari struct bfe_rx_data *rd; 746119917Swpaul int i; 747119917Swpaul 748181953Syongari sc->bfe_rx_prod = sc->bfe_rx_cons = 0; 749181953Syongari bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE); 750181953Syongari for (i = 0; i < BFE_RX_LIST_CNT; i++) { 751181953Syongari rd = &sc->bfe_rx_ring[i]; 752181953Syongari rd->bfe_mbuf = NULL; 753181953Syongari rd->bfe_ctrl = 0; 754181953Syongari if (bfe_list_newbuf(sc, i) != 0) 755133282Sdes return (ENOBUFS); 756119917Swpaul } 757119917Swpaul 758181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 759181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 760119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_PTR, (i * sizeof(struct bfe_desc))); 761119917Swpaul 762133282Sdes return (0); 763119917Swpaul} 764119917Swpaul 765181953Syongaristatic void 766181953Syongaribfe_list_tx_init(struct bfe_softc *sc) 767181953Syongari{ 768181953Syongari int i; 769181953Syongari 770181953Syongari sc->bfe_tx_cnt = sc->bfe_tx_prod = sc->bfe_tx_cons = 0; 771181953Syongari bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE); 772181953Syongari for (i = 0; i < BFE_TX_LIST_CNT; i++) 773181953Syongari sc->bfe_tx_ring[i].bfe_mbuf = NULL; 774181953Syongari 775181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 776181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 777181953Syongari} 778181953Syongari 779181953Syongaristatic void 780181953Syongaribfe_discard_buf(struct bfe_softc *sc, int c) 781181953Syongari{ 782181953Syongari struct bfe_rx_data *r; 783181953Syongari struct bfe_desc *d; 784181953Syongari 785181953Syongari r = &sc->bfe_rx_ring[c]; 786181953Syongari d = &sc->bfe_rx_list[c]; 787181953Syongari d->bfe_ctrl = htole32(r->bfe_ctrl); 788181953Syongari} 789181953Syongari 790119917Swpaulstatic int 791181953Syongaribfe_list_newbuf(struct bfe_softc *sc, int c) 792119917Swpaul{ 793119917Swpaul struct bfe_rxheader *rx_header; 794119917Swpaul struct bfe_desc *d; 795181953Syongari struct bfe_rx_data *r; 796181953Syongari struct mbuf *m; 797181953Syongari bus_dma_segment_t segs[1]; 798181953Syongari bus_dmamap_t map; 799119917Swpaul u_int32_t ctrl; 800181953Syongari int nsegs; 801119917Swpaul 802181953Syongari m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 803181953Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 804119917Swpaul 805181953Syongari if (bus_dmamap_load_mbuf_sg(sc->bfe_rxmbuf_tag, sc->bfe_rx_sparemap, 806181953Syongari m, segs, &nsegs, 0) != 0) { 807181953Syongari m_freem(m); 808181953Syongari return (ENOBUFS); 809119917Swpaul } 810119917Swpaul 811181953Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 812181953Syongari r = &sc->bfe_rx_ring[c]; 813181953Syongari if (r->bfe_mbuf != NULL) { 814181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, r->bfe_map, 815181953Syongari BUS_DMASYNC_POSTREAD); 816181953Syongari bus_dmamap_unload(sc->bfe_rxmbuf_tag, r->bfe_map); 817181953Syongari } 818181953Syongari map = r->bfe_map; 819181953Syongari r->bfe_map = sc->bfe_rx_sparemap; 820181953Syongari sc->bfe_rx_sparemap = map; 821181953Syongari r->bfe_mbuf = m; 822181953Syongari 823119917Swpaul rx_header = mtod(m, struct bfe_rxheader *); 824119917Swpaul rx_header->len = 0; 825119917Swpaul rx_header->flags = 0; 826181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, r->bfe_map, BUS_DMASYNC_PREREAD); 827181953Syongari 828181953Syongari ctrl = segs[0].ds_len & BFE_DESC_LEN; 829181953Syongari KASSERT(ctrl > ETHER_MAX_LEN + 32, ("%s: buffer size too small(%d)!", 830181953Syongari __func__, ctrl)); 831181953Syongari if (c == BFE_RX_LIST_CNT - 1) 832181953Syongari ctrl |= BFE_DESC_EOT; 833181953Syongari r->bfe_ctrl = ctrl; 834119917Swpaul 835119917Swpaul d = &sc->bfe_rx_list[c]; 836181953Syongari d->bfe_ctrl = htole32(ctrl); 837181953Syongari /* The chip needs all addresses to be added to BFE_PCI_DMA. */ 838181953Syongari d->bfe_addr = htole32(BFE_ADDR_LO(segs[0].ds_addr) + BFE_PCI_DMA); 839119917Swpaul 840133282Sdes return (0); 841119917Swpaul} 842119917Swpaul 843119917Swpaulstatic void 844119917Swpaulbfe_get_config(struct bfe_softc *sc) 845119917Swpaul{ 846119917Swpaul u_int8_t eeprom[128]; 847119917Swpaul 848119917Swpaul bfe_read_eeprom(sc, eeprom); 849119917Swpaul 850147256Sbrooks sc->bfe_enaddr[0] = eeprom[79]; 851147256Sbrooks sc->bfe_enaddr[1] = eeprom[78]; 852147256Sbrooks sc->bfe_enaddr[2] = eeprom[81]; 853147256Sbrooks sc->bfe_enaddr[3] = eeprom[80]; 854147256Sbrooks sc->bfe_enaddr[4] = eeprom[83]; 855147256Sbrooks sc->bfe_enaddr[5] = eeprom[82]; 856119917Swpaul 857119917Swpaul sc->bfe_phyaddr = eeprom[90] & 0x1f; 858119917Swpaul sc->bfe_mdc_port = (eeprom[90] >> 14) & 0x1; 859119917Swpaul 860133282Sdes sc->bfe_core_unit = 0; 861119917Swpaul sc->bfe_dma_offset = BFE_PCI_DMA; 862119917Swpaul} 863119917Swpaul 864119917Swpaulstatic void 865119917Swpaulbfe_pci_setup(struct bfe_softc *sc, u_int32_t cores) 866119917Swpaul{ 867119917Swpaul u_int32_t bar_orig, pci_rev, val; 868119917Swpaul 869119917Swpaul bar_orig = pci_read_config(sc->bfe_dev, BFE_BAR0_WIN, 4); 870119917Swpaul pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, BFE_REG_PCI, 4); 871119917Swpaul pci_rev = CSR_READ_4(sc, BFE_SBIDHIGH) & BFE_RC_MASK; 872119917Swpaul 873119917Swpaul val = CSR_READ_4(sc, BFE_SBINTVEC); 874119917Swpaul val |= cores; 875119917Swpaul CSR_WRITE_4(sc, BFE_SBINTVEC, val); 876119917Swpaul 877119917Swpaul val = CSR_READ_4(sc, BFE_SSB_PCI_TRANS_2); 878119917Swpaul val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST; 879119917Swpaul CSR_WRITE_4(sc, BFE_SSB_PCI_TRANS_2, val); 880119917Swpaul 881119917Swpaul pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, bar_orig, 4); 882119917Swpaul} 883119917Swpaul 884133282Sdesstatic void 885119917Swpaulbfe_clear_stats(struct bfe_softc *sc) 886119917Swpaul{ 887181994Syongari uint32_t reg; 888119917Swpaul 889136804Smtm BFE_LOCK_ASSERT(sc); 890119917Swpaul 891119917Swpaul CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 892119917Swpaul for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) 893119917Swpaul CSR_READ_4(sc, reg); 894119917Swpaul for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) 895119917Swpaul CSR_READ_4(sc, reg); 896119917Swpaul} 897119917Swpaul 898133282Sdesstatic int 899119917Swpaulbfe_resetphy(struct bfe_softc *sc) 900119917Swpaul{ 901119917Swpaul u_int32_t val; 902119917Swpaul 903119917Swpaul bfe_writephy(sc, 0, BMCR_RESET); 904119917Swpaul DELAY(100); 905119917Swpaul bfe_readphy(sc, 0, &val); 906119917Swpaul if (val & BMCR_RESET) { 907180950Syongari device_printf(sc->bfe_dev, "PHY Reset would not complete.\n"); 908133282Sdes return (ENXIO); 909119917Swpaul } 910133282Sdes return (0); 911119917Swpaul} 912119917Swpaul 913119917Swpaulstatic void 914119917Swpaulbfe_chip_halt(struct bfe_softc *sc) 915119917Swpaul{ 916136804Smtm BFE_LOCK_ASSERT(sc); 917119917Swpaul /* disable interrupts - not that it actually does..*/ 918119917Swpaul CSR_WRITE_4(sc, BFE_IMASK, 0); 919119917Swpaul CSR_READ_4(sc, BFE_IMASK); 920119917Swpaul 921119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); 922119917Swpaul bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 200, 1); 923119917Swpaul 924119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); 925119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); 926119917Swpaul DELAY(10); 927119917Swpaul} 928119917Swpaul 929119917Swpaulstatic void 930119917Swpaulbfe_chip_reset(struct bfe_softc *sc) 931119917Swpaul{ 932133282Sdes u_int32_t val; 933119917Swpaul 934136804Smtm BFE_LOCK_ASSERT(sc); 935119917Swpaul 936119917Swpaul /* Set the interrupt vector for the enet core */ 937119917Swpaul bfe_pci_setup(sc, BFE_INTVEC_ENET0); 938119917Swpaul 939119917Swpaul /* is core up? */ 940126470Sjulian val = CSR_READ_4(sc, BFE_SBTMSLOW) & 941126470Sjulian (BFE_RESET | BFE_REJECT | BFE_CLOCK); 942119917Swpaul if (val == BFE_CLOCK) { 943119917Swpaul /* It is, so shut it down */ 944119917Swpaul CSR_WRITE_4(sc, BFE_RCV_LAZY, 0); 945119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); 946119917Swpaul bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 100, 1); 947119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); 948133282Sdes if (CSR_READ_4(sc, BFE_DMARX_STAT) & BFE_STAT_EMASK) 949126470Sjulian bfe_wait_bit(sc, BFE_DMARX_STAT, BFE_STAT_SIDLE, 950126470Sjulian 100, 0); 951119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); 952119917Swpaul } 953119917Swpaul 954119917Swpaul bfe_core_reset(sc); 955119917Swpaul bfe_clear_stats(sc); 956119917Swpaul 957119917Swpaul /* 958119917Swpaul * We want the phy registers to be accessible even when 959119917Swpaul * the driver is "downed" so initialize MDC preamble, frequency, 960119917Swpaul * and whether internal or external phy here. 961119917Swpaul */ 962119917Swpaul 963119917Swpaul /* 4402 has 62.5Mhz SB clock and internal phy */ 964119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d); 965119917Swpaul 966119917Swpaul /* Internal or external PHY? */ 967119917Swpaul val = CSR_READ_4(sc, BFE_DEVCTRL); 968180954Syongari if (!(val & BFE_IPP)) 969119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_EPSEL); 970180954Syongari else if (CSR_READ_4(sc, BFE_DEVCTRL) & BFE_EPR) { 971119917Swpaul BFE_AND(sc, BFE_DEVCTRL, ~BFE_EPR); 972119917Swpaul DELAY(100); 973119917Swpaul } 974119917Swpaul 975133282Sdes /* Enable CRC32 generation and set proper LED modes */ 976133282Sdes BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED); 977129602Sdmlb 978133282Sdes /* Reset or clear powerdown control bit */ 979133282Sdes BFE_AND(sc, BFE_MAC_CTRL, ~BFE_CTRL_PDOWN); 980129602Sdmlb 981133282Sdes CSR_WRITE_4(sc, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) & 982119917Swpaul BFE_LAZY_FC_MASK)); 983119917Swpaul 984133282Sdes /* 985126470Sjulian * We don't want lazy interrupts, so just send them at 986133282Sdes * the end of a frame, please 987119917Swpaul */ 988119917Swpaul BFE_OR(sc, BFE_RCV_LAZY, 0); 989119917Swpaul 990119917Swpaul /* Set max lengths, accounting for VLAN tags */ 991119917Swpaul CSR_WRITE_4(sc, BFE_RXMAXLEN, ETHER_MAX_LEN+32); 992119917Swpaul CSR_WRITE_4(sc, BFE_TXMAXLEN, ETHER_MAX_LEN+32); 993119917Swpaul 994119917Swpaul /* Set watermark XXX - magic */ 995119917Swpaul CSR_WRITE_4(sc, BFE_TX_WMARK, 56); 996119917Swpaul 997133282Sdes /* 998126470Sjulian * Initialise DMA channels 999133282Sdes * - not forgetting dma addresses need to be added to BFE_PCI_DMA 1000119917Swpaul */ 1001119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE); 1002119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_ADDR, sc->bfe_tx_dma + BFE_PCI_DMA); 1003119917Swpaul 1004133282Sdes CSR_WRITE_4(sc, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) | 1005119917Swpaul BFE_RX_CTRL_ENABLE); 1006119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_ADDR, sc->bfe_rx_dma + BFE_PCI_DMA); 1007119917Swpaul 1008119917Swpaul bfe_resetphy(sc); 1009119917Swpaul bfe_setupphy(sc); 1010119917Swpaul} 1011119917Swpaul 1012119917Swpaulstatic void 1013119917Swpaulbfe_core_disable(struct bfe_softc *sc) 1014119917Swpaul{ 1015180954Syongari if ((CSR_READ_4(sc, BFE_SBTMSLOW)) & BFE_RESET) 1016119917Swpaul return; 1017119917Swpaul 1018133282Sdes /* 1019126470Sjulian * Set reject, wait for it set, then wait for the core to stop 1020126470Sjulian * being busy, then set reset and reject and enable the clocks. 1021119917Swpaul */ 1022119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK)); 1023119917Swpaul bfe_wait_bit(sc, BFE_SBTMSLOW, BFE_REJECT, 1000, 0); 1024119917Swpaul bfe_wait_bit(sc, BFE_SBTMSHIGH, BFE_BUSY, 1000, 1); 1025119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | 1026119917Swpaul BFE_RESET)); 1027119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1028119917Swpaul DELAY(10); 1029119917Swpaul /* Leave reset and reject set */ 1030119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET)); 1031119917Swpaul DELAY(10); 1032119917Swpaul} 1033119917Swpaul 1034119917Swpaulstatic void 1035119917Swpaulbfe_core_reset(struct bfe_softc *sc) 1036119917Swpaul{ 1037119917Swpaul u_int32_t val; 1038119917Swpaul 1039119917Swpaul /* Disable the core */ 1040119917Swpaul bfe_core_disable(sc); 1041119917Swpaul 1042119917Swpaul /* and bring it back up */ 1043119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC)); 1044119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1045119917Swpaul DELAY(10); 1046119917Swpaul 1047119917Swpaul /* Chip bug, clear SERR, IB and TO if they are set. */ 1048119917Swpaul if (CSR_READ_4(sc, BFE_SBTMSHIGH) & BFE_SERR) 1049119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSHIGH, 0); 1050119917Swpaul val = CSR_READ_4(sc, BFE_SBIMSTATE); 1051119917Swpaul if (val & (BFE_IBE | BFE_TO)) 1052119917Swpaul CSR_WRITE_4(sc, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO)); 1053119917Swpaul 1054119917Swpaul /* Clear reset and allow it to move through the core */ 1055119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC)); 1056119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1057119917Swpaul DELAY(10); 1058119917Swpaul 1059119917Swpaul /* Leave the clock set */ 1060119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, BFE_CLOCK); 1061119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1062119917Swpaul DELAY(10); 1063119917Swpaul} 1064119917Swpaul 1065133282Sdesstatic void 1066119917Swpaulbfe_cam_write(struct bfe_softc *sc, u_char *data, int index) 1067119917Swpaul{ 1068119917Swpaul u_int32_t val; 1069119917Swpaul 1070119917Swpaul val = ((u_int32_t) data[2]) << 24; 1071119917Swpaul val |= ((u_int32_t) data[3]) << 16; 1072119917Swpaul val |= ((u_int32_t) data[4]) << 8; 1073119917Swpaul val |= ((u_int32_t) data[5]); 1074119917Swpaul CSR_WRITE_4(sc, BFE_CAM_DATA_LO, val); 1075119917Swpaul val = (BFE_CAM_HI_VALID | 1076119917Swpaul (((u_int32_t) data[0]) << 8) | 1077119917Swpaul (((u_int32_t) data[1]))); 1078119917Swpaul CSR_WRITE_4(sc, BFE_CAM_DATA_HI, val); 1079119917Swpaul CSR_WRITE_4(sc, BFE_CAM_CTRL, (BFE_CAM_WRITE | 1080129602Sdmlb ((u_int32_t) index << BFE_CAM_INDEX_SHIFT))); 1081119917Swpaul bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1); 1082119917Swpaul} 1083119917Swpaul 1084133282Sdesstatic void 1085119917Swpaulbfe_set_rx_mode(struct bfe_softc *sc) 1086119917Swpaul{ 1087147256Sbrooks struct ifnet *ifp = sc->bfe_ifp; 1088119917Swpaul struct ifmultiaddr *ifma; 1089119917Swpaul u_int32_t val; 1090119917Swpaul int i = 0; 1091119917Swpaul 1092181994Syongari BFE_LOCK_ASSERT(sc); 1093181994Syongari 1094119917Swpaul val = CSR_READ_4(sc, BFE_RXCONF); 1095119917Swpaul 1096119917Swpaul if (ifp->if_flags & IFF_PROMISC) 1097119917Swpaul val |= BFE_RXCONF_PROMISC; 1098119917Swpaul else 1099119917Swpaul val &= ~BFE_RXCONF_PROMISC; 1100119917Swpaul 1101119917Swpaul if (ifp->if_flags & IFF_BROADCAST) 1102119917Swpaul val &= ~BFE_RXCONF_DBCAST; 1103119917Swpaul else 1104119917Swpaul val |= BFE_RXCONF_DBCAST; 1105119917Swpaul 1106119917Swpaul 1107119917Swpaul CSR_WRITE_4(sc, BFE_CAM_CTRL, 0); 1108152315Sru bfe_cam_write(sc, IF_LLADDR(sc->bfe_ifp), i++); 1109119917Swpaul 1110119917Swpaul if (ifp->if_flags & IFF_ALLMULTI) 1111119917Swpaul val |= BFE_RXCONF_ALLMULTI; 1112119917Swpaul else { 1113119917Swpaul val &= ~BFE_RXCONF_ALLMULTI; 1114148654Srwatson IF_ADDR_LOCK(ifp); 1115119917Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1116119917Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 1117119917Swpaul continue; 1118126470Sjulian bfe_cam_write(sc, 1119126470Sjulian LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i++); 1120119917Swpaul } 1121148654Srwatson IF_ADDR_UNLOCK(ifp); 1122119917Swpaul } 1123119917Swpaul 1124119917Swpaul CSR_WRITE_4(sc, BFE_RXCONF, val); 1125119917Swpaul BFE_OR(sc, BFE_CAM_CTRL, BFE_CAM_ENABLE); 1126119917Swpaul} 1127119917Swpaul 1128119917Swpaulstatic void 1129119917Swpaulbfe_dma_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1130119917Swpaul{ 1131181953Syongari struct bfe_dmamap_arg *ctx; 1132119917Swpaul 1133181953Syongari if (error != 0) 1134181953Syongari return; 1135119917Swpaul 1136181953Syongari KASSERT(nseg == 1, ("%s : %d segments returned!", __func__, nseg)); 1137119917Swpaul 1138181953Syongari ctx = (struct bfe_dmamap_arg *)arg; 1139181953Syongari ctx->bfe_busaddr = segs[0].ds_addr; 1140119917Swpaul} 1141119917Swpaul 1142119917Swpaulstatic void 1143119917Swpaulbfe_release_resources(struct bfe_softc *sc) 1144119917Swpaul{ 1145119917Swpaul 1146119917Swpaul if (sc->bfe_intrhand != NULL) 1147181953Syongari bus_teardown_intr(sc->bfe_dev, sc->bfe_irq, sc->bfe_intrhand); 1148119917Swpaul 1149119917Swpaul if (sc->bfe_irq != NULL) 1150181953Syongari bus_release_resource(sc->bfe_dev, SYS_RES_IRQ, 0, sc->bfe_irq); 1151119917Swpaul 1152119917Swpaul if (sc->bfe_res != NULL) 1153181953Syongari bus_release_resource(sc->bfe_dev, SYS_RES_MEMORY, PCIR_BAR(0), 1154181953Syongari sc->bfe_res); 1155119917Swpaul 1156150215Sru if (sc->bfe_ifp != NULL) 1157150215Sru if_free(sc->bfe_ifp); 1158119917Swpaul} 1159119917Swpaul 1160119917Swpaulstatic void 1161119917Swpaulbfe_read_eeprom(struct bfe_softc *sc, u_int8_t *data) 1162119917Swpaul{ 1163119917Swpaul long i; 1164119917Swpaul u_int16_t *ptr = (u_int16_t *)data; 1165119917Swpaul 1166119917Swpaul for(i = 0; i < 128; i += 2) 1167119917Swpaul ptr[i/2] = CSR_READ_4(sc, 4096 + i); 1168119917Swpaul} 1169119917Swpaul 1170119917Swpaulstatic int 1171133282Sdesbfe_wait_bit(struct bfe_softc *sc, u_int32_t reg, u_int32_t bit, 1172119917Swpaul u_long timeout, const int clear) 1173119917Swpaul{ 1174119917Swpaul u_long i; 1175119917Swpaul 1176119917Swpaul for (i = 0; i < timeout; i++) { 1177119917Swpaul u_int32_t val = CSR_READ_4(sc, reg); 1178119917Swpaul 1179119917Swpaul if (clear && !(val & bit)) 1180119917Swpaul break; 1181119917Swpaul if (!clear && (val & bit)) 1182119917Swpaul break; 1183119917Swpaul DELAY(10); 1184119917Swpaul } 1185119917Swpaul if (i == timeout) { 1186180950Syongari device_printf(sc->bfe_dev, 1187180950Syongari "BUG! Timeout waiting for bit %08x of register " 1188180950Syongari "%x to %s.\n", bit, reg, (clear ? "clear" : "set")); 1189133282Sdes return (-1); 1190119917Swpaul } 1191133282Sdes return (0); 1192119917Swpaul} 1193119917Swpaul 1194119917Swpaulstatic int 1195119917Swpaulbfe_readphy(struct bfe_softc *sc, u_int32_t reg, u_int32_t *val) 1196119917Swpaul{ 1197133282Sdes int err; 1198119917Swpaul 1199119917Swpaul /* Clear MII ISR */ 1200119917Swpaul CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 1201119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 1202119917Swpaul (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) | 1203119917Swpaul (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | 1204119917Swpaul (reg << BFE_MDIO_RA_SHIFT) | 1205119917Swpaul (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT))); 1206119917Swpaul err = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); 1207119917Swpaul *val = CSR_READ_4(sc, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA; 1208119917Swpaul 1209133282Sdes return (err); 1210119917Swpaul} 1211119917Swpaul 1212119917Swpaulstatic int 1213119917Swpaulbfe_writephy(struct bfe_softc *sc, u_int32_t reg, u_int32_t val) 1214119917Swpaul{ 1215119917Swpaul int status; 1216119917Swpaul 1217119917Swpaul CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 1218119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 1219119917Swpaul (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) | 1220119917Swpaul (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | 1221119917Swpaul (reg << BFE_MDIO_RA_SHIFT) | 1222119917Swpaul (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) | 1223119917Swpaul (val & BFE_MDIO_DATA_DATA))); 1224119917Swpaul status = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); 1225119917Swpaul 1226133282Sdes return (status); 1227119917Swpaul} 1228119917Swpaul 1229133282Sdes/* 1230119917Swpaul * XXX - I think this is handled by the PHY driver, but it can't hurt to do it 1231119917Swpaul * twice 1232119917Swpaul */ 1233119917Swpaulstatic int 1234119917Swpaulbfe_setupphy(struct bfe_softc *sc) 1235119917Swpaul{ 1236119917Swpaul u_int32_t val; 1237119917Swpaul 1238119917Swpaul /* Enable activity LED */ 1239119917Swpaul bfe_readphy(sc, 26, &val); 1240133282Sdes bfe_writephy(sc, 26, val & 0x7fff); 1241119917Swpaul bfe_readphy(sc, 26, &val); 1242119917Swpaul 1243119917Swpaul /* Enable traffic meter LED mode */ 1244119917Swpaul bfe_readphy(sc, 27, &val); 1245119917Swpaul bfe_writephy(sc, 27, val | (1 << 6)); 1246119917Swpaul 1247133282Sdes return (0); 1248119917Swpaul} 1249119917Swpaul 1250133282Sdesstatic void 1251119917Swpaulbfe_stats_update(struct bfe_softc *sc) 1252119917Swpaul{ 1253181994Syongari struct bfe_hw_stats *stats; 1254181994Syongari struct ifnet *ifp; 1255181994Syongari uint32_t mib[BFE_MIB_CNT]; 1256181994Syongari uint32_t reg, *val; 1257119917Swpaul 1258181994Syongari BFE_LOCK_ASSERT(sc); 1259181994Syongari 1260181994Syongari val = mib; 1261181994Syongari CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 1262181994Syongari for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) 1263181994Syongari *val++ = CSR_READ_4(sc, reg); 1264181994Syongari for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) 1265181994Syongari *val++ = CSR_READ_4(sc, reg); 1266181994Syongari 1267181994Syongari ifp = sc->bfe_ifp; 1268181994Syongari stats = &sc->bfe_stats; 1269181994Syongari /* Tx stat. */ 1270181994Syongari stats->tx_good_octets += mib[MIB_TX_GOOD_O]; 1271181994Syongari stats->tx_good_frames += mib[MIB_TX_GOOD_P]; 1272181994Syongari stats->tx_octets += mib[MIB_TX_O]; 1273181994Syongari stats->tx_frames += mib[MIB_TX_P]; 1274181994Syongari stats->tx_bcast_frames += mib[MIB_TX_BCAST]; 1275181994Syongari stats->tx_mcast_frames += mib[MIB_TX_MCAST]; 1276181994Syongari stats->tx_pkts_64 += mib[MIB_TX_64]; 1277181994Syongari stats->tx_pkts_65_127 += mib[MIB_TX_65_127]; 1278181994Syongari stats->tx_pkts_128_255 += mib[MIB_TX_128_255]; 1279181994Syongari stats->tx_pkts_256_511 += mib[MIB_TX_256_511]; 1280181994Syongari stats->tx_pkts_512_1023 += mib[MIB_TX_512_1023]; 1281181994Syongari stats->tx_pkts_1024_max += mib[MIB_TX_1024_MAX]; 1282181994Syongari stats->tx_jabbers += mib[MIB_TX_JABBER]; 1283181994Syongari stats->tx_oversize_frames += mib[MIB_TX_OSIZE]; 1284181994Syongari stats->tx_frag_frames += mib[MIB_TX_FRAG]; 1285181994Syongari stats->tx_underruns += mib[MIB_TX_URUNS]; 1286181994Syongari stats->tx_colls += mib[MIB_TX_TCOLS]; 1287181994Syongari stats->tx_single_colls += mib[MIB_TX_SCOLS]; 1288181994Syongari stats->tx_multi_colls += mib[MIB_TX_MCOLS]; 1289181994Syongari stats->tx_excess_colls += mib[MIB_TX_ECOLS]; 1290181994Syongari stats->tx_late_colls += mib[MIB_TX_LCOLS]; 1291181994Syongari stats->tx_deferrals += mib[MIB_TX_DEFERED]; 1292181994Syongari stats->tx_carrier_losts += mib[MIB_TX_CLOST]; 1293181994Syongari stats->tx_pause_frames += mib[MIB_TX_PAUSE]; 1294181994Syongari /* Rx stat. */ 1295181994Syongari stats->rx_good_octets += mib[MIB_RX_GOOD_O]; 1296181994Syongari stats->rx_good_frames += mib[MIB_RX_GOOD_P]; 1297181994Syongari stats->rx_octets += mib[MIB_RX_O]; 1298181994Syongari stats->rx_frames += mib[MIB_RX_P]; 1299181994Syongari stats->rx_bcast_frames += mib[MIB_RX_BCAST]; 1300181994Syongari stats->rx_mcast_frames += mib[MIB_RX_MCAST]; 1301181994Syongari stats->rx_pkts_64 += mib[MIB_RX_64]; 1302181994Syongari stats->rx_pkts_65_127 += mib[MIB_RX_65_127]; 1303181994Syongari stats->rx_pkts_128_255 += mib[MIB_RX_128_255]; 1304181994Syongari stats->rx_pkts_256_511 += mib[MIB_RX_256_511]; 1305181994Syongari stats->rx_pkts_512_1023 += mib[MIB_RX_512_1023]; 1306181994Syongari stats->rx_pkts_1024_max += mib[MIB_RX_1024_MAX]; 1307181994Syongari stats->rx_jabbers += mib[MIB_RX_JABBER]; 1308181994Syongari stats->rx_oversize_frames += mib[MIB_RX_OSIZE]; 1309181994Syongari stats->rx_frag_frames += mib[MIB_RX_FRAG]; 1310181994Syongari stats->rx_missed_frames += mib[MIB_RX_MISS]; 1311181994Syongari stats->rx_crc_align_errs += mib[MIB_RX_CRCA]; 1312181994Syongari stats->rx_runts += mib[MIB_RX_USIZE]; 1313181994Syongari stats->rx_crc_errs += mib[MIB_RX_CRC]; 1314181994Syongari stats->rx_align_errs += mib[MIB_RX_ALIGN]; 1315181994Syongari stats->rx_symbol_errs += mib[MIB_RX_SYM]; 1316181994Syongari stats->rx_pause_frames += mib[MIB_RX_PAUSE]; 1317181994Syongari stats->rx_control_frames += mib[MIB_RX_NPAUSE]; 1318181994Syongari 1319181994Syongari /* Update counters in ifnet. */ 1320181994Syongari ifp->if_opackets += (u_long)mib[MIB_TX_GOOD_P]; 1321181994Syongari ifp->if_collisions += (u_long)mib[MIB_TX_TCOLS]; 1322181994Syongari ifp->if_oerrors += (u_long)mib[MIB_TX_URUNS] + 1323181994Syongari (u_long)mib[MIB_TX_ECOLS] + 1324181994Syongari (u_long)mib[MIB_TX_DEFERED] + 1325181994Syongari (u_long)mib[MIB_TX_CLOST]; 1326181994Syongari 1327181994Syongari ifp->if_ipackets += (u_long)mib[MIB_RX_GOOD_P]; 1328181994Syongari 1329181994Syongari ifp->if_ierrors += mib[MIB_RX_JABBER] + 1330181994Syongari mib[MIB_RX_MISS] + 1331181994Syongari mib[MIB_RX_CRCA] + 1332181994Syongari mib[MIB_RX_USIZE] + 1333181994Syongari mib[MIB_RX_CRC] + 1334181994Syongari mib[MIB_RX_ALIGN] + 1335181994Syongari mib[MIB_RX_SYM]; 1336119917Swpaul} 1337119917Swpaul 1338119917Swpaulstatic void 1339119917Swpaulbfe_txeof(struct bfe_softc *sc) 1340119917Swpaul{ 1341181953Syongari struct bfe_tx_data *r; 1342119917Swpaul struct ifnet *ifp; 1343119917Swpaul int i, chipidx; 1344119917Swpaul 1345136804Smtm BFE_LOCK_ASSERT(sc); 1346119917Swpaul 1347147256Sbrooks ifp = sc->bfe_ifp; 1348119917Swpaul 1349119917Swpaul chipidx = CSR_READ_4(sc, BFE_DMATX_STAT) & BFE_STAT_CDMASK; 1350119917Swpaul chipidx /= sizeof(struct bfe_desc); 1351119917Swpaul 1352126470Sjulian i = sc->bfe_tx_cons; 1353181953Syongari if (i == chipidx) 1354181953Syongari return; 1355181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 1356181953Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1357119917Swpaul /* Go through the mbufs and free those that have been transmitted */ 1358181953Syongari for (; i != chipidx; BFE_INC(i, BFE_TX_LIST_CNT)) { 1359181953Syongari r = &sc->bfe_tx_ring[i]; 1360126470Sjulian sc->bfe_tx_cnt--; 1361181953Syongari if (r->bfe_mbuf == NULL) 1362181953Syongari continue; 1363181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, r->bfe_map, 1364181953Syongari BUS_DMASYNC_POSTWRITE); 1365181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, r->bfe_map); 1366181953Syongari 1367181953Syongari m_freem(r->bfe_mbuf); 1368181953Syongari r->bfe_mbuf = NULL; 1369119917Swpaul } 1370119917Swpaul 1371180954Syongari if (i != sc->bfe_tx_cons) { 1372119917Swpaul /* we freed up some mbufs */ 1373119917Swpaul sc->bfe_tx_cons = i; 1374148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1375119917Swpaul } 1376175787Syongari 1377175787Syongari if (sc->bfe_tx_cnt == 0) 1378175787Syongari sc->bfe_watchdog_timer = 0; 1379119917Swpaul} 1380119917Swpaul 1381119917Swpaul/* Pass a received packet up the stack */ 1382119917Swpaulstatic void 1383119917Swpaulbfe_rxeof(struct bfe_softc *sc) 1384119917Swpaul{ 1385119917Swpaul struct mbuf *m; 1386119917Swpaul struct ifnet *ifp; 1387119917Swpaul struct bfe_rxheader *rxheader; 1388181953Syongari struct bfe_rx_data *r; 1389181953Syongari int cons, prog; 1390119917Swpaul u_int32_t status, current, len, flags; 1391119917Swpaul 1392136804Smtm BFE_LOCK_ASSERT(sc); 1393119917Swpaul cons = sc->bfe_rx_cons; 1394119917Swpaul status = CSR_READ_4(sc, BFE_DMARX_STAT); 1395119917Swpaul current = (status & BFE_STAT_CDMASK) / sizeof(struct bfe_desc); 1396119917Swpaul 1397147256Sbrooks ifp = sc->bfe_ifp; 1398119917Swpaul 1399181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 1400181953Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1401181953Syongari 1402181953Syongari for (prog = 0; current != cons; prog++, 1403181953Syongari BFE_INC(cons, BFE_RX_LIST_CNT)) { 1404119917Swpaul r = &sc->bfe_rx_ring[cons]; 1405119917Swpaul m = r->bfe_mbuf; 1406181953Syongari /* 1407181953Syongari * Rx status should be read from mbuf such that we can't 1408181953Syongari * delay bus_dmamap_sync(9). This hardware limiation 1409181953Syongari * results in inefficent mbuf usage as bfe(4) couldn't 1410181953Syongari * reuse mapped buffer from errored frame. 1411181953Syongari */ 1412181953Syongari if (bfe_list_newbuf(sc, cons) != 0) { 1413181953Syongari ifp->if_iqdrops++; 1414181953Syongari bfe_discard_buf(sc, cons); 1415181953Syongari continue; 1416181953Syongari } 1417119917Swpaul rxheader = mtod(m, struct bfe_rxheader*); 1418181953Syongari len = le16toh(rxheader->len); 1419181953Syongari flags = le16toh(rxheader->flags); 1420119917Swpaul 1421181953Syongari /* Remove CRC bytes. */ 1422119917Swpaul len -= ETHER_CRC_LEN; 1423119917Swpaul 1424119917Swpaul /* flag an error and try again */ 1425119917Swpaul if ((len > ETHER_MAX_LEN+32) || (flags & BFE_RX_FLAG_ERRORS)) { 1426181953Syongari m_freem(m); 1427119917Swpaul continue; 1428119917Swpaul } 1429119917Swpaul 1430181953Syongari /* Make sure to skip header bytes written by hardware. */ 1431181953Syongari m_adj(m, BFE_RX_OFFSET); 1432181953Syongari m->m_len = m->m_pkthdr.len = len; 1433119917Swpaul 1434119917Swpaul m->m_pkthdr.rcvif = ifp; 1435122689Ssam BFE_UNLOCK(sc); 1436119917Swpaul (*ifp->if_input)(ifp, m); 1437122689Ssam BFE_LOCK(sc); 1438181953Syongari } 1439119917Swpaul 1440181953Syongari if (prog > 0) { 1441181953Syongari sc->bfe_rx_cons = cons; 1442181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 1443181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1444119917Swpaul } 1445119917Swpaul} 1446119917Swpaul 1447119917Swpaulstatic void 1448119917Swpaulbfe_intr(void *xsc) 1449119917Swpaul{ 1450119917Swpaul struct bfe_softc *sc = xsc; 1451119917Swpaul struct ifnet *ifp; 1452181994Syongari u_int32_t istat; 1453119917Swpaul 1454147256Sbrooks ifp = sc->bfe_ifp; 1455119917Swpaul 1456119917Swpaul BFE_LOCK(sc); 1457119917Swpaul 1458119917Swpaul istat = CSR_READ_4(sc, BFE_ISTAT); 1459119917Swpaul 1460133282Sdes /* 1461119917Swpaul * Defer unsolicited interrupts - This is necessary because setting the 1462119917Swpaul * chips interrupt mask register to 0 doesn't actually stop the 1463119917Swpaul * interrupts 1464119917Swpaul */ 1465181992Syongari istat &= BFE_IMASK_DEF; 1466119917Swpaul CSR_WRITE_4(sc, BFE_ISTAT, istat); 1467119917Swpaul CSR_READ_4(sc, BFE_ISTAT); 1468119917Swpaul 1469119917Swpaul /* not expecting this interrupt, disregard it */ 1470181992Syongari if (istat == 0 || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1471119917Swpaul BFE_UNLOCK(sc); 1472119917Swpaul return; 1473119917Swpaul } 1474119917Swpaul 1475181994Syongari /* A packet was received */ 1476181994Syongari if (istat & BFE_ISTAT_RX) 1477181994Syongari bfe_rxeof(sc); 1478181994Syongari 1479181994Syongari /* A packet was sent */ 1480181994Syongari if (istat & BFE_ISTAT_TX) 1481181994Syongari bfe_txeof(sc); 1482181994Syongari 1483180954Syongari if (istat & BFE_ISTAT_ERRORS) { 1484159013Ssilby 1485159013Ssilby if (istat & BFE_ISTAT_DSCE) { 1486180950Syongari device_printf(sc->bfe_dev, "Descriptor Error\n"); 1487159013Ssilby bfe_stop(sc); 1488159013Ssilby BFE_UNLOCK(sc); 1489159013Ssilby return; 1490159013Ssilby } 1491159013Ssilby 1492159013Ssilby if (istat & BFE_ISTAT_DPE) { 1493180950Syongari device_printf(sc->bfe_dev, 1494180950Syongari "Descriptor Protocol Error\n"); 1495159013Ssilby bfe_stop(sc); 1496159013Ssilby BFE_UNLOCK(sc); 1497159013Ssilby return; 1498159013Ssilby } 1499148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1500136804Smtm bfe_init_locked(sc); 1501119917Swpaul } 1502119917Swpaul 1503133282Sdes /* We have packets pending, fire them out */ 1504181992Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1505136804Smtm bfe_start_locked(ifp); 1506119917Swpaul 1507119917Swpaul BFE_UNLOCK(sc); 1508119917Swpaul} 1509119917Swpaul 1510119917Swpaulstatic int 1511181953Syongaribfe_encap(struct bfe_softc *sc, struct mbuf **m_head) 1512119917Swpaul{ 1513181953Syongari struct bfe_desc *d; 1514181953Syongari struct bfe_tx_data *r, *r1; 1515181953Syongari struct mbuf *m; 1516181953Syongari bus_dmamap_t map; 1517181953Syongari bus_dma_segment_t txsegs[BFE_MAXTXSEGS]; 1518181953Syongari uint32_t cur, si; 1519181953Syongari int error, i, nsegs; 1520119917Swpaul 1521181953Syongari BFE_LOCK_ASSERT(sc); 1522119917Swpaul 1523181953Syongari M_ASSERTPKTHDR((*m_head)); 1524119917Swpaul 1525181953Syongari si = cur = sc->bfe_tx_prod; 1526181953Syongari r = &sc->bfe_tx_ring[cur]; 1527181953Syongari error = bus_dmamap_load_mbuf_sg(sc->bfe_txmbuf_tag, r->bfe_map, *m_head, 1528181953Syongari txsegs, &nsegs, 0); 1529181953Syongari if (error == EFBIG) { 1530181953Syongari m = m_collapse(*m_head, M_DONTWAIT, BFE_MAXTXSEGS); 1531181953Syongari if (m == NULL) { 1532181953Syongari m_freem(*m_head); 1533181953Syongari *m_head = NULL; 1534181953Syongari return (ENOMEM); 1535181953Syongari } 1536158285Ssilby *m_head = m; 1537181953Syongari error = bus_dmamap_load_mbuf_sg(sc->bfe_txmbuf_tag, r->bfe_map, 1538181953Syongari *m_head, txsegs, &nsegs, 0); 1539181953Syongari if (error != 0) { 1540181953Syongari m_freem(*m_head); 1541181953Syongari *m_head = NULL; 1542181953Syongari return (error); 1543181953Syongari } 1544181953Syongari } else if (error != 0) 1545181953Syongari return (error); 1546181953Syongari if (nsegs == 0) { 1547181953Syongari m_freem(*m_head); 1548181953Syongari *m_head = NULL; 1549181953Syongari return (EIO); 1550119917Swpaul } 1551119917Swpaul 1552181953Syongari if (sc->bfe_tx_cnt + nsegs > BFE_TX_LIST_CNT - 1) { 1553181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, r->bfe_map); 1554181953Syongari return (ENOBUFS); 1555181953Syongari } 1556119917Swpaul 1557181953Syongari for (i = 0; i < nsegs; i++) { 1558181953Syongari d = &sc->bfe_tx_list[cur]; 1559181953Syongari d->bfe_ctrl = htole32(txsegs[i].ds_len & BFE_DESC_LEN); 1560181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_IOC); 1561181953Syongari if (cur == BFE_TX_LIST_CNT - 1) 1562181953Syongari /* 1563181953Syongari * Tell the chip to wrap to the start of 1564181953Syongari * the descriptor list. 1565181953Syongari */ 1566181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_EOT); 1567181953Syongari /* The chip needs all addresses to be added to BFE_PCI_DMA. */ 1568181953Syongari d->bfe_addr = htole32(BFE_ADDR_LO(txsegs[i].ds_addr) + 1569181953Syongari BFE_PCI_DMA); 1570181953Syongari BFE_INC(cur, BFE_TX_LIST_CNT); 1571181953Syongari } 1572119917Swpaul 1573181953Syongari /* Update producer index. */ 1574181953Syongari sc->bfe_tx_prod = cur; 1575119917Swpaul 1576181953Syongari /* Set EOF on the last descriptor. */ 1577181953Syongari cur = (cur + BFE_TX_LIST_CNT - 1) % BFE_TX_LIST_CNT; 1578181953Syongari d = &sc->bfe_tx_list[cur]; 1579181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_EOF); 1580119917Swpaul 1581181953Syongari /* Lastly set SOF on the first descriptor to avoid races. */ 1582181953Syongari d = &sc->bfe_tx_list[si]; 1583181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_SOF); 1584119917Swpaul 1585181953Syongari r1 = &sc->bfe_tx_ring[cur]; 1586181953Syongari map = r->bfe_map; 1587181953Syongari r->bfe_map = r1->bfe_map; 1588181953Syongari r1->bfe_map = map; 1589181953Syongari r1->bfe_mbuf = *m_head; 1590181953Syongari sc->bfe_tx_cnt += nsegs; 1591119917Swpaul 1592181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, map, BUS_DMASYNC_PREWRITE); 1593119917Swpaul 1594119917Swpaul return (0); 1595119917Swpaul} 1596119917Swpaul 1597119917Swpaul/* 1598136804Smtm * Set up to transmit a packet. 1599119917Swpaul */ 1600119917Swpaulstatic void 1601119917Swpaulbfe_start(struct ifnet *ifp) 1602119917Swpaul{ 1603136804Smtm BFE_LOCK((struct bfe_softc *)ifp->if_softc); 1604136804Smtm bfe_start_locked(ifp); 1605136804Smtm BFE_UNLOCK((struct bfe_softc *)ifp->if_softc); 1606136804Smtm} 1607136804Smtm 1608136804Smtm/* 1609136804Smtm * Set up to transmit a packet. The softc is already locked. 1610136804Smtm */ 1611136804Smtmstatic void 1612136804Smtmbfe_start_locked(struct ifnet *ifp) 1613136804Smtm{ 1614119917Swpaul struct bfe_softc *sc; 1615181953Syongari struct mbuf *m_head; 1616181953Syongari int queued; 1617119917Swpaul 1618119917Swpaul sc = ifp->if_softc; 1619119917Swpaul 1620136804Smtm BFE_LOCK_ASSERT(sc); 1621119917Swpaul 1622133282Sdes /* 1623126470Sjulian * Not much point trying to send if the link is down 1624126470Sjulian * or we have nothing to send. 1625119917Swpaul */ 1626175787Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1627181976Syongari IFF_DRV_RUNNING || (sc->bfe_flags & BFE_FLAG_LINK) == 0) 1628119917Swpaul return; 1629119917Swpaul 1630181953Syongari for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 1631181953Syongari sc->bfe_tx_cnt < BFE_TX_LIST_CNT - 1;) { 1632131455Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1633180954Syongari if (m_head == NULL) 1634119917Swpaul break; 1635119917Swpaul 1636133282Sdes /* 1637126470Sjulian * Pack the data into the tx ring. If we dont have 1638126470Sjulian * enough room, let the chip drain the ring. 1639119917Swpaul */ 1640181953Syongari if (bfe_encap(sc, &m_head)) { 1641181953Syongari if (m_head == NULL) 1642181953Syongari break; 1643131455Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1644148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1645119917Swpaul break; 1646119917Swpaul } 1647119917Swpaul 1648136269Smlaier queued++; 1649136269Smlaier 1650119917Swpaul /* 1651119917Swpaul * If there's a BPF listener, bounce a copy of this frame 1652119917Swpaul * to him. 1653119917Swpaul */ 1654119917Swpaul BPF_MTAP(ifp, m_head); 1655119917Swpaul } 1656119917Swpaul 1657136269Smlaier if (queued) { 1658181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 1659181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1660136269Smlaier /* Transmit - twice due to apparent hardware bug */ 1661181953Syongari CSR_WRITE_4(sc, BFE_DMATX_PTR, 1662181953Syongari sc->bfe_tx_prod * sizeof(struct bfe_desc)); 1663181953Syongari /* 1664181953Syongari * XXX It seems the following write is not necessary 1665181953Syongari * to kick Tx command. What might be required would be 1666181953Syongari * a way flushing PCI posted write. Reading the register 1667181953Syongari * back ensures the flush operation. In addition, 1668181953Syongari * hardware will execute PCI posted write in the long 1669181953Syongari * run and watchdog timer for the kick command was set 1670181953Syongari * to 5 seconds. Therefore I think the second write 1671181953Syongari * access is not necessary or could be replaced with 1672181953Syongari * read operation. 1673181953Syongari */ 1674181953Syongari CSR_WRITE_4(sc, BFE_DMATX_PTR, 1675181953Syongari sc->bfe_tx_prod * sizeof(struct bfe_desc)); 1676119917Swpaul 1677136269Smlaier /* 1678136269Smlaier * Set a timeout in case the chip goes out to lunch. 1679136269Smlaier */ 1680175787Syongari sc->bfe_watchdog_timer = 5; 1681136269Smlaier } 1682119917Swpaul} 1683119917Swpaul 1684119917Swpaulstatic void 1685119917Swpaulbfe_init(void *xsc) 1686119917Swpaul{ 1687136804Smtm BFE_LOCK((struct bfe_softc *)xsc); 1688136804Smtm bfe_init_locked(xsc); 1689136804Smtm BFE_UNLOCK((struct bfe_softc *)xsc); 1690136804Smtm} 1691136804Smtm 1692136804Smtmstatic void 1693136804Smtmbfe_init_locked(void *xsc) 1694136804Smtm{ 1695119917Swpaul struct bfe_softc *sc = (struct bfe_softc*)xsc; 1696147256Sbrooks struct ifnet *ifp = sc->bfe_ifp; 1697175787Syongari struct mii_data *mii; 1698119917Swpaul 1699136804Smtm BFE_LOCK_ASSERT(sc); 1700119917Swpaul 1701175787Syongari mii = device_get_softc(sc->bfe_miibus); 1702175787Syongari 1703148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1704119917Swpaul return; 1705119917Swpaul 1706119917Swpaul bfe_stop(sc); 1707119917Swpaul bfe_chip_reset(sc); 1708119917Swpaul 1709119917Swpaul if (bfe_list_rx_init(sc) == ENOBUFS) { 1710180950Syongari device_printf(sc->bfe_dev, 1711180950Syongari "%s: Not enough memory for list buffers\n", __func__); 1712119917Swpaul bfe_stop(sc); 1713119917Swpaul return; 1714119917Swpaul } 1715181953Syongari bfe_list_tx_init(sc); 1716119917Swpaul 1717119917Swpaul bfe_set_rx_mode(sc); 1718119917Swpaul 1719119917Swpaul /* Enable the chip and core */ 1720119917Swpaul BFE_OR(sc, BFE_ENET_CTRL, BFE_ENET_ENABLE); 1721119917Swpaul /* Enable interrupts */ 1722119917Swpaul CSR_WRITE_4(sc, BFE_IMASK, BFE_IMASK_DEF); 1723119917Swpaul 1724175787Syongari /* Clear link state and change media. */ 1725181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 1726175787Syongari mii_mediachg(mii); 1727175787Syongari 1728148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1729148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1730119917Swpaul 1731175787Syongari callout_reset(&sc->bfe_stat_co, hz, bfe_tick, sc); 1732119917Swpaul} 1733119917Swpaul 1734119917Swpaul/* 1735119917Swpaul * Set media options. 1736119917Swpaul */ 1737119917Swpaulstatic int 1738119917Swpaulbfe_ifmedia_upd(struct ifnet *ifp) 1739119917Swpaul{ 1740119917Swpaul struct bfe_softc *sc; 1741119917Swpaul struct mii_data *mii; 1742175787Syongari int error; 1743119917Swpaul 1744119917Swpaul sc = ifp->if_softc; 1745175787Syongari BFE_LOCK(sc); 1746119917Swpaul 1747119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1748119917Swpaul if (mii->mii_instance) { 1749119917Swpaul struct mii_softc *miisc; 1750119917Swpaul for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 1751119917Swpaul miisc = LIST_NEXT(miisc, mii_list)) 1752119917Swpaul mii_phy_reset(miisc); 1753119917Swpaul } 1754175787Syongari error = mii_mediachg(mii); 1755175787Syongari BFE_UNLOCK(sc); 1756119917Swpaul 1757175787Syongari return (error); 1758119917Swpaul} 1759119917Swpaul 1760119917Swpaul/* 1761119917Swpaul * Report current media status. 1762119917Swpaul */ 1763119917Swpaulstatic void 1764119917Swpaulbfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1765119917Swpaul{ 1766119917Swpaul struct bfe_softc *sc = ifp->if_softc; 1767119917Swpaul struct mii_data *mii; 1768119917Swpaul 1769175787Syongari BFE_LOCK(sc); 1770119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1771119917Swpaul mii_pollstat(mii); 1772119917Swpaul ifmr->ifm_active = mii->mii_media_active; 1773119917Swpaul ifmr->ifm_status = mii->mii_media_status; 1774175787Syongari BFE_UNLOCK(sc); 1775119917Swpaul} 1776119917Swpaul 1777119917Swpaulstatic int 1778119917Swpaulbfe_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1779119917Swpaul{ 1780119917Swpaul struct bfe_softc *sc = ifp->if_softc; 1781119917Swpaul struct ifreq *ifr = (struct ifreq *) data; 1782119917Swpaul struct mii_data *mii; 1783119917Swpaul int error = 0; 1784119917Swpaul 1785180954Syongari switch (command) { 1786180954Syongari case SIOCSIFFLAGS: 1787180954Syongari BFE_LOCK(sc); 1788181976Syongari if (ifp->if_flags & IFF_UP) { 1789180954Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1790119917Swpaul bfe_set_rx_mode(sc); 1791181976Syongari else if ((sc->bfe_flags & BFE_FLAG_DETACH) == 0) 1792180954Syongari bfe_init_locked(sc); 1793181976Syongari } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1794180954Syongari bfe_stop(sc); 1795180954Syongari BFE_UNLOCK(sc); 1796180954Syongari break; 1797180954Syongari case SIOCADDMULTI: 1798180954Syongari case SIOCDELMULTI: 1799180954Syongari BFE_LOCK(sc); 1800180954Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1801180954Syongari bfe_set_rx_mode(sc); 1802180954Syongari BFE_UNLOCK(sc); 1803180954Syongari break; 1804180954Syongari case SIOCGIFMEDIA: 1805180954Syongari case SIOCSIFMEDIA: 1806180954Syongari mii = device_get_softc(sc->bfe_miibus); 1807180954Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1808180954Syongari break; 1809180954Syongari default: 1810180954Syongari error = ether_ioctl(ifp, command, data); 1811180954Syongari break; 1812119917Swpaul } 1813119917Swpaul 1814133282Sdes return (error); 1815119917Swpaul} 1816119917Swpaul 1817119917Swpaulstatic void 1818175787Syongaribfe_watchdog(struct bfe_softc *sc) 1819119917Swpaul{ 1820175787Syongari struct ifnet *ifp; 1821119917Swpaul 1822175787Syongari BFE_LOCK_ASSERT(sc); 1823119917Swpaul 1824175787Syongari if (sc->bfe_watchdog_timer == 0 || --sc->bfe_watchdog_timer) 1825175787Syongari return; 1826119917Swpaul 1827175787Syongari ifp = sc->bfe_ifp; 1828175787Syongari 1829180950Syongari device_printf(sc->bfe_dev, "watchdog timeout -- resetting\n"); 1830119917Swpaul 1831175787Syongari ifp->if_oerrors++; 1832148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1833136804Smtm bfe_init_locked(sc); 1834119917Swpaul 1835175787Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1836175787Syongari bfe_start_locked(ifp); 1837119917Swpaul} 1838119917Swpaul 1839119917Swpaulstatic void 1840119917Swpaulbfe_tick(void *xsc) 1841119917Swpaul{ 1842119917Swpaul struct bfe_softc *sc = xsc; 1843119917Swpaul struct mii_data *mii; 1844119917Swpaul 1845175787Syongari BFE_LOCK_ASSERT(sc); 1846119917Swpaul 1847119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1848175787Syongari mii_tick(mii); 1849119917Swpaul bfe_stats_update(sc); 1850175787Syongari bfe_watchdog(sc); 1851175787Syongari callout_reset(&sc->bfe_stat_co, hz, bfe_tick, sc); 1852119917Swpaul} 1853119917Swpaul 1854119917Swpaul/* 1855119917Swpaul * Stop the adapter and free any mbufs allocated to the 1856119917Swpaul * RX and TX lists. 1857119917Swpaul */ 1858119917Swpaulstatic void 1859119917Swpaulbfe_stop(struct bfe_softc *sc) 1860119917Swpaul{ 1861119917Swpaul struct ifnet *ifp; 1862119917Swpaul 1863136804Smtm BFE_LOCK_ASSERT(sc); 1864119917Swpaul 1865147256Sbrooks ifp = sc->bfe_ifp; 1866175787Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1867181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 1868175787Syongari callout_stop(&sc->bfe_stat_co); 1869175787Syongari sc->bfe_watchdog_timer = 0; 1870119917Swpaul 1871119917Swpaul bfe_chip_halt(sc); 1872126470Sjulian bfe_tx_ring_free(sc); 1873119917Swpaul bfe_rx_ring_free(sc); 1874119917Swpaul} 1875181994Syongari 1876181994Syongaristatic int 1877181994Syongarisysctl_bfe_stats(SYSCTL_HANDLER_ARGS) 1878181994Syongari{ 1879181994Syongari struct bfe_softc *sc; 1880181994Syongari struct bfe_hw_stats *stats; 1881181994Syongari int error, result; 1882181994Syongari 1883181994Syongari result = -1; 1884181994Syongari error = sysctl_handle_int(oidp, &result, 0, req); 1885181994Syongari 1886181994Syongari if (error != 0 || req->newptr == NULL) 1887181994Syongari return (error); 1888181994Syongari 1889181994Syongari if (result != 1) 1890181994Syongari return (error); 1891181994Syongari 1892181994Syongari sc = (struct bfe_softc *)arg1; 1893181994Syongari stats = &sc->bfe_stats; 1894181994Syongari 1895181994Syongari printf("%s statistics:\n", device_get_nameunit(sc->bfe_dev)); 1896181994Syongari printf("Transmit good octets : %ju\n", 1897181994Syongari (uintmax_t)stats->tx_good_octets); 1898181994Syongari printf("Transmit good frames : %ju\n", 1899181994Syongari (uintmax_t)stats->tx_good_frames); 1900181994Syongari printf("Transmit octets : %ju\n", 1901181994Syongari (uintmax_t)stats->tx_octets); 1902181994Syongari printf("Transmit frames : %ju\n", 1903181994Syongari (uintmax_t)stats->tx_frames); 1904181994Syongari printf("Transmit broadcast frames : %ju\n", 1905181994Syongari (uintmax_t)stats->tx_bcast_frames); 1906181994Syongari printf("Transmit multicast frames : %ju\n", 1907181994Syongari (uintmax_t)stats->tx_mcast_frames); 1908181994Syongari printf("Transmit frames 64 bytes : %ju\n", 1909181994Syongari (uint64_t)stats->tx_pkts_64); 1910181994Syongari printf("Transmit frames 65 to 127 bytes : %ju\n", 1911181994Syongari (uint64_t)stats->tx_pkts_65_127); 1912181994Syongari printf("Transmit frames 128 to 255 bytes : %ju\n", 1913181994Syongari (uint64_t)stats->tx_pkts_128_255); 1914181994Syongari printf("Transmit frames 256 to 511 bytes : %ju\n", 1915181994Syongari (uint64_t)stats->tx_pkts_256_511); 1916181994Syongari printf("Transmit frames 512 to 1023 bytes : %ju\n", 1917181994Syongari (uint64_t)stats->tx_pkts_512_1023); 1918181994Syongari printf("Transmit frames 1024 to max bytes : %ju\n", 1919181994Syongari (uint64_t)stats->tx_pkts_1024_max); 1920181994Syongari printf("Transmit jabber errors : %u\n", stats->tx_jabbers); 1921181994Syongari printf("Transmit oversized frames : %ju\n", 1922181994Syongari (uint64_t)stats->tx_oversize_frames); 1923181994Syongari printf("Transmit fragmented frames : %ju\n", 1924181994Syongari (uint64_t)stats->tx_frag_frames); 1925181994Syongari printf("Transmit underruns : %u\n", stats->tx_colls); 1926181994Syongari printf("Transmit total collisions : %u\n", stats->tx_single_colls); 1927181994Syongari printf("Transmit single collisions : %u\n", stats->tx_single_colls); 1928181994Syongari printf("Transmit multiple collisions : %u\n", stats->tx_multi_colls); 1929181994Syongari printf("Transmit excess collisions : %u\n", stats->tx_excess_colls); 1930181994Syongari printf("Transmit late collisions : %u\n", stats->tx_late_colls); 1931181994Syongari printf("Transmit deferrals : %u\n", stats->tx_deferrals); 1932181994Syongari printf("Transmit carrier losts : %u\n", stats->tx_carrier_losts); 1933181994Syongari printf("Transmit pause frames : %u\n", stats->tx_pause_frames); 1934181994Syongari 1935181994Syongari printf("Receive good octets : %ju\n", 1936181994Syongari (uintmax_t)stats->rx_good_octets); 1937181994Syongari printf("Receive good frames : %ju\n", 1938181994Syongari (uintmax_t)stats->rx_good_frames); 1939181994Syongari printf("Receive octets : %ju\n", 1940181994Syongari (uintmax_t)stats->rx_octets); 1941181994Syongari printf("Receive frames : %ju\n", 1942181994Syongari (uintmax_t)stats->rx_frames); 1943181994Syongari printf("Receive broadcast frames : %ju\n", 1944181994Syongari (uintmax_t)stats->rx_bcast_frames); 1945181994Syongari printf("Receive multicast frames : %ju\n", 1946181994Syongari (uintmax_t)stats->rx_mcast_frames); 1947181994Syongari printf("Receive frames 64 bytes : %ju\n", 1948181994Syongari (uint64_t)stats->rx_pkts_64); 1949181994Syongari printf("Receive frames 65 to 127 bytes : %ju\n", 1950181994Syongari (uint64_t)stats->rx_pkts_65_127); 1951181994Syongari printf("Receive frames 128 to 255 bytes : %ju\n", 1952181994Syongari (uint64_t)stats->rx_pkts_128_255); 1953181994Syongari printf("Receive frames 256 to 511 bytes : %ju\n", 1954181994Syongari (uint64_t)stats->rx_pkts_256_511); 1955181994Syongari printf("Receive frames 512 to 1023 bytes : %ju\n", 1956181994Syongari (uint64_t)stats->rx_pkts_512_1023); 1957181994Syongari printf("Receive frames 1024 to max bytes : %ju\n", 1958181994Syongari (uint64_t)stats->rx_pkts_1024_max); 1959181994Syongari printf("Receive jabber errors : %u\n", stats->rx_jabbers); 1960181994Syongari printf("Receive oversized frames : %ju\n", 1961181994Syongari (uint64_t)stats->rx_oversize_frames); 1962181994Syongari printf("Receive fragmented frames : %ju\n", 1963181994Syongari (uint64_t)stats->rx_frag_frames); 1964181994Syongari printf("Receive missed frames : %u\n", stats->rx_missed_frames); 1965181994Syongari printf("Receive CRC align errors : %u\n", stats->rx_crc_align_errs); 1966181994Syongari printf("Receive undersized frames : %u\n", stats->rx_runts); 1967181994Syongari printf("Receive CRC errors : %u\n", stats->rx_crc_errs); 1968181994Syongari printf("Receive align errors : %u\n", stats->rx_align_errs); 1969181994Syongari printf("Receive symbol errors : %u\n", stats->rx_symbol_errs); 1970181994Syongari printf("Receive pause frames : %u\n", stats->rx_pause_frames); 1971181994Syongari printf("Receive control frames : %u\n", stats->rx_control_frames); 1972181994Syongari 1973181994Syongari return (error); 1974181994Syongari} 1975