if_bfe.c revision 213893
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 213893 2010-10-15 14:52:11Z marius $"); 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 508213893Smarius error = mii_attach(dev, &sc->bfe_miibus, ifp, bfe_ifmedia_upd, 509213893Smarius bfe_ifmedia_sts, BMSR_DEFCAPMASK, sc->bfe_phyaddr, MII_OFFSET_ANY, 510213893Smarius 0); 511213893Smarius if (error != 0) { 512213893Smarius device_printf(dev, "attaching PHYs failed\n"); 513119917Swpaul goto fail; 514119917Swpaul } 515119917Swpaul 516147256Sbrooks ether_ifattach(ifp, sc->bfe_enaddr); 517119917Swpaul 518119917Swpaul /* 519129708Sdes * Tell the upper layer(s) we support long frames. 520129708Sdes */ 521129708Sdes ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 522129708Sdes ifp->if_capabilities |= IFCAP_VLAN_MTU; 523129709Sdes ifp->if_capenable |= IFCAP_VLAN_MTU; 524129708Sdes 525129708Sdes /* 526119917Swpaul * Hook interrupt last to avoid having to lock softc 527119917Swpaul */ 528136804Smtm error = bus_setup_intr(dev, sc->bfe_irq, INTR_TYPE_NET | INTR_MPSAFE, 529166901Spiso NULL, bfe_intr, sc, &sc->bfe_intrhand); 530119917Swpaul 531119917Swpaul if (error) { 532180950Syongari device_printf(dev, "couldn't set up irq\n"); 533119917Swpaul goto fail; 534119917Swpaul } 535119917Swpaulfail: 536181953Syongari if (error != 0) 537181953Syongari bfe_detach(dev); 538133282Sdes return (error); 539119917Swpaul} 540119917Swpaul 541119917Swpaulstatic int 542119917Swpaulbfe_detach(device_t dev) 543119917Swpaul{ 544119917Swpaul struct bfe_softc *sc; 545119917Swpaul struct ifnet *ifp; 546119917Swpaul 547119917Swpaul sc = device_get_softc(dev); 548119917Swpaul 549147256Sbrooks ifp = sc->bfe_ifp; 550119917Swpaul 551119917Swpaul if (device_is_attached(dev)) { 552175787Syongari BFE_LOCK(sc); 553181976Syongari sc->bfe_flags |= BFE_FLAG_DETACH; 554119917Swpaul bfe_stop(sc); 555175787Syongari BFE_UNLOCK(sc); 556175787Syongari callout_drain(&sc->bfe_stat_co); 557175787Syongari if (ifp != NULL) 558175787Syongari ether_ifdetach(ifp); 559119917Swpaul } 560119917Swpaul 561181953Syongari BFE_LOCK(sc); 562119917Swpaul bfe_chip_reset(sc); 563181953Syongari BFE_UNLOCK(sc); 564119917Swpaul 565119917Swpaul bus_generic_detach(dev); 566180954Syongari if (sc->bfe_miibus != NULL) 567119917Swpaul device_delete_child(dev, sc->bfe_miibus); 568119917Swpaul 569119917Swpaul bfe_release_resources(sc); 570181953Syongari bfe_dma_free(sc); 571119917Swpaul mtx_destroy(&sc->bfe_mtx); 572119917Swpaul 573133282Sdes return (0); 574119917Swpaul} 575119917Swpaul 576119917Swpaul/* 577119917Swpaul * Stop all chip I/O so that the kernel's probe routines don't 578119917Swpaul * get confused by errant DMAs when rebooting. 579119917Swpaul */ 580173839Syongaristatic int 581119917Swpaulbfe_shutdown(device_t dev) 582119917Swpaul{ 583119917Swpaul struct bfe_softc *sc; 584119917Swpaul 585119917Swpaul sc = device_get_softc(dev); 586119917Swpaul BFE_LOCK(sc); 587133282Sdes bfe_stop(sc); 588119917Swpaul 589119917Swpaul BFE_UNLOCK(sc); 590173839Syongari 591173839Syongari return (0); 592119917Swpaul} 593119917Swpaul 594119917Swpaulstatic int 595164456Sjhbbfe_suspend(device_t dev) 596164456Sjhb{ 597164456Sjhb struct bfe_softc *sc; 598164456Sjhb 599164456Sjhb sc = device_get_softc(dev); 600164456Sjhb BFE_LOCK(sc); 601164456Sjhb bfe_stop(sc); 602164456Sjhb BFE_UNLOCK(sc); 603164456Sjhb 604164456Sjhb return (0); 605164456Sjhb} 606164456Sjhb 607164456Sjhbstatic int 608164456Sjhbbfe_resume(device_t dev) 609164456Sjhb{ 610164456Sjhb struct bfe_softc *sc; 611164456Sjhb struct ifnet *ifp; 612164456Sjhb 613164456Sjhb sc = device_get_softc(dev); 614164456Sjhb ifp = sc->bfe_ifp; 615164456Sjhb BFE_LOCK(sc); 616164456Sjhb bfe_chip_reset(sc); 617164456Sjhb if (ifp->if_flags & IFF_UP) { 618164456Sjhb bfe_init_locked(sc); 619164456Sjhb if (ifp->if_drv_flags & IFF_DRV_RUNNING && 620164456Sjhb !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 621164456Sjhb bfe_start_locked(ifp); 622164456Sjhb } 623164456Sjhb BFE_UNLOCK(sc); 624164456Sjhb 625164456Sjhb return (0); 626164456Sjhb} 627164456Sjhb 628164456Sjhbstatic int 629119917Swpaulbfe_miibus_readreg(device_t dev, int phy, int reg) 630119917Swpaul{ 631119917Swpaul struct bfe_softc *sc; 632119917Swpaul u_int32_t ret; 633119917Swpaul 634119917Swpaul sc = device_get_softc(dev); 635119917Swpaul bfe_readphy(sc, reg, &ret); 636119917Swpaul 637133282Sdes return (ret); 638119917Swpaul} 639119917Swpaul 640119917Swpaulstatic int 641119917Swpaulbfe_miibus_writereg(device_t dev, int phy, int reg, int val) 642119917Swpaul{ 643119917Swpaul struct bfe_softc *sc; 644119917Swpaul 645119917Swpaul sc = device_get_softc(dev); 646133282Sdes bfe_writephy(sc, reg, val); 647119917Swpaul 648133282Sdes return (0); 649119917Swpaul} 650119917Swpaul 651119917Swpaulstatic void 652119917Swpaulbfe_miibus_statchg(device_t dev) 653119917Swpaul{ 654175787Syongari struct bfe_softc *sc; 655175787Syongari struct mii_data *mii; 656175787Syongari u_int32_t val, flow; 657175787Syongari 658175787Syongari sc = device_get_softc(dev); 659175787Syongari mii = device_get_softc(sc->bfe_miibus); 660175787Syongari 661181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 662181976Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 663181976Syongari (IFM_ACTIVE | IFM_AVALID)) { 664181976Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 665181976Syongari case IFM_10_T: 666181976Syongari case IFM_100_TX: 667181976Syongari sc->bfe_flags |= BFE_FLAG_LINK; 668181976Syongari break; 669181976Syongari default: 670181976Syongari break; 671181976Syongari } 672181976Syongari } 673175787Syongari 674175787Syongari /* XXX Should stop Rx/Tx engine prior to touching MAC. */ 675175787Syongari val = CSR_READ_4(sc, BFE_TX_CTRL); 676175787Syongari val &= ~BFE_TX_DUPLEX; 677175787Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 678175787Syongari val |= BFE_TX_DUPLEX; 679175787Syongari flow = 0; 680175787Syongari#ifdef notyet 681175787Syongari flow = CSR_READ_4(sc, BFE_RXCONF); 682175787Syongari flow &= ~BFE_RXCONF_FLOW; 683175787Syongari if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 684175787Syongari IFM_ETH_RXPAUSE) != 0) 685175787Syongari flow |= BFE_RXCONF_FLOW; 686175787Syongari CSR_WRITE_4(sc, BFE_RXCONF, flow); 687175787Syongari /* 688175787Syongari * It seems that the hardware has Tx pause issues 689175787Syongari * so enable only Rx pause. 690175787Syongari */ 691175787Syongari flow = CSR_READ_4(sc, BFE_MAC_FLOW); 692175787Syongari flow &= ~BFE_FLOW_PAUSE_ENAB; 693175787Syongari CSR_WRITE_4(sc, BFE_MAC_FLOW, flow); 694175787Syongari#endif 695175787Syongari } 696175787Syongari CSR_WRITE_4(sc, BFE_TX_CTRL, val); 697119917Swpaul} 698119917Swpaul 699119917Swpaulstatic void 700119917Swpaulbfe_tx_ring_free(struct bfe_softc *sc) 701119917Swpaul{ 702126470Sjulian int i; 703133282Sdes 704126470Sjulian for(i = 0; i < BFE_TX_LIST_CNT; i++) { 705180954Syongari if (sc->bfe_tx_ring[i].bfe_mbuf != NULL) { 706181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, 707181953Syongari sc->bfe_tx_ring[i].bfe_map, BUS_DMASYNC_POSTWRITE); 708181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, 709181953Syongari sc->bfe_tx_ring[i].bfe_map); 710126470Sjulian m_freem(sc->bfe_tx_ring[i].bfe_mbuf); 711126470Sjulian sc->bfe_tx_ring[i].bfe_mbuf = NULL; 712126470Sjulian } 713126470Sjulian } 714126470Sjulian bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE); 715181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 716181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 717119917Swpaul} 718119917Swpaul 719119917Swpaulstatic void 720119917Swpaulbfe_rx_ring_free(struct bfe_softc *sc) 721119917Swpaul{ 722119917Swpaul int i; 723119917Swpaul 724119917Swpaul for (i = 0; i < BFE_RX_LIST_CNT; i++) { 725119917Swpaul if (sc->bfe_rx_ring[i].bfe_mbuf != NULL) { 726181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, 727181953Syongari sc->bfe_rx_ring[i].bfe_map, BUS_DMASYNC_POSTREAD); 728181953Syongari bus_dmamap_unload(sc->bfe_rxmbuf_tag, 729181953Syongari sc->bfe_rx_ring[i].bfe_map); 730119917Swpaul m_freem(sc->bfe_rx_ring[i].bfe_mbuf); 731119917Swpaul sc->bfe_rx_ring[i].bfe_mbuf = NULL; 732119917Swpaul } 733119917Swpaul } 734119917Swpaul bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE); 735181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 736181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 737119917Swpaul} 738119917Swpaul 739133282Sdesstatic int 740119917Swpaulbfe_list_rx_init(struct bfe_softc *sc) 741119917Swpaul{ 742181953Syongari struct bfe_rx_data *rd; 743119917Swpaul int i; 744119917Swpaul 745181953Syongari sc->bfe_rx_prod = sc->bfe_rx_cons = 0; 746181953Syongari bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE); 747181953Syongari for (i = 0; i < BFE_RX_LIST_CNT; i++) { 748181953Syongari rd = &sc->bfe_rx_ring[i]; 749181953Syongari rd->bfe_mbuf = NULL; 750181953Syongari rd->bfe_ctrl = 0; 751181953Syongari if (bfe_list_newbuf(sc, i) != 0) 752133282Sdes return (ENOBUFS); 753119917Swpaul } 754119917Swpaul 755181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 756181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 757119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_PTR, (i * sizeof(struct bfe_desc))); 758119917Swpaul 759133282Sdes return (0); 760119917Swpaul} 761119917Swpaul 762181953Syongaristatic void 763181953Syongaribfe_list_tx_init(struct bfe_softc *sc) 764181953Syongari{ 765181953Syongari int i; 766181953Syongari 767181953Syongari sc->bfe_tx_cnt = sc->bfe_tx_prod = sc->bfe_tx_cons = 0; 768181953Syongari bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE); 769181953Syongari for (i = 0; i < BFE_TX_LIST_CNT; i++) 770181953Syongari sc->bfe_tx_ring[i].bfe_mbuf = NULL; 771181953Syongari 772181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 773181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 774181953Syongari} 775181953Syongari 776181953Syongaristatic void 777181953Syongaribfe_discard_buf(struct bfe_softc *sc, int c) 778181953Syongari{ 779181953Syongari struct bfe_rx_data *r; 780181953Syongari struct bfe_desc *d; 781181953Syongari 782181953Syongari r = &sc->bfe_rx_ring[c]; 783181953Syongari d = &sc->bfe_rx_list[c]; 784181953Syongari d->bfe_ctrl = htole32(r->bfe_ctrl); 785181953Syongari} 786181953Syongari 787119917Swpaulstatic int 788181953Syongaribfe_list_newbuf(struct bfe_softc *sc, int c) 789119917Swpaul{ 790119917Swpaul struct bfe_rxheader *rx_header; 791119917Swpaul struct bfe_desc *d; 792181953Syongari struct bfe_rx_data *r; 793181953Syongari struct mbuf *m; 794181953Syongari bus_dma_segment_t segs[1]; 795181953Syongari bus_dmamap_t map; 796119917Swpaul u_int32_t ctrl; 797181953Syongari int nsegs; 798119917Swpaul 799181953Syongari m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 800181953Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 801119917Swpaul 802181953Syongari if (bus_dmamap_load_mbuf_sg(sc->bfe_rxmbuf_tag, sc->bfe_rx_sparemap, 803181953Syongari m, segs, &nsegs, 0) != 0) { 804181953Syongari m_freem(m); 805181953Syongari return (ENOBUFS); 806119917Swpaul } 807119917Swpaul 808181953Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 809181953Syongari r = &sc->bfe_rx_ring[c]; 810181953Syongari if (r->bfe_mbuf != NULL) { 811181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, r->bfe_map, 812181953Syongari BUS_DMASYNC_POSTREAD); 813181953Syongari bus_dmamap_unload(sc->bfe_rxmbuf_tag, r->bfe_map); 814181953Syongari } 815181953Syongari map = r->bfe_map; 816181953Syongari r->bfe_map = sc->bfe_rx_sparemap; 817181953Syongari sc->bfe_rx_sparemap = map; 818181953Syongari r->bfe_mbuf = m; 819181953Syongari 820119917Swpaul rx_header = mtod(m, struct bfe_rxheader *); 821119917Swpaul rx_header->len = 0; 822119917Swpaul rx_header->flags = 0; 823181953Syongari bus_dmamap_sync(sc->bfe_rxmbuf_tag, r->bfe_map, BUS_DMASYNC_PREREAD); 824181953Syongari 825181953Syongari ctrl = segs[0].ds_len & BFE_DESC_LEN; 826181953Syongari KASSERT(ctrl > ETHER_MAX_LEN + 32, ("%s: buffer size too small(%d)!", 827181953Syongari __func__, ctrl)); 828181953Syongari if (c == BFE_RX_LIST_CNT - 1) 829181953Syongari ctrl |= BFE_DESC_EOT; 830181953Syongari r->bfe_ctrl = ctrl; 831119917Swpaul 832119917Swpaul d = &sc->bfe_rx_list[c]; 833181953Syongari d->bfe_ctrl = htole32(ctrl); 834181953Syongari /* The chip needs all addresses to be added to BFE_PCI_DMA. */ 835181953Syongari d->bfe_addr = htole32(BFE_ADDR_LO(segs[0].ds_addr) + BFE_PCI_DMA); 836119917Swpaul 837133282Sdes return (0); 838119917Swpaul} 839119917Swpaul 840119917Swpaulstatic void 841119917Swpaulbfe_get_config(struct bfe_softc *sc) 842119917Swpaul{ 843119917Swpaul u_int8_t eeprom[128]; 844119917Swpaul 845119917Swpaul bfe_read_eeprom(sc, eeprom); 846119917Swpaul 847147256Sbrooks sc->bfe_enaddr[0] = eeprom[79]; 848147256Sbrooks sc->bfe_enaddr[1] = eeprom[78]; 849147256Sbrooks sc->bfe_enaddr[2] = eeprom[81]; 850147256Sbrooks sc->bfe_enaddr[3] = eeprom[80]; 851147256Sbrooks sc->bfe_enaddr[4] = eeprom[83]; 852147256Sbrooks sc->bfe_enaddr[5] = eeprom[82]; 853119917Swpaul 854119917Swpaul sc->bfe_phyaddr = eeprom[90] & 0x1f; 855119917Swpaul sc->bfe_mdc_port = (eeprom[90] >> 14) & 0x1; 856119917Swpaul 857133282Sdes sc->bfe_core_unit = 0; 858119917Swpaul sc->bfe_dma_offset = BFE_PCI_DMA; 859119917Swpaul} 860119917Swpaul 861119917Swpaulstatic void 862119917Swpaulbfe_pci_setup(struct bfe_softc *sc, u_int32_t cores) 863119917Swpaul{ 864119917Swpaul u_int32_t bar_orig, pci_rev, val; 865119917Swpaul 866119917Swpaul bar_orig = pci_read_config(sc->bfe_dev, BFE_BAR0_WIN, 4); 867119917Swpaul pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, BFE_REG_PCI, 4); 868119917Swpaul pci_rev = CSR_READ_4(sc, BFE_SBIDHIGH) & BFE_RC_MASK; 869119917Swpaul 870119917Swpaul val = CSR_READ_4(sc, BFE_SBINTVEC); 871119917Swpaul val |= cores; 872119917Swpaul CSR_WRITE_4(sc, BFE_SBINTVEC, val); 873119917Swpaul 874119917Swpaul val = CSR_READ_4(sc, BFE_SSB_PCI_TRANS_2); 875119917Swpaul val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST; 876119917Swpaul CSR_WRITE_4(sc, BFE_SSB_PCI_TRANS_2, val); 877119917Swpaul 878119917Swpaul pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, bar_orig, 4); 879119917Swpaul} 880119917Swpaul 881133282Sdesstatic void 882119917Swpaulbfe_clear_stats(struct bfe_softc *sc) 883119917Swpaul{ 884181994Syongari uint32_t reg; 885119917Swpaul 886136804Smtm BFE_LOCK_ASSERT(sc); 887119917Swpaul 888119917Swpaul CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 889119917Swpaul for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) 890119917Swpaul CSR_READ_4(sc, reg); 891119917Swpaul for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) 892119917Swpaul CSR_READ_4(sc, reg); 893119917Swpaul} 894119917Swpaul 895133282Sdesstatic int 896119917Swpaulbfe_resetphy(struct bfe_softc *sc) 897119917Swpaul{ 898119917Swpaul u_int32_t val; 899119917Swpaul 900119917Swpaul bfe_writephy(sc, 0, BMCR_RESET); 901119917Swpaul DELAY(100); 902119917Swpaul bfe_readphy(sc, 0, &val); 903119917Swpaul if (val & BMCR_RESET) { 904180950Syongari device_printf(sc->bfe_dev, "PHY Reset would not complete.\n"); 905133282Sdes return (ENXIO); 906119917Swpaul } 907133282Sdes return (0); 908119917Swpaul} 909119917Swpaul 910119917Swpaulstatic void 911119917Swpaulbfe_chip_halt(struct bfe_softc *sc) 912119917Swpaul{ 913136804Smtm BFE_LOCK_ASSERT(sc); 914119917Swpaul /* disable interrupts - not that it actually does..*/ 915119917Swpaul CSR_WRITE_4(sc, BFE_IMASK, 0); 916119917Swpaul CSR_READ_4(sc, BFE_IMASK); 917119917Swpaul 918119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); 919119917Swpaul bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 200, 1); 920119917Swpaul 921119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); 922119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); 923119917Swpaul DELAY(10); 924119917Swpaul} 925119917Swpaul 926119917Swpaulstatic void 927119917Swpaulbfe_chip_reset(struct bfe_softc *sc) 928119917Swpaul{ 929133282Sdes u_int32_t val; 930119917Swpaul 931136804Smtm BFE_LOCK_ASSERT(sc); 932119917Swpaul 933119917Swpaul /* Set the interrupt vector for the enet core */ 934119917Swpaul bfe_pci_setup(sc, BFE_INTVEC_ENET0); 935119917Swpaul 936119917Swpaul /* is core up? */ 937126470Sjulian val = CSR_READ_4(sc, BFE_SBTMSLOW) & 938126470Sjulian (BFE_RESET | BFE_REJECT | BFE_CLOCK); 939119917Swpaul if (val == BFE_CLOCK) { 940119917Swpaul /* It is, so shut it down */ 941119917Swpaul CSR_WRITE_4(sc, BFE_RCV_LAZY, 0); 942119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); 943119917Swpaul bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 100, 1); 944119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); 945133282Sdes if (CSR_READ_4(sc, BFE_DMARX_STAT) & BFE_STAT_EMASK) 946126470Sjulian bfe_wait_bit(sc, BFE_DMARX_STAT, BFE_STAT_SIDLE, 947126470Sjulian 100, 0); 948119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); 949119917Swpaul } 950119917Swpaul 951119917Swpaul bfe_core_reset(sc); 952119917Swpaul bfe_clear_stats(sc); 953119917Swpaul 954119917Swpaul /* 955119917Swpaul * We want the phy registers to be accessible even when 956119917Swpaul * the driver is "downed" so initialize MDC preamble, frequency, 957119917Swpaul * and whether internal or external phy here. 958119917Swpaul */ 959119917Swpaul 960119917Swpaul /* 4402 has 62.5Mhz SB clock and internal phy */ 961119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d); 962119917Swpaul 963119917Swpaul /* Internal or external PHY? */ 964119917Swpaul val = CSR_READ_4(sc, BFE_DEVCTRL); 965180954Syongari if (!(val & BFE_IPP)) 966119917Swpaul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_EPSEL); 967180954Syongari else if (CSR_READ_4(sc, BFE_DEVCTRL) & BFE_EPR) { 968119917Swpaul BFE_AND(sc, BFE_DEVCTRL, ~BFE_EPR); 969119917Swpaul DELAY(100); 970119917Swpaul } 971119917Swpaul 972133282Sdes /* Enable CRC32 generation and set proper LED modes */ 973133282Sdes BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED); 974129602Sdmlb 975133282Sdes /* Reset or clear powerdown control bit */ 976133282Sdes BFE_AND(sc, BFE_MAC_CTRL, ~BFE_CTRL_PDOWN); 977129602Sdmlb 978133282Sdes CSR_WRITE_4(sc, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) & 979119917Swpaul BFE_LAZY_FC_MASK)); 980119917Swpaul 981133282Sdes /* 982126470Sjulian * We don't want lazy interrupts, so just send them at 983133282Sdes * the end of a frame, please 984119917Swpaul */ 985119917Swpaul BFE_OR(sc, BFE_RCV_LAZY, 0); 986119917Swpaul 987119917Swpaul /* Set max lengths, accounting for VLAN tags */ 988119917Swpaul CSR_WRITE_4(sc, BFE_RXMAXLEN, ETHER_MAX_LEN+32); 989119917Swpaul CSR_WRITE_4(sc, BFE_TXMAXLEN, ETHER_MAX_LEN+32); 990119917Swpaul 991119917Swpaul /* Set watermark XXX - magic */ 992119917Swpaul CSR_WRITE_4(sc, BFE_TX_WMARK, 56); 993119917Swpaul 994133282Sdes /* 995126470Sjulian * Initialise DMA channels 996133282Sdes * - not forgetting dma addresses need to be added to BFE_PCI_DMA 997119917Swpaul */ 998119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE); 999119917Swpaul CSR_WRITE_4(sc, BFE_DMATX_ADDR, sc->bfe_tx_dma + BFE_PCI_DMA); 1000119917Swpaul 1001133282Sdes CSR_WRITE_4(sc, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) | 1002119917Swpaul BFE_RX_CTRL_ENABLE); 1003119917Swpaul CSR_WRITE_4(sc, BFE_DMARX_ADDR, sc->bfe_rx_dma + BFE_PCI_DMA); 1004119917Swpaul 1005119917Swpaul bfe_resetphy(sc); 1006119917Swpaul bfe_setupphy(sc); 1007119917Swpaul} 1008119917Swpaul 1009119917Swpaulstatic void 1010119917Swpaulbfe_core_disable(struct bfe_softc *sc) 1011119917Swpaul{ 1012180954Syongari if ((CSR_READ_4(sc, BFE_SBTMSLOW)) & BFE_RESET) 1013119917Swpaul return; 1014119917Swpaul 1015133282Sdes /* 1016126470Sjulian * Set reject, wait for it set, then wait for the core to stop 1017126470Sjulian * being busy, then set reset and reject and enable the clocks. 1018119917Swpaul */ 1019119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK)); 1020119917Swpaul bfe_wait_bit(sc, BFE_SBTMSLOW, BFE_REJECT, 1000, 0); 1021119917Swpaul bfe_wait_bit(sc, BFE_SBTMSHIGH, BFE_BUSY, 1000, 1); 1022119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | 1023119917Swpaul BFE_RESET)); 1024119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1025119917Swpaul DELAY(10); 1026119917Swpaul /* Leave reset and reject set */ 1027119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET)); 1028119917Swpaul DELAY(10); 1029119917Swpaul} 1030119917Swpaul 1031119917Swpaulstatic void 1032119917Swpaulbfe_core_reset(struct bfe_softc *sc) 1033119917Swpaul{ 1034119917Swpaul u_int32_t val; 1035119917Swpaul 1036119917Swpaul /* Disable the core */ 1037119917Swpaul bfe_core_disable(sc); 1038119917Swpaul 1039119917Swpaul /* and bring it back up */ 1040119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC)); 1041119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1042119917Swpaul DELAY(10); 1043119917Swpaul 1044119917Swpaul /* Chip bug, clear SERR, IB and TO if they are set. */ 1045119917Swpaul if (CSR_READ_4(sc, BFE_SBTMSHIGH) & BFE_SERR) 1046119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSHIGH, 0); 1047119917Swpaul val = CSR_READ_4(sc, BFE_SBIMSTATE); 1048119917Swpaul if (val & (BFE_IBE | BFE_TO)) 1049119917Swpaul CSR_WRITE_4(sc, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO)); 1050119917Swpaul 1051119917Swpaul /* Clear reset and allow it to move through the core */ 1052119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC)); 1053119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1054119917Swpaul DELAY(10); 1055119917Swpaul 1056119917Swpaul /* Leave the clock set */ 1057119917Swpaul CSR_WRITE_4(sc, BFE_SBTMSLOW, BFE_CLOCK); 1058119917Swpaul CSR_READ_4(sc, BFE_SBTMSLOW); 1059119917Swpaul DELAY(10); 1060119917Swpaul} 1061119917Swpaul 1062133282Sdesstatic void 1063119917Swpaulbfe_cam_write(struct bfe_softc *sc, u_char *data, int index) 1064119917Swpaul{ 1065119917Swpaul u_int32_t val; 1066119917Swpaul 1067119917Swpaul val = ((u_int32_t) data[2]) << 24; 1068119917Swpaul val |= ((u_int32_t) data[3]) << 16; 1069119917Swpaul val |= ((u_int32_t) data[4]) << 8; 1070119917Swpaul val |= ((u_int32_t) data[5]); 1071119917Swpaul CSR_WRITE_4(sc, BFE_CAM_DATA_LO, val); 1072119917Swpaul val = (BFE_CAM_HI_VALID | 1073119917Swpaul (((u_int32_t) data[0]) << 8) | 1074119917Swpaul (((u_int32_t) data[1]))); 1075119917Swpaul CSR_WRITE_4(sc, BFE_CAM_DATA_HI, val); 1076119917Swpaul CSR_WRITE_4(sc, BFE_CAM_CTRL, (BFE_CAM_WRITE | 1077129602Sdmlb ((u_int32_t) index << BFE_CAM_INDEX_SHIFT))); 1078119917Swpaul bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1); 1079119917Swpaul} 1080119917Swpaul 1081133282Sdesstatic void 1082119917Swpaulbfe_set_rx_mode(struct bfe_softc *sc) 1083119917Swpaul{ 1084147256Sbrooks struct ifnet *ifp = sc->bfe_ifp; 1085119917Swpaul struct ifmultiaddr *ifma; 1086119917Swpaul u_int32_t val; 1087119917Swpaul int i = 0; 1088119917Swpaul 1089181994Syongari BFE_LOCK_ASSERT(sc); 1090181994Syongari 1091119917Swpaul val = CSR_READ_4(sc, BFE_RXCONF); 1092119917Swpaul 1093119917Swpaul if (ifp->if_flags & IFF_PROMISC) 1094119917Swpaul val |= BFE_RXCONF_PROMISC; 1095119917Swpaul else 1096119917Swpaul val &= ~BFE_RXCONF_PROMISC; 1097119917Swpaul 1098119917Swpaul if (ifp->if_flags & IFF_BROADCAST) 1099119917Swpaul val &= ~BFE_RXCONF_DBCAST; 1100119917Swpaul else 1101119917Swpaul val |= BFE_RXCONF_DBCAST; 1102119917Swpaul 1103119917Swpaul 1104119917Swpaul CSR_WRITE_4(sc, BFE_CAM_CTRL, 0); 1105152315Sru bfe_cam_write(sc, IF_LLADDR(sc->bfe_ifp), i++); 1106119917Swpaul 1107119917Swpaul if (ifp->if_flags & IFF_ALLMULTI) 1108119917Swpaul val |= BFE_RXCONF_ALLMULTI; 1109119917Swpaul else { 1110119917Swpaul val &= ~BFE_RXCONF_ALLMULTI; 1111195049Srwatson if_maddr_rlock(ifp); 1112119917Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1113119917Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 1114119917Swpaul continue; 1115126470Sjulian bfe_cam_write(sc, 1116126470Sjulian LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i++); 1117119917Swpaul } 1118195049Srwatson if_maddr_runlock(ifp); 1119119917Swpaul } 1120119917Swpaul 1121119917Swpaul CSR_WRITE_4(sc, BFE_RXCONF, val); 1122119917Swpaul BFE_OR(sc, BFE_CAM_CTRL, BFE_CAM_ENABLE); 1123119917Swpaul} 1124119917Swpaul 1125119917Swpaulstatic void 1126119917Swpaulbfe_dma_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1127119917Swpaul{ 1128181953Syongari struct bfe_dmamap_arg *ctx; 1129119917Swpaul 1130181953Syongari if (error != 0) 1131181953Syongari return; 1132119917Swpaul 1133181953Syongari KASSERT(nseg == 1, ("%s : %d segments returned!", __func__, nseg)); 1134119917Swpaul 1135181953Syongari ctx = (struct bfe_dmamap_arg *)arg; 1136181953Syongari ctx->bfe_busaddr = segs[0].ds_addr; 1137119917Swpaul} 1138119917Swpaul 1139119917Swpaulstatic void 1140119917Swpaulbfe_release_resources(struct bfe_softc *sc) 1141119917Swpaul{ 1142119917Swpaul 1143119917Swpaul if (sc->bfe_intrhand != NULL) 1144181953Syongari bus_teardown_intr(sc->bfe_dev, sc->bfe_irq, sc->bfe_intrhand); 1145119917Swpaul 1146119917Swpaul if (sc->bfe_irq != NULL) 1147181953Syongari bus_release_resource(sc->bfe_dev, SYS_RES_IRQ, 0, sc->bfe_irq); 1148119917Swpaul 1149119917Swpaul if (sc->bfe_res != NULL) 1150181953Syongari bus_release_resource(sc->bfe_dev, SYS_RES_MEMORY, PCIR_BAR(0), 1151181953Syongari sc->bfe_res); 1152119917Swpaul 1153150215Sru if (sc->bfe_ifp != NULL) 1154150215Sru if_free(sc->bfe_ifp); 1155119917Swpaul} 1156119917Swpaul 1157119917Swpaulstatic void 1158119917Swpaulbfe_read_eeprom(struct bfe_softc *sc, u_int8_t *data) 1159119917Swpaul{ 1160119917Swpaul long i; 1161119917Swpaul u_int16_t *ptr = (u_int16_t *)data; 1162119917Swpaul 1163119917Swpaul for(i = 0; i < 128; i += 2) 1164119917Swpaul ptr[i/2] = CSR_READ_4(sc, 4096 + i); 1165119917Swpaul} 1166119917Swpaul 1167119917Swpaulstatic int 1168133282Sdesbfe_wait_bit(struct bfe_softc *sc, u_int32_t reg, u_int32_t bit, 1169119917Swpaul u_long timeout, const int clear) 1170119917Swpaul{ 1171119917Swpaul u_long i; 1172119917Swpaul 1173119917Swpaul for (i = 0; i < timeout; i++) { 1174119917Swpaul u_int32_t val = CSR_READ_4(sc, reg); 1175119917Swpaul 1176119917Swpaul if (clear && !(val & bit)) 1177119917Swpaul break; 1178119917Swpaul if (!clear && (val & bit)) 1179119917Swpaul break; 1180119917Swpaul DELAY(10); 1181119917Swpaul } 1182119917Swpaul if (i == timeout) { 1183180950Syongari device_printf(sc->bfe_dev, 1184180950Syongari "BUG! Timeout waiting for bit %08x of register " 1185180950Syongari "%x to %s.\n", bit, reg, (clear ? "clear" : "set")); 1186133282Sdes return (-1); 1187119917Swpaul } 1188133282Sdes return (0); 1189119917Swpaul} 1190119917Swpaul 1191119917Swpaulstatic int 1192119917Swpaulbfe_readphy(struct bfe_softc *sc, u_int32_t reg, u_int32_t *val) 1193119917Swpaul{ 1194133282Sdes int err; 1195119917Swpaul 1196119917Swpaul /* Clear MII ISR */ 1197119917Swpaul CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 1198119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 1199119917Swpaul (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) | 1200119917Swpaul (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | 1201119917Swpaul (reg << BFE_MDIO_RA_SHIFT) | 1202119917Swpaul (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT))); 1203119917Swpaul err = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); 1204119917Swpaul *val = CSR_READ_4(sc, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA; 1205119917Swpaul 1206133282Sdes return (err); 1207119917Swpaul} 1208119917Swpaul 1209119917Swpaulstatic int 1210119917Swpaulbfe_writephy(struct bfe_softc *sc, u_int32_t reg, u_int32_t val) 1211119917Swpaul{ 1212119917Swpaul int status; 1213119917Swpaul 1214119917Swpaul CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 1215119917Swpaul CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 1216119917Swpaul (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) | 1217119917Swpaul (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | 1218119917Swpaul (reg << BFE_MDIO_RA_SHIFT) | 1219119917Swpaul (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) | 1220119917Swpaul (val & BFE_MDIO_DATA_DATA))); 1221119917Swpaul status = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); 1222119917Swpaul 1223133282Sdes return (status); 1224119917Swpaul} 1225119917Swpaul 1226133282Sdes/* 1227119917Swpaul * XXX - I think this is handled by the PHY driver, but it can't hurt to do it 1228119917Swpaul * twice 1229119917Swpaul */ 1230119917Swpaulstatic int 1231119917Swpaulbfe_setupphy(struct bfe_softc *sc) 1232119917Swpaul{ 1233119917Swpaul u_int32_t val; 1234119917Swpaul 1235119917Swpaul /* Enable activity LED */ 1236119917Swpaul bfe_readphy(sc, 26, &val); 1237133282Sdes bfe_writephy(sc, 26, val & 0x7fff); 1238119917Swpaul bfe_readphy(sc, 26, &val); 1239119917Swpaul 1240119917Swpaul /* Enable traffic meter LED mode */ 1241119917Swpaul bfe_readphy(sc, 27, &val); 1242119917Swpaul bfe_writephy(sc, 27, val | (1 << 6)); 1243119917Swpaul 1244133282Sdes return (0); 1245119917Swpaul} 1246119917Swpaul 1247133282Sdesstatic void 1248119917Swpaulbfe_stats_update(struct bfe_softc *sc) 1249119917Swpaul{ 1250181994Syongari struct bfe_hw_stats *stats; 1251181994Syongari struct ifnet *ifp; 1252181994Syongari uint32_t mib[BFE_MIB_CNT]; 1253181994Syongari uint32_t reg, *val; 1254119917Swpaul 1255181994Syongari BFE_LOCK_ASSERT(sc); 1256181994Syongari 1257181994Syongari val = mib; 1258181994Syongari CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 1259181994Syongari for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) 1260181994Syongari *val++ = CSR_READ_4(sc, reg); 1261181994Syongari for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) 1262181994Syongari *val++ = CSR_READ_4(sc, reg); 1263181994Syongari 1264181994Syongari ifp = sc->bfe_ifp; 1265181994Syongari stats = &sc->bfe_stats; 1266181994Syongari /* Tx stat. */ 1267181994Syongari stats->tx_good_octets += mib[MIB_TX_GOOD_O]; 1268181994Syongari stats->tx_good_frames += mib[MIB_TX_GOOD_P]; 1269181994Syongari stats->tx_octets += mib[MIB_TX_O]; 1270181994Syongari stats->tx_frames += mib[MIB_TX_P]; 1271181994Syongari stats->tx_bcast_frames += mib[MIB_TX_BCAST]; 1272181994Syongari stats->tx_mcast_frames += mib[MIB_TX_MCAST]; 1273181994Syongari stats->tx_pkts_64 += mib[MIB_TX_64]; 1274181994Syongari stats->tx_pkts_65_127 += mib[MIB_TX_65_127]; 1275181994Syongari stats->tx_pkts_128_255 += mib[MIB_TX_128_255]; 1276181994Syongari stats->tx_pkts_256_511 += mib[MIB_TX_256_511]; 1277181994Syongari stats->tx_pkts_512_1023 += mib[MIB_TX_512_1023]; 1278181994Syongari stats->tx_pkts_1024_max += mib[MIB_TX_1024_MAX]; 1279181994Syongari stats->tx_jabbers += mib[MIB_TX_JABBER]; 1280181994Syongari stats->tx_oversize_frames += mib[MIB_TX_OSIZE]; 1281181994Syongari stats->tx_frag_frames += mib[MIB_TX_FRAG]; 1282181994Syongari stats->tx_underruns += mib[MIB_TX_URUNS]; 1283181994Syongari stats->tx_colls += mib[MIB_TX_TCOLS]; 1284181994Syongari stats->tx_single_colls += mib[MIB_TX_SCOLS]; 1285181994Syongari stats->tx_multi_colls += mib[MIB_TX_MCOLS]; 1286181994Syongari stats->tx_excess_colls += mib[MIB_TX_ECOLS]; 1287181994Syongari stats->tx_late_colls += mib[MIB_TX_LCOLS]; 1288181994Syongari stats->tx_deferrals += mib[MIB_TX_DEFERED]; 1289181994Syongari stats->tx_carrier_losts += mib[MIB_TX_CLOST]; 1290181994Syongari stats->tx_pause_frames += mib[MIB_TX_PAUSE]; 1291181994Syongari /* Rx stat. */ 1292181994Syongari stats->rx_good_octets += mib[MIB_RX_GOOD_O]; 1293181994Syongari stats->rx_good_frames += mib[MIB_RX_GOOD_P]; 1294181994Syongari stats->rx_octets += mib[MIB_RX_O]; 1295181994Syongari stats->rx_frames += mib[MIB_RX_P]; 1296181994Syongari stats->rx_bcast_frames += mib[MIB_RX_BCAST]; 1297181994Syongari stats->rx_mcast_frames += mib[MIB_RX_MCAST]; 1298181994Syongari stats->rx_pkts_64 += mib[MIB_RX_64]; 1299181994Syongari stats->rx_pkts_65_127 += mib[MIB_RX_65_127]; 1300181994Syongari stats->rx_pkts_128_255 += mib[MIB_RX_128_255]; 1301181994Syongari stats->rx_pkts_256_511 += mib[MIB_RX_256_511]; 1302181994Syongari stats->rx_pkts_512_1023 += mib[MIB_RX_512_1023]; 1303181994Syongari stats->rx_pkts_1024_max += mib[MIB_RX_1024_MAX]; 1304181994Syongari stats->rx_jabbers += mib[MIB_RX_JABBER]; 1305181994Syongari stats->rx_oversize_frames += mib[MIB_RX_OSIZE]; 1306181994Syongari stats->rx_frag_frames += mib[MIB_RX_FRAG]; 1307181994Syongari stats->rx_missed_frames += mib[MIB_RX_MISS]; 1308181994Syongari stats->rx_crc_align_errs += mib[MIB_RX_CRCA]; 1309181994Syongari stats->rx_runts += mib[MIB_RX_USIZE]; 1310181994Syongari stats->rx_crc_errs += mib[MIB_RX_CRC]; 1311181994Syongari stats->rx_align_errs += mib[MIB_RX_ALIGN]; 1312181994Syongari stats->rx_symbol_errs += mib[MIB_RX_SYM]; 1313181994Syongari stats->rx_pause_frames += mib[MIB_RX_PAUSE]; 1314181994Syongari stats->rx_control_frames += mib[MIB_RX_NPAUSE]; 1315181994Syongari 1316181994Syongari /* Update counters in ifnet. */ 1317181994Syongari ifp->if_opackets += (u_long)mib[MIB_TX_GOOD_P]; 1318181994Syongari ifp->if_collisions += (u_long)mib[MIB_TX_TCOLS]; 1319181994Syongari ifp->if_oerrors += (u_long)mib[MIB_TX_URUNS] + 1320181994Syongari (u_long)mib[MIB_TX_ECOLS] + 1321181994Syongari (u_long)mib[MIB_TX_DEFERED] + 1322181994Syongari (u_long)mib[MIB_TX_CLOST]; 1323181994Syongari 1324181994Syongari ifp->if_ipackets += (u_long)mib[MIB_RX_GOOD_P]; 1325181994Syongari 1326181994Syongari ifp->if_ierrors += mib[MIB_RX_JABBER] + 1327181994Syongari mib[MIB_RX_MISS] + 1328181994Syongari mib[MIB_RX_CRCA] + 1329181994Syongari mib[MIB_RX_USIZE] + 1330181994Syongari mib[MIB_RX_CRC] + 1331181994Syongari mib[MIB_RX_ALIGN] + 1332181994Syongari mib[MIB_RX_SYM]; 1333119917Swpaul} 1334119917Swpaul 1335119917Swpaulstatic void 1336119917Swpaulbfe_txeof(struct bfe_softc *sc) 1337119917Swpaul{ 1338181953Syongari struct bfe_tx_data *r; 1339119917Swpaul struct ifnet *ifp; 1340119917Swpaul int i, chipidx; 1341119917Swpaul 1342136804Smtm BFE_LOCK_ASSERT(sc); 1343119917Swpaul 1344147256Sbrooks ifp = sc->bfe_ifp; 1345119917Swpaul 1346119917Swpaul chipidx = CSR_READ_4(sc, BFE_DMATX_STAT) & BFE_STAT_CDMASK; 1347119917Swpaul chipidx /= sizeof(struct bfe_desc); 1348119917Swpaul 1349126470Sjulian i = sc->bfe_tx_cons; 1350181953Syongari if (i == chipidx) 1351181953Syongari return; 1352181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 1353181953Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1354119917Swpaul /* Go through the mbufs and free those that have been transmitted */ 1355181953Syongari for (; i != chipidx; BFE_INC(i, BFE_TX_LIST_CNT)) { 1356181953Syongari r = &sc->bfe_tx_ring[i]; 1357126470Sjulian sc->bfe_tx_cnt--; 1358181953Syongari if (r->bfe_mbuf == NULL) 1359181953Syongari continue; 1360181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, r->bfe_map, 1361181953Syongari BUS_DMASYNC_POSTWRITE); 1362181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, r->bfe_map); 1363181953Syongari 1364181953Syongari m_freem(r->bfe_mbuf); 1365181953Syongari r->bfe_mbuf = NULL; 1366119917Swpaul } 1367119917Swpaul 1368180954Syongari if (i != sc->bfe_tx_cons) { 1369119917Swpaul /* we freed up some mbufs */ 1370119917Swpaul sc->bfe_tx_cons = i; 1371148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1372119917Swpaul } 1373175787Syongari 1374175787Syongari if (sc->bfe_tx_cnt == 0) 1375175787Syongari sc->bfe_watchdog_timer = 0; 1376119917Swpaul} 1377119917Swpaul 1378119917Swpaul/* Pass a received packet up the stack */ 1379119917Swpaulstatic void 1380119917Swpaulbfe_rxeof(struct bfe_softc *sc) 1381119917Swpaul{ 1382119917Swpaul struct mbuf *m; 1383119917Swpaul struct ifnet *ifp; 1384119917Swpaul struct bfe_rxheader *rxheader; 1385181953Syongari struct bfe_rx_data *r; 1386181953Syongari int cons, prog; 1387119917Swpaul u_int32_t status, current, len, flags; 1388119917Swpaul 1389136804Smtm BFE_LOCK_ASSERT(sc); 1390119917Swpaul cons = sc->bfe_rx_cons; 1391119917Swpaul status = CSR_READ_4(sc, BFE_DMARX_STAT); 1392119917Swpaul current = (status & BFE_STAT_CDMASK) / sizeof(struct bfe_desc); 1393119917Swpaul 1394147256Sbrooks ifp = sc->bfe_ifp; 1395119917Swpaul 1396181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 1397181953Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1398181953Syongari 1399181953Syongari for (prog = 0; current != cons; prog++, 1400181953Syongari BFE_INC(cons, BFE_RX_LIST_CNT)) { 1401119917Swpaul r = &sc->bfe_rx_ring[cons]; 1402119917Swpaul m = r->bfe_mbuf; 1403181953Syongari /* 1404181953Syongari * Rx status should be read from mbuf such that we can't 1405181953Syongari * delay bus_dmamap_sync(9). This hardware limiation 1406181953Syongari * results in inefficent mbuf usage as bfe(4) couldn't 1407181953Syongari * reuse mapped buffer from errored frame. 1408181953Syongari */ 1409181953Syongari if (bfe_list_newbuf(sc, cons) != 0) { 1410181953Syongari ifp->if_iqdrops++; 1411181953Syongari bfe_discard_buf(sc, cons); 1412181953Syongari continue; 1413181953Syongari } 1414119917Swpaul rxheader = mtod(m, struct bfe_rxheader*); 1415181953Syongari len = le16toh(rxheader->len); 1416181953Syongari flags = le16toh(rxheader->flags); 1417119917Swpaul 1418181953Syongari /* Remove CRC bytes. */ 1419119917Swpaul len -= ETHER_CRC_LEN; 1420119917Swpaul 1421119917Swpaul /* flag an error and try again */ 1422119917Swpaul if ((len > ETHER_MAX_LEN+32) || (flags & BFE_RX_FLAG_ERRORS)) { 1423181953Syongari m_freem(m); 1424119917Swpaul continue; 1425119917Swpaul } 1426119917Swpaul 1427181953Syongari /* Make sure to skip header bytes written by hardware. */ 1428181953Syongari m_adj(m, BFE_RX_OFFSET); 1429181953Syongari m->m_len = m->m_pkthdr.len = len; 1430119917Swpaul 1431119917Swpaul m->m_pkthdr.rcvif = ifp; 1432122689Ssam BFE_UNLOCK(sc); 1433119917Swpaul (*ifp->if_input)(ifp, m); 1434122689Ssam BFE_LOCK(sc); 1435181953Syongari } 1436119917Swpaul 1437181953Syongari if (prog > 0) { 1438181953Syongari sc->bfe_rx_cons = cons; 1439181953Syongari bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 1440181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1441119917Swpaul } 1442119917Swpaul} 1443119917Swpaul 1444119917Swpaulstatic void 1445119917Swpaulbfe_intr(void *xsc) 1446119917Swpaul{ 1447119917Swpaul struct bfe_softc *sc = xsc; 1448119917Swpaul struct ifnet *ifp; 1449181994Syongari u_int32_t istat; 1450119917Swpaul 1451147256Sbrooks ifp = sc->bfe_ifp; 1452119917Swpaul 1453119917Swpaul BFE_LOCK(sc); 1454119917Swpaul 1455119917Swpaul istat = CSR_READ_4(sc, BFE_ISTAT); 1456119917Swpaul 1457133282Sdes /* 1458119917Swpaul * Defer unsolicited interrupts - This is necessary because setting the 1459119917Swpaul * chips interrupt mask register to 0 doesn't actually stop the 1460119917Swpaul * interrupts 1461119917Swpaul */ 1462181992Syongari istat &= BFE_IMASK_DEF; 1463119917Swpaul CSR_WRITE_4(sc, BFE_ISTAT, istat); 1464119917Swpaul CSR_READ_4(sc, BFE_ISTAT); 1465119917Swpaul 1466119917Swpaul /* not expecting this interrupt, disregard it */ 1467181992Syongari if (istat == 0 || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1468119917Swpaul BFE_UNLOCK(sc); 1469119917Swpaul return; 1470119917Swpaul } 1471119917Swpaul 1472181994Syongari /* A packet was received */ 1473181994Syongari if (istat & BFE_ISTAT_RX) 1474181994Syongari bfe_rxeof(sc); 1475181994Syongari 1476181994Syongari /* A packet was sent */ 1477181994Syongari if (istat & BFE_ISTAT_TX) 1478181994Syongari bfe_txeof(sc); 1479181994Syongari 1480180954Syongari if (istat & BFE_ISTAT_ERRORS) { 1481159013Ssilby 1482159013Ssilby if (istat & BFE_ISTAT_DSCE) { 1483180950Syongari device_printf(sc->bfe_dev, "Descriptor Error\n"); 1484159013Ssilby bfe_stop(sc); 1485159013Ssilby BFE_UNLOCK(sc); 1486159013Ssilby return; 1487159013Ssilby } 1488159013Ssilby 1489159013Ssilby if (istat & BFE_ISTAT_DPE) { 1490180950Syongari device_printf(sc->bfe_dev, 1491180950Syongari "Descriptor Protocol Error\n"); 1492159013Ssilby bfe_stop(sc); 1493159013Ssilby BFE_UNLOCK(sc); 1494159013Ssilby return; 1495159013Ssilby } 1496148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1497136804Smtm bfe_init_locked(sc); 1498119917Swpaul } 1499119917Swpaul 1500133282Sdes /* We have packets pending, fire them out */ 1501181992Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1502136804Smtm bfe_start_locked(ifp); 1503119917Swpaul 1504119917Swpaul BFE_UNLOCK(sc); 1505119917Swpaul} 1506119917Swpaul 1507119917Swpaulstatic int 1508181953Syongaribfe_encap(struct bfe_softc *sc, struct mbuf **m_head) 1509119917Swpaul{ 1510181953Syongari struct bfe_desc *d; 1511181953Syongari struct bfe_tx_data *r, *r1; 1512181953Syongari struct mbuf *m; 1513181953Syongari bus_dmamap_t map; 1514181953Syongari bus_dma_segment_t txsegs[BFE_MAXTXSEGS]; 1515181953Syongari uint32_t cur, si; 1516181953Syongari int error, i, nsegs; 1517119917Swpaul 1518181953Syongari BFE_LOCK_ASSERT(sc); 1519119917Swpaul 1520181953Syongari M_ASSERTPKTHDR((*m_head)); 1521119917Swpaul 1522181953Syongari si = cur = sc->bfe_tx_prod; 1523181953Syongari r = &sc->bfe_tx_ring[cur]; 1524181953Syongari error = bus_dmamap_load_mbuf_sg(sc->bfe_txmbuf_tag, r->bfe_map, *m_head, 1525181953Syongari txsegs, &nsegs, 0); 1526181953Syongari if (error == EFBIG) { 1527181953Syongari m = m_collapse(*m_head, M_DONTWAIT, BFE_MAXTXSEGS); 1528181953Syongari if (m == NULL) { 1529181953Syongari m_freem(*m_head); 1530181953Syongari *m_head = NULL; 1531181953Syongari return (ENOMEM); 1532181953Syongari } 1533158285Ssilby *m_head = m; 1534181953Syongari error = bus_dmamap_load_mbuf_sg(sc->bfe_txmbuf_tag, r->bfe_map, 1535181953Syongari *m_head, txsegs, &nsegs, 0); 1536181953Syongari if (error != 0) { 1537181953Syongari m_freem(*m_head); 1538181953Syongari *m_head = NULL; 1539181953Syongari return (error); 1540181953Syongari } 1541181953Syongari } else if (error != 0) 1542181953Syongari return (error); 1543181953Syongari if (nsegs == 0) { 1544181953Syongari m_freem(*m_head); 1545181953Syongari *m_head = NULL; 1546181953Syongari return (EIO); 1547119917Swpaul } 1548119917Swpaul 1549181953Syongari if (sc->bfe_tx_cnt + nsegs > BFE_TX_LIST_CNT - 1) { 1550181953Syongari bus_dmamap_unload(sc->bfe_txmbuf_tag, r->bfe_map); 1551181953Syongari return (ENOBUFS); 1552181953Syongari } 1553119917Swpaul 1554181953Syongari for (i = 0; i < nsegs; i++) { 1555181953Syongari d = &sc->bfe_tx_list[cur]; 1556181953Syongari d->bfe_ctrl = htole32(txsegs[i].ds_len & BFE_DESC_LEN); 1557181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_IOC); 1558181953Syongari if (cur == BFE_TX_LIST_CNT - 1) 1559181953Syongari /* 1560181953Syongari * Tell the chip to wrap to the start of 1561181953Syongari * the descriptor list. 1562181953Syongari */ 1563181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_EOT); 1564181953Syongari /* The chip needs all addresses to be added to BFE_PCI_DMA. */ 1565181953Syongari d->bfe_addr = htole32(BFE_ADDR_LO(txsegs[i].ds_addr) + 1566181953Syongari BFE_PCI_DMA); 1567181953Syongari BFE_INC(cur, BFE_TX_LIST_CNT); 1568181953Syongari } 1569119917Swpaul 1570181953Syongari /* Update producer index. */ 1571181953Syongari sc->bfe_tx_prod = cur; 1572119917Swpaul 1573181953Syongari /* Set EOF on the last descriptor. */ 1574181953Syongari cur = (cur + BFE_TX_LIST_CNT - 1) % BFE_TX_LIST_CNT; 1575181953Syongari d = &sc->bfe_tx_list[cur]; 1576181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_EOF); 1577119917Swpaul 1578181953Syongari /* Lastly set SOF on the first descriptor to avoid races. */ 1579181953Syongari d = &sc->bfe_tx_list[si]; 1580181953Syongari d->bfe_ctrl |= htole32(BFE_DESC_SOF); 1581119917Swpaul 1582181953Syongari r1 = &sc->bfe_tx_ring[cur]; 1583181953Syongari map = r->bfe_map; 1584181953Syongari r->bfe_map = r1->bfe_map; 1585181953Syongari r1->bfe_map = map; 1586181953Syongari r1->bfe_mbuf = *m_head; 1587181953Syongari sc->bfe_tx_cnt += nsegs; 1588119917Swpaul 1589181953Syongari bus_dmamap_sync(sc->bfe_txmbuf_tag, map, BUS_DMASYNC_PREWRITE); 1590119917Swpaul 1591119917Swpaul return (0); 1592119917Swpaul} 1593119917Swpaul 1594119917Swpaul/* 1595136804Smtm * Set up to transmit a packet. 1596119917Swpaul */ 1597119917Swpaulstatic void 1598119917Swpaulbfe_start(struct ifnet *ifp) 1599119917Swpaul{ 1600136804Smtm BFE_LOCK((struct bfe_softc *)ifp->if_softc); 1601136804Smtm bfe_start_locked(ifp); 1602136804Smtm BFE_UNLOCK((struct bfe_softc *)ifp->if_softc); 1603136804Smtm} 1604136804Smtm 1605136804Smtm/* 1606136804Smtm * Set up to transmit a packet. The softc is already locked. 1607136804Smtm */ 1608136804Smtmstatic void 1609136804Smtmbfe_start_locked(struct ifnet *ifp) 1610136804Smtm{ 1611119917Swpaul struct bfe_softc *sc; 1612181953Syongari struct mbuf *m_head; 1613181953Syongari int queued; 1614119917Swpaul 1615119917Swpaul sc = ifp->if_softc; 1616119917Swpaul 1617136804Smtm BFE_LOCK_ASSERT(sc); 1618119917Swpaul 1619133282Sdes /* 1620126470Sjulian * Not much point trying to send if the link is down 1621126470Sjulian * or we have nothing to send. 1622119917Swpaul */ 1623175787Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1624181976Syongari IFF_DRV_RUNNING || (sc->bfe_flags & BFE_FLAG_LINK) == 0) 1625119917Swpaul return; 1626119917Swpaul 1627181953Syongari for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 1628181953Syongari sc->bfe_tx_cnt < BFE_TX_LIST_CNT - 1;) { 1629131455Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1630180954Syongari if (m_head == NULL) 1631119917Swpaul break; 1632119917Swpaul 1633133282Sdes /* 1634126470Sjulian * Pack the data into the tx ring. If we dont have 1635126470Sjulian * enough room, let the chip drain the ring. 1636119917Swpaul */ 1637181953Syongari if (bfe_encap(sc, &m_head)) { 1638181953Syongari if (m_head == NULL) 1639181953Syongari break; 1640131455Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1641148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1642119917Swpaul break; 1643119917Swpaul } 1644119917Swpaul 1645136269Smlaier queued++; 1646136269Smlaier 1647119917Swpaul /* 1648119917Swpaul * If there's a BPF listener, bounce a copy of this frame 1649119917Swpaul * to him. 1650119917Swpaul */ 1651119917Swpaul BPF_MTAP(ifp, m_head); 1652119917Swpaul } 1653119917Swpaul 1654136269Smlaier if (queued) { 1655181953Syongari bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 1656181953Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1657136269Smlaier /* Transmit - twice due to apparent hardware bug */ 1658181953Syongari CSR_WRITE_4(sc, BFE_DMATX_PTR, 1659181953Syongari sc->bfe_tx_prod * sizeof(struct bfe_desc)); 1660181953Syongari /* 1661181953Syongari * XXX It seems the following write is not necessary 1662181953Syongari * to kick Tx command. What might be required would be 1663181953Syongari * a way flushing PCI posted write. Reading the register 1664181953Syongari * back ensures the flush operation. In addition, 1665181953Syongari * hardware will execute PCI posted write in the long 1666181953Syongari * run and watchdog timer for the kick command was set 1667181953Syongari * to 5 seconds. Therefore I think the second write 1668181953Syongari * access is not necessary or could be replaced with 1669181953Syongari * read operation. 1670181953Syongari */ 1671181953Syongari CSR_WRITE_4(sc, BFE_DMATX_PTR, 1672181953Syongari sc->bfe_tx_prod * sizeof(struct bfe_desc)); 1673119917Swpaul 1674136269Smlaier /* 1675136269Smlaier * Set a timeout in case the chip goes out to lunch. 1676136269Smlaier */ 1677175787Syongari sc->bfe_watchdog_timer = 5; 1678136269Smlaier } 1679119917Swpaul} 1680119917Swpaul 1681119917Swpaulstatic void 1682119917Swpaulbfe_init(void *xsc) 1683119917Swpaul{ 1684136804Smtm BFE_LOCK((struct bfe_softc *)xsc); 1685136804Smtm bfe_init_locked(xsc); 1686136804Smtm BFE_UNLOCK((struct bfe_softc *)xsc); 1687136804Smtm} 1688136804Smtm 1689136804Smtmstatic void 1690136804Smtmbfe_init_locked(void *xsc) 1691136804Smtm{ 1692119917Swpaul struct bfe_softc *sc = (struct bfe_softc*)xsc; 1693147256Sbrooks struct ifnet *ifp = sc->bfe_ifp; 1694175787Syongari struct mii_data *mii; 1695119917Swpaul 1696136804Smtm BFE_LOCK_ASSERT(sc); 1697119917Swpaul 1698175787Syongari mii = device_get_softc(sc->bfe_miibus); 1699175787Syongari 1700148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1701119917Swpaul return; 1702119917Swpaul 1703119917Swpaul bfe_stop(sc); 1704119917Swpaul bfe_chip_reset(sc); 1705119917Swpaul 1706119917Swpaul if (bfe_list_rx_init(sc) == ENOBUFS) { 1707180950Syongari device_printf(sc->bfe_dev, 1708180950Syongari "%s: Not enough memory for list buffers\n", __func__); 1709119917Swpaul bfe_stop(sc); 1710119917Swpaul return; 1711119917Swpaul } 1712181953Syongari bfe_list_tx_init(sc); 1713119917Swpaul 1714119917Swpaul bfe_set_rx_mode(sc); 1715119917Swpaul 1716119917Swpaul /* Enable the chip and core */ 1717119917Swpaul BFE_OR(sc, BFE_ENET_CTRL, BFE_ENET_ENABLE); 1718119917Swpaul /* Enable interrupts */ 1719119917Swpaul CSR_WRITE_4(sc, BFE_IMASK, BFE_IMASK_DEF); 1720119917Swpaul 1721175787Syongari /* Clear link state and change media. */ 1722181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 1723175787Syongari mii_mediachg(mii); 1724175787Syongari 1725148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1726148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1727119917Swpaul 1728175787Syongari callout_reset(&sc->bfe_stat_co, hz, bfe_tick, sc); 1729119917Swpaul} 1730119917Swpaul 1731119917Swpaul/* 1732119917Swpaul * Set media options. 1733119917Swpaul */ 1734119917Swpaulstatic int 1735119917Swpaulbfe_ifmedia_upd(struct ifnet *ifp) 1736119917Swpaul{ 1737119917Swpaul struct bfe_softc *sc; 1738119917Swpaul struct mii_data *mii; 1739175787Syongari int error; 1740119917Swpaul 1741119917Swpaul sc = ifp->if_softc; 1742175787Syongari BFE_LOCK(sc); 1743119917Swpaul 1744119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1745119917Swpaul if (mii->mii_instance) { 1746119917Swpaul struct mii_softc *miisc; 1747119917Swpaul for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 1748119917Swpaul miisc = LIST_NEXT(miisc, mii_list)) 1749119917Swpaul mii_phy_reset(miisc); 1750119917Swpaul } 1751175787Syongari error = mii_mediachg(mii); 1752175787Syongari BFE_UNLOCK(sc); 1753119917Swpaul 1754175787Syongari return (error); 1755119917Swpaul} 1756119917Swpaul 1757119917Swpaul/* 1758119917Swpaul * Report current media status. 1759119917Swpaul */ 1760119917Swpaulstatic void 1761119917Swpaulbfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1762119917Swpaul{ 1763119917Swpaul struct bfe_softc *sc = ifp->if_softc; 1764119917Swpaul struct mii_data *mii; 1765119917Swpaul 1766175787Syongari BFE_LOCK(sc); 1767119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1768119917Swpaul mii_pollstat(mii); 1769119917Swpaul ifmr->ifm_active = mii->mii_media_active; 1770119917Swpaul ifmr->ifm_status = mii->mii_media_status; 1771175787Syongari BFE_UNLOCK(sc); 1772119917Swpaul} 1773119917Swpaul 1774119917Swpaulstatic int 1775119917Swpaulbfe_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1776119917Swpaul{ 1777119917Swpaul struct bfe_softc *sc = ifp->if_softc; 1778119917Swpaul struct ifreq *ifr = (struct ifreq *) data; 1779119917Swpaul struct mii_data *mii; 1780119917Swpaul int error = 0; 1781119917Swpaul 1782180954Syongari switch (command) { 1783180954Syongari case SIOCSIFFLAGS: 1784180954Syongari BFE_LOCK(sc); 1785181976Syongari if (ifp->if_flags & IFF_UP) { 1786180954Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1787119917Swpaul bfe_set_rx_mode(sc); 1788181976Syongari else if ((sc->bfe_flags & BFE_FLAG_DETACH) == 0) 1789180954Syongari bfe_init_locked(sc); 1790181976Syongari } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1791180954Syongari bfe_stop(sc); 1792180954Syongari BFE_UNLOCK(sc); 1793180954Syongari break; 1794180954Syongari case SIOCADDMULTI: 1795180954Syongari case SIOCDELMULTI: 1796180954Syongari BFE_LOCK(sc); 1797180954Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1798180954Syongari bfe_set_rx_mode(sc); 1799180954Syongari BFE_UNLOCK(sc); 1800180954Syongari break; 1801180954Syongari case SIOCGIFMEDIA: 1802180954Syongari case SIOCSIFMEDIA: 1803180954Syongari mii = device_get_softc(sc->bfe_miibus); 1804180954Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1805180954Syongari break; 1806180954Syongari default: 1807180954Syongari error = ether_ioctl(ifp, command, data); 1808180954Syongari break; 1809119917Swpaul } 1810119917Swpaul 1811133282Sdes return (error); 1812119917Swpaul} 1813119917Swpaul 1814119917Swpaulstatic void 1815175787Syongaribfe_watchdog(struct bfe_softc *sc) 1816119917Swpaul{ 1817175787Syongari struct ifnet *ifp; 1818119917Swpaul 1819175787Syongari BFE_LOCK_ASSERT(sc); 1820119917Swpaul 1821175787Syongari if (sc->bfe_watchdog_timer == 0 || --sc->bfe_watchdog_timer) 1822175787Syongari return; 1823119917Swpaul 1824175787Syongari ifp = sc->bfe_ifp; 1825175787Syongari 1826180950Syongari device_printf(sc->bfe_dev, "watchdog timeout -- resetting\n"); 1827119917Swpaul 1828175787Syongari ifp->if_oerrors++; 1829148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1830136804Smtm bfe_init_locked(sc); 1831119917Swpaul 1832175787Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1833175787Syongari bfe_start_locked(ifp); 1834119917Swpaul} 1835119917Swpaul 1836119917Swpaulstatic void 1837119917Swpaulbfe_tick(void *xsc) 1838119917Swpaul{ 1839119917Swpaul struct bfe_softc *sc = xsc; 1840119917Swpaul struct mii_data *mii; 1841119917Swpaul 1842175787Syongari BFE_LOCK_ASSERT(sc); 1843119917Swpaul 1844119917Swpaul mii = device_get_softc(sc->bfe_miibus); 1845175787Syongari mii_tick(mii); 1846119917Swpaul bfe_stats_update(sc); 1847175787Syongari bfe_watchdog(sc); 1848175787Syongari callout_reset(&sc->bfe_stat_co, hz, bfe_tick, sc); 1849119917Swpaul} 1850119917Swpaul 1851119917Swpaul/* 1852119917Swpaul * Stop the adapter and free any mbufs allocated to the 1853119917Swpaul * RX and TX lists. 1854119917Swpaul */ 1855119917Swpaulstatic void 1856119917Swpaulbfe_stop(struct bfe_softc *sc) 1857119917Swpaul{ 1858119917Swpaul struct ifnet *ifp; 1859119917Swpaul 1860136804Smtm BFE_LOCK_ASSERT(sc); 1861119917Swpaul 1862147256Sbrooks ifp = sc->bfe_ifp; 1863175787Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1864181976Syongari sc->bfe_flags &= ~BFE_FLAG_LINK; 1865175787Syongari callout_stop(&sc->bfe_stat_co); 1866175787Syongari sc->bfe_watchdog_timer = 0; 1867119917Swpaul 1868119917Swpaul bfe_chip_halt(sc); 1869126470Sjulian bfe_tx_ring_free(sc); 1870119917Swpaul bfe_rx_ring_free(sc); 1871119917Swpaul} 1872181994Syongari 1873181994Syongaristatic int 1874181994Syongarisysctl_bfe_stats(SYSCTL_HANDLER_ARGS) 1875181994Syongari{ 1876181994Syongari struct bfe_softc *sc; 1877181994Syongari struct bfe_hw_stats *stats; 1878181994Syongari int error, result; 1879181994Syongari 1880181994Syongari result = -1; 1881181994Syongari error = sysctl_handle_int(oidp, &result, 0, req); 1882181994Syongari 1883181994Syongari if (error != 0 || req->newptr == NULL) 1884181994Syongari return (error); 1885181994Syongari 1886181994Syongari if (result != 1) 1887181994Syongari return (error); 1888181994Syongari 1889181994Syongari sc = (struct bfe_softc *)arg1; 1890181994Syongari stats = &sc->bfe_stats; 1891181994Syongari 1892181994Syongari printf("%s statistics:\n", device_get_nameunit(sc->bfe_dev)); 1893181994Syongari printf("Transmit good octets : %ju\n", 1894181994Syongari (uintmax_t)stats->tx_good_octets); 1895181994Syongari printf("Transmit good frames : %ju\n", 1896181994Syongari (uintmax_t)stats->tx_good_frames); 1897181994Syongari printf("Transmit octets : %ju\n", 1898181994Syongari (uintmax_t)stats->tx_octets); 1899181994Syongari printf("Transmit frames : %ju\n", 1900181994Syongari (uintmax_t)stats->tx_frames); 1901181994Syongari printf("Transmit broadcast frames : %ju\n", 1902181994Syongari (uintmax_t)stats->tx_bcast_frames); 1903181994Syongari printf("Transmit multicast frames : %ju\n", 1904181994Syongari (uintmax_t)stats->tx_mcast_frames); 1905181994Syongari printf("Transmit frames 64 bytes : %ju\n", 1906181994Syongari (uint64_t)stats->tx_pkts_64); 1907181994Syongari printf("Transmit frames 65 to 127 bytes : %ju\n", 1908181994Syongari (uint64_t)stats->tx_pkts_65_127); 1909181994Syongari printf("Transmit frames 128 to 255 bytes : %ju\n", 1910181994Syongari (uint64_t)stats->tx_pkts_128_255); 1911181994Syongari printf("Transmit frames 256 to 511 bytes : %ju\n", 1912181994Syongari (uint64_t)stats->tx_pkts_256_511); 1913181994Syongari printf("Transmit frames 512 to 1023 bytes : %ju\n", 1914181994Syongari (uint64_t)stats->tx_pkts_512_1023); 1915181994Syongari printf("Transmit frames 1024 to max bytes : %ju\n", 1916181994Syongari (uint64_t)stats->tx_pkts_1024_max); 1917181994Syongari printf("Transmit jabber errors : %u\n", stats->tx_jabbers); 1918181994Syongari printf("Transmit oversized frames : %ju\n", 1919181994Syongari (uint64_t)stats->tx_oversize_frames); 1920181994Syongari printf("Transmit fragmented frames : %ju\n", 1921181994Syongari (uint64_t)stats->tx_frag_frames); 1922181994Syongari printf("Transmit underruns : %u\n", stats->tx_colls); 1923181994Syongari printf("Transmit total collisions : %u\n", stats->tx_single_colls); 1924181994Syongari printf("Transmit single collisions : %u\n", stats->tx_single_colls); 1925181994Syongari printf("Transmit multiple collisions : %u\n", stats->tx_multi_colls); 1926181994Syongari printf("Transmit excess collisions : %u\n", stats->tx_excess_colls); 1927181994Syongari printf("Transmit late collisions : %u\n", stats->tx_late_colls); 1928181994Syongari printf("Transmit deferrals : %u\n", stats->tx_deferrals); 1929181994Syongari printf("Transmit carrier losts : %u\n", stats->tx_carrier_losts); 1930181994Syongari printf("Transmit pause frames : %u\n", stats->tx_pause_frames); 1931181994Syongari 1932181994Syongari printf("Receive good octets : %ju\n", 1933181994Syongari (uintmax_t)stats->rx_good_octets); 1934181994Syongari printf("Receive good frames : %ju\n", 1935181994Syongari (uintmax_t)stats->rx_good_frames); 1936181994Syongari printf("Receive octets : %ju\n", 1937181994Syongari (uintmax_t)stats->rx_octets); 1938181994Syongari printf("Receive frames : %ju\n", 1939181994Syongari (uintmax_t)stats->rx_frames); 1940181994Syongari printf("Receive broadcast frames : %ju\n", 1941181994Syongari (uintmax_t)stats->rx_bcast_frames); 1942181994Syongari printf("Receive multicast frames : %ju\n", 1943181994Syongari (uintmax_t)stats->rx_mcast_frames); 1944181994Syongari printf("Receive frames 64 bytes : %ju\n", 1945181994Syongari (uint64_t)stats->rx_pkts_64); 1946181994Syongari printf("Receive frames 65 to 127 bytes : %ju\n", 1947181994Syongari (uint64_t)stats->rx_pkts_65_127); 1948181994Syongari printf("Receive frames 128 to 255 bytes : %ju\n", 1949181994Syongari (uint64_t)stats->rx_pkts_128_255); 1950181994Syongari printf("Receive frames 256 to 511 bytes : %ju\n", 1951181994Syongari (uint64_t)stats->rx_pkts_256_511); 1952181994Syongari printf("Receive frames 512 to 1023 bytes : %ju\n", 1953181994Syongari (uint64_t)stats->rx_pkts_512_1023); 1954181994Syongari printf("Receive frames 1024 to max bytes : %ju\n", 1955181994Syongari (uint64_t)stats->rx_pkts_1024_max); 1956181994Syongari printf("Receive jabber errors : %u\n", stats->rx_jabbers); 1957181994Syongari printf("Receive oversized frames : %ju\n", 1958181994Syongari (uint64_t)stats->rx_oversize_frames); 1959181994Syongari printf("Receive fragmented frames : %ju\n", 1960181994Syongari (uint64_t)stats->rx_frag_frames); 1961181994Syongari printf("Receive missed frames : %u\n", stats->rx_missed_frames); 1962181994Syongari printf("Receive CRC align errors : %u\n", stats->rx_crc_align_errs); 1963181994Syongari printf("Receive undersized frames : %u\n", stats->rx_runts); 1964181994Syongari printf("Receive CRC errors : %u\n", stats->rx_crc_errs); 1965181994Syongari printf("Receive align errors : %u\n", stats->rx_align_errs); 1966181994Syongari printf("Receive symbol errors : %u\n", stats->rx_symbol_errs); 1967181994Syongari printf("Receive pause frames : %u\n", stats->rx_pause_frames); 1968181994Syongari printf("Receive control frames : %u\n", stats->rx_control_frames); 1969181994Syongari 1970181994Syongari return (error); 1971181994Syongari} 1972