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$"); 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> 46257176Sglebius#include <net/if_var.h> 47119917Swpaul#include <net/ethernet.h> 48119917Swpaul#include <net/if_dl.h> 49119917Swpaul#include <net/if_media.h> 50119917Swpaul#include <net/if_types.h> 51119917Swpaul#include <net/if_vlan_var.h> 52119917Swpaul 53119917Swpaul#include <dev/mii/mii.h> 54119917Swpaul#include <dev/mii/miivar.h> 55119917Swpaul 56119917Swpaul#include <dev/pci/pcireg.h> 57119917Swpaul#include <dev/pci/pcivar.h> 58119917Swpaul 59181953Syongari#include <machine/bus.h> 60181953Syongari 61119917Swpaul#include <dev/bfe/if_bfereg.h> 62119917Swpaul 63119917SwpaulMODULE_DEPEND(bfe, pci, 1, 1, 1); 64119917SwpaulMODULE_DEPEND(bfe, ether, 1, 1, 1); 65119917SwpaulMODULE_DEPEND(bfe, miibus, 1, 1, 1); 66119917Swpaul 67151545Simp/* "device miibus" required. See GENERIC if you get errors here. */ 68119917Swpaul#include "miibus_if.h" 69119917Swpaul 70119917Swpaul#define BFE_DEVDESC_MAX 64 /* Maximum device description length */ 71119917Swpaul 72119917Swpaulstatic struct bfe_type bfe_devs[] = { 73119917Swpaul { BCOM_VENDORID, BCOM_DEVICEID_BCM4401, 74119917Swpaul "Broadcom BCM4401 Fast Ethernet" }, 75134590Sdes { BCOM_VENDORID, BCOM_DEVICEID_BCM4401B0, 76134590Sdes "Broadcom BCM4401-B0 Fast Ethernet" }, 77119917Swpaul { 0, 0, NULL } 78119917Swpaul}; 79119917Swpaul 80119917Swpaulstatic int bfe_probe (device_t); 81119917Swpaulstatic int bfe_attach (device_t); 82119917Swpaulstatic int bfe_detach (device_t); 83164456Sjhbstatic int bfe_suspend (device_t); 84164456Sjhbstatic int bfe_resume (device_t); 85119917Swpaulstatic void bfe_release_resources (struct bfe_softc *); 86119917Swpaulstatic void bfe_intr (void *); 87181953Syongaristatic int bfe_encap (struct bfe_softc *, struct mbuf **); 88119917Swpaulstatic void bfe_start (struct ifnet *); 89136804Smtmstatic void bfe_start_locked (struct ifnet *); 90119917Swpaulstatic int bfe_ioctl (struct ifnet *, u_long, caddr_t); 91119917Swpaulstatic void bfe_init (void *); 92136804Smtmstatic void bfe_init_locked (void *); 93119917Swpaulstatic void bfe_stop (struct bfe_softc *); 94175787Syongaristatic void bfe_watchdog (struct bfe_softc *); 95173839Syongaristatic int bfe_shutdown (device_t); 96119917Swpaulstatic void bfe_tick (void *); 97119917Swpaulstatic void bfe_txeof (struct bfe_softc *); 98119917Swpaulstatic void bfe_rxeof (struct bfe_softc *); 99119917Swpaulstatic void bfe_set_rx_mode (struct bfe_softc *); 100119917Swpaulstatic int bfe_list_rx_init (struct bfe_softc *); 101181953Syongaristatic void bfe_list_tx_init (struct bfe_softc *); 102181953Syongaristatic void bfe_discard_buf (struct bfe_softc *, int); 103181953Syongaristatic int bfe_list_newbuf (struct bfe_softc *, int); 104119917Swpaulstatic void bfe_rx_ring_free (struct bfe_softc *); 105119917Swpaul 106119917Swpaulstatic void bfe_pci_setup (struct bfe_softc *, u_int32_t); 107119917Swpaulstatic int bfe_ifmedia_upd (struct ifnet *); 108119917Swpaulstatic void bfe_ifmedia_sts (struct ifnet *, struct ifmediareq *); 109119917Swpaulstatic int bfe_miibus_readreg (device_t, int, int); 110119917Swpaulstatic int bfe_miibus_writereg (device_t, int, int, int); 111119917Swpaulstatic void bfe_miibus_statchg (device_t); 112133282Sdesstatic int bfe_wait_bit (struct bfe_softc *, u_int32_t, u_int32_t, 113119917Swpaul u_long, const int); 114119917Swpaulstatic void bfe_get_config (struct bfe_softc *sc); 115119917Swpaulstatic void bfe_read_eeprom (struct bfe_softc *, u_int8_t *); 116119917Swpaulstatic void bfe_stats_update (struct bfe_softc *); 117119917Swpaulstatic void bfe_clear_stats (struct bfe_softc *); 118119917Swpaulstatic int bfe_readphy (struct bfe_softc *, u_int32_t, u_int32_t*); 119119917Swpaulstatic int bfe_writephy (struct bfe_softc *, u_int32_t, u_int32_t); 120119917Swpaulstatic int bfe_resetphy (struct bfe_softc *); 121119917Swpaulstatic int bfe_setupphy (struct bfe_softc *); 122119917Swpaulstatic void bfe_chip_reset (struct bfe_softc *); 123119917Swpaulstatic void bfe_chip_halt (struct bfe_softc *); 124119917Swpaulstatic void bfe_core_reset (struct bfe_softc *); 125119917Swpaulstatic void bfe_core_disable (struct bfe_softc *); 126181953Syongaristatic int bfe_dma_alloc (struct bfe_softc *); 127181953Syongaristatic void bfe_dma_free (struct bfe_softc *sc); 128119917Swpaulstatic void bfe_dma_map (void *, bus_dma_segment_t *, int, int); 129119917Swpaulstatic void bfe_cam_write (struct bfe_softc *, u_char *, int); 130181994Syongaristatic int sysctl_bfe_stats (SYSCTL_HANDLER_ARGS); 131119917Swpaul 132119917Swpaulstatic device_method_t bfe_methods[] = { 133119917Swpaul /* Device interface */ 134119917Swpaul DEVMETHOD(device_probe, bfe_probe), 135119917Swpaul DEVMETHOD(device_attach, bfe_attach), 136119917Swpaul DEVMETHOD(device_detach, bfe_detach), 137119917Swpaul DEVMETHOD(device_shutdown, bfe_shutdown), 138164456Sjhb DEVMETHOD(device_suspend, bfe_suspend), 139164456Sjhb DEVMETHOD(device_resume, bfe_resume), 140119917Swpaul 141119917Swpaul /* MII interface */ 142119917Swpaul DEVMETHOD(miibus_readreg, bfe_miibus_readreg), 143119917Swpaul DEVMETHOD(miibus_writereg, bfe_miibus_writereg), 144119917Swpaul DEVMETHOD(miibus_statchg, bfe_miibus_statchg), 145119917Swpaul 146227843Smarius DEVMETHOD_END 147119917Swpaul}; 148119917Swpaul 149119917Swpaulstatic driver_t bfe_driver = { 150119917Swpaul "bfe", 151119917Swpaul bfe_methods, 152119917Swpaul sizeof(struct bfe_softc) 153119917Swpaul}; 154119917Swpaul 155119917Swpaulstatic devclass_t bfe_devclass; 156119917Swpaul 157119917SwpaulDRIVER_MODULE(bfe, pci, bfe_driver, bfe_devclass, 0, 0); 158119917SwpaulDRIVER_MODULE(miibus, bfe, miibus_driver, miibus_devclass, 0, 0); 159119917Swpaul 160119917Swpaul/* 161133282Sdes * Probe for a Broadcom 4401 chip. 162119917Swpaul */ 163119917Swpaulstatic int 164119917Swpaulbfe_probe(device_t dev) 165119917Swpaul{ 166119917Swpaul struct bfe_type *t; 167119917Swpaul 168119917Swpaul t = bfe_devs; 169119917Swpaul 170180954Syongari while (t->bfe_name != NULL) { 171181556Syongari if (pci_get_vendor(dev) == t->bfe_vid && 172181556Syongari pci_get_device(dev) == t->bfe_did) { 173181557Syongari device_set_desc(dev, t->bfe_name); 174143163Simp return (BUS_PROBE_DEFAULT); 175119917Swpaul } 176119917Swpaul t++; 177119917Swpaul } 178119917Swpaul 179133282Sdes return (ENXIO); 180119917Swpaul} 181119917Swpaul 182181953Syongaristruct bfe_dmamap_arg { 183181953Syongari bus_addr_t bfe_busaddr; 184181953Syongari}; 185181953Syongari 186119917Swpaulstatic int 187181953Syongaribfe_dma_alloc(struct bfe_softc *sc) 188119917Swpaul{ 189181953Syongari struct bfe_dmamap_arg ctx; 190181953Syongari struct bfe_rx_data *rd; 191181953Syongari struct bfe_tx_data *td; 192119917Swpaul int error, i; 193119917Swpaul 194158075Sscottl /* 195158075Sscottl * parent tag. Apparently the chip cannot handle any DMA address 196158075Sscottl * greater than 1GB. 197158075Sscottl */ 198181953Syongari error = bus_dma_tag_create(bus_get_dma_tag(sc->bfe_dev), /* parent */ 199181953Syongari 1, 0, /* alignment, boundary */ 200181953Syongari BFE_DMA_MAXADDR, /* lowaddr */ 201181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 202181953Syongari NULL, NULL, /* filter, filterarg */ 203181953Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 204181953Syongari 0, /* nsegments */ 205181953Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 206181953Syongari 0, /* flags */ 207181953Syongari NULL, NULL, /* lockfunc, lockarg */ 208181953Syongari &sc->bfe_parent_tag); 209181953Syongari if (error != 0) { 210181953Syongari device_printf(sc->bfe_dev, "cannot create parent DMA tag.\n"); 211181953Syongari goto fail; 212181953Syongari } 213119917Swpaul 214181953Syongari /* Create tag for Tx ring. */ 215181953Syongari error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 216181953Syongari BFE_TX_RING_ALIGN, 0, /* alignment, boundary */ 217181953Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 218181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 219181953Syongari NULL, NULL, /* filter, filterarg */ 220181953Syongari BFE_TX_LIST_SIZE, /* maxsize */ 221181953Syongari 1, /* nsegments */ 222181953Syongari BFE_TX_LIST_SIZE, /* maxsegsize */ 223181953Syongari 0, /* flags */ 224181953Syongari NULL, NULL, /* lockfunc, lockarg */ 225181953Syongari &sc->bfe_tx_tag); 226181953Syongari if (error != 0) { 227181953Syongari device_printf(sc->bfe_dev, "cannot create Tx ring DMA tag.\n"); 228181953Syongari goto fail; 229181953Syongari } 230119917Swpaul 231181953Syongari /* Create tag for Rx ring. */ 232181953Syongari error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 233181953Syongari BFE_RX_RING_ALIGN, 0, /* alignment, boundary */ 234181953Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 235181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 236181953Syongari NULL, NULL, /* filter, filterarg */ 237181953Syongari BFE_RX_LIST_SIZE, /* maxsize */ 238181953Syongari 1, /* nsegments */ 239181953Syongari BFE_RX_LIST_SIZE, /* maxsegsize */ 240181953Syongari 0, /* flags */ 241181953Syongari NULL, NULL, /* lockfunc, lockarg */ 242181953Syongari &sc->bfe_rx_tag); 243181953Syongari if (error != 0) { 244181953Syongari device_printf(sc->bfe_dev, "cannot create Rx ring DMA tag.\n"); 245181953Syongari goto fail; 246119917Swpaul } 247119917Swpaul 248181953Syongari /* Create tag for Tx buffers. */ 249181953Syongari error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 250181953Syongari 1, 0, /* alignment, boundary */ 251181953Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 252181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 253181953Syongari NULL, NULL, /* filter, filterarg */ 254181953Syongari MCLBYTES * BFE_MAXTXSEGS, /* maxsize */ 255181953Syongari BFE_MAXTXSEGS, /* nsegments */ 256181953Syongari MCLBYTES, /* maxsegsize */ 257181953Syongari 0, /* flags */ 258181953Syongari NULL, NULL, /* lockfunc, lockarg */ 259181953Syongari &sc->bfe_txmbuf_tag); 260181953Syongari if (error != 0) { 261181953Syongari device_printf(sc->bfe_dev, 262181953Syongari "cannot create Tx buffer DMA tag.\n"); 263181953Syongari goto fail; 264181953Syongari } 265119917Swpaul 266181953Syongari /* Create tag for Rx buffers. */ 267181953Syongari error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 268181953Syongari 1, 0, /* alignment, boundary */ 269181953Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 270181953Syongari BUS_SPACE_MAXADDR, /* highaddr */ 271181953Syongari NULL, NULL, /* filter, filterarg */ 272181953Syongari MCLBYTES, /* maxsize */ 273181953Syongari 1, /* nsegments */ 274181953Syongari MCLBYTES, /* maxsegsize */ 275181953Syongari 0, /* flags */ 276181953Syongari NULL, NULL, /* lockfunc, lockarg */ 277181953Syongari &sc->bfe_rxmbuf_tag); 278181953Syongari if (error != 0) { 279181953Syongari device_printf(sc->bfe_dev, 280181953Syongari "cannot create Rx buffer DMA tag.\n"); 281181953Syongari goto fail; 282119917Swpaul } 283119917Swpaul 284181953Syongari /* Allocate DMA'able memory and load DMA map. */ 285181953Syongari error = bus_dmamem_alloc(sc->bfe_tx_tag, (void *)&sc->bfe_tx_list, 286181953Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->bfe_tx_map); 287181953Syongari if (error != 0) { 288181953Syongari device_printf(sc->bfe_dev, 289181953Syongari "cannot allocate DMA'able memory for Tx ring.\n"); 290181953Syongari goto fail; 291181953Syongari } 292181953Syongari ctx.bfe_busaddr = 0; 293181953Syongari error = bus_dmamap_load(sc->bfe_tx_tag, sc->bfe_tx_map, 294181953Syongari sc->bfe_tx_list, BFE_TX_LIST_SIZE, bfe_dma_map, &ctx, 295181953Syongari BUS_DMA_NOWAIT); 296181953Syongari if (error != 0 || ctx.bfe_busaddr == 0) { 297181953Syongari device_printf(sc->bfe_dev, 298181953Syongari "cannot load DMA'able memory for Tx ring.\n"); 299181953Syongari goto fail; 300181953Syongari } 301181953Syongari sc->bfe_tx_dma = BFE_ADDR_LO(ctx.bfe_busaddr); 302119917Swpaul 303181953Syongari error = bus_dmamem_alloc(sc->bfe_rx_tag, (void *)&sc->bfe_rx_list, 304181953Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->bfe_rx_map); 305181953Syongari if (error != 0) { 306181953Syongari device_printf(sc->bfe_dev, 307181953Syongari "cannot allocate DMA'able memory for Rx ring.\n"); 308181953Syongari goto fail; 309119917Swpaul } 310181953Syongari ctx.bfe_busaddr = 0; 311181953Syongari error = bus_dmamap_load(sc->bfe_rx_tag, sc->bfe_rx_map, 312181953Syongari sc->bfe_rx_list, BFE_RX_LIST_SIZE, bfe_dma_map, &ctx, 313181953Syongari BUS_DMA_NOWAIT); 314181953Syongari if (error != 0 || ctx.bfe_busaddr == 0) { 315181953Syongari device_printf(sc->bfe_dev, 316181953Syongari "cannot load DMA'able memory for Rx ring.\n"); 317181953Syongari goto fail; 318181953Syongari } 319181953Syongari sc->bfe_rx_dma = BFE_ADDR_LO(ctx.bfe_busaddr); 320119917Swpaul 321181953Syongari /* Create DMA maps for Tx buffers. */ 322181953Syongari for (i = 0; i < BFE_TX_LIST_CNT; i++) { 323181953Syongari td = &sc->bfe_tx_ring[i]; 324181953Syongari td->bfe_mbuf = NULL; 325181953Syongari td->bfe_map = NULL; 326181953Syongari error = bus_dmamap_create(sc->bfe_txmbuf_tag, 0, &td->bfe_map); 327181953Syongari if (error != 0) { 328181953Syongari device_printf(sc->bfe_dev, 329181953Syongari "cannot create DMA map for Tx.\n"); 330181953Syongari goto fail; 331119917Swpaul } 332119917Swpaul } 333119917Swpaul 334181953Syongari /* Create spare DMA map for Rx buffers. */ 335181953Syongari error = bus_dmamap_create(sc->bfe_rxmbuf_tag, 0, &sc->bfe_rx_sparemap); 336181953Syongari if (error != 0) { 337181953Syongari device_printf(sc->bfe_dev, "cannot create spare DMA map for Rx.\n"); 338181953Syongari goto fail; 339181953Syongari } 340181953Syongari /* Create DMA maps for Rx buffers. */ 341181953Syongari for (i = 0; i < BFE_RX_LIST_CNT; i++) { 342181953Syongari rd = &sc->bfe_rx_ring[i]; 343181953Syongari rd->bfe_mbuf = NULL; 344181953Syongari rd->bfe_map = NULL; 345181953Syongari rd->bfe_ctrl = 0; 346181953Syongari error = bus_dmamap_create(sc->bfe_rxmbuf_tag, 0, &rd->bfe_map); 347181953Syongari if (error != 0) { 348181953Syongari device_printf(sc->bfe_dev, 349181953Syongari "cannot create DMA map for Rx.\n"); 350181953Syongari goto fail; 351119917Swpaul } 352119917Swpaul } 353119917Swpaul 354181953Syongarifail: 355181953Syongari return (error); 356181953Syongari} 357119917Swpaul 358181953Syongaristatic void 359181953Syongaribfe_dma_free(struct bfe_softc *sc) 360181953Syongari{ 361181953Syongari struct bfe_tx_data *td; 362181953Syongari struct bfe_rx_data *rd; 363181953Syongari int i; 364119917Swpaul 365181953Syongari /* Tx ring. */ 366181953Syongari if (sc->bfe_tx_tag != NULL) { 367267363Sjhb if (sc->bfe_tx_dma != 0) 368181953Syongari bus_dmamap_unload(sc->bfe_tx_tag, sc->bfe_tx_map); 369267363Sjhb if (sc->bfe_tx_list != NULL) 370181953Syongari bus_dmamem_free(sc->bfe_tx_tag, sc->bfe_tx_list, 371181953Syongari sc->bfe_tx_map); 372267363Sjhb sc->bfe_tx_dma = 0; 373181953Syongari sc->bfe_tx_list = NULL; 374181953Syongari bus_dma_tag_destroy(sc->bfe_tx_tag); 375181953Syongari sc->bfe_tx_tag = NULL; 376181953Syongari } 377119917Swpaul 378181953Syongari /* Rx ring. */ 379181953Syongari if (sc->bfe_rx_tag != NULL) { 380267363Sjhb if (sc->bfe_rx_dma != 0) 381181953Syongari bus_dmamap_unload(sc->bfe_rx_tag, sc->bfe_rx_map); 382267363Sjhb if (sc->bfe_rx_list != NULL) 383181953Syongari bus_dmamem_free(sc->bfe_rx_tag, sc->bfe_rx_list, 384181953Syongari sc->bfe_rx_map); 385267363Sjhb sc->bfe_rx_dma = 0; 386181953Syongari sc->bfe_rx_list = NULL; 387181953Syongari bus_dma_tag_destroy(sc->bfe_rx_tag); 388181953Syongari sc->bfe_rx_tag = NULL; 389181953Syongari } 390119917Swpaul 391181953Syongari /* Tx buffers. */ 392181953Syongari if (sc->bfe_txmbuf_tag != NULL) { 393181953Syongari for (i = 0; i < BFE_TX_LIST_CNT; i++) { 394181953Syongari td = &sc->bfe_tx_ring[i]; 395181953Syongari if (td->bfe_map != NULL) { 396181953Syongari bus_dmamap_destroy(sc->bfe_txmbuf_tag, 397181953Syongari td->bfe_map); 398181953Syongari td->bfe_map = NULL; 399181953Syongari } 400181953Syongari } 401181953Syongari bus_dma_tag_destroy(sc->bfe_txmbuf_tag); 402181953Syongari sc->bfe_txmbuf_tag = NULL; 403181953Syongari } 404119917Swpaul 405181953Syongari /* Rx buffers. */ 406181953Syongari if (sc->bfe_rxmbuf_tag != NULL) { 407181953Syongari for (i = 0; i < BFE_RX_LIST_CNT; i++) { 408181953Syongari rd = &sc->bfe_rx_ring[i]; 409181953Syongari if (rd->bfe_map != NULL) { 410181953Syongari bus_dmamap_destroy(sc->bfe_rxmbuf_tag, 411181953Syongari rd->bfe_map); 412181953Syongari rd->bfe_map = NULL; 413181953Syongari } 414181953Syongari } 415181953Syongari if (sc->bfe_rx_sparemap != NULL) { 416181953Syongari bus_dmamap_destroy(sc->bfe_rxmbuf_tag, 417181953Syongari sc->bfe_rx_sparemap); 418181953Syongari sc->bfe_rx_sparemap = NULL; 419181953Syongari } 420181953Syongari bus_dma_tag_destroy(sc->bfe_rxmbuf_tag); 421181953Syongari sc->bfe_rxmbuf_tag = NULL; 422181953Syongari } 423119917Swpaul 424181953Syongari if (sc->bfe_parent_tag != NULL) { 425181953Syongari bus_dma_tag_destroy(sc->bfe_parent_tag); 426181953Syongari sc->bfe_parent_tag = NULL; 427181953Syongari } 428119917Swpaul} 429119917Swpaul 430119917Swpaulstatic int 431119917Swpaulbfe_attach(device_t dev) 432119917Swpaul{ 433147256Sbrooks struct ifnet *ifp = NULL; 434119917Swpaul struct bfe_softc *sc; 435180950Syongari int error = 0, rid; 436119917Swpaul 437119917Swpaul sc = device_get_softc(dev); 438119917Swpaul mtx_init(&sc->bfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 439136804Smtm MTX_DEF); 440175787Syongari callout_init_mtx(&sc->bfe_stat_co, &sc->bfe_mtx, 0); 441119917Swpaul 442119917Swpaul sc->bfe_dev = dev; 443119917Swpaul 444119917Swpaul /* 445119917Swpaul * Map control/status registers. 446119917Swpaul */ 447119917Swpaul pci_enable_busmaster(dev); 448119917Swpaul 449181953Syongari rid = PCIR_BAR(0); 450127135Snjl sc->bfe_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 451119917Swpaul RF_ACTIVE); 452119917Swpaul if (sc->bfe_res == NULL) { 453180950Syongari device_printf(dev, "couldn't map memory\n"); 454119917Swpaul error = ENXIO; 455119917Swpaul goto fail; 456119917Swpaul } 457119917Swpaul 458119917Swpaul /* Allocate interrupt */ 459119917Swpaul rid = 0; 460119917Swpaul 461127135Snjl sc->bfe_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 462119917Swpaul RF_SHAREABLE | RF_ACTIVE); 463119917Swpaul if (sc->bfe_irq == NULL) { 464180950Syongari device_printf(dev, "couldn't map interrupt\n"); 465119917Swpaul error = ENXIO; 466119917Swpaul goto fail; 467119917Swpaul } 468119917Swpaul 469181953Syongari if (bfe_dma_alloc(sc) != 0) { 470180950Syongari device_printf(dev, "failed to allocate DMA resources\n"); 471119917Swpaul error = ENXIO; 472119917Swpaul goto fail; 473119917Swpaul } 474119917Swpaul 475181994Syongari SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 476181994Syongari SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 477181994Syongari "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, sysctl_bfe_stats, 478181994Syongari "I", "Statistics"); 479181994Syongari 480119917Swpaul /* Set up ifnet structure */ 481147256Sbrooks ifp = sc->bfe_ifp = if_alloc(IFT_ETHER); 482147256Sbrooks if (ifp == NULL) { 483180950Syongari device_printf(dev, "failed to if_alloc()\n"); 484147256Sbrooks error = ENOSPC; 485147256Sbrooks goto fail; 486147256Sbrooks } 487119917Swpaul ifp->if_softc = sc; 488121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 489119917Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 490119917Swpaul ifp->if_ioctl = bfe_ioctl; 491119917Swpaul ifp->if_start = bfe_start; 492119917Swpaul ifp->if_init = bfe_init; 493131455Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, BFE_TX_QLEN); 494131455Smlaier ifp->if_snd.ifq_drv_maxlen = BFE_TX_QLEN; 495131455Smlaier IFQ_SET_READY(&ifp->if_snd); 496119917Swpaul 497119917Swpaul bfe_get_config(sc); 498119917Swpaul 499119917Swpaul /* Reset the chip and turn on the PHY */ 500136804Smtm BFE_LOCK(sc); 501119917Swpaul bfe_chip_reset(sc); 502136804Smtm BFE_UNLOCK(sc); 503119917Swpaul 504213893Smarius error = mii_attach(dev, &sc->bfe_miibus, ifp, bfe_ifmedia_upd, 505213893Smarius bfe_ifmedia_sts, BMSR_DEFCAPMASK, sc->bfe_phyaddr, MII_OFFSET_ANY, 506213893Smarius 0); 507213893Smarius if (error != 0) { 508213893Smarius device_printf(dev, "attaching PHYs failed\n"); 509119917Swpaul goto fail; 510119917Swpaul } 511119917Swpaul 512147256Sbrooks ether_ifattach(ifp, sc->bfe_enaddr); 513119917Swpaul 514119917Swpaul /* 515129708Sdes * Tell the upper layer(s) we support long frames. 516129708Sdes */ 517270856Sglebius ifp->if_hdrlen = sizeof(struct ether_vlan_header); 518129708Sdes ifp->if_capabilities |= IFCAP_VLAN_MTU; 519129709Sdes ifp->if_capenable |= IFCAP_VLAN_MTU; 520129708Sdes 521129708Sdes /* 522119917Swpaul * Hook interrupt last to avoid having to lock softc 523119917Swpaul */ 524136804Smtm error = bus_setup_intr(dev, sc->bfe_irq, INTR_TYPE_NET | INTR_MPSAFE, 525166901Spiso NULL, bfe_intr, sc, &sc->bfe_intrhand); 526119917Swpaul 527119917Swpaul if (error) { 528180950Syongari device_printf(dev, "couldn't set up irq\n"); 529119917Swpaul goto fail; 530119917Swpaul } 531119917Swpaulfail: 532181953Syongari if (error != 0) 533181953Syongari bfe_detach(dev); 534133282Sdes return (error); 535119917Swpaul} 536119917Swpaul 537119917Swpaulstatic int 538119917Swpaulbfe_detach(device_t dev) 539119917Swpaul{ 540119917Swpaul struct bfe_softc *sc; 541119917Swpaul struct ifnet *ifp; 542119917Swpaul 543119917Swpaul sc = device_get_softc(dev); 544119917Swpaul 545147256Sbrooks ifp = sc->bfe_ifp; 546119917Swpaul 547119917Swpaul if (device_is_attached(dev)) { 548175787Syongari BFE_LOCK(sc); 549181976Syongari sc->bfe_flags |= BFE_FLAG_DETACH; 550119917Swpaul bfe_stop(sc); 551175787Syongari BFE_UNLOCK(sc); 552175787Syongari callout_drain(&sc->bfe_stat_co); 553175787Syongari if (ifp != NULL) 554175787Syongari ether_ifdetach(ifp); 555119917Swpaul } 556119917Swpaul 557181953Syongari BFE_LOCK(sc); 558119917Swpaul bfe_chip_reset(sc); 559181953Syongari BFE_UNLOCK(sc); 560119917Swpaul 561119917Swpaul bus_generic_detach(dev); 562180954Syongari if (sc->bfe_miibus != NULL) 563119917Swpaul device_delete_child(dev, sc->bfe_miibus); 564119917Swpaul 565119917Swpaul bfe_release_resources(sc); 566181953Syongari bfe_dma_free(sc); 567119917Swpaul mtx_destroy(&sc->bfe_mtx); 568119917Swpaul 569133282Sdes return (0); 570119917Swpaul} 571119917Swpaul 572119917Swpaul/* 573119917Swpaul * Stop all chip I/O so that the kernel's probe routines don't 574119917Swpaul * get confused by errant DMAs when rebooting. 575119917Swpaul */ 576173839Syongaristatic int 577119917Swpaulbfe_shutdown(device_t dev) 578119917Swpaul{ 579119917Swpaul struct bfe_softc *sc; 580119917Swpaul 581119917Swpaul sc = device_get_softc(dev); 582119917Swpaul BFE_LOCK(sc); 583133282Sdes bfe_stop(sc); 584119917Swpaul 585119917Swpaul BFE_UNLOCK(sc); 586173839Syongari 587173839Syongari return (0); 588119917Swpaul} 589119917Swpaul 590119917Swpaulstatic int 591164456Sjhbbfe_suspend(device_t dev) 592164456Sjhb{ 593164456Sjhb struct bfe_softc *sc; 594164456Sjhb 595164456Sjhb sc = device_get_softc(dev); 596164456Sjhb BFE_LOCK(sc); 597164456Sjhb bfe_stop(sc); 598164456Sjhb BFE_UNLOCK(sc); 599164456Sjhb 600164456Sjhb return (0); 601164456Sjhb} 602164456Sjhb 603164456Sjhbstatic int 604164456Sjhbbfe_resume(device_t dev) 605164456Sjhb{ 606164456Sjhb struct bfe_softc *sc; 607164456Sjhb struct ifnet *ifp; 608164456Sjhb 609164456Sjhb sc = device_get_softc(dev); 610164456Sjhb ifp = sc->bfe_ifp; 611164456Sjhb BFE_LOCK(sc); 612164456Sjhb bfe_chip_reset(sc); 613164456Sjhb if (ifp->if_flags & IFF_UP) { 614164456Sjhb bfe_init_locked(sc); 615164456Sjhb if (ifp->if_drv_flags & IFF_DRV_RUNNING && 616164456Sjhb !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 617164456Sjhb bfe_start_locked(ifp); 618164456Sjhb } 619164456Sjhb BFE_UNLOCK(sc); 620164456Sjhb 621164456Sjhb return (0); 622164456Sjhb} 623164456Sjhb 624164456Sjhbstatic int 625119917Swpaulbfe_miibus_readreg(device_t dev, int phy, int reg) 626119917Swpaul{ 627119917Swpaul struct bfe_softc *sc; 628119917Swpaul u_int32_t ret; 629119917Swpaul 630119917Swpaul sc = device_get_softc(dev); 631119917Swpaul bfe_readphy(sc, reg, &ret); 632119917Swpaul 633133282Sdes return (ret); 634119917Swpaul} 635119917Swpaul 636119917Swpaulstatic int 637119917Swpaulbfe_miibus_writereg(device_t dev, int phy, int reg, int val) 638119917Swpaul{ 639119917Swpaul struct bfe_softc *sc; 640119917Swpaul 641119917Swpaul sc = device_get_softc(dev); 642133282Sdes bfe_writephy(sc, reg, val); 643119917Swpaul 644133282Sdes return (0); 645119917Swpaul} 646119917Swpaul 647119917Swpaulstatic void 648119917Swpaulbfe_miibus_statchg(device_t dev) 649119917Swpaul{ 650175787Syongari struct bfe_softc *sc; 651175787Syongari struct mii_data *mii; 652175787Syongari u_int32_t val, flow; 653175787Syongari 654175787Syongari sc = device_get_softc(dev); 655175787Syongari mii = device_get_softc(sc->bfe_miibus); 656175787Syongari 657181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 658181976Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 659181976Syongari (IFM_ACTIVE | IFM_AVALID)) { 660181976Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 661181976Syongari case IFM_10_T: 662181976Syongari case IFM_100_TX: 663181976Syongari sc->bfe_flags |= BFE_FLAG_LINK; 664181976Syongari break; 665181976Syongari default: 666181976Syongari break; 667181976Syongari } 668181976Syongari } 669175787Syongari 670175787Syongari /* XXX Should stop Rx/Tx engine prior to touching MAC. */ 671175787Syongari val = CSR_READ_4(sc, BFE_TX_CTRL); 672175787Syongari val &= ~BFE_TX_DUPLEX; 673175787Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 674175787Syongari val |= BFE_TX_DUPLEX; 675175787Syongari flow = 0; 676175787Syongari#ifdef notyet 677175787Syongari flow = CSR_READ_4(sc, BFE_RXCONF); 678175787Syongari flow &= ~BFE_RXCONF_FLOW; 679175787Syongari if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 680175787Syongari IFM_ETH_RXPAUSE) != 0) 681175787Syongari flow |= BFE_RXCONF_FLOW; 682175787Syongari CSR_WRITE_4(sc, BFE_RXCONF, flow); 683175787Syongari /* 684175787Syongari * It seems that the hardware has Tx pause issues 685175787Syongari * so enable only Rx pause. 686175787Syongari */ 687175787Syongari flow = CSR_READ_4(sc, BFE_MAC_FLOW); 688175787Syongari flow &= ~BFE_FLOW_PAUSE_ENAB; 689175787Syongari CSR_WRITE_4(sc, BFE_MAC_FLOW, flow); 690175787Syongari#endif 691175787Syongari } 692175787Syongari CSR_WRITE_4(sc, BFE_TX_CTRL, val); 693119917Swpaul} 694119917Swpaul 695119917Swpaulstatic void 696119917Swpaulbfe_tx_ring_free(struct bfe_softc *sc) 697119917Swpaul{ 698126470Sjulian int i; 699133282Sdes 700126470Sjulian for(i = 0; i < BFE_TX_LIST_CNT; i++) { 701180954Syongari if (sc->bfe_tx_ring[i].bfe_mbuf != NULL) { 702181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, 703181953Syongari sc->bfe_tx_ring[i].bfe_map, BUS_DMASYNC_POSTWRITE); 704181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, 705181953Syongari sc->bfe_tx_ring[i].bfe_map); 706126470Sjulian m_freem(sc->bfe_tx_ring[i].bfe_mbuf); 707126470Sjulian sc->bfe_tx_ring[i].bfe_mbuf = NULL; 708126470Sjulian } 709126470Sjulian } 710126470Sjulian bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE); 711181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 712181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 713119917Swpaul} 714119917Swpaul 715119917Swpaulstatic void 716119917Swpaulbfe_rx_ring_free(struct bfe_softc *sc) 717119917Swpaul{ 718119917Swpaul int i; 719119917Swpaul 720119917Swpaul for (i = 0; i < BFE_RX_LIST_CNT; i++) { 721119917Swpaul if (sc->bfe_rx_ring[i].bfe_mbuf != NULL) { 722181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, 723181953Syongari sc->bfe_rx_ring[i].bfe_map, BUS_DMASYNC_POSTREAD); 724181953Syongari bus_dmamap_unload(sc->bfe_rxmbuf_tag, 725181953Syongari sc->bfe_rx_ring[i].bfe_map); 726119917Swpaul m_freem(sc->bfe_rx_ring[i].bfe_mbuf); 727119917Swpaul sc->bfe_rx_ring[i].bfe_mbuf = NULL; 728119917Swpaul } 729119917Swpaul } 730119917Swpaul bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE); 731181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 732181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 733119917Swpaul} 734119917Swpaul 735133282Sdesstatic int 736119917Swpaulbfe_list_rx_init(struct bfe_softc *sc) 737119917Swpaul{ 738181953Syongari struct bfe_rx_data *rd; 739119917Swpaul int i; 740119917Swpaul 741181953Syongari sc->bfe_rx_prod = sc->bfe_rx_cons = 0; 742181953Syongari bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE); 743181953Syongari for (i = 0; i < BFE_RX_LIST_CNT; i++) { 744181953Syongari rd = &sc->bfe_rx_ring[i]; 745181953Syongari rd->bfe_mbuf = NULL; 746181953Syongari rd->bfe_ctrl = 0; 747181953Syongari if (bfe_list_newbuf(sc, i) != 0) 748133282Sdes return (ENOBUFS); 749119917Swpaul } 750119917Swpaul 751181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 752181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 753119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_PTR, (i * sizeof(struct bfe_desc))); 754119917Swpaul 755133282Sdes return (0); 756119917Swpaul} 757119917Swpaul 758181953Syongaristatic void 759181953Syongaribfe_list_tx_init(struct bfe_softc *sc) 760181953Syongari{ 761181953Syongari int i; 762181953Syongari 763181953Syongari sc->bfe_tx_cnt = sc->bfe_tx_prod = sc->bfe_tx_cons = 0; 764181953Syongari bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE); 765181953Syongari for (i = 0; i < BFE_TX_LIST_CNT; i++) 766181953Syongari sc->bfe_tx_ring[i].bfe_mbuf = NULL; 767181953Syongari 768181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 769181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 770181953Syongari} 771181953Syongari 772181953Syongaristatic void 773181953Syongaribfe_discard_buf(struct bfe_softc *sc, int c) 774181953Syongari{ 775181953Syongari struct bfe_rx_data *r; 776181953Syongari struct bfe_desc *d; 777181953Syongari 778181953Syongari r = &sc->bfe_rx_ring[c]; 779181953Syongari d = &sc->bfe_rx_list[c]; 780181953Syongari d->bfe_ctrl = htole32(r->bfe_ctrl); 781181953Syongari} 782181953Syongari 783119917Swpaulstatic int 784181953Syongaribfe_list_newbuf(struct bfe_softc *sc, int c) 785119917Swpaul{ 786119917Swpaul struct bfe_rxheader *rx_header; 787119917Swpaul struct bfe_desc *d; 788181953Syongari struct bfe_rx_data *r; 789181953Syongari struct mbuf *m; 790181953Syongari bus_dma_segment_t segs[1]; 791181953Syongari bus_dmamap_t map; 792119917Swpaul u_int32_t ctrl; 793181953Syongari int nsegs; 794119917Swpaul 795243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 796181953Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 797119917Swpaul 798181953Syongari if (bus_dmamap_load_mbuf_sg(sc->bfe_rxmbuf_tag, sc->bfe_rx_sparemap, 799181953Syongari m, segs, &nsegs, 0) != 0) { 800181953Syongari m_freem(m); 801181953Syongari return (ENOBUFS); 802119917Swpaul } 803119917Swpaul 804181953Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 805181953Syongari r = &sc->bfe_rx_ring[c]; 806181953Syongari if (r->bfe_mbuf != NULL) { 807181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, r->bfe_map, 808181953Syongari BUS_DMASYNC_POSTREAD); 809181953Syongari bus_dmamap_unload(sc->bfe_rxmbuf_tag, r->bfe_map); 810181953Syongari } 811181953Syongari map = r->bfe_map; 812181953Syongari r->bfe_map = sc->bfe_rx_sparemap; 813181953Syongari sc->bfe_rx_sparemap = map; 814181953Syongari r->bfe_mbuf = m; 815181953Syongari 816119917Swpaul rx_header = mtod(m, struct bfe_rxheader *); 817119917Swpaul rx_header->len = 0; 818119917Swpaul rx_header->flags = 0; 819181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, r->bfe_map, BUS_DMASYNC_PREREAD); 820181953Syongari 821181953Syongari ctrl = segs[0].ds_len & BFE_DESC_LEN; 822181953Syongari KASSERT(ctrl > ETHER_MAX_LEN + 32, ("%s: buffer size too small(%d)!", 823181953Syongari __func__, ctrl)); 824181953Syongari if (c == BFE_RX_LIST_CNT - 1) 825181953Syongari ctrl |= BFE_DESC_EOT; 826181953Syongari r->bfe_ctrl = ctrl; 827119917Swpaul 828119917Swpaul d = &sc->bfe_rx_list[c]; 829181953Syongari d->bfe_ctrl = htole32(ctrl); 830181953Syongari /* The chip needs all addresses to be added to BFE_PCI_DMA. */ 831181953Syongari d->bfe_addr = htole32(BFE_ADDR_LO(segs[0].ds_addr) + BFE_PCI_DMA); 832119917Swpaul 833133282Sdes return (0); 834119917Swpaul} 835119917Swpaul 836119917Swpaulstatic void 837119917Swpaulbfe_get_config(struct bfe_softc *sc) 838119917Swpaul{ 839119917Swpaul u_int8_t eeprom[128]; 840119917Swpaul 841119917Swpaul bfe_read_eeprom(sc, eeprom); 842119917Swpaul 843147256Sbrooks sc->bfe_enaddr[0] = eeprom[79]; 844147256Sbrooks sc->bfe_enaddr[1] = eeprom[78]; 845147256Sbrooks sc->bfe_enaddr[2] = eeprom[81]; 846147256Sbrooks sc->bfe_enaddr[3] = eeprom[80]; 847147256Sbrooks sc->bfe_enaddr[4] = eeprom[83]; 848147256Sbrooks sc->bfe_enaddr[5] = eeprom[82]; 849119917Swpaul 850119917Swpaul sc->bfe_phyaddr = eeprom[90] & 0x1f; 851119917Swpaul sc->bfe_mdc_port = (eeprom[90] >> 14) & 0x1; 852119917Swpaul 853133282Sdes sc->bfe_core_unit = 0; 854119917Swpaul sc->bfe_dma_offset = BFE_PCI_DMA; 855119917Swpaul} 856119917Swpaul 857119917Swpaulstatic void 858119917Swpaulbfe_pci_setup(struct bfe_softc *sc, u_int32_t cores) 859119917Swpaul{ 860119917Swpaul u_int32_t bar_orig, pci_rev, val; 861119917Swpaul 862119917Swpaul bar_orig = pci_read_config(sc->bfe_dev, BFE_BAR0_WIN, 4); 863119917Swpaul pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, BFE_REG_PCI, 4); 864119917Swpaul pci_rev = CSR_READ_4(sc, BFE_SBIDHIGH) & BFE_RC_MASK; 865119917Swpaul 866119917Swpaul val = CSR_READ_4(sc, BFE_SBINTVEC); 867119917Swpaul val |= cores; 868119917Swpaul CSR_WRITE_4(sc, BFE_SBINTVEC, val); 869119917Swpaul 870119917Swpaul val = CSR_READ_4(sc, BFE_SSB_PCI_TRANS_2); 871119917Swpaul val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST; 872119917Swpaul CSR_WRITE_4(sc, BFE_SSB_PCI_TRANS_2, val); 873119917Swpaul 874119917Swpaul pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, bar_orig, 4); 875119917Swpaul} 876119917Swpaul 877133282Sdesstatic void 878119917Swpaulbfe_clear_stats(struct bfe_softc *sc) 879119917Swpaul{ 880181994Syongari uint32_t reg; 881119917Swpaul 882136804Smtm BFE_LOCK_ASSERT(sc); 883119917Swpaul 884119917Swpaul CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 885119917Swpaul for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) 886119917Swpaul CSR_READ_4(sc, reg); 887119917Swpaul for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) 888119917Swpaul CSR_READ_4(sc, reg); 889119917Swpaul} 890119917Swpaul 891133282Sdesstatic int 892119917Swpaulbfe_resetphy(struct bfe_softc *sc) 893119917Swpaul{ 894119917Swpaul u_int32_t val; 895119917Swpaul 896119917Swpaul bfe_writephy(sc, 0, BMCR_RESET); 897119917Swpaul DELAY(100); 898119917Swpaul bfe_readphy(sc, 0, &val); 899119917Swpaul if (val & BMCR_RESET) { 900180950Syongari device_printf(sc->bfe_dev, "PHY Reset would not complete.\n"); 901133282Sdes return (ENXIO); 902119917Swpaul } 903133282Sdes return (0); 904119917Swpaul} 905119917Swpaul 906119917Swpaulstatic void 907119917Swpaulbfe_chip_halt(struct bfe_softc *sc) 908119917Swpaul{ 909136804Smtm BFE_LOCK_ASSERT(sc); 910119917Swpaul /* disable interrupts - not that it actually does..*/ 911119917Swpaul CSR_WRITE_4(sc, BFE_IMASK, 0); 912119917Swpaul CSR_READ_4(sc, BFE_IMASK); 913119917Swpaul 914119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); 915119917Swpaul bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 200, 1); 916119917Swpaul 917119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); 918119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); 919119917Swpaul DELAY(10); 920119917Swpaul} 921119917Swpaul 922119917Swpaulstatic void 923119917Swpaulbfe_chip_reset(struct bfe_softc *sc) 924119917Swpaul{ 925133282Sdes u_int32_t val; 926119917Swpaul 927136804Smtm BFE_LOCK_ASSERT(sc); 928119917Swpaul 929119917Swpaul /* Set the interrupt vector for the enet core */ 930119917Swpaul bfe_pci_setup(sc, BFE_INTVEC_ENET0); 931119917Swpaul 932119917Swpaul /* is core up? */ 933126470Sjulian val = CSR_READ_4(sc, BFE_SBTMSLOW) & 934126470Sjulian (BFE_RESET | BFE_REJECT | BFE_CLOCK); 935119917Swpaul if (val == BFE_CLOCK) { 936119917Swpaul /* It is, so shut it down */ 937119917Swpaul CSR_WRITE_4(sc, BFE_RCV_LAZY, 0); 938119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); 939119917Swpaul bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 100, 1); 940119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); 941133282Sdes if (CSR_READ_4(sc, BFE_DMARX_STAT) & BFE_STAT_EMASK) 942126470Sjulian bfe_wait_bit(sc, BFE_DMARX_STAT, BFE_STAT_SIDLE, 943126470Sjulian 100, 0); 944119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); 945119917Swpaul } 946119917Swpaul 947119917Swpaul bfe_core_reset(sc); 948119917Swpaul bfe_clear_stats(sc); 949119917Swpaul 950119917Swpaul /* 951119917Swpaul * We want the phy registers to be accessible even when 952119917Swpaul * the driver is "downed" so initialize MDC preamble, frequency, 953119917Swpaul * and whether internal or external phy here. 954119917Swpaul */ 955119917Swpaul 956119917Swpaul /* 4402 has 62.5Mhz SB clock and internal phy */ 957119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d); 958119917Swpaul 959119917Swpaul /* Internal or external PHY? */ 960119917Swpaul val = CSR_READ_4(sc, BFE_DEVCTRL); 961180954Syongari if (!(val & BFE_IPP)) 962119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_EPSEL); 963180954Syongari else if (CSR_READ_4(sc, BFE_DEVCTRL) & BFE_EPR) { 964119917Swpaul BFE_AND(sc, BFE_DEVCTRL, ~BFE_EPR); 965119917Swpaul DELAY(100); 966119917Swpaul } 967119917Swpaul 968133282Sdes /* Enable CRC32 generation and set proper LED modes */ 969133282Sdes BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED); 970129602Sdmlb 971133282Sdes /* Reset or clear powerdown control bit */ 972133282Sdes BFE_AND(sc, BFE_MAC_CTRL, ~BFE_CTRL_PDOWN); 973129602Sdmlb 974133282Sdes CSR_WRITE_4(sc, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) & 975119917Swpaul BFE_LAZY_FC_MASK)); 976119917Swpaul 977133282Sdes /* 978126470Sjulian * We don't want lazy interrupts, so just send them at 979133282Sdes * the end of a frame, please 980119917Swpaul */ 981119917Swpaul BFE_OR(sc, BFE_RCV_LAZY, 0); 982119917Swpaul 983119917Swpaul /* Set max lengths, accounting for VLAN tags */ 984119917Swpaul CSR_WRITE_4(sc, BFE_RXMAXLEN, ETHER_MAX_LEN+32); 985119917Swpaul CSR_WRITE_4(sc, BFE_TXMAXLEN, ETHER_MAX_LEN+32); 986119917Swpaul 987119917Swpaul /* Set watermark XXX - magic */ 988119917Swpaul CSR_WRITE_4(sc, BFE_TX_WMARK, 56); 989119917Swpaul 990133282Sdes /* 991126470Sjulian * Initialise DMA channels 992133282Sdes * - not forgetting dma addresses need to be added to BFE_PCI_DMA 993119917Swpaul */ 994119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE); 995119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_ADDR, sc->bfe_tx_dma + BFE_PCI_DMA); 996119917Swpaul 997133282Sdes CSR_WRITE_4(sc, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) | 998119917Swpaul BFE_RX_CTRL_ENABLE); 999119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_ADDR, sc->bfe_rx_dma + BFE_PCI_DMA); 1000119917Swpaul 1001119917Swpaul bfe_resetphy(sc); 1002119917Swpaul bfe_setupphy(sc); 1003119917Swpaul} 1004119917Swpaul 1005119917Swpaulstatic void 1006119917Swpaulbfe_core_disable(struct bfe_softc *sc) 1007119917Swpaul{ 1008180954Syongari if ((CSR_READ_4(sc, BFE_SBTMSLOW)) & BFE_RESET) 1009119917Swpaul return; 1010119917Swpaul 1011133282Sdes /* 1012126470Sjulian * Set reject, wait for it set, then wait for the core to stop 1013126470Sjulian * being busy, then set reset and reject and enable the clocks. 1014119917Swpaul */ 1015119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK)); 1016119917Swpaul bfe_wait_bit(sc, BFE_SBTMSLOW, BFE_REJECT, 1000, 0); 1017119917Swpaul bfe_wait_bit(sc, BFE_SBTMSHIGH, BFE_BUSY, 1000, 1); 1018119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | 1019119917Swpaul BFE_RESET)); 1020119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1021119917Swpaul DELAY(10); 1022119917Swpaul /* Leave reset and reject set */ 1023119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET)); 1024119917Swpaul DELAY(10); 1025119917Swpaul} 1026119917Swpaul 1027119917Swpaulstatic void 1028119917Swpaulbfe_core_reset(struct bfe_softc *sc) 1029119917Swpaul{ 1030119917Swpaul u_int32_t val; 1031119917Swpaul 1032119917Swpaul /* Disable the core */ 1033119917Swpaul bfe_core_disable(sc); 1034119917Swpaul 1035119917Swpaul /* and bring it back up */ 1036119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC)); 1037119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1038119917Swpaul DELAY(10); 1039119917Swpaul 1040119917Swpaul /* Chip bug, clear SERR, IB and TO if they are set. */ 1041119917Swpaul if (CSR_READ_4(sc, BFE_SBTMSHIGH) & BFE_SERR) 1042119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSHIGH, 0); 1043119917Swpaul val = CSR_READ_4(sc, BFE_SBIMSTATE); 1044119917Swpaul if (val & (BFE_IBE | BFE_TO)) 1045119917Swpaul CSR_WRITE_4(sc, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO)); 1046119917Swpaul 1047119917Swpaul /* Clear reset and allow it to move through the core */ 1048119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC)); 1049119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1050119917Swpaul DELAY(10); 1051119917Swpaul 1052119917Swpaul /* Leave the clock set */ 1053119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, BFE_CLOCK); 1054119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1055119917Swpaul DELAY(10); 1056119917Swpaul} 1057119917Swpaul 1058133282Sdesstatic void 1059119917Swpaulbfe_cam_write(struct bfe_softc *sc, u_char *data, int index) 1060119917Swpaul{ 1061119917Swpaul u_int32_t val; 1062119917Swpaul 1063119917Swpaul val = ((u_int32_t) data[2]) << 24; 1064119917Swpaul val |= ((u_int32_t) data[3]) << 16; 1065119917Swpaul val |= ((u_int32_t) data[4]) << 8; 1066119917Swpaul val |= ((u_int32_t) data[5]); 1067119917Swpaul CSR_WRITE_4(sc, BFE_CAM_DATA_LO, val); 1068119917Swpaul val = (BFE_CAM_HI_VALID | 1069119917Swpaul (((u_int32_t) data[0]) << 8) | 1070119917Swpaul (((u_int32_t) data[1]))); 1071119917Swpaul CSR_WRITE_4(sc, BFE_CAM_DATA_HI, val); 1072119917Swpaul CSR_WRITE_4(sc, BFE_CAM_CTRL, (BFE_CAM_WRITE | 1073129602Sdmlb ((u_int32_t) index << BFE_CAM_INDEX_SHIFT))); 1074119917Swpaul bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1); 1075119917Swpaul} 1076119917Swpaul 1077133282Sdesstatic void 1078119917Swpaulbfe_set_rx_mode(struct bfe_softc *sc) 1079119917Swpaul{ 1080147256Sbrooks struct ifnet *ifp = sc->bfe_ifp; 1081119917Swpaul struct ifmultiaddr *ifma; 1082119917Swpaul u_int32_t val; 1083119917Swpaul int i = 0; 1084119917Swpaul 1085181994Syongari BFE_LOCK_ASSERT(sc); 1086181994Syongari 1087119917Swpaul val = CSR_READ_4(sc, BFE_RXCONF); 1088119917Swpaul 1089119917Swpaul if (ifp->if_flags & IFF_PROMISC) 1090119917Swpaul val |= BFE_RXCONF_PROMISC; 1091119917Swpaul else 1092119917Swpaul val &= ~BFE_RXCONF_PROMISC; 1093119917Swpaul 1094119917Swpaul if (ifp->if_flags & IFF_BROADCAST) 1095119917Swpaul val &= ~BFE_RXCONF_DBCAST; 1096119917Swpaul else 1097119917Swpaul val |= BFE_RXCONF_DBCAST; 1098119917Swpaul 1099119917Swpaul 1100119917Swpaul CSR_WRITE_4(sc, BFE_CAM_CTRL, 0); 1101152315Sru bfe_cam_write(sc, IF_LLADDR(sc->bfe_ifp), i++); 1102119917Swpaul 1103119917Swpaul if (ifp->if_flags & IFF_ALLMULTI) 1104119917Swpaul val |= BFE_RXCONF_ALLMULTI; 1105119917Swpaul else { 1106119917Swpaul val &= ~BFE_RXCONF_ALLMULTI; 1107195049Srwatson if_maddr_rlock(ifp); 1108119917Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1109119917Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 1110119917Swpaul continue; 1111126470Sjulian bfe_cam_write(sc, 1112126470Sjulian LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i++); 1113119917Swpaul } 1114195049Srwatson if_maddr_runlock(ifp); 1115119917Swpaul } 1116119917Swpaul 1117119917Swpaul CSR_WRITE_4(sc, BFE_RXCONF, val); 1118119917Swpaul BFE_OR(sc, BFE_CAM_CTRL, BFE_CAM_ENABLE); 1119119917Swpaul} 1120119917Swpaul 1121119917Swpaulstatic void 1122119917Swpaulbfe_dma_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1123119917Swpaul{ 1124181953Syongari struct bfe_dmamap_arg *ctx; 1125119917Swpaul 1126181953Syongari if (error != 0) 1127181953Syongari return; 1128119917Swpaul 1129181953Syongari KASSERT(nseg == 1, ("%s : %d segments returned!", __func__, nseg)); 1130119917Swpaul 1131181953Syongari ctx = (struct bfe_dmamap_arg *)arg; 1132181953Syongari ctx->bfe_busaddr = segs[0].ds_addr; 1133119917Swpaul} 1134119917Swpaul 1135119917Swpaulstatic void 1136119917Swpaulbfe_release_resources(struct bfe_softc *sc) 1137119917Swpaul{ 1138119917Swpaul 1139119917Swpaul if (sc->bfe_intrhand != NULL) 1140181953Syongari bus_teardown_intr(sc->bfe_dev, sc->bfe_irq, sc->bfe_intrhand); 1141119917Swpaul 1142119917Swpaul if (sc->bfe_irq != NULL) 1143181953Syongari bus_release_resource(sc->bfe_dev, SYS_RES_IRQ, 0, sc->bfe_irq); 1144119917Swpaul 1145119917Swpaul if (sc->bfe_res != NULL) 1146181953Syongari bus_release_resource(sc->bfe_dev, SYS_RES_MEMORY, PCIR_BAR(0), 1147181953Syongari sc->bfe_res); 1148119917Swpaul 1149150215Sru if (sc->bfe_ifp != NULL) 1150150215Sru if_free(sc->bfe_ifp); 1151119917Swpaul} 1152119917Swpaul 1153119917Swpaulstatic void 1154119917Swpaulbfe_read_eeprom(struct bfe_softc *sc, u_int8_t *data) 1155119917Swpaul{ 1156119917Swpaul long i; 1157119917Swpaul u_int16_t *ptr = (u_int16_t *)data; 1158119917Swpaul 1159119917Swpaul for(i = 0; i < 128; i += 2) 1160119917Swpaul ptr[i/2] = CSR_READ_4(sc, 4096 + i); 1161119917Swpaul} 1162119917Swpaul 1163119917Swpaulstatic int 1164133282Sdesbfe_wait_bit(struct bfe_softc *sc, u_int32_t reg, u_int32_t bit, 1165119917Swpaul u_long timeout, const int clear) 1166119917Swpaul{ 1167119917Swpaul u_long i; 1168119917Swpaul 1169119917Swpaul for (i = 0; i < timeout; i++) { 1170119917Swpaul u_int32_t val = CSR_READ_4(sc, reg); 1171119917Swpaul 1172119917Swpaul if (clear && !(val & bit)) 1173119917Swpaul break; 1174119917Swpaul if (!clear && (val & bit)) 1175119917Swpaul break; 1176119917Swpaul DELAY(10); 1177119917Swpaul } 1178119917Swpaul if (i == timeout) { 1179180950Syongari device_printf(sc->bfe_dev, 1180180950Syongari "BUG! Timeout waiting for bit %08x of register " 1181180950Syongari "%x to %s.\n", bit, reg, (clear ? "clear" : "set")); 1182133282Sdes return (-1); 1183119917Swpaul } 1184133282Sdes return (0); 1185119917Swpaul} 1186119917Swpaul 1187119917Swpaulstatic int 1188119917Swpaulbfe_readphy(struct bfe_softc *sc, u_int32_t reg, u_int32_t *val) 1189119917Swpaul{ 1190133282Sdes int err; 1191119917Swpaul 1192119917Swpaul /* Clear MII ISR */ 1193119917Swpaul CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 1194119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 1195119917Swpaul (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) | 1196119917Swpaul (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | 1197119917Swpaul (reg << BFE_MDIO_RA_SHIFT) | 1198119917Swpaul (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT))); 1199119917Swpaul err = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); 1200119917Swpaul *val = CSR_READ_4(sc, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA; 1201119917Swpaul 1202133282Sdes return (err); 1203119917Swpaul} 1204119917Swpaul 1205119917Swpaulstatic int 1206119917Swpaulbfe_writephy(struct bfe_softc *sc, u_int32_t reg, u_int32_t val) 1207119917Swpaul{ 1208119917Swpaul int status; 1209119917Swpaul 1210119917Swpaul CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 1211119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 1212119917Swpaul (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) | 1213119917Swpaul (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | 1214119917Swpaul (reg << BFE_MDIO_RA_SHIFT) | 1215119917Swpaul (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) | 1216119917Swpaul (val & BFE_MDIO_DATA_DATA))); 1217119917Swpaul status = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); 1218119917Swpaul 1219133282Sdes return (status); 1220119917Swpaul} 1221119917Swpaul 1222133282Sdes/* 1223119917Swpaul * XXX - I think this is handled by the PHY driver, but it can't hurt to do it 1224119917Swpaul * twice 1225119917Swpaul */ 1226119917Swpaulstatic int 1227119917Swpaulbfe_setupphy(struct bfe_softc *sc) 1228119917Swpaul{ 1229119917Swpaul u_int32_t val; 1230119917Swpaul 1231119917Swpaul /* Enable activity LED */ 1232119917Swpaul bfe_readphy(sc, 26, &val); 1233133282Sdes bfe_writephy(sc, 26, val & 0x7fff); 1234119917Swpaul bfe_readphy(sc, 26, &val); 1235119917Swpaul 1236119917Swpaul /* Enable traffic meter LED mode */ 1237119917Swpaul bfe_readphy(sc, 27, &val); 1238119917Swpaul bfe_writephy(sc, 27, val | (1 << 6)); 1239119917Swpaul 1240133282Sdes return (0); 1241119917Swpaul} 1242119917Swpaul 1243133282Sdesstatic void 1244119917Swpaulbfe_stats_update(struct bfe_softc *sc) 1245119917Swpaul{ 1246181994Syongari struct bfe_hw_stats *stats; 1247181994Syongari struct ifnet *ifp; 1248181994Syongari uint32_t mib[BFE_MIB_CNT]; 1249181994Syongari uint32_t reg, *val; 1250119917Swpaul 1251181994Syongari BFE_LOCK_ASSERT(sc); 1252181994Syongari 1253181994Syongari val = mib; 1254181994Syongari CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 1255181994Syongari for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) 1256181994Syongari *val++ = CSR_READ_4(sc, reg); 1257181994Syongari for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) 1258181994Syongari *val++ = CSR_READ_4(sc, reg); 1259181994Syongari 1260181994Syongari ifp = sc->bfe_ifp; 1261181994Syongari stats = &sc->bfe_stats; 1262181994Syongari /* Tx stat. */ 1263181994Syongari stats->tx_good_octets += mib[MIB_TX_GOOD_O]; 1264181994Syongari stats->tx_good_frames += mib[MIB_TX_GOOD_P]; 1265181994Syongari stats->tx_octets += mib[MIB_TX_O]; 1266181994Syongari stats->tx_frames += mib[MIB_TX_P]; 1267181994Syongari stats->tx_bcast_frames += mib[MIB_TX_BCAST]; 1268181994Syongari stats->tx_mcast_frames += mib[MIB_TX_MCAST]; 1269181994Syongari stats->tx_pkts_64 += mib[MIB_TX_64]; 1270181994Syongari stats->tx_pkts_65_127 += mib[MIB_TX_65_127]; 1271181994Syongari stats->tx_pkts_128_255 += mib[MIB_TX_128_255]; 1272181994Syongari stats->tx_pkts_256_511 += mib[MIB_TX_256_511]; 1273181994Syongari stats->tx_pkts_512_1023 += mib[MIB_TX_512_1023]; 1274181994Syongari stats->tx_pkts_1024_max += mib[MIB_TX_1024_MAX]; 1275181994Syongari stats->tx_jabbers += mib[MIB_TX_JABBER]; 1276181994Syongari stats->tx_oversize_frames += mib[MIB_TX_OSIZE]; 1277181994Syongari stats->tx_frag_frames += mib[MIB_TX_FRAG]; 1278181994Syongari stats->tx_underruns += mib[MIB_TX_URUNS]; 1279181994Syongari stats->tx_colls += mib[MIB_TX_TCOLS]; 1280181994Syongari stats->tx_single_colls += mib[MIB_TX_SCOLS]; 1281181994Syongari stats->tx_multi_colls += mib[MIB_TX_MCOLS]; 1282181994Syongari stats->tx_excess_colls += mib[MIB_TX_ECOLS]; 1283181994Syongari stats->tx_late_colls += mib[MIB_TX_LCOLS]; 1284181994Syongari stats->tx_deferrals += mib[MIB_TX_DEFERED]; 1285181994Syongari stats->tx_carrier_losts += mib[MIB_TX_CLOST]; 1286181994Syongari stats->tx_pause_frames += mib[MIB_TX_PAUSE]; 1287181994Syongari /* Rx stat. */ 1288181994Syongari stats->rx_good_octets += mib[MIB_RX_GOOD_O]; 1289181994Syongari stats->rx_good_frames += mib[MIB_RX_GOOD_P]; 1290181994Syongari stats->rx_octets += mib[MIB_RX_O]; 1291181994Syongari stats->rx_frames += mib[MIB_RX_P]; 1292181994Syongari stats->rx_bcast_frames += mib[MIB_RX_BCAST]; 1293181994Syongari stats->rx_mcast_frames += mib[MIB_RX_MCAST]; 1294181994Syongari stats->rx_pkts_64 += mib[MIB_RX_64]; 1295181994Syongari stats->rx_pkts_65_127 += mib[MIB_RX_65_127]; 1296181994Syongari stats->rx_pkts_128_255 += mib[MIB_RX_128_255]; 1297181994Syongari stats->rx_pkts_256_511 += mib[MIB_RX_256_511]; 1298181994Syongari stats->rx_pkts_512_1023 += mib[MIB_RX_512_1023]; 1299181994Syongari stats->rx_pkts_1024_max += mib[MIB_RX_1024_MAX]; 1300181994Syongari stats->rx_jabbers += mib[MIB_RX_JABBER]; 1301181994Syongari stats->rx_oversize_frames += mib[MIB_RX_OSIZE]; 1302181994Syongari stats->rx_frag_frames += mib[MIB_RX_FRAG]; 1303181994Syongari stats->rx_missed_frames += mib[MIB_RX_MISS]; 1304181994Syongari stats->rx_crc_align_errs += mib[MIB_RX_CRCA]; 1305181994Syongari stats->rx_runts += mib[MIB_RX_USIZE]; 1306181994Syongari stats->rx_crc_errs += mib[MIB_RX_CRC]; 1307181994Syongari stats->rx_align_errs += mib[MIB_RX_ALIGN]; 1308181994Syongari stats->rx_symbol_errs += mib[MIB_RX_SYM]; 1309181994Syongari stats->rx_pause_frames += mib[MIB_RX_PAUSE]; 1310181994Syongari stats->rx_control_frames += mib[MIB_RX_NPAUSE]; 1311181994Syongari 1312181994Syongari /* Update counters in ifnet. */ 1313271829Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, (u_long)mib[MIB_TX_GOOD_P]); 1314271829Sglebius if_inc_counter(ifp, IFCOUNTER_COLLISIONS, (u_long)mib[MIB_TX_TCOLS]); 1315271829Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, (u_long)mib[MIB_TX_URUNS] + 1316181994Syongari (u_long)mib[MIB_TX_ECOLS] + 1317181994Syongari (u_long)mib[MIB_TX_DEFERED] + 1318271829Sglebius (u_long)mib[MIB_TX_CLOST]); 1319181994Syongari 1320271829Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, (u_long)mib[MIB_RX_GOOD_P]); 1321181994Syongari 1322271829Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, mib[MIB_RX_JABBER] + 1323181994Syongari mib[MIB_RX_MISS] + 1324181994Syongari mib[MIB_RX_CRCA] + 1325181994Syongari mib[MIB_RX_USIZE] + 1326181994Syongari mib[MIB_RX_CRC] + 1327181994Syongari mib[MIB_RX_ALIGN] + 1328271829Sglebius mib[MIB_RX_SYM]); 1329119917Swpaul} 1330119917Swpaul 1331119917Swpaulstatic void 1332119917Swpaulbfe_txeof(struct bfe_softc *sc) 1333119917Swpaul{ 1334181953Syongari struct bfe_tx_data *r; 1335119917Swpaul struct ifnet *ifp; 1336119917Swpaul int i, chipidx; 1337119917Swpaul 1338136804Smtm BFE_LOCK_ASSERT(sc); 1339119917Swpaul 1340147256Sbrooks ifp = sc->bfe_ifp; 1341119917Swpaul 1342119917Swpaul chipidx = CSR_READ_4(sc, BFE_DMATX_STAT) & BFE_STAT_CDMASK; 1343119917Swpaul chipidx /= sizeof(struct bfe_desc); 1344119917Swpaul 1345126470Sjulian i = sc->bfe_tx_cons; 1346181953Syongari if (i == chipidx) 1347181953Syongari return; 1348181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 1349181953Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1350119917Swpaul /* Go through the mbufs and free those that have been transmitted */ 1351181953Syongari for (; i != chipidx; BFE_INC(i, BFE_TX_LIST_CNT)) { 1352181953Syongari r = &sc->bfe_tx_ring[i]; 1353126470Sjulian sc->bfe_tx_cnt--; 1354181953Syongari if (r->bfe_mbuf == NULL) 1355181953Syongari continue; 1356181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, r->bfe_map, 1357181953Syongari BUS_DMASYNC_POSTWRITE); 1358181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, r->bfe_map); 1359181953Syongari 1360181953Syongari m_freem(r->bfe_mbuf); 1361181953Syongari r->bfe_mbuf = NULL; 1362119917Swpaul } 1363119917Swpaul 1364180954Syongari if (i != sc->bfe_tx_cons) { 1365119917Swpaul /* we freed up some mbufs */ 1366119917Swpaul sc->bfe_tx_cons = i; 1367148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1368119917Swpaul } 1369175787Syongari 1370175787Syongari if (sc->bfe_tx_cnt == 0) 1371175787Syongari sc->bfe_watchdog_timer = 0; 1372119917Swpaul} 1373119917Swpaul 1374119917Swpaul/* Pass a received packet up the stack */ 1375119917Swpaulstatic void 1376119917Swpaulbfe_rxeof(struct bfe_softc *sc) 1377119917Swpaul{ 1378119917Swpaul struct mbuf *m; 1379119917Swpaul struct ifnet *ifp; 1380119917Swpaul struct bfe_rxheader *rxheader; 1381181953Syongari struct bfe_rx_data *r; 1382181953Syongari int cons, prog; 1383119917Swpaul u_int32_t status, current, len, flags; 1384119917Swpaul 1385136804Smtm BFE_LOCK_ASSERT(sc); 1386119917Swpaul cons = sc->bfe_rx_cons; 1387119917Swpaul status = CSR_READ_4(sc, BFE_DMARX_STAT); 1388119917Swpaul current = (status & BFE_STAT_CDMASK) / sizeof(struct bfe_desc); 1389119917Swpaul 1390147256Sbrooks ifp = sc->bfe_ifp; 1391119917Swpaul 1392181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 1393181953Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1394181953Syongari 1395181953Syongari for (prog = 0; current != cons; prog++, 1396181953Syongari BFE_INC(cons, BFE_RX_LIST_CNT)) { 1397119917Swpaul r = &sc->bfe_rx_ring[cons]; 1398119917Swpaul m = r->bfe_mbuf; 1399181953Syongari /* 1400181953Syongari * Rx status should be read from mbuf such that we can't 1401181953Syongari * delay bus_dmamap_sync(9). This hardware limiation 1402181953Syongari * results in inefficent mbuf usage as bfe(4) couldn't 1403181953Syongari * reuse mapped buffer from errored frame. 1404181953Syongari */ 1405181953Syongari if (bfe_list_newbuf(sc, cons) != 0) { 1406271829Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 1407181953Syongari bfe_discard_buf(sc, cons); 1408181953Syongari continue; 1409181953Syongari } 1410119917Swpaul rxheader = mtod(m, struct bfe_rxheader*); 1411181953Syongari len = le16toh(rxheader->len); 1412181953Syongari flags = le16toh(rxheader->flags); 1413119917Swpaul 1414181953Syongari /* Remove CRC bytes. */ 1415119917Swpaul len -= ETHER_CRC_LEN; 1416119917Swpaul 1417119917Swpaul /* flag an error and try again */ 1418119917Swpaul if ((len > ETHER_MAX_LEN+32) || (flags & BFE_RX_FLAG_ERRORS)) { 1419181953Syongari m_freem(m); 1420119917Swpaul continue; 1421119917Swpaul } 1422119917Swpaul 1423181953Syongari /* Make sure to skip header bytes written by hardware. */ 1424181953Syongari m_adj(m, BFE_RX_OFFSET); 1425181953Syongari m->m_len = m->m_pkthdr.len = len; 1426119917Swpaul 1427119917Swpaul m->m_pkthdr.rcvif = ifp; 1428122689Ssam BFE_UNLOCK(sc); 1429119917Swpaul (*ifp->if_input)(ifp, m); 1430122689Ssam BFE_LOCK(sc); 1431181953Syongari } 1432119917Swpaul 1433181953Syongari if (prog > 0) { 1434181953Syongari sc->bfe_rx_cons = cons; 1435181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 1436181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1437119917Swpaul } 1438119917Swpaul} 1439119917Swpaul 1440119917Swpaulstatic void 1441119917Swpaulbfe_intr(void *xsc) 1442119917Swpaul{ 1443119917Swpaul struct bfe_softc *sc = xsc; 1444119917Swpaul struct ifnet *ifp; 1445181994Syongari u_int32_t istat; 1446119917Swpaul 1447147256Sbrooks ifp = sc->bfe_ifp; 1448119917Swpaul 1449119917Swpaul BFE_LOCK(sc); 1450119917Swpaul 1451119917Swpaul istat = CSR_READ_4(sc, BFE_ISTAT); 1452119917Swpaul 1453133282Sdes /* 1454119917Swpaul * Defer unsolicited interrupts - This is necessary because setting the 1455119917Swpaul * chips interrupt mask register to 0 doesn't actually stop the 1456119917Swpaul * interrupts 1457119917Swpaul */ 1458181992Syongari istat &= BFE_IMASK_DEF; 1459119917Swpaul CSR_WRITE_4(sc, BFE_ISTAT, istat); 1460119917Swpaul CSR_READ_4(sc, BFE_ISTAT); 1461119917Swpaul 1462119917Swpaul /* not expecting this interrupt, disregard it */ 1463181992Syongari if (istat == 0 || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1464119917Swpaul BFE_UNLOCK(sc); 1465119917Swpaul return; 1466119917Swpaul } 1467119917Swpaul 1468181994Syongari /* A packet was received */ 1469181994Syongari if (istat & BFE_ISTAT_RX) 1470181994Syongari bfe_rxeof(sc); 1471181994Syongari 1472181994Syongari /* A packet was sent */ 1473181994Syongari if (istat & BFE_ISTAT_TX) 1474181994Syongari bfe_txeof(sc); 1475181994Syongari 1476180954Syongari if (istat & BFE_ISTAT_ERRORS) { 1477159013Ssilby 1478159013Ssilby if (istat & BFE_ISTAT_DSCE) { 1479180950Syongari device_printf(sc->bfe_dev, "Descriptor Error\n"); 1480159013Ssilby bfe_stop(sc); 1481159013Ssilby BFE_UNLOCK(sc); 1482159013Ssilby return; 1483159013Ssilby } 1484159013Ssilby 1485159013Ssilby if (istat & BFE_ISTAT_DPE) { 1486180950Syongari device_printf(sc->bfe_dev, 1487180950Syongari "Descriptor Protocol Error\n"); 1488159013Ssilby bfe_stop(sc); 1489159013Ssilby BFE_UNLOCK(sc); 1490159013Ssilby return; 1491159013Ssilby } 1492148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1493136804Smtm bfe_init_locked(sc); 1494119917Swpaul } 1495119917Swpaul 1496133282Sdes /* We have packets pending, fire them out */ 1497181992Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1498136804Smtm bfe_start_locked(ifp); 1499119917Swpaul 1500119917Swpaul BFE_UNLOCK(sc); 1501119917Swpaul} 1502119917Swpaul 1503119917Swpaulstatic int 1504181953Syongaribfe_encap(struct bfe_softc *sc, struct mbuf **m_head) 1505119917Swpaul{ 1506181953Syongari struct bfe_desc *d; 1507181953Syongari struct bfe_tx_data *r, *r1; 1508181953Syongari struct mbuf *m; 1509181953Syongari bus_dmamap_t map; 1510181953Syongari bus_dma_segment_t txsegs[BFE_MAXTXSEGS]; 1511181953Syongari uint32_t cur, si; 1512181953Syongari int error, i, nsegs; 1513119917Swpaul 1514181953Syongari BFE_LOCK_ASSERT(sc); 1515119917Swpaul 1516181953Syongari M_ASSERTPKTHDR((*m_head)); 1517119917Swpaul 1518181953Syongari si = cur = sc->bfe_tx_prod; 1519181953Syongari r = &sc->bfe_tx_ring[cur]; 1520181953Syongari error = bus_dmamap_load_mbuf_sg(sc->bfe_txmbuf_tag, r->bfe_map, *m_head, 1521181953Syongari txsegs, &nsegs, 0); 1522181953Syongari if (error == EFBIG) { 1523243857Sglebius m = m_collapse(*m_head, M_NOWAIT, BFE_MAXTXSEGS); 1524181953Syongari if (m == NULL) { 1525181953Syongari m_freem(*m_head); 1526181953Syongari *m_head = NULL; 1527181953Syongari return (ENOMEM); 1528181953Syongari } 1529158285Ssilby *m_head = m; 1530181953Syongari error = bus_dmamap_load_mbuf_sg(sc->bfe_txmbuf_tag, r->bfe_map, 1531181953Syongari *m_head, txsegs, &nsegs, 0); 1532181953Syongari if (error != 0) { 1533181953Syongari m_freem(*m_head); 1534181953Syongari *m_head = NULL; 1535181953Syongari return (error); 1536181953Syongari } 1537181953Syongari } else if (error != 0) 1538181953Syongari return (error); 1539181953Syongari if (nsegs == 0) { 1540181953Syongari m_freem(*m_head); 1541181953Syongari *m_head = NULL; 1542181953Syongari return (EIO); 1543119917Swpaul } 1544119917Swpaul 1545181953Syongari if (sc->bfe_tx_cnt + nsegs > BFE_TX_LIST_CNT - 1) { 1546181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, r->bfe_map); 1547181953Syongari return (ENOBUFS); 1548181953Syongari } 1549119917Swpaul 1550181953Syongari for (i = 0; i < nsegs; i++) { 1551181953Syongari d = &sc->bfe_tx_list[cur]; 1552181953Syongari d->bfe_ctrl = htole32(txsegs[i].ds_len & BFE_DESC_LEN); 1553181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_IOC); 1554181953Syongari if (cur == BFE_TX_LIST_CNT - 1) 1555181953Syongari /* 1556181953Syongari * Tell the chip to wrap to the start of 1557181953Syongari * the descriptor list. 1558181953Syongari */ 1559181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_EOT); 1560181953Syongari /* The chip needs all addresses to be added to BFE_PCI_DMA. */ 1561181953Syongari d->bfe_addr = htole32(BFE_ADDR_LO(txsegs[i].ds_addr) + 1562181953Syongari BFE_PCI_DMA); 1563181953Syongari BFE_INC(cur, BFE_TX_LIST_CNT); 1564181953Syongari } 1565119917Swpaul 1566181953Syongari /* Update producer index. */ 1567181953Syongari sc->bfe_tx_prod = cur; 1568119917Swpaul 1569181953Syongari /* Set EOF on the last descriptor. */ 1570181953Syongari cur = (cur + BFE_TX_LIST_CNT - 1) % BFE_TX_LIST_CNT; 1571181953Syongari d = &sc->bfe_tx_list[cur]; 1572181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_EOF); 1573119917Swpaul 1574181953Syongari /* Lastly set SOF on the first descriptor to avoid races. */ 1575181953Syongari d = &sc->bfe_tx_list[si]; 1576181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_SOF); 1577119917Swpaul 1578181953Syongari r1 = &sc->bfe_tx_ring[cur]; 1579181953Syongari map = r->bfe_map; 1580181953Syongari r->bfe_map = r1->bfe_map; 1581181953Syongari r1->bfe_map = map; 1582181953Syongari r1->bfe_mbuf = *m_head; 1583181953Syongari sc->bfe_tx_cnt += nsegs; 1584119917Swpaul 1585181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, map, BUS_DMASYNC_PREWRITE); 1586119917Swpaul 1587119917Swpaul return (0); 1588119917Swpaul} 1589119917Swpaul 1590119917Swpaul/* 1591136804Smtm * Set up to transmit a packet. 1592119917Swpaul */ 1593119917Swpaulstatic void 1594119917Swpaulbfe_start(struct ifnet *ifp) 1595119917Swpaul{ 1596136804Smtm BFE_LOCK((struct bfe_softc *)ifp->if_softc); 1597136804Smtm bfe_start_locked(ifp); 1598136804Smtm BFE_UNLOCK((struct bfe_softc *)ifp->if_softc); 1599136804Smtm} 1600136804Smtm 1601136804Smtm/* 1602136804Smtm * Set up to transmit a packet. The softc is already locked. 1603136804Smtm */ 1604136804Smtmstatic void 1605136804Smtmbfe_start_locked(struct ifnet *ifp) 1606136804Smtm{ 1607119917Swpaul struct bfe_softc *sc; 1608181953Syongari struct mbuf *m_head; 1609181953Syongari int queued; 1610119917Swpaul 1611119917Swpaul sc = ifp->if_softc; 1612119917Swpaul 1613136804Smtm BFE_LOCK_ASSERT(sc); 1614119917Swpaul 1615133282Sdes /* 1616126470Sjulian * Not much point trying to send if the link is down 1617126470Sjulian * or we have nothing to send. 1618119917Swpaul */ 1619175787Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1620181976Syongari IFF_DRV_RUNNING || (sc->bfe_flags & BFE_FLAG_LINK) == 0) 1621119917Swpaul return; 1622119917Swpaul 1623181953Syongari for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 1624181953Syongari sc->bfe_tx_cnt < BFE_TX_LIST_CNT - 1;) { 1625131455Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1626180954Syongari if (m_head == NULL) 1627119917Swpaul break; 1628119917Swpaul 1629133282Sdes /* 1630126470Sjulian * Pack the data into the tx ring. If we dont have 1631126470Sjulian * enough room, let the chip drain the ring. 1632119917Swpaul */ 1633181953Syongari if (bfe_encap(sc, &m_head)) { 1634181953Syongari if (m_head == NULL) 1635181953Syongari break; 1636131455Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1637148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1638119917Swpaul break; 1639119917Swpaul } 1640119917Swpaul 1641136269Smlaier queued++; 1642136269Smlaier 1643119917Swpaul /* 1644119917Swpaul * If there's a BPF listener, bounce a copy of this frame 1645119917Swpaul * to him. 1646119917Swpaul */ 1647119917Swpaul BPF_MTAP(ifp, m_head); 1648119917Swpaul } 1649119917Swpaul 1650136269Smlaier if (queued) { 1651181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 1652181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1653136269Smlaier /* Transmit - twice due to apparent hardware bug */ 1654181953Syongari CSR_WRITE_4(sc, BFE_DMATX_PTR, 1655181953Syongari sc->bfe_tx_prod * sizeof(struct bfe_desc)); 1656181953Syongari /* 1657181953Syongari * XXX It seems the following write is not necessary 1658181953Syongari * to kick Tx command. What might be required would be 1659181953Syongari * a way flushing PCI posted write. Reading the register 1660181953Syongari * back ensures the flush operation. In addition, 1661181953Syongari * hardware will execute PCI posted write in the long 1662181953Syongari * run and watchdog timer for the kick command was set 1663181953Syongari * to 5 seconds. Therefore I think the second write 1664181953Syongari * access is not necessary or could be replaced with 1665181953Syongari * read operation. 1666181953Syongari */ 1667181953Syongari CSR_WRITE_4(sc, BFE_DMATX_PTR, 1668181953Syongari sc->bfe_tx_prod * sizeof(struct bfe_desc)); 1669119917Swpaul 1670136269Smlaier /* 1671136269Smlaier * Set a timeout in case the chip goes out to lunch. 1672136269Smlaier */ 1673175787Syongari sc->bfe_watchdog_timer = 5; 1674136269Smlaier } 1675119917Swpaul} 1676119917Swpaul 1677119917Swpaulstatic void 1678119917Swpaulbfe_init(void *xsc) 1679119917Swpaul{ 1680136804Smtm BFE_LOCK((struct bfe_softc *)xsc); 1681136804Smtm bfe_init_locked(xsc); 1682136804Smtm BFE_UNLOCK((struct bfe_softc *)xsc); 1683136804Smtm} 1684136804Smtm 1685136804Smtmstatic void 1686136804Smtmbfe_init_locked(void *xsc) 1687136804Smtm{ 1688119917Swpaul struct bfe_softc *sc = (struct bfe_softc*)xsc; 1689147256Sbrooks struct ifnet *ifp = sc->bfe_ifp; 1690175787Syongari struct mii_data *mii; 1691119917Swpaul 1692136804Smtm BFE_LOCK_ASSERT(sc); 1693119917Swpaul 1694175787Syongari mii = device_get_softc(sc->bfe_miibus); 1695175787Syongari 1696148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1697119917Swpaul return; 1698119917Swpaul 1699119917Swpaul bfe_stop(sc); 1700119917Swpaul bfe_chip_reset(sc); 1701119917Swpaul 1702119917Swpaul if (bfe_list_rx_init(sc) == ENOBUFS) { 1703180950Syongari device_printf(sc->bfe_dev, 1704180950Syongari "%s: Not enough memory for list buffers\n", __func__); 1705119917Swpaul bfe_stop(sc); 1706119917Swpaul return; 1707119917Swpaul } 1708181953Syongari bfe_list_tx_init(sc); 1709119917Swpaul 1710119917Swpaul bfe_set_rx_mode(sc); 1711119917Swpaul 1712119917Swpaul /* Enable the chip and core */ 1713119917Swpaul BFE_OR(sc, BFE_ENET_CTRL, BFE_ENET_ENABLE); 1714119917Swpaul /* Enable interrupts */ 1715119917Swpaul CSR_WRITE_4(sc, BFE_IMASK, BFE_IMASK_DEF); 1716119917Swpaul 1717175787Syongari /* Clear link state and change media. */ 1718181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 1719175787Syongari mii_mediachg(mii); 1720175787Syongari 1721148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1722148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1723119917Swpaul 1724175787Syongari callout_reset(&sc->bfe_stat_co, hz, bfe_tick, sc); 1725119917Swpaul} 1726119917Swpaul 1727119917Swpaul/* 1728119917Swpaul * Set media options. 1729119917Swpaul */ 1730119917Swpaulstatic int 1731119917Swpaulbfe_ifmedia_upd(struct ifnet *ifp) 1732119917Swpaul{ 1733119917Swpaul struct bfe_softc *sc; 1734119917Swpaul struct mii_data *mii; 1735221407Smarius struct mii_softc *miisc; 1736175787Syongari int error; 1737119917Swpaul 1738119917Swpaul sc = ifp->if_softc; 1739175787Syongari BFE_LOCK(sc); 1740119917Swpaul 1741119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1742221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1743221407Smarius PHY_RESET(miisc); 1744175787Syongari error = mii_mediachg(mii); 1745175787Syongari BFE_UNLOCK(sc); 1746119917Swpaul 1747175787Syongari return (error); 1748119917Swpaul} 1749119917Swpaul 1750119917Swpaul/* 1751119917Swpaul * Report current media status. 1752119917Swpaul */ 1753119917Swpaulstatic void 1754119917Swpaulbfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1755119917Swpaul{ 1756119917Swpaul struct bfe_softc *sc = ifp->if_softc; 1757119917Swpaul struct mii_data *mii; 1758119917Swpaul 1759175787Syongari BFE_LOCK(sc); 1760119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1761119917Swpaul mii_pollstat(mii); 1762119917Swpaul ifmr->ifm_active = mii->mii_media_active; 1763119917Swpaul ifmr->ifm_status = mii->mii_media_status; 1764175787Syongari BFE_UNLOCK(sc); 1765119917Swpaul} 1766119917Swpaul 1767119917Swpaulstatic int 1768119917Swpaulbfe_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1769119917Swpaul{ 1770119917Swpaul struct bfe_softc *sc = ifp->if_softc; 1771119917Swpaul struct ifreq *ifr = (struct ifreq *) data; 1772119917Swpaul struct mii_data *mii; 1773119917Swpaul int error = 0; 1774119917Swpaul 1775180954Syongari switch (command) { 1776180954Syongari case SIOCSIFFLAGS: 1777180954Syongari BFE_LOCK(sc); 1778181976Syongari if (ifp->if_flags & IFF_UP) { 1779180954Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1780119917Swpaul bfe_set_rx_mode(sc); 1781181976Syongari else if ((sc->bfe_flags & BFE_FLAG_DETACH) == 0) 1782180954Syongari bfe_init_locked(sc); 1783181976Syongari } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1784180954Syongari bfe_stop(sc); 1785180954Syongari BFE_UNLOCK(sc); 1786180954Syongari break; 1787180954Syongari case SIOCADDMULTI: 1788180954Syongari case SIOCDELMULTI: 1789180954Syongari BFE_LOCK(sc); 1790180954Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1791180954Syongari bfe_set_rx_mode(sc); 1792180954Syongari BFE_UNLOCK(sc); 1793180954Syongari break; 1794180954Syongari case SIOCGIFMEDIA: 1795180954Syongari case SIOCSIFMEDIA: 1796180954Syongari mii = device_get_softc(sc->bfe_miibus); 1797180954Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1798180954Syongari break; 1799180954Syongari default: 1800180954Syongari error = ether_ioctl(ifp, command, data); 1801180954Syongari break; 1802119917Swpaul } 1803119917Swpaul 1804133282Sdes return (error); 1805119917Swpaul} 1806119917Swpaul 1807119917Swpaulstatic void 1808175787Syongaribfe_watchdog(struct bfe_softc *sc) 1809119917Swpaul{ 1810175787Syongari struct ifnet *ifp; 1811119917Swpaul 1812175787Syongari BFE_LOCK_ASSERT(sc); 1813119917Swpaul 1814175787Syongari if (sc->bfe_watchdog_timer == 0 || --sc->bfe_watchdog_timer) 1815175787Syongari return; 1816119917Swpaul 1817175787Syongari ifp = sc->bfe_ifp; 1818175787Syongari 1819180950Syongari device_printf(sc->bfe_dev, "watchdog timeout -- resetting\n"); 1820119917Swpaul 1821271829Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1822148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1823136804Smtm bfe_init_locked(sc); 1824119917Swpaul 1825175787Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1826175787Syongari bfe_start_locked(ifp); 1827119917Swpaul} 1828119917Swpaul 1829119917Swpaulstatic void 1830119917Swpaulbfe_tick(void *xsc) 1831119917Swpaul{ 1832119917Swpaul struct bfe_softc *sc = xsc; 1833119917Swpaul struct mii_data *mii; 1834119917Swpaul 1835175787Syongari BFE_LOCK_ASSERT(sc); 1836119917Swpaul 1837119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1838175787Syongari mii_tick(mii); 1839119917Swpaul bfe_stats_update(sc); 1840175787Syongari bfe_watchdog(sc); 1841175787Syongari callout_reset(&sc->bfe_stat_co, hz, bfe_tick, sc); 1842119917Swpaul} 1843119917Swpaul 1844119917Swpaul/* 1845119917Swpaul * Stop the adapter and free any mbufs allocated to the 1846119917Swpaul * RX and TX lists. 1847119917Swpaul */ 1848119917Swpaulstatic void 1849119917Swpaulbfe_stop(struct bfe_softc *sc) 1850119917Swpaul{ 1851119917Swpaul struct ifnet *ifp; 1852119917Swpaul 1853136804Smtm BFE_LOCK_ASSERT(sc); 1854119917Swpaul 1855147256Sbrooks ifp = sc->bfe_ifp; 1856175787Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1857181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 1858175787Syongari callout_stop(&sc->bfe_stat_co); 1859175787Syongari sc->bfe_watchdog_timer = 0; 1860119917Swpaul 1861119917Swpaul bfe_chip_halt(sc); 1862126470Sjulian bfe_tx_ring_free(sc); 1863119917Swpaul bfe_rx_ring_free(sc); 1864119917Swpaul} 1865181994Syongari 1866181994Syongaristatic int 1867181994Syongarisysctl_bfe_stats(SYSCTL_HANDLER_ARGS) 1868181994Syongari{ 1869181994Syongari struct bfe_softc *sc; 1870181994Syongari struct bfe_hw_stats *stats; 1871181994Syongari int error, result; 1872181994Syongari 1873181994Syongari result = -1; 1874181994Syongari error = sysctl_handle_int(oidp, &result, 0, req); 1875181994Syongari 1876181994Syongari if (error != 0 || req->newptr == NULL) 1877181994Syongari return (error); 1878181994Syongari 1879181994Syongari if (result != 1) 1880181994Syongari return (error); 1881181994Syongari 1882181994Syongari sc = (struct bfe_softc *)arg1; 1883181994Syongari stats = &sc->bfe_stats; 1884181994Syongari 1885181994Syongari printf("%s statistics:\n", device_get_nameunit(sc->bfe_dev)); 1886181994Syongari printf("Transmit good octets : %ju\n", 1887181994Syongari (uintmax_t)stats->tx_good_octets); 1888181994Syongari printf("Transmit good frames : %ju\n", 1889181994Syongari (uintmax_t)stats->tx_good_frames); 1890181994Syongari printf("Transmit octets : %ju\n", 1891181994Syongari (uintmax_t)stats->tx_octets); 1892181994Syongari printf("Transmit frames : %ju\n", 1893181994Syongari (uintmax_t)stats->tx_frames); 1894181994Syongari printf("Transmit broadcast frames : %ju\n", 1895181994Syongari (uintmax_t)stats->tx_bcast_frames); 1896181994Syongari printf("Transmit multicast frames : %ju\n", 1897181994Syongari (uintmax_t)stats->tx_mcast_frames); 1898181994Syongari printf("Transmit frames 64 bytes : %ju\n", 1899181994Syongari (uint64_t)stats->tx_pkts_64); 1900181994Syongari printf("Transmit frames 65 to 127 bytes : %ju\n", 1901181994Syongari (uint64_t)stats->tx_pkts_65_127); 1902181994Syongari printf("Transmit frames 128 to 255 bytes : %ju\n", 1903181994Syongari (uint64_t)stats->tx_pkts_128_255); 1904181994Syongari printf("Transmit frames 256 to 511 bytes : %ju\n", 1905181994Syongari (uint64_t)stats->tx_pkts_256_511); 1906181994Syongari printf("Transmit frames 512 to 1023 bytes : %ju\n", 1907181994Syongari (uint64_t)stats->tx_pkts_512_1023); 1908181994Syongari printf("Transmit frames 1024 to max bytes : %ju\n", 1909181994Syongari (uint64_t)stats->tx_pkts_1024_max); 1910181994Syongari printf("Transmit jabber errors : %u\n", stats->tx_jabbers); 1911181994Syongari printf("Transmit oversized frames : %ju\n", 1912181994Syongari (uint64_t)stats->tx_oversize_frames); 1913181994Syongari printf("Transmit fragmented frames : %ju\n", 1914181994Syongari (uint64_t)stats->tx_frag_frames); 1915181994Syongari printf("Transmit underruns : %u\n", stats->tx_colls); 1916181994Syongari printf("Transmit total collisions : %u\n", stats->tx_single_colls); 1917181994Syongari printf("Transmit single collisions : %u\n", stats->tx_single_colls); 1918181994Syongari printf("Transmit multiple collisions : %u\n", stats->tx_multi_colls); 1919181994Syongari printf("Transmit excess collisions : %u\n", stats->tx_excess_colls); 1920181994Syongari printf("Transmit late collisions : %u\n", stats->tx_late_colls); 1921181994Syongari printf("Transmit deferrals : %u\n", stats->tx_deferrals); 1922181994Syongari printf("Transmit carrier losts : %u\n", stats->tx_carrier_losts); 1923181994Syongari printf("Transmit pause frames : %u\n", stats->tx_pause_frames); 1924181994Syongari 1925181994Syongari printf("Receive good octets : %ju\n", 1926181994Syongari (uintmax_t)stats->rx_good_octets); 1927181994Syongari printf("Receive good frames : %ju\n", 1928181994Syongari (uintmax_t)stats->rx_good_frames); 1929181994Syongari printf("Receive octets : %ju\n", 1930181994Syongari (uintmax_t)stats->rx_octets); 1931181994Syongari printf("Receive frames : %ju\n", 1932181994Syongari (uintmax_t)stats->rx_frames); 1933181994Syongari printf("Receive broadcast frames : %ju\n", 1934181994Syongari (uintmax_t)stats->rx_bcast_frames); 1935181994Syongari printf("Receive multicast frames : %ju\n", 1936181994Syongari (uintmax_t)stats->rx_mcast_frames); 1937181994Syongari printf("Receive frames 64 bytes : %ju\n", 1938181994Syongari (uint64_t)stats->rx_pkts_64); 1939181994Syongari printf("Receive frames 65 to 127 bytes : %ju\n", 1940181994Syongari (uint64_t)stats->rx_pkts_65_127); 1941181994Syongari printf("Receive frames 128 to 255 bytes : %ju\n", 1942181994Syongari (uint64_t)stats->rx_pkts_128_255); 1943181994Syongari printf("Receive frames 256 to 511 bytes : %ju\n", 1944181994Syongari (uint64_t)stats->rx_pkts_256_511); 1945181994Syongari printf("Receive frames 512 to 1023 bytes : %ju\n", 1946181994Syongari (uint64_t)stats->rx_pkts_512_1023); 1947181994Syongari printf("Receive frames 1024 to max bytes : %ju\n", 1948181994Syongari (uint64_t)stats->rx_pkts_1024_max); 1949181994Syongari printf("Receive jabber errors : %u\n", stats->rx_jabbers); 1950181994Syongari printf("Receive oversized frames : %ju\n", 1951181994Syongari (uint64_t)stats->rx_oversize_frames); 1952181994Syongari printf("Receive fragmented frames : %ju\n", 1953181994Syongari (uint64_t)stats->rx_frag_frames); 1954181994Syongari printf("Receive missed frames : %u\n", stats->rx_missed_frames); 1955181994Syongari printf("Receive CRC align errors : %u\n", stats->rx_crc_align_errs); 1956181994Syongari printf("Receive undersized frames : %u\n", stats->rx_runts); 1957181994Syongari printf("Receive CRC errors : %u\n", stats->rx_crc_errs); 1958181994Syongari printf("Receive align errors : %u\n", stats->rx_align_errs); 1959181994Syongari printf("Receive symbol errors : %u\n", stats->rx_symbol_errs); 1960181994Syongari printf("Receive pause frames : %u\n", stats->rx_pause_frames); 1961181994Syongari printf("Receive control frames : %u\n", stats->rx_control_frames); 1962181994Syongari 1963181994Syongari return (error); 1964181994Syongari} 1965