1098ca2bdSWarner Losh /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 4b9f78d2bSBill Paul * Copyright (c) 2003 Stuart Walsh<stu@ipng.org.uk> 5b9f78d2bSBill Paul * and Duncan Barclay<dmlb@dmlb.org> 6098ca2bdSWarner Losh * 7b9f78d2bSBill Paul * Redistribution and use in source and binary forms, with or without 8b9f78d2bSBill Paul * modification, are permitted provided that the following conditions 9b9f78d2bSBill Paul * are met: 10b9f78d2bSBill Paul * 1. Redistributions of source code must retain the above copyright 11b9f78d2bSBill Paul * notice, this list of conditions and the following disclaimer. 12b9f78d2bSBill Paul * 2. Redistributions in binary form must reproduce the above copyright 13b9f78d2bSBill Paul * notice, this list of conditions and the following disclaimer in the 14b9f78d2bSBill Paul * documentation and/or other materials provided with the distribution. 15b9f78d2bSBill Paul * 16b9f78d2bSBill Paul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND 17b9f78d2bSBill Paul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18b9f78d2bSBill Paul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19b9f78d2bSBill Paul * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20b9f78d2bSBill Paul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21b9f78d2bSBill Paul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22b9f78d2bSBill Paul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23b9f78d2bSBill Paul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24b9f78d2bSBill Paul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25b9f78d2bSBill Paul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26b9f78d2bSBill Paul * SUCH DAMAGE. 27b9f78d2bSBill Paul */ 28b9f78d2bSBill Paul 29b9f78d2bSBill Paul #include <sys/param.h> 30b9f78d2bSBill Paul #include <sys/systm.h> 3196ee09c5SPyun YongHyeon #include <sys/bus.h> 3296ee09c5SPyun YongHyeon #include <sys/endian.h> 33b9f78d2bSBill Paul #include <sys/kernel.h> 3496ee09c5SPyun YongHyeon #include <sys/malloc.h> 3596ee09c5SPyun YongHyeon #include <sys/mbuf.h> 36fe12f24bSPoul-Henning Kamp #include <sys/module.h> 3796ee09c5SPyun YongHyeon #include <sys/rman.h> 38b9f78d2bSBill Paul #include <sys/socket.h> 3996ee09c5SPyun YongHyeon #include <sys/sockio.h> 40861cf54cSPyun YongHyeon #include <sys/sysctl.h> 41b9f78d2bSBill Paul 4296ee09c5SPyun YongHyeon #include <net/bpf.h> 43b9f78d2bSBill Paul #include <net/if.h> 4476039bc8SGleb Smirnoff #include <net/if_var.h> 45b9f78d2bSBill Paul #include <net/ethernet.h> 46b9f78d2bSBill Paul #include <net/if_dl.h> 47b9f78d2bSBill Paul #include <net/if_media.h> 48b9f78d2bSBill Paul #include <net/if_types.h> 49b9f78d2bSBill Paul #include <net/if_vlan_var.h> 50b9f78d2bSBill Paul 51b9f78d2bSBill Paul #include <dev/mii/mii.h> 52b9f78d2bSBill Paul #include <dev/mii/miivar.h> 53b9f78d2bSBill Paul 54b9f78d2bSBill Paul #include <dev/pci/pcireg.h> 55b9f78d2bSBill Paul #include <dev/pci/pcivar.h> 56b9f78d2bSBill Paul 5796ee09c5SPyun YongHyeon #include <machine/bus.h> 5896ee09c5SPyun YongHyeon 59b9f78d2bSBill Paul #include <dev/bfe/if_bfereg.h> 60b9f78d2bSBill Paul 61b9f78d2bSBill Paul MODULE_DEPEND(bfe, pci, 1, 1, 1); 62b9f78d2bSBill Paul MODULE_DEPEND(bfe, ether, 1, 1, 1); 63b9f78d2bSBill Paul MODULE_DEPEND(bfe, miibus, 1, 1, 1); 64b9f78d2bSBill Paul 657b279558SWarner Losh /* "device miibus" required. See GENERIC if you get errors here. */ 66b9f78d2bSBill Paul #include "miibus_if.h" 67b9f78d2bSBill Paul 68b9f78d2bSBill Paul #define BFE_DEVDESC_MAX 64 /* Maximum device description length */ 69b9f78d2bSBill Paul 70b9f78d2bSBill Paul static struct bfe_type bfe_devs[] = { 71b9f78d2bSBill Paul { BCOM_VENDORID, BCOM_DEVICEID_BCM4401, 72b9f78d2bSBill Paul "Broadcom BCM4401 Fast Ethernet" }, 73037fc73dSDag-Erling Smørgrav { BCOM_VENDORID, BCOM_DEVICEID_BCM4401B0, 74037fc73dSDag-Erling Smørgrav "Broadcom BCM4401-B0 Fast Ethernet" }, 75b9f78d2bSBill Paul { 0, 0, NULL } 76b9f78d2bSBill Paul }; 77b9f78d2bSBill Paul 78b9f78d2bSBill Paul static int bfe_probe (device_t); 79b9f78d2bSBill Paul static int bfe_attach (device_t); 80b9f78d2bSBill Paul static int bfe_detach (device_t); 816daee769SJohn Baldwin static int bfe_suspend (device_t); 826daee769SJohn Baldwin static int bfe_resume (device_t); 83b9f78d2bSBill Paul static void bfe_release_resources (struct bfe_softc *); 84b9f78d2bSBill Paul static void bfe_intr (void *); 8596ee09c5SPyun YongHyeon static int bfe_encap (struct bfe_softc *, struct mbuf **); 86c0e5e270SJustin Hibbits static void bfe_start (if_t); 87c0e5e270SJustin Hibbits static void bfe_start_locked (if_t); 88c0e5e270SJustin Hibbits static int bfe_ioctl (if_t, u_long, caddr_t); 89b9f78d2bSBill Paul static void bfe_init (void *); 90f16b4811SMike Makonnen static void bfe_init_locked (void *); 91b9f78d2bSBill Paul static void bfe_stop (struct bfe_softc *); 926ceb40baSPyun YongHyeon static void bfe_watchdog (struct bfe_softc *); 936a087a87SPyun YongHyeon static int bfe_shutdown (device_t); 94b9f78d2bSBill Paul static void bfe_tick (void *); 95b9f78d2bSBill Paul static void bfe_txeof (struct bfe_softc *); 96b9f78d2bSBill Paul static void bfe_rxeof (struct bfe_softc *); 97b9f78d2bSBill Paul static void bfe_set_rx_mode (struct bfe_softc *); 98b9f78d2bSBill Paul static int bfe_list_rx_init (struct bfe_softc *); 9996ee09c5SPyun YongHyeon static void bfe_list_tx_init (struct bfe_softc *); 10096ee09c5SPyun YongHyeon static void bfe_discard_buf (struct bfe_softc *, int); 10196ee09c5SPyun YongHyeon static int bfe_list_newbuf (struct bfe_softc *, int); 102b9f78d2bSBill Paul static void bfe_rx_ring_free (struct bfe_softc *); 103b9f78d2bSBill Paul 104b9f78d2bSBill Paul static void bfe_pci_setup (struct bfe_softc *, u_int32_t); 105c0e5e270SJustin Hibbits static int bfe_ifmedia_upd (if_t); 106c0e5e270SJustin Hibbits static void bfe_ifmedia_sts (if_t, struct ifmediareq *); 107b9f78d2bSBill Paul static int bfe_miibus_readreg (device_t, int, int); 108b9f78d2bSBill Paul static int bfe_miibus_writereg (device_t, int, int, int); 109b9f78d2bSBill Paul static void bfe_miibus_statchg (device_t); 110b9f78d2bSBill Paul static int bfe_wait_bit (struct bfe_softc *, u_int32_t, u_int32_t, 111b9f78d2bSBill Paul u_long, const int); 112b9f78d2bSBill Paul static void bfe_get_config (struct bfe_softc *sc); 113b9f78d2bSBill Paul static void bfe_read_eeprom (struct bfe_softc *, u_int8_t *); 114b9f78d2bSBill Paul static void bfe_stats_update (struct bfe_softc *); 115b9f78d2bSBill Paul static void bfe_clear_stats (struct bfe_softc *); 116b9f78d2bSBill Paul static int bfe_readphy (struct bfe_softc *, u_int32_t, u_int32_t*); 117b9f78d2bSBill Paul static int bfe_writephy (struct bfe_softc *, u_int32_t, u_int32_t); 118b9f78d2bSBill Paul static int bfe_resetphy (struct bfe_softc *); 119b9f78d2bSBill Paul static int bfe_setupphy (struct bfe_softc *); 120b9f78d2bSBill Paul static void bfe_chip_reset (struct bfe_softc *); 121b9f78d2bSBill Paul static void bfe_chip_halt (struct bfe_softc *); 122b9f78d2bSBill Paul static void bfe_core_reset (struct bfe_softc *); 123b9f78d2bSBill Paul static void bfe_core_disable (struct bfe_softc *); 12496ee09c5SPyun YongHyeon static int bfe_dma_alloc (struct bfe_softc *); 12596ee09c5SPyun YongHyeon static void bfe_dma_free (struct bfe_softc *sc); 126b9f78d2bSBill Paul static void bfe_dma_map (void *, bus_dma_segment_t *, int, int); 127b9f78d2bSBill Paul static void bfe_cam_write (struct bfe_softc *, u_char *, int); 128861cf54cSPyun YongHyeon static int sysctl_bfe_stats (SYSCTL_HANDLER_ARGS); 129b9f78d2bSBill Paul 130b9f78d2bSBill Paul static device_method_t bfe_methods[] = { 131b9f78d2bSBill Paul /* Device interface */ 132b9f78d2bSBill Paul DEVMETHOD(device_probe, bfe_probe), 133b9f78d2bSBill Paul DEVMETHOD(device_attach, bfe_attach), 134b9f78d2bSBill Paul DEVMETHOD(device_detach, bfe_detach), 135b9f78d2bSBill Paul DEVMETHOD(device_shutdown, bfe_shutdown), 1366daee769SJohn Baldwin DEVMETHOD(device_suspend, bfe_suspend), 1376daee769SJohn Baldwin DEVMETHOD(device_resume, bfe_resume), 138b9f78d2bSBill Paul 139b9f78d2bSBill Paul /* MII interface */ 140b9f78d2bSBill Paul DEVMETHOD(miibus_readreg, bfe_miibus_readreg), 141b9f78d2bSBill Paul DEVMETHOD(miibus_writereg, bfe_miibus_writereg), 142b9f78d2bSBill Paul DEVMETHOD(miibus_statchg, bfe_miibus_statchg), 143b9f78d2bSBill Paul 1444b7ec270SMarius Strobl DEVMETHOD_END 145b9f78d2bSBill Paul }; 146b9f78d2bSBill Paul 147b9f78d2bSBill Paul static driver_t bfe_driver = { 148b9f78d2bSBill Paul "bfe", 149b9f78d2bSBill Paul bfe_methods, 150b9f78d2bSBill Paul sizeof(struct bfe_softc) 151b9f78d2bSBill Paul }; 152b9f78d2bSBill Paul 15348ebc940SJohn Baldwin DRIVER_MODULE(bfe, pci, bfe_driver, 0, 0); 1546c15b8d9SWarner Losh MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, bfe, bfe_devs, 155329e817fSWarner Losh nitems(bfe_devs) - 1); 1563e38757dSJohn Baldwin DRIVER_MODULE(miibus, bfe, miibus_driver, 0, 0); 157b9f78d2bSBill Paul 158b9f78d2bSBill Paul /* 159b9f78d2bSBill Paul * Probe for a Broadcom 4401 chip. 160b9f78d2bSBill Paul */ 161b9f78d2bSBill Paul static int 162b9f78d2bSBill Paul bfe_probe(device_t dev) 163b9f78d2bSBill Paul { 164b9f78d2bSBill Paul struct bfe_type *t; 165b9f78d2bSBill Paul 166b9f78d2bSBill Paul t = bfe_devs; 167b9f78d2bSBill Paul 168b9f78d2bSBill Paul while (t->bfe_name != NULL) { 169a73a4056SPyun YongHyeon if (pci_get_vendor(dev) == t->bfe_vid && 170a73a4056SPyun YongHyeon pci_get_device(dev) == t->bfe_did) { 171a823cbc6SPyun YongHyeon device_set_desc(dev, t->bfe_name); 17253ee7173SWarner Losh return (BUS_PROBE_DEFAULT); 173b9f78d2bSBill Paul } 174b9f78d2bSBill Paul t++; 175b9f78d2bSBill Paul } 176b9f78d2bSBill Paul 177b9f78d2bSBill Paul return (ENXIO); 178b9f78d2bSBill Paul } 179b9f78d2bSBill Paul 18096ee09c5SPyun YongHyeon struct bfe_dmamap_arg { 18196ee09c5SPyun YongHyeon bus_addr_t bfe_busaddr; 18296ee09c5SPyun YongHyeon }; 183b9f78d2bSBill Paul 18496ee09c5SPyun YongHyeon static int 18596ee09c5SPyun YongHyeon bfe_dma_alloc(struct bfe_softc *sc) 18696ee09c5SPyun YongHyeon { 18796ee09c5SPyun YongHyeon struct bfe_dmamap_arg ctx; 18896ee09c5SPyun YongHyeon struct bfe_rx_data *rd; 18996ee09c5SPyun YongHyeon struct bfe_tx_data *td; 19096ee09c5SPyun YongHyeon int error, i; 191b9f78d2bSBill Paul 1929171a12bSScott Long /* 1939171a12bSScott Long * parent tag. Apparently the chip cannot handle any DMA address 1949171a12bSScott Long * greater than 1GB. 1959171a12bSScott Long */ 19696ee09c5SPyun YongHyeon error = bus_dma_tag_create(bus_get_dma_tag(sc->bfe_dev), /* parent */ 19796ee09c5SPyun YongHyeon 1, 0, /* alignment, boundary */ 19896ee09c5SPyun YongHyeon BFE_DMA_MAXADDR, /* lowaddr */ 1999171a12bSScott Long BUS_SPACE_MAXADDR, /* highaddr */ 200b9f78d2bSBill Paul NULL, NULL, /* filter, filterarg */ 20196ee09c5SPyun YongHyeon BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 20296ee09c5SPyun YongHyeon 0, /* nsegments */ 20396ee09c5SPyun YongHyeon BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 2043981b687SMike Silbersack 0, /* flags */ 205b9f78d2bSBill Paul NULL, NULL, /* lockfunc, lockarg */ 206b9f78d2bSBill Paul &sc->bfe_parent_tag); 20796ee09c5SPyun YongHyeon if (error != 0) { 20896ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, "cannot create parent DMA tag.\n"); 20996ee09c5SPyun YongHyeon goto fail; 21096ee09c5SPyun YongHyeon } 211b9f78d2bSBill Paul 21296ee09c5SPyun YongHyeon /* Create tag for Tx ring. */ 21396ee09c5SPyun YongHyeon error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 21496ee09c5SPyun YongHyeon BFE_TX_RING_ALIGN, 0, /* alignment, boundary */ 21596ee09c5SPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 21696ee09c5SPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 21796ee09c5SPyun YongHyeon NULL, NULL, /* filter, filterarg */ 21896ee09c5SPyun YongHyeon BFE_TX_LIST_SIZE, /* maxsize */ 21996ee09c5SPyun YongHyeon 1, /* nsegments */ 22096ee09c5SPyun YongHyeon BFE_TX_LIST_SIZE, /* maxsegsize */ 22196ee09c5SPyun YongHyeon 0, /* flags */ 22296ee09c5SPyun YongHyeon NULL, NULL, /* lockfunc, lockarg */ 223f2b1c158SJulian Elischer &sc->bfe_tx_tag); 22496ee09c5SPyun YongHyeon if (error != 0) { 22596ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, "cannot create Tx ring DMA tag.\n"); 22696ee09c5SPyun YongHyeon goto fail; 227b9f78d2bSBill Paul } 228b9f78d2bSBill Paul 22996ee09c5SPyun YongHyeon /* Create tag for Rx ring. */ 23096ee09c5SPyun YongHyeon error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 23196ee09c5SPyun YongHyeon BFE_RX_RING_ALIGN, 0, /* alignment, boundary */ 23296ee09c5SPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 23396ee09c5SPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 23496ee09c5SPyun YongHyeon NULL, NULL, /* filter, filterarg */ 23596ee09c5SPyun YongHyeon BFE_RX_LIST_SIZE, /* maxsize */ 23696ee09c5SPyun YongHyeon 1, /* nsegments */ 23796ee09c5SPyun YongHyeon BFE_RX_LIST_SIZE, /* maxsegsize */ 23896ee09c5SPyun YongHyeon 0, /* flags */ 23996ee09c5SPyun YongHyeon NULL, NULL, /* lockfunc, lockarg */ 240f2b1c158SJulian Elischer &sc->bfe_rx_tag); 24196ee09c5SPyun YongHyeon if (error != 0) { 24296ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, "cannot create Rx ring DMA tag.\n"); 24396ee09c5SPyun YongHyeon goto fail; 244b9f78d2bSBill Paul } 245b9f78d2bSBill Paul 24696ee09c5SPyun YongHyeon /* Create tag for Tx buffers. */ 24796ee09c5SPyun YongHyeon error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 24896ee09c5SPyun YongHyeon 1, 0, /* alignment, boundary */ 24996ee09c5SPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 25096ee09c5SPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 25196ee09c5SPyun YongHyeon NULL, NULL, /* filter, filterarg */ 25296ee09c5SPyun YongHyeon MCLBYTES * BFE_MAXTXSEGS, /* maxsize */ 25396ee09c5SPyun YongHyeon BFE_MAXTXSEGS, /* nsegments */ 25496ee09c5SPyun YongHyeon MCLBYTES, /* maxsegsize */ 25596ee09c5SPyun YongHyeon 0, /* flags */ 25696ee09c5SPyun YongHyeon NULL, NULL, /* lockfunc, lockarg */ 25796ee09c5SPyun YongHyeon &sc->bfe_txmbuf_tag); 25896ee09c5SPyun YongHyeon if (error != 0) { 25996ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, 26096ee09c5SPyun YongHyeon "cannot create Tx buffer DMA tag.\n"); 26196ee09c5SPyun YongHyeon goto fail; 262b9f78d2bSBill Paul } 263b9f78d2bSBill Paul 26496ee09c5SPyun YongHyeon /* Create tag for Rx buffers. */ 26596ee09c5SPyun YongHyeon error = bus_dma_tag_create(sc->bfe_parent_tag, /* parent */ 26696ee09c5SPyun YongHyeon 1, 0, /* alignment, boundary */ 26796ee09c5SPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 26896ee09c5SPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 26996ee09c5SPyun YongHyeon NULL, NULL, /* filter, filterarg */ 27096ee09c5SPyun YongHyeon MCLBYTES, /* maxsize */ 27196ee09c5SPyun YongHyeon 1, /* nsegments */ 27296ee09c5SPyun YongHyeon MCLBYTES, /* maxsegsize */ 27396ee09c5SPyun YongHyeon 0, /* flags */ 27496ee09c5SPyun YongHyeon NULL, NULL, /* lockfunc, lockarg */ 27596ee09c5SPyun YongHyeon &sc->bfe_rxmbuf_tag); 27696ee09c5SPyun YongHyeon if (error != 0) { 27796ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, 27896ee09c5SPyun YongHyeon "cannot create Rx buffer DMA tag.\n"); 27996ee09c5SPyun YongHyeon goto fail; 280b9f78d2bSBill Paul } 281b9f78d2bSBill Paul 28296ee09c5SPyun YongHyeon /* Allocate DMA'able memory and load DMA map. */ 283b9f78d2bSBill Paul error = bus_dmamem_alloc(sc->bfe_tx_tag, (void *)&sc->bfe_tx_list, 28496ee09c5SPyun YongHyeon BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->bfe_tx_map); 28596ee09c5SPyun YongHyeon if (error != 0) { 28696ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, 28796ee09c5SPyun YongHyeon "cannot allocate DMA'able memory for Tx ring.\n"); 28896ee09c5SPyun YongHyeon goto fail; 28996ee09c5SPyun YongHyeon } 29096ee09c5SPyun YongHyeon ctx.bfe_busaddr = 0; 291b9f78d2bSBill Paul error = bus_dmamap_load(sc->bfe_tx_tag, sc->bfe_tx_map, 29296ee09c5SPyun YongHyeon sc->bfe_tx_list, BFE_TX_LIST_SIZE, bfe_dma_map, &ctx, 29396ee09c5SPyun YongHyeon BUS_DMA_NOWAIT); 29496ee09c5SPyun YongHyeon if (error != 0 || ctx.bfe_busaddr == 0) { 29596ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, 29696ee09c5SPyun YongHyeon "cannot load DMA'able memory for Tx ring.\n"); 29796ee09c5SPyun YongHyeon goto fail; 29896ee09c5SPyun YongHyeon } 29996ee09c5SPyun YongHyeon sc->bfe_tx_dma = BFE_ADDR_LO(ctx.bfe_busaddr); 300b9f78d2bSBill Paul 30196ee09c5SPyun YongHyeon error = bus_dmamem_alloc(sc->bfe_rx_tag, (void *)&sc->bfe_rx_list, 30296ee09c5SPyun YongHyeon BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->bfe_rx_map); 30396ee09c5SPyun YongHyeon if (error != 0) { 30496ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, 30596ee09c5SPyun YongHyeon "cannot allocate DMA'able memory for Rx ring.\n"); 30696ee09c5SPyun YongHyeon goto fail; 30796ee09c5SPyun YongHyeon } 30896ee09c5SPyun YongHyeon ctx.bfe_busaddr = 0; 30996ee09c5SPyun YongHyeon error = bus_dmamap_load(sc->bfe_rx_tag, sc->bfe_rx_map, 31096ee09c5SPyun YongHyeon sc->bfe_rx_list, BFE_RX_LIST_SIZE, bfe_dma_map, &ctx, 31196ee09c5SPyun YongHyeon BUS_DMA_NOWAIT); 31296ee09c5SPyun YongHyeon if (error != 0 || ctx.bfe_busaddr == 0) { 31396ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, 31496ee09c5SPyun YongHyeon "cannot load DMA'able memory for Rx ring.\n"); 31596ee09c5SPyun YongHyeon goto fail; 31696ee09c5SPyun YongHyeon } 31796ee09c5SPyun YongHyeon sc->bfe_rx_dma = BFE_ADDR_LO(ctx.bfe_busaddr); 318b9f78d2bSBill Paul 31996ee09c5SPyun YongHyeon /* Create DMA maps for Tx buffers. */ 32096ee09c5SPyun YongHyeon for (i = 0; i < BFE_TX_LIST_CNT; i++) { 32196ee09c5SPyun YongHyeon td = &sc->bfe_tx_ring[i]; 32296ee09c5SPyun YongHyeon td->bfe_mbuf = NULL; 32396ee09c5SPyun YongHyeon td->bfe_map = NULL; 32496ee09c5SPyun YongHyeon error = bus_dmamap_create(sc->bfe_txmbuf_tag, 0, &td->bfe_map); 32596ee09c5SPyun YongHyeon if (error != 0) { 32696ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, 32796ee09c5SPyun YongHyeon "cannot create DMA map for Tx.\n"); 32896ee09c5SPyun YongHyeon goto fail; 32996ee09c5SPyun YongHyeon } 33096ee09c5SPyun YongHyeon } 33196ee09c5SPyun YongHyeon 33296ee09c5SPyun YongHyeon /* Create spare DMA map for Rx buffers. */ 33396ee09c5SPyun YongHyeon error = bus_dmamap_create(sc->bfe_rxmbuf_tag, 0, &sc->bfe_rx_sparemap); 33496ee09c5SPyun YongHyeon if (error != 0) { 33596ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, "cannot create spare DMA map for Rx.\n"); 33696ee09c5SPyun YongHyeon goto fail; 33796ee09c5SPyun YongHyeon } 33896ee09c5SPyun YongHyeon /* Create DMA maps for Rx buffers. */ 33996ee09c5SPyun YongHyeon for (i = 0; i < BFE_RX_LIST_CNT; i++) { 34096ee09c5SPyun YongHyeon rd = &sc->bfe_rx_ring[i]; 34196ee09c5SPyun YongHyeon rd->bfe_mbuf = NULL; 34296ee09c5SPyun YongHyeon rd->bfe_map = NULL; 34396ee09c5SPyun YongHyeon rd->bfe_ctrl = 0; 34496ee09c5SPyun YongHyeon error = bus_dmamap_create(sc->bfe_rxmbuf_tag, 0, &rd->bfe_map); 34596ee09c5SPyun YongHyeon if (error != 0) { 34696ee09c5SPyun YongHyeon device_printf(sc->bfe_dev, 34796ee09c5SPyun YongHyeon "cannot create DMA map for Rx.\n"); 34896ee09c5SPyun YongHyeon goto fail; 34996ee09c5SPyun YongHyeon } 35096ee09c5SPyun YongHyeon } 35196ee09c5SPyun YongHyeon 35296ee09c5SPyun YongHyeon fail: 35396ee09c5SPyun YongHyeon return (error); 35496ee09c5SPyun YongHyeon } 35596ee09c5SPyun YongHyeon 35696ee09c5SPyun YongHyeon static void 35796ee09c5SPyun YongHyeon bfe_dma_free(struct bfe_softc *sc) 35896ee09c5SPyun YongHyeon { 35996ee09c5SPyun YongHyeon struct bfe_tx_data *td; 36096ee09c5SPyun YongHyeon struct bfe_rx_data *rd; 36196ee09c5SPyun YongHyeon int i; 36296ee09c5SPyun YongHyeon 36396ee09c5SPyun YongHyeon /* Tx ring. */ 36496ee09c5SPyun YongHyeon if (sc->bfe_tx_tag != NULL) { 365068d8643SJohn Baldwin if (sc->bfe_tx_dma != 0) 36696ee09c5SPyun YongHyeon bus_dmamap_unload(sc->bfe_tx_tag, sc->bfe_tx_map); 367068d8643SJohn Baldwin if (sc->bfe_tx_list != NULL) 36896ee09c5SPyun YongHyeon bus_dmamem_free(sc->bfe_tx_tag, sc->bfe_tx_list, 36996ee09c5SPyun YongHyeon sc->bfe_tx_map); 370068d8643SJohn Baldwin sc->bfe_tx_dma = 0; 37196ee09c5SPyun YongHyeon sc->bfe_tx_list = NULL; 37296ee09c5SPyun YongHyeon bus_dma_tag_destroy(sc->bfe_tx_tag); 37396ee09c5SPyun YongHyeon sc->bfe_tx_tag = NULL; 37496ee09c5SPyun YongHyeon } 37596ee09c5SPyun YongHyeon 37696ee09c5SPyun YongHyeon /* Rx ring. */ 37796ee09c5SPyun YongHyeon if (sc->bfe_rx_tag != NULL) { 378068d8643SJohn Baldwin if (sc->bfe_rx_dma != 0) 37996ee09c5SPyun YongHyeon bus_dmamap_unload(sc->bfe_rx_tag, sc->bfe_rx_map); 380068d8643SJohn Baldwin if (sc->bfe_rx_list != NULL) 38196ee09c5SPyun YongHyeon bus_dmamem_free(sc->bfe_rx_tag, sc->bfe_rx_list, 38296ee09c5SPyun YongHyeon sc->bfe_rx_map); 383068d8643SJohn Baldwin sc->bfe_rx_dma = 0; 38496ee09c5SPyun YongHyeon sc->bfe_rx_list = NULL; 38596ee09c5SPyun YongHyeon bus_dma_tag_destroy(sc->bfe_rx_tag); 38696ee09c5SPyun YongHyeon sc->bfe_rx_tag = NULL; 38796ee09c5SPyun YongHyeon } 38896ee09c5SPyun YongHyeon 38996ee09c5SPyun YongHyeon /* Tx buffers. */ 39096ee09c5SPyun YongHyeon if (sc->bfe_txmbuf_tag != NULL) { 39196ee09c5SPyun YongHyeon for (i = 0; i < BFE_TX_LIST_CNT; i++) { 39296ee09c5SPyun YongHyeon td = &sc->bfe_tx_ring[i]; 39396ee09c5SPyun YongHyeon if (td->bfe_map != NULL) { 39496ee09c5SPyun YongHyeon bus_dmamap_destroy(sc->bfe_txmbuf_tag, 39596ee09c5SPyun YongHyeon td->bfe_map); 39696ee09c5SPyun YongHyeon td->bfe_map = NULL; 39796ee09c5SPyun YongHyeon } 39896ee09c5SPyun YongHyeon } 39996ee09c5SPyun YongHyeon bus_dma_tag_destroy(sc->bfe_txmbuf_tag); 40096ee09c5SPyun YongHyeon sc->bfe_txmbuf_tag = NULL; 40196ee09c5SPyun YongHyeon } 40296ee09c5SPyun YongHyeon 40396ee09c5SPyun YongHyeon /* Rx buffers. */ 40496ee09c5SPyun YongHyeon if (sc->bfe_rxmbuf_tag != NULL) { 40596ee09c5SPyun YongHyeon for (i = 0; i < BFE_RX_LIST_CNT; i++) { 40696ee09c5SPyun YongHyeon rd = &sc->bfe_rx_ring[i]; 40796ee09c5SPyun YongHyeon if (rd->bfe_map != NULL) { 40896ee09c5SPyun YongHyeon bus_dmamap_destroy(sc->bfe_rxmbuf_tag, 40996ee09c5SPyun YongHyeon rd->bfe_map); 41096ee09c5SPyun YongHyeon rd->bfe_map = NULL; 41196ee09c5SPyun YongHyeon } 41296ee09c5SPyun YongHyeon } 41396ee09c5SPyun YongHyeon if (sc->bfe_rx_sparemap != NULL) { 41496ee09c5SPyun YongHyeon bus_dmamap_destroy(sc->bfe_rxmbuf_tag, 41596ee09c5SPyun YongHyeon sc->bfe_rx_sparemap); 41696ee09c5SPyun YongHyeon sc->bfe_rx_sparemap = NULL; 41796ee09c5SPyun YongHyeon } 41896ee09c5SPyun YongHyeon bus_dma_tag_destroy(sc->bfe_rxmbuf_tag); 41996ee09c5SPyun YongHyeon sc->bfe_rxmbuf_tag = NULL; 42096ee09c5SPyun YongHyeon } 42196ee09c5SPyun YongHyeon 42296ee09c5SPyun YongHyeon if (sc->bfe_parent_tag != NULL) { 42396ee09c5SPyun YongHyeon bus_dma_tag_destroy(sc->bfe_parent_tag); 42496ee09c5SPyun YongHyeon sc->bfe_parent_tag = NULL; 42596ee09c5SPyun YongHyeon } 426b9f78d2bSBill Paul } 427b9f78d2bSBill Paul 428b9f78d2bSBill Paul static int 429b9f78d2bSBill Paul bfe_attach(device_t dev) 430b9f78d2bSBill Paul { 431c0e5e270SJustin Hibbits if_t ifp = NULL; 432b9f78d2bSBill Paul struct bfe_softc *sc; 433be280562SPyun YongHyeon int error = 0, rid; 434b9f78d2bSBill Paul 435b9f78d2bSBill Paul sc = device_get_softc(dev); 436b9f78d2bSBill Paul mtx_init(&sc->bfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 437f16b4811SMike Makonnen MTX_DEF); 4386ceb40baSPyun YongHyeon callout_init_mtx(&sc->bfe_stat_co, &sc->bfe_mtx, 0); 439b9f78d2bSBill Paul 440b9f78d2bSBill Paul sc->bfe_dev = dev; 441b9f78d2bSBill Paul 442b9f78d2bSBill Paul /* 443b9f78d2bSBill Paul * Map control/status registers. 444b9f78d2bSBill Paul */ 445b9f78d2bSBill Paul pci_enable_busmaster(dev); 446b9f78d2bSBill Paul 44796ee09c5SPyun YongHyeon rid = PCIR_BAR(0); 4485f96beb9SNate Lawson sc->bfe_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 449b9f78d2bSBill Paul RF_ACTIVE); 450b9f78d2bSBill Paul if (sc->bfe_res == NULL) { 451be280562SPyun YongHyeon device_printf(dev, "couldn't map memory\n"); 452b9f78d2bSBill Paul error = ENXIO; 453b9f78d2bSBill Paul goto fail; 454b9f78d2bSBill Paul } 455b9f78d2bSBill Paul 456b9f78d2bSBill Paul /* Allocate interrupt */ 457b9f78d2bSBill Paul rid = 0; 458b9f78d2bSBill Paul 4595f96beb9SNate Lawson sc->bfe_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 460b9f78d2bSBill Paul RF_SHAREABLE | RF_ACTIVE); 461b9f78d2bSBill Paul if (sc->bfe_irq == NULL) { 462be280562SPyun YongHyeon device_printf(dev, "couldn't map interrupt\n"); 463b9f78d2bSBill Paul error = ENXIO; 464b9f78d2bSBill Paul goto fail; 465b9f78d2bSBill Paul } 466b9f78d2bSBill Paul 46796ee09c5SPyun YongHyeon if (bfe_dma_alloc(sc) != 0) { 468be280562SPyun YongHyeon device_printf(dev, "failed to allocate DMA resources\n"); 469b9f78d2bSBill Paul error = ENXIO; 470b9f78d2bSBill Paul goto fail; 471b9f78d2bSBill Paul } 472b9f78d2bSBill Paul 473861cf54cSPyun YongHyeon SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 474861cf54cSPyun YongHyeon SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 4757029da5cSPawel Biernacki "stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, 4767029da5cSPawel Biernacki sysctl_bfe_stats, "I", "Statistics"); 477861cf54cSPyun YongHyeon 478b9f78d2bSBill Paul /* Set up ifnet structure */ 479fc74a9f9SBrooks Davis ifp = sc->bfe_ifp = if_alloc(IFT_ETHER); 480c0e5e270SJustin Hibbits if_setsoftc(ifp, sc); 4819bf40edeSBrooks Davis if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 482c0e5e270SJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 483c0e5e270SJustin Hibbits if_setioctlfn(ifp, bfe_ioctl); 484c0e5e270SJustin Hibbits if_setstartfn(ifp, bfe_start); 485c0e5e270SJustin Hibbits if_setinitfn(ifp, bfe_init); 486c0e5e270SJustin Hibbits if_setsendqlen(ifp, BFE_TX_QLEN); 487c0e5e270SJustin Hibbits if_setsendqready(ifp); 488b9f78d2bSBill Paul 489b9f78d2bSBill Paul bfe_get_config(sc); 490b9f78d2bSBill Paul 491b9f78d2bSBill Paul /* Reset the chip and turn on the PHY */ 492f16b4811SMike Makonnen BFE_LOCK(sc); 493b9f78d2bSBill Paul bfe_chip_reset(sc); 494f16b4811SMike Makonnen BFE_UNLOCK(sc); 495b9f78d2bSBill Paul 4968e5d93dbSMarius Strobl error = mii_attach(dev, &sc->bfe_miibus, ifp, bfe_ifmedia_upd, 4978e5d93dbSMarius Strobl bfe_ifmedia_sts, BMSR_DEFCAPMASK, sc->bfe_phyaddr, MII_OFFSET_ANY, 4988e5d93dbSMarius Strobl 0); 4998e5d93dbSMarius Strobl if (error != 0) { 5008e5d93dbSMarius Strobl device_printf(dev, "attaching PHYs failed\n"); 501b9f78d2bSBill Paul goto fail; 502b9f78d2bSBill Paul } 503b9f78d2bSBill Paul 504fc74a9f9SBrooks Davis ether_ifattach(ifp, sc->bfe_enaddr); 505b9f78d2bSBill Paul 506b9f78d2bSBill Paul /* 507912bf9d3SDag-Erling Smørgrav * Tell the upper layer(s) we support long frames. 508912bf9d3SDag-Erling Smørgrav */ 509c0e5e270SJustin Hibbits if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); 510c0e5e270SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0); 511c0e5e270SJustin Hibbits if_setcapenablebit(ifp, IFCAP_VLAN_MTU, 0); 512912bf9d3SDag-Erling Smørgrav 513912bf9d3SDag-Erling Smørgrav /* 514b9f78d2bSBill Paul * Hook interrupt last to avoid having to lock softc 515b9f78d2bSBill Paul */ 516f16b4811SMike Makonnen error = bus_setup_intr(dev, sc->bfe_irq, INTR_TYPE_NET | INTR_MPSAFE, 517ef544f63SPaolo Pisati NULL, bfe_intr, sc, &sc->bfe_intrhand); 518b9f78d2bSBill Paul 519b9f78d2bSBill Paul if (error) { 520be280562SPyun YongHyeon device_printf(dev, "couldn't set up irq\n"); 521b9f78d2bSBill Paul goto fail; 522b9f78d2bSBill Paul } 523b9f78d2bSBill Paul fail: 52496ee09c5SPyun YongHyeon if (error != 0) 52596ee09c5SPyun YongHyeon bfe_detach(dev); 526b9f78d2bSBill Paul return (error); 527b9f78d2bSBill Paul } 528b9f78d2bSBill Paul 529b9f78d2bSBill Paul static int 530b9f78d2bSBill Paul bfe_detach(device_t dev) 531b9f78d2bSBill Paul { 532b9f78d2bSBill Paul struct bfe_softc *sc; 533c0e5e270SJustin Hibbits if_t ifp; 534b9f78d2bSBill Paul 535b9f78d2bSBill Paul sc = device_get_softc(dev); 536b9f78d2bSBill Paul 537fc74a9f9SBrooks Davis ifp = sc->bfe_ifp; 538b9f78d2bSBill Paul 539b9f78d2bSBill Paul if (device_is_attached(dev)) { 5406ceb40baSPyun YongHyeon BFE_LOCK(sc); 54149bbfbc5SPyun YongHyeon sc->bfe_flags |= BFE_FLAG_DETACH; 542b9f78d2bSBill Paul bfe_stop(sc); 5436ceb40baSPyun YongHyeon BFE_UNLOCK(sc); 5446ceb40baSPyun YongHyeon callout_drain(&sc->bfe_stat_co); 5456ceb40baSPyun YongHyeon if (ifp != NULL) 546b9f78d2bSBill Paul ether_ifdetach(ifp); 547b9f78d2bSBill Paul } 548b9f78d2bSBill Paul 54996ee09c5SPyun YongHyeon BFE_LOCK(sc); 550b9f78d2bSBill Paul bfe_chip_reset(sc); 55196ee09c5SPyun YongHyeon BFE_UNLOCK(sc); 552b9f78d2bSBill Paul 553b9f78d2bSBill Paul bus_generic_detach(dev); 554b9f78d2bSBill Paul 555b9f78d2bSBill Paul bfe_release_resources(sc); 55696ee09c5SPyun YongHyeon bfe_dma_free(sc); 557b9f78d2bSBill Paul mtx_destroy(&sc->bfe_mtx); 558b9f78d2bSBill Paul 559b9f78d2bSBill Paul return (0); 560b9f78d2bSBill Paul } 561b9f78d2bSBill Paul 562b9f78d2bSBill Paul /* 563b9f78d2bSBill Paul * Stop all chip I/O so that the kernel's probe routines don't 564b9f78d2bSBill Paul * get confused by errant DMAs when rebooting. 565b9f78d2bSBill Paul */ 5666a087a87SPyun YongHyeon static int 567b9f78d2bSBill Paul bfe_shutdown(device_t dev) 568b9f78d2bSBill Paul { 569b9f78d2bSBill Paul struct bfe_softc *sc; 570b9f78d2bSBill Paul 571b9f78d2bSBill Paul sc = device_get_softc(dev); 572b9f78d2bSBill Paul BFE_LOCK(sc); 573b9f78d2bSBill Paul bfe_stop(sc); 574b9f78d2bSBill Paul 575b9f78d2bSBill Paul BFE_UNLOCK(sc); 5766a087a87SPyun YongHyeon 5776a087a87SPyun YongHyeon return (0); 578b9f78d2bSBill Paul } 579b9f78d2bSBill Paul 580b9f78d2bSBill Paul static int 5816daee769SJohn Baldwin bfe_suspend(device_t dev) 5826daee769SJohn Baldwin { 5836daee769SJohn Baldwin struct bfe_softc *sc; 5846daee769SJohn Baldwin 5856daee769SJohn Baldwin sc = device_get_softc(dev); 5866daee769SJohn Baldwin BFE_LOCK(sc); 5876daee769SJohn Baldwin bfe_stop(sc); 5886daee769SJohn Baldwin BFE_UNLOCK(sc); 5896daee769SJohn Baldwin 5906daee769SJohn Baldwin return (0); 5916daee769SJohn Baldwin } 5926daee769SJohn Baldwin 5936daee769SJohn Baldwin static int 5946daee769SJohn Baldwin bfe_resume(device_t dev) 5956daee769SJohn Baldwin { 5966daee769SJohn Baldwin struct bfe_softc *sc; 597c0e5e270SJustin Hibbits if_t ifp; 5986daee769SJohn Baldwin 5996daee769SJohn Baldwin sc = device_get_softc(dev); 6006daee769SJohn Baldwin ifp = sc->bfe_ifp; 6016daee769SJohn Baldwin BFE_LOCK(sc); 6026daee769SJohn Baldwin bfe_chip_reset(sc); 603c0e5e270SJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 6046daee769SJohn Baldwin bfe_init_locked(sc); 605c0e5e270SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING && 606c0e5e270SJustin Hibbits !if_sendq_empty(ifp)) 6076daee769SJohn Baldwin bfe_start_locked(ifp); 6086daee769SJohn Baldwin } 6096daee769SJohn Baldwin BFE_UNLOCK(sc); 6106daee769SJohn Baldwin 6116daee769SJohn Baldwin return (0); 6126daee769SJohn Baldwin } 6136daee769SJohn Baldwin 6146daee769SJohn Baldwin static int 615b9f78d2bSBill Paul bfe_miibus_readreg(device_t dev, int phy, int reg) 616b9f78d2bSBill Paul { 617b9f78d2bSBill Paul struct bfe_softc *sc; 618b9f78d2bSBill Paul u_int32_t ret; 619b9f78d2bSBill Paul 620b9f78d2bSBill Paul sc = device_get_softc(dev); 621b9f78d2bSBill Paul bfe_readphy(sc, reg, &ret); 622b9f78d2bSBill Paul 623b9f78d2bSBill Paul return (ret); 624b9f78d2bSBill Paul } 625b9f78d2bSBill Paul 626b9f78d2bSBill Paul static int 627b9f78d2bSBill Paul bfe_miibus_writereg(device_t dev, int phy, int reg, int val) 628b9f78d2bSBill Paul { 629b9f78d2bSBill Paul struct bfe_softc *sc; 630b9f78d2bSBill Paul 631b9f78d2bSBill Paul sc = device_get_softc(dev); 632b9f78d2bSBill Paul bfe_writephy(sc, reg, val); 633b9f78d2bSBill Paul 634b9f78d2bSBill Paul return (0); 635b9f78d2bSBill Paul } 636b9f78d2bSBill Paul 637b9f78d2bSBill Paul static void 638b9f78d2bSBill Paul bfe_miibus_statchg(device_t dev) 639b9f78d2bSBill Paul { 6406ceb40baSPyun YongHyeon struct bfe_softc *sc; 6416ceb40baSPyun YongHyeon struct mii_data *mii; 6428f3562e2SMateusz Guzik u_int32_t val; 6438f3562e2SMateusz Guzik #ifdef notyet 6448f3562e2SMateusz Guzik u_int32_t flow; 6458f3562e2SMateusz Guzik #endif 6466ceb40baSPyun YongHyeon 6476ceb40baSPyun YongHyeon sc = device_get_softc(dev); 6486ceb40baSPyun YongHyeon mii = device_get_softc(sc->bfe_miibus); 6496ceb40baSPyun YongHyeon 65049bbfbc5SPyun YongHyeon sc->bfe_flags &= ~BFE_FLAG_LINK; 65149bbfbc5SPyun YongHyeon if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 65249bbfbc5SPyun YongHyeon (IFM_ACTIVE | IFM_AVALID)) { 65349bbfbc5SPyun YongHyeon switch (IFM_SUBTYPE(mii->mii_media_active)) { 65449bbfbc5SPyun YongHyeon case IFM_10_T: 65549bbfbc5SPyun YongHyeon case IFM_100_TX: 65649bbfbc5SPyun YongHyeon sc->bfe_flags |= BFE_FLAG_LINK; 65749bbfbc5SPyun YongHyeon break; 65849bbfbc5SPyun YongHyeon default: 65949bbfbc5SPyun YongHyeon break; 66049bbfbc5SPyun YongHyeon } 66149bbfbc5SPyun YongHyeon } 6626ceb40baSPyun YongHyeon 6636ceb40baSPyun YongHyeon /* XXX Should stop Rx/Tx engine prior to touching MAC. */ 6646ceb40baSPyun YongHyeon val = CSR_READ_4(sc, BFE_TX_CTRL); 6656ceb40baSPyun YongHyeon val &= ~BFE_TX_DUPLEX; 6666ceb40baSPyun YongHyeon if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 6676ceb40baSPyun YongHyeon val |= BFE_TX_DUPLEX; 6686ceb40baSPyun YongHyeon #ifdef notyet 6696ceb40baSPyun YongHyeon flow = CSR_READ_4(sc, BFE_RXCONF); 6706ceb40baSPyun YongHyeon flow &= ~BFE_RXCONF_FLOW; 6716ceb40baSPyun YongHyeon if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 6726ceb40baSPyun YongHyeon IFM_ETH_RXPAUSE) != 0) 6736ceb40baSPyun YongHyeon flow |= BFE_RXCONF_FLOW; 6746ceb40baSPyun YongHyeon CSR_WRITE_4(sc, BFE_RXCONF, flow); 6756ceb40baSPyun YongHyeon /* 6766ceb40baSPyun YongHyeon * It seems that the hardware has Tx pause issues 6776ceb40baSPyun YongHyeon * so enable only Rx pause. 6786ceb40baSPyun YongHyeon */ 6796ceb40baSPyun YongHyeon flow = CSR_READ_4(sc, BFE_MAC_FLOW); 6806ceb40baSPyun YongHyeon flow &= ~BFE_FLOW_PAUSE_ENAB; 6816ceb40baSPyun YongHyeon CSR_WRITE_4(sc, BFE_MAC_FLOW, flow); 6826ceb40baSPyun YongHyeon #endif 6836ceb40baSPyun YongHyeon } 6846ceb40baSPyun YongHyeon CSR_WRITE_4(sc, BFE_TX_CTRL, val); 685b9f78d2bSBill Paul } 686b9f78d2bSBill Paul 687b9f78d2bSBill Paul static void 688b9f78d2bSBill Paul bfe_tx_ring_free(struct bfe_softc *sc) 689b9f78d2bSBill Paul { 690b9f78d2bSBill Paul int i; 691b9f78d2bSBill Paul 692b9f78d2bSBill Paul for(i = 0; i < BFE_TX_LIST_CNT; i++) { 693b9f78d2bSBill Paul if (sc->bfe_tx_ring[i].bfe_mbuf != NULL) { 69496ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_txmbuf_tag, 69596ee09c5SPyun YongHyeon sc->bfe_tx_ring[i].bfe_map, BUS_DMASYNC_POSTWRITE); 69696ee09c5SPyun YongHyeon bus_dmamap_unload(sc->bfe_txmbuf_tag, 69796ee09c5SPyun YongHyeon sc->bfe_tx_ring[i].bfe_map); 698b9f78d2bSBill Paul m_freem(sc->bfe_tx_ring[i].bfe_mbuf); 699b9f78d2bSBill Paul sc->bfe_tx_ring[i].bfe_mbuf = NULL; 700b9f78d2bSBill Paul } 701b9f78d2bSBill Paul } 702b9f78d2bSBill Paul bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE); 70396ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 70496ee09c5SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 705b9f78d2bSBill Paul } 706b9f78d2bSBill Paul 707b9f78d2bSBill Paul static void 708b9f78d2bSBill Paul bfe_rx_ring_free(struct bfe_softc *sc) 709b9f78d2bSBill Paul { 710b9f78d2bSBill Paul int i; 711b9f78d2bSBill Paul 712b9f78d2bSBill Paul for (i = 0; i < BFE_RX_LIST_CNT; i++) { 713b9f78d2bSBill Paul if (sc->bfe_rx_ring[i].bfe_mbuf != NULL) { 71496ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_rxmbuf_tag, 71596ee09c5SPyun YongHyeon sc->bfe_rx_ring[i].bfe_map, BUS_DMASYNC_POSTREAD); 71696ee09c5SPyun YongHyeon bus_dmamap_unload(sc->bfe_rxmbuf_tag, 71796ee09c5SPyun YongHyeon sc->bfe_rx_ring[i].bfe_map); 718b9f78d2bSBill Paul m_freem(sc->bfe_rx_ring[i].bfe_mbuf); 719b9f78d2bSBill Paul sc->bfe_rx_ring[i].bfe_mbuf = NULL; 720b9f78d2bSBill Paul } 721b9f78d2bSBill Paul } 722b9f78d2bSBill Paul bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE); 72396ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 72496ee09c5SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 725b9f78d2bSBill Paul } 726b9f78d2bSBill Paul 727b9f78d2bSBill Paul static int 728b9f78d2bSBill Paul bfe_list_rx_init(struct bfe_softc *sc) 729b9f78d2bSBill Paul { 73096ee09c5SPyun YongHyeon struct bfe_rx_data *rd; 731b9f78d2bSBill Paul int i; 732b9f78d2bSBill Paul 73396ee09c5SPyun YongHyeon sc->bfe_rx_prod = sc->bfe_rx_cons = 0; 73496ee09c5SPyun YongHyeon bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE); 735b9f78d2bSBill Paul for (i = 0; i < BFE_RX_LIST_CNT; i++) { 73696ee09c5SPyun YongHyeon rd = &sc->bfe_rx_ring[i]; 73796ee09c5SPyun YongHyeon rd->bfe_mbuf = NULL; 73896ee09c5SPyun YongHyeon rd->bfe_ctrl = 0; 73996ee09c5SPyun YongHyeon if (bfe_list_newbuf(sc, i) != 0) 74027de24a7SDag-Erling Smørgrav return (ENOBUFS); 741b9f78d2bSBill Paul } 742b9f78d2bSBill Paul 74396ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 74496ee09c5SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 745b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMARX_PTR, (i * sizeof(struct bfe_desc))); 746b9f78d2bSBill Paul 747b9f78d2bSBill Paul return (0); 748b9f78d2bSBill Paul } 749b9f78d2bSBill Paul 75096ee09c5SPyun YongHyeon static void 75196ee09c5SPyun YongHyeon bfe_list_tx_init(struct bfe_softc *sc) 75296ee09c5SPyun YongHyeon { 75396ee09c5SPyun YongHyeon int i; 75496ee09c5SPyun YongHyeon 75596ee09c5SPyun YongHyeon sc->bfe_tx_cnt = sc->bfe_tx_prod = sc->bfe_tx_cons = 0; 75696ee09c5SPyun YongHyeon bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE); 75796ee09c5SPyun YongHyeon for (i = 0; i < BFE_TX_LIST_CNT; i++) 75896ee09c5SPyun YongHyeon sc->bfe_tx_ring[i].bfe_mbuf = NULL; 75996ee09c5SPyun YongHyeon 76096ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 76196ee09c5SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 76296ee09c5SPyun YongHyeon } 76396ee09c5SPyun YongHyeon 76496ee09c5SPyun YongHyeon static void 76596ee09c5SPyun YongHyeon bfe_discard_buf(struct bfe_softc *sc, int c) 76696ee09c5SPyun YongHyeon { 76796ee09c5SPyun YongHyeon struct bfe_rx_data *r; 76896ee09c5SPyun YongHyeon struct bfe_desc *d; 76996ee09c5SPyun YongHyeon 77096ee09c5SPyun YongHyeon r = &sc->bfe_rx_ring[c]; 77196ee09c5SPyun YongHyeon d = &sc->bfe_rx_list[c]; 77296ee09c5SPyun YongHyeon d->bfe_ctrl = htole32(r->bfe_ctrl); 77396ee09c5SPyun YongHyeon } 77496ee09c5SPyun YongHyeon 775b9f78d2bSBill Paul static int 77696ee09c5SPyun YongHyeon bfe_list_newbuf(struct bfe_softc *sc, int c) 777b9f78d2bSBill Paul { 778b9f78d2bSBill Paul struct bfe_rxheader *rx_header; 779b9f78d2bSBill Paul struct bfe_desc *d; 78096ee09c5SPyun YongHyeon struct bfe_rx_data *r; 78196ee09c5SPyun YongHyeon struct mbuf *m; 78296ee09c5SPyun YongHyeon bus_dma_segment_t segs[1]; 78396ee09c5SPyun YongHyeon bus_dmamap_t map; 784b9f78d2bSBill Paul u_int32_t ctrl; 78596ee09c5SPyun YongHyeon int nsegs; 786b9f78d2bSBill Paul 787c6499eccSGleb Smirnoff m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 78872b09927SGleb Smirnoff if (m == NULL) 78972b09927SGleb Smirnoff return (ENOBUFS); 790b9f78d2bSBill Paul m->m_len = m->m_pkthdr.len = MCLBYTES; 79196ee09c5SPyun YongHyeon 79296ee09c5SPyun YongHyeon if (bus_dmamap_load_mbuf_sg(sc->bfe_rxmbuf_tag, sc->bfe_rx_sparemap, 79396ee09c5SPyun YongHyeon m, segs, &nsegs, 0) != 0) { 79496ee09c5SPyun YongHyeon m_freem(m); 79596ee09c5SPyun YongHyeon return (ENOBUFS); 796b9f78d2bSBill Paul } 79796ee09c5SPyun YongHyeon 79896ee09c5SPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 79996ee09c5SPyun YongHyeon r = &sc->bfe_rx_ring[c]; 80096ee09c5SPyun YongHyeon if (r->bfe_mbuf != NULL) { 80196ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_rxmbuf_tag, r->bfe_map, 80296ee09c5SPyun YongHyeon BUS_DMASYNC_POSTREAD); 80396ee09c5SPyun YongHyeon bus_dmamap_unload(sc->bfe_rxmbuf_tag, r->bfe_map); 80496ee09c5SPyun YongHyeon } 80596ee09c5SPyun YongHyeon map = r->bfe_map; 80696ee09c5SPyun YongHyeon r->bfe_map = sc->bfe_rx_sparemap; 80796ee09c5SPyun YongHyeon sc->bfe_rx_sparemap = map; 80896ee09c5SPyun YongHyeon r->bfe_mbuf = m; 809b9f78d2bSBill Paul 810b9f78d2bSBill Paul rx_header = mtod(m, struct bfe_rxheader *); 811b9f78d2bSBill Paul rx_header->len = 0; 812b9f78d2bSBill Paul rx_header->flags = 0; 81396ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_rxmbuf_tag, r->bfe_map, BUS_DMASYNC_PREREAD); 814b9f78d2bSBill Paul 81596ee09c5SPyun YongHyeon ctrl = segs[0].ds_len & BFE_DESC_LEN; 81696ee09c5SPyun YongHyeon KASSERT(ctrl > ETHER_MAX_LEN + 32, ("%s: buffer size too small(%d)!", 81796ee09c5SPyun YongHyeon __func__, ctrl)); 818b9f78d2bSBill Paul if (c == BFE_RX_LIST_CNT - 1) 819b9f78d2bSBill Paul ctrl |= BFE_DESC_EOT; 82096ee09c5SPyun YongHyeon r->bfe_ctrl = ctrl; 821b9f78d2bSBill Paul 82296ee09c5SPyun YongHyeon d = &sc->bfe_rx_list[c]; 82396ee09c5SPyun YongHyeon d->bfe_ctrl = htole32(ctrl); 82496ee09c5SPyun YongHyeon /* The chip needs all addresses to be added to BFE_PCI_DMA. */ 82596ee09c5SPyun YongHyeon d->bfe_addr = htole32(BFE_ADDR_LO(segs[0].ds_addr) + BFE_PCI_DMA); 82696ee09c5SPyun YongHyeon 827b9f78d2bSBill Paul return (0); 828b9f78d2bSBill Paul } 829b9f78d2bSBill Paul 830b9f78d2bSBill Paul static void 831b9f78d2bSBill Paul bfe_get_config(struct bfe_softc *sc) 832b9f78d2bSBill Paul { 833b9f78d2bSBill Paul u_int8_t eeprom[128]; 834b9f78d2bSBill Paul 835b9f78d2bSBill Paul bfe_read_eeprom(sc, eeprom); 836b9f78d2bSBill Paul 837fc74a9f9SBrooks Davis sc->bfe_enaddr[0] = eeprom[79]; 838fc74a9f9SBrooks Davis sc->bfe_enaddr[1] = eeprom[78]; 839fc74a9f9SBrooks Davis sc->bfe_enaddr[2] = eeprom[81]; 840fc74a9f9SBrooks Davis sc->bfe_enaddr[3] = eeprom[80]; 841fc74a9f9SBrooks Davis sc->bfe_enaddr[4] = eeprom[83]; 842fc74a9f9SBrooks Davis sc->bfe_enaddr[5] = eeprom[82]; 843b9f78d2bSBill Paul 844b9f78d2bSBill Paul sc->bfe_phyaddr = eeprom[90] & 0x1f; 845b9f78d2bSBill Paul sc->bfe_mdc_port = (eeprom[90] >> 14) & 0x1; 846b9f78d2bSBill Paul 847b9f78d2bSBill Paul sc->bfe_core_unit = 0; 848b9f78d2bSBill Paul sc->bfe_dma_offset = BFE_PCI_DMA; 849b9f78d2bSBill Paul } 850b9f78d2bSBill Paul 851b9f78d2bSBill Paul static void 852b9f78d2bSBill Paul bfe_pci_setup(struct bfe_softc *sc, u_int32_t cores) 853b9f78d2bSBill Paul { 8540fd7b4c7SScott Long u_int32_t bar_orig, val; 855b9f78d2bSBill Paul 856b9f78d2bSBill Paul bar_orig = pci_read_config(sc->bfe_dev, BFE_BAR0_WIN, 4); 857b9f78d2bSBill Paul pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, BFE_REG_PCI, 4); 858b9f78d2bSBill Paul 859b9f78d2bSBill Paul val = CSR_READ_4(sc, BFE_SBINTVEC); 860b9f78d2bSBill Paul val |= cores; 861b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBINTVEC, val); 862b9f78d2bSBill Paul 863b9f78d2bSBill Paul val = CSR_READ_4(sc, BFE_SSB_PCI_TRANS_2); 864b9f78d2bSBill Paul val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST; 865b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SSB_PCI_TRANS_2, val); 866b9f78d2bSBill Paul 867b9f78d2bSBill Paul pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, bar_orig, 4); 868b9f78d2bSBill Paul } 869b9f78d2bSBill Paul 870b9f78d2bSBill Paul static void 871b9f78d2bSBill Paul bfe_clear_stats(struct bfe_softc *sc) 872b9f78d2bSBill Paul { 873861cf54cSPyun YongHyeon uint32_t reg; 874b9f78d2bSBill Paul 875f16b4811SMike Makonnen BFE_LOCK_ASSERT(sc); 876b9f78d2bSBill Paul 877b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 878b9f78d2bSBill Paul for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) 879b9f78d2bSBill Paul CSR_READ_4(sc, reg); 880b9f78d2bSBill Paul for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) 881b9f78d2bSBill Paul CSR_READ_4(sc, reg); 882b9f78d2bSBill Paul } 883b9f78d2bSBill Paul 884b9f78d2bSBill Paul static int 885b9f78d2bSBill Paul bfe_resetphy(struct bfe_softc *sc) 886b9f78d2bSBill Paul { 887b9f78d2bSBill Paul u_int32_t val; 888b9f78d2bSBill Paul 889b9f78d2bSBill Paul bfe_writephy(sc, 0, BMCR_RESET); 890b9f78d2bSBill Paul DELAY(100); 891b9f78d2bSBill Paul bfe_readphy(sc, 0, &val); 892b9f78d2bSBill Paul if (val & BMCR_RESET) { 893be280562SPyun YongHyeon device_printf(sc->bfe_dev, "PHY Reset would not complete.\n"); 89427de24a7SDag-Erling Smørgrav return (ENXIO); 895b9f78d2bSBill Paul } 89627de24a7SDag-Erling Smørgrav return (0); 897b9f78d2bSBill Paul } 898b9f78d2bSBill Paul 899b9f78d2bSBill Paul static void 900b9f78d2bSBill Paul bfe_chip_halt(struct bfe_softc *sc) 901b9f78d2bSBill Paul { 902f16b4811SMike Makonnen BFE_LOCK_ASSERT(sc); 903b9f78d2bSBill Paul /* disable interrupts - not that it actually does..*/ 904b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_IMASK, 0); 905b9f78d2bSBill Paul CSR_READ_4(sc, BFE_IMASK); 906b9f78d2bSBill Paul 907b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); 908b9f78d2bSBill Paul bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 200, 1); 909b9f78d2bSBill Paul 910b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); 911b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); 912b9f78d2bSBill Paul DELAY(10); 913b9f78d2bSBill Paul } 914b9f78d2bSBill Paul 915b9f78d2bSBill Paul static void 916b9f78d2bSBill Paul bfe_chip_reset(struct bfe_softc *sc) 917b9f78d2bSBill Paul { 918b9f78d2bSBill Paul u_int32_t val; 919b9f78d2bSBill Paul 920f16b4811SMike Makonnen BFE_LOCK_ASSERT(sc); 921b9f78d2bSBill Paul 922b9f78d2bSBill Paul /* Set the interrupt vector for the enet core */ 923b9f78d2bSBill Paul bfe_pci_setup(sc, BFE_INTVEC_ENET0); 924b9f78d2bSBill Paul 925b9f78d2bSBill Paul /* is core up? */ 926f2b1c158SJulian Elischer val = CSR_READ_4(sc, BFE_SBTMSLOW) & 927f2b1c158SJulian Elischer (BFE_RESET | BFE_REJECT | BFE_CLOCK); 928b9f78d2bSBill Paul if (val == BFE_CLOCK) { 929b9f78d2bSBill Paul /* It is, so shut it down */ 930b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_RCV_LAZY, 0); 931b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE); 932b9f78d2bSBill Paul bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 100, 1); 933b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0); 934b9f78d2bSBill Paul if (CSR_READ_4(sc, BFE_DMARX_STAT) & BFE_STAT_EMASK) 935f2b1c158SJulian Elischer bfe_wait_bit(sc, BFE_DMARX_STAT, BFE_STAT_SIDLE, 936f2b1c158SJulian Elischer 100, 0); 937b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0); 938b9f78d2bSBill Paul } 939b9f78d2bSBill Paul 940b9f78d2bSBill Paul bfe_core_reset(sc); 941b9f78d2bSBill Paul bfe_clear_stats(sc); 942b9f78d2bSBill Paul 943b9f78d2bSBill Paul /* 944b9f78d2bSBill Paul * We want the phy registers to be accessible even when 945b9f78d2bSBill Paul * the driver is "downed" so initialize MDC preamble, frequency, 946b9f78d2bSBill Paul * and whether internal or external phy here. 947b9f78d2bSBill Paul */ 948b9f78d2bSBill Paul 949b9f78d2bSBill Paul /* 4402 has 62.5Mhz SB clock and internal phy */ 950b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d); 951b9f78d2bSBill Paul 952b9f78d2bSBill Paul /* Internal or external PHY? */ 953b9f78d2bSBill Paul val = CSR_READ_4(sc, BFE_DEVCTRL); 954b9f78d2bSBill Paul if (!(val & BFE_IPP)) 955b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_EPSEL); 956b9f78d2bSBill Paul else if (CSR_READ_4(sc, BFE_DEVCTRL) & BFE_EPR) { 957b9f78d2bSBill Paul BFE_AND(sc, BFE_DEVCTRL, ~BFE_EPR); 958b9f78d2bSBill Paul DELAY(100); 959b9f78d2bSBill Paul } 960b9f78d2bSBill Paul 96162a9464cSDuncan Barclay /* Enable CRC32 generation and set proper LED modes */ 96262a9464cSDuncan Barclay BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED); 96362a9464cSDuncan Barclay 96462a9464cSDuncan Barclay /* Reset or clear powerdown control bit */ 96562a9464cSDuncan Barclay BFE_AND(sc, BFE_MAC_CTRL, ~BFE_CTRL_PDOWN); 96662a9464cSDuncan Barclay 967b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) & 968b9f78d2bSBill Paul BFE_LAZY_FC_MASK)); 969b9f78d2bSBill Paul 970b9f78d2bSBill Paul /* 971f2b1c158SJulian Elischer * We don't want lazy interrupts, so just send them at 972f2b1c158SJulian Elischer * the end of a frame, please 973b9f78d2bSBill Paul */ 974b9f78d2bSBill Paul BFE_OR(sc, BFE_RCV_LAZY, 0); 975b9f78d2bSBill Paul 976b9f78d2bSBill Paul /* Set max lengths, accounting for VLAN tags */ 977b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_RXMAXLEN, ETHER_MAX_LEN+32); 978b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_TXMAXLEN, ETHER_MAX_LEN+32); 979b9f78d2bSBill Paul 980b9f78d2bSBill Paul /* Set watermark XXX - magic */ 981b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_TX_WMARK, 56); 982b9f78d2bSBill Paul 983b9f78d2bSBill Paul /* 984f2b1c158SJulian Elischer * Initialise DMA channels 985f2b1c158SJulian Elischer * - not forgetting dma addresses need to be added to BFE_PCI_DMA 986b9f78d2bSBill Paul */ 987b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE); 988b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMATX_ADDR, sc->bfe_tx_dma + BFE_PCI_DMA); 989b9f78d2bSBill Paul 990b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) | 991b9f78d2bSBill Paul BFE_RX_CTRL_ENABLE); 992b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_DMARX_ADDR, sc->bfe_rx_dma + BFE_PCI_DMA); 993b9f78d2bSBill Paul 994b9f78d2bSBill Paul bfe_resetphy(sc); 995b9f78d2bSBill Paul bfe_setupphy(sc); 996b9f78d2bSBill Paul } 997b9f78d2bSBill Paul 998b9f78d2bSBill Paul static void 999b9f78d2bSBill Paul bfe_core_disable(struct bfe_softc *sc) 1000b9f78d2bSBill Paul { 1001b9f78d2bSBill Paul if ((CSR_READ_4(sc, BFE_SBTMSLOW)) & BFE_RESET) 1002b9f78d2bSBill Paul return; 1003b9f78d2bSBill Paul 1004b9f78d2bSBill Paul /* 1005f2b1c158SJulian Elischer * Set reject, wait for it set, then wait for the core to stop 1006f2b1c158SJulian Elischer * being busy, then set reset and reject and enable the clocks. 1007b9f78d2bSBill Paul */ 1008b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK)); 1009b9f78d2bSBill Paul bfe_wait_bit(sc, BFE_SBTMSLOW, BFE_REJECT, 1000, 0); 1010b9f78d2bSBill Paul bfe_wait_bit(sc, BFE_SBTMSHIGH, BFE_BUSY, 1000, 1); 1011b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | 1012b9f78d2bSBill Paul BFE_RESET)); 1013b9f78d2bSBill Paul CSR_READ_4(sc, BFE_SBTMSLOW); 1014b9f78d2bSBill Paul DELAY(10); 1015b9f78d2bSBill Paul /* Leave reset and reject set */ 1016b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET)); 1017b9f78d2bSBill Paul DELAY(10); 1018b9f78d2bSBill Paul } 1019b9f78d2bSBill Paul 1020b9f78d2bSBill Paul static void 1021b9f78d2bSBill Paul bfe_core_reset(struct bfe_softc *sc) 1022b9f78d2bSBill Paul { 1023b9f78d2bSBill Paul u_int32_t val; 1024b9f78d2bSBill Paul 1025b9f78d2bSBill Paul /* Disable the core */ 1026b9f78d2bSBill Paul bfe_core_disable(sc); 1027b9f78d2bSBill Paul 1028b9f78d2bSBill Paul /* and bring it back up */ 1029b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC)); 1030b9f78d2bSBill Paul CSR_READ_4(sc, BFE_SBTMSLOW); 1031b9f78d2bSBill Paul DELAY(10); 1032b9f78d2bSBill Paul 1033b9f78d2bSBill Paul /* Chip bug, clear SERR, IB and TO if they are set. */ 1034b9f78d2bSBill Paul if (CSR_READ_4(sc, BFE_SBTMSHIGH) & BFE_SERR) 1035b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBTMSHIGH, 0); 1036b9f78d2bSBill Paul val = CSR_READ_4(sc, BFE_SBIMSTATE); 1037b9f78d2bSBill Paul if (val & (BFE_IBE | BFE_TO)) 1038b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO)); 1039b9f78d2bSBill Paul 1040b9f78d2bSBill Paul /* Clear reset and allow it to move through the core */ 1041b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC)); 1042b9f78d2bSBill Paul CSR_READ_4(sc, BFE_SBTMSLOW); 1043b9f78d2bSBill Paul DELAY(10); 1044b9f78d2bSBill Paul 1045b9f78d2bSBill Paul /* Leave the clock set */ 1046b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_SBTMSLOW, BFE_CLOCK); 1047b9f78d2bSBill Paul CSR_READ_4(sc, BFE_SBTMSLOW); 1048b9f78d2bSBill Paul DELAY(10); 1049b9f78d2bSBill Paul } 1050b9f78d2bSBill Paul 1051b9f78d2bSBill Paul static void 1052b9f78d2bSBill Paul bfe_cam_write(struct bfe_softc *sc, u_char *data, int index) 1053b9f78d2bSBill Paul { 1054b9f78d2bSBill Paul u_int32_t val; 1055b9f78d2bSBill Paul 1056b9f78d2bSBill Paul val = ((u_int32_t) data[2]) << 24; 1057b9f78d2bSBill Paul val |= ((u_int32_t) data[3]) << 16; 1058b9f78d2bSBill Paul val |= ((u_int32_t) data[4]) << 8; 1059b9f78d2bSBill Paul val |= ((u_int32_t) data[5]); 1060b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_CAM_DATA_LO, val); 1061b9f78d2bSBill Paul val = (BFE_CAM_HI_VALID | 1062b9f78d2bSBill Paul (((u_int32_t) data[0]) << 8) | 1063b9f78d2bSBill Paul (((u_int32_t) data[1]))); 1064b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_CAM_DATA_HI, val); 1065b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_CAM_CTRL, (BFE_CAM_WRITE | 106662a9464cSDuncan Barclay ((u_int32_t) index << BFE_CAM_INDEX_SHIFT))); 1067b9f78d2bSBill Paul bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1); 1068b9f78d2bSBill Paul } 1069b9f78d2bSBill Paul 1070f0bcd699SGleb Smirnoff static u_int 1071f0bcd699SGleb Smirnoff bfe_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 1072f0bcd699SGleb Smirnoff { 1073f0bcd699SGleb Smirnoff struct bfe_softc *sc = arg; 1074f0bcd699SGleb Smirnoff 1075f0bcd699SGleb Smirnoff bfe_cam_write(sc, LLADDR(sdl), cnt + 1); 1076f0bcd699SGleb Smirnoff 1077f0bcd699SGleb Smirnoff return (1); 1078f0bcd699SGleb Smirnoff } 1079f0bcd699SGleb Smirnoff 1080b9f78d2bSBill Paul static void 1081b9f78d2bSBill Paul bfe_set_rx_mode(struct bfe_softc *sc) 1082b9f78d2bSBill Paul { 1083c0e5e270SJustin Hibbits if_t ifp = sc->bfe_ifp; 1084b9f78d2bSBill Paul u_int32_t val; 1085b9f78d2bSBill Paul 1086861cf54cSPyun YongHyeon BFE_LOCK_ASSERT(sc); 1087861cf54cSPyun YongHyeon 1088b9f78d2bSBill Paul val = CSR_READ_4(sc, BFE_RXCONF); 1089b9f78d2bSBill Paul 1090c0e5e270SJustin Hibbits if (if_getflags(ifp) & IFF_PROMISC) 1091b9f78d2bSBill Paul val |= BFE_RXCONF_PROMISC; 1092b9f78d2bSBill Paul else 1093b9f78d2bSBill Paul val &= ~BFE_RXCONF_PROMISC; 1094b9f78d2bSBill Paul 1095c0e5e270SJustin Hibbits if (if_getflags(ifp) & IFF_BROADCAST) 1096b9f78d2bSBill Paul val &= ~BFE_RXCONF_DBCAST; 1097b9f78d2bSBill Paul else 1098b9f78d2bSBill Paul val |= BFE_RXCONF_DBCAST; 1099b9f78d2bSBill Paul 1100b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_CAM_CTRL, 0); 1101c0e5e270SJustin Hibbits bfe_cam_write(sc, if_getlladdr(sc->bfe_ifp), 0); 1102b9f78d2bSBill Paul 1103c0e5e270SJustin Hibbits if (if_getflags(ifp) & IFF_ALLMULTI) 1104b9f78d2bSBill Paul val |= BFE_RXCONF_ALLMULTI; 1105b9f78d2bSBill Paul else { 1106b9f78d2bSBill Paul val &= ~BFE_RXCONF_ALLMULTI; 1107f0bcd699SGleb Smirnoff if_foreach_llmaddr(ifp, bfe_write_maddr, sc); 1108b9f78d2bSBill Paul } 1109b9f78d2bSBill Paul 1110b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_RXCONF, val); 1111b9f78d2bSBill Paul BFE_OR(sc, BFE_CAM_CTRL, BFE_CAM_ENABLE); 1112b9f78d2bSBill Paul } 1113b9f78d2bSBill Paul 1114b9f78d2bSBill Paul static void 1115b9f78d2bSBill Paul bfe_dma_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1116b9f78d2bSBill Paul { 111796ee09c5SPyun YongHyeon struct bfe_dmamap_arg *ctx; 1118b9f78d2bSBill Paul 111996ee09c5SPyun YongHyeon if (error != 0) 112096ee09c5SPyun YongHyeon return; 1121b9f78d2bSBill Paul 112296ee09c5SPyun YongHyeon KASSERT(nseg == 1, ("%s : %d segments returned!", __func__, nseg)); 1123b9f78d2bSBill Paul 112496ee09c5SPyun YongHyeon ctx = (struct bfe_dmamap_arg *)arg; 112596ee09c5SPyun YongHyeon ctx->bfe_busaddr = segs[0].ds_addr; 1126b9f78d2bSBill Paul } 1127b9f78d2bSBill Paul 1128b9f78d2bSBill Paul static void 1129b9f78d2bSBill Paul bfe_release_resources(struct bfe_softc *sc) 1130b9f78d2bSBill Paul { 1131b9f78d2bSBill Paul 1132b9f78d2bSBill Paul if (sc->bfe_intrhand != NULL) 113396ee09c5SPyun YongHyeon bus_teardown_intr(sc->bfe_dev, sc->bfe_irq, sc->bfe_intrhand); 1134b9f78d2bSBill Paul 1135b9f78d2bSBill Paul if (sc->bfe_irq != NULL) 113696ee09c5SPyun YongHyeon bus_release_resource(sc->bfe_dev, SYS_RES_IRQ, 0, sc->bfe_irq); 1137b9f78d2bSBill Paul 1138b9f78d2bSBill Paul if (sc->bfe_res != NULL) 113996ee09c5SPyun YongHyeon bus_release_resource(sc->bfe_dev, SYS_RES_MEMORY, PCIR_BAR(0), 114096ee09c5SPyun YongHyeon sc->bfe_res); 1141b9f78d2bSBill Paul 1142ad61f896SRuslan Ermilov if (sc->bfe_ifp != NULL) 1143ad61f896SRuslan Ermilov if_free(sc->bfe_ifp); 1144b9f78d2bSBill Paul } 1145b9f78d2bSBill Paul 1146b9f78d2bSBill Paul static void 1147b9f78d2bSBill Paul bfe_read_eeprom(struct bfe_softc *sc, u_int8_t *data) 1148b9f78d2bSBill Paul { 1149b9f78d2bSBill Paul long i; 1150b9f78d2bSBill Paul u_int16_t *ptr = (u_int16_t *)data; 1151b9f78d2bSBill Paul 1152b9f78d2bSBill Paul for(i = 0; i < 128; i += 2) 1153b9f78d2bSBill Paul ptr[i/2] = CSR_READ_4(sc, 4096 + i); 1154b9f78d2bSBill Paul } 1155b9f78d2bSBill Paul 1156b9f78d2bSBill Paul static int 1157b9f78d2bSBill Paul bfe_wait_bit(struct bfe_softc *sc, u_int32_t reg, u_int32_t bit, 1158b9f78d2bSBill Paul u_long timeout, const int clear) 1159b9f78d2bSBill Paul { 1160b9f78d2bSBill Paul u_long i; 1161b9f78d2bSBill Paul 1162b9f78d2bSBill Paul for (i = 0; i < timeout; i++) { 1163b9f78d2bSBill Paul u_int32_t val = CSR_READ_4(sc, reg); 1164b9f78d2bSBill Paul 1165b9f78d2bSBill Paul if (clear && !(val & bit)) 1166b9f78d2bSBill Paul break; 1167b9f78d2bSBill Paul if (!clear && (val & bit)) 1168b9f78d2bSBill Paul break; 1169b9f78d2bSBill Paul DELAY(10); 1170b9f78d2bSBill Paul } 1171b9f78d2bSBill Paul if (i == timeout) { 1172be280562SPyun YongHyeon device_printf(sc->bfe_dev, 1173be280562SPyun YongHyeon "BUG! Timeout waiting for bit %08x of register " 1174be280562SPyun YongHyeon "%x to %s.\n", bit, reg, (clear ? "clear" : "set")); 117527de24a7SDag-Erling Smørgrav return (-1); 1176b9f78d2bSBill Paul } 117727de24a7SDag-Erling Smørgrav return (0); 1178b9f78d2bSBill Paul } 1179b9f78d2bSBill Paul 1180b9f78d2bSBill Paul static int 1181b9f78d2bSBill Paul bfe_readphy(struct bfe_softc *sc, u_int32_t reg, u_int32_t *val) 1182b9f78d2bSBill Paul { 1183b9f78d2bSBill Paul int err; 1184b9f78d2bSBill Paul 1185b9f78d2bSBill Paul /* Clear MII ISR */ 1186b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 1187b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 1188b9f78d2bSBill Paul (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) | 1189b9f78d2bSBill Paul (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | 1190b9f78d2bSBill Paul (reg << BFE_MDIO_RA_SHIFT) | 1191b9f78d2bSBill Paul (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT))); 1192b9f78d2bSBill Paul err = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); 1193b9f78d2bSBill Paul *val = CSR_READ_4(sc, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA; 1194b9f78d2bSBill Paul 119527de24a7SDag-Erling Smørgrav return (err); 1196b9f78d2bSBill Paul } 1197b9f78d2bSBill Paul 1198b9f78d2bSBill Paul static int 1199b9f78d2bSBill Paul bfe_writephy(struct bfe_softc *sc, u_int32_t reg, u_int32_t val) 1200b9f78d2bSBill Paul { 1201b9f78d2bSBill Paul int status; 1202b9f78d2bSBill Paul 1203b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII); 1204b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START | 1205b9f78d2bSBill Paul (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) | 1206b9f78d2bSBill Paul (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) | 1207b9f78d2bSBill Paul (reg << BFE_MDIO_RA_SHIFT) | 1208b9f78d2bSBill Paul (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) | 1209b9f78d2bSBill Paul (val & BFE_MDIO_DATA_DATA))); 1210b9f78d2bSBill Paul status = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0); 1211b9f78d2bSBill Paul 121227de24a7SDag-Erling Smørgrav return (status); 1213b9f78d2bSBill Paul } 1214b9f78d2bSBill Paul 1215b9f78d2bSBill Paul /* 1216b9f78d2bSBill Paul * XXX - I think this is handled by the PHY driver, but it can't hurt to do it 1217b9f78d2bSBill Paul * twice 1218b9f78d2bSBill Paul */ 1219b9f78d2bSBill Paul static int 1220b9f78d2bSBill Paul bfe_setupphy(struct bfe_softc *sc) 1221b9f78d2bSBill Paul { 1222b9f78d2bSBill Paul u_int32_t val; 1223b9f78d2bSBill Paul 1224b9f78d2bSBill Paul /* Enable activity LED */ 1225b9f78d2bSBill Paul bfe_readphy(sc, 26, &val); 1226b9f78d2bSBill Paul bfe_writephy(sc, 26, val & 0x7fff); 1227b9f78d2bSBill Paul bfe_readphy(sc, 26, &val); 1228b9f78d2bSBill Paul 1229b9f78d2bSBill Paul /* Enable traffic meter LED mode */ 1230b9f78d2bSBill Paul bfe_readphy(sc, 27, &val); 1231b9f78d2bSBill Paul bfe_writephy(sc, 27, val | (1 << 6)); 1232b9f78d2bSBill Paul 123327de24a7SDag-Erling Smørgrav return (0); 1234b9f78d2bSBill Paul } 1235b9f78d2bSBill Paul 1236b9f78d2bSBill Paul static void 1237b9f78d2bSBill Paul bfe_stats_update(struct bfe_softc *sc) 1238b9f78d2bSBill Paul { 1239861cf54cSPyun YongHyeon struct bfe_hw_stats *stats; 1240c0e5e270SJustin Hibbits if_t ifp; 1241861cf54cSPyun YongHyeon uint32_t mib[BFE_MIB_CNT]; 1242861cf54cSPyun YongHyeon uint32_t reg, *val; 1243b9f78d2bSBill Paul 1244861cf54cSPyun YongHyeon BFE_LOCK_ASSERT(sc); 1245861cf54cSPyun YongHyeon 1246861cf54cSPyun YongHyeon val = mib; 1247861cf54cSPyun YongHyeon CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ); 1248861cf54cSPyun YongHyeon for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) 1249861cf54cSPyun YongHyeon *val++ = CSR_READ_4(sc, reg); 1250861cf54cSPyun YongHyeon for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) 1251861cf54cSPyun YongHyeon *val++ = CSR_READ_4(sc, reg); 1252861cf54cSPyun YongHyeon 1253861cf54cSPyun YongHyeon ifp = sc->bfe_ifp; 1254861cf54cSPyun YongHyeon stats = &sc->bfe_stats; 1255861cf54cSPyun YongHyeon /* Tx stat. */ 1256861cf54cSPyun YongHyeon stats->tx_good_octets += mib[MIB_TX_GOOD_O]; 1257861cf54cSPyun YongHyeon stats->tx_good_frames += mib[MIB_TX_GOOD_P]; 1258861cf54cSPyun YongHyeon stats->tx_octets += mib[MIB_TX_O]; 1259861cf54cSPyun YongHyeon stats->tx_frames += mib[MIB_TX_P]; 1260861cf54cSPyun YongHyeon stats->tx_bcast_frames += mib[MIB_TX_BCAST]; 1261861cf54cSPyun YongHyeon stats->tx_mcast_frames += mib[MIB_TX_MCAST]; 1262861cf54cSPyun YongHyeon stats->tx_pkts_64 += mib[MIB_TX_64]; 1263861cf54cSPyun YongHyeon stats->tx_pkts_65_127 += mib[MIB_TX_65_127]; 1264861cf54cSPyun YongHyeon stats->tx_pkts_128_255 += mib[MIB_TX_128_255]; 1265861cf54cSPyun YongHyeon stats->tx_pkts_256_511 += mib[MIB_TX_256_511]; 1266861cf54cSPyun YongHyeon stats->tx_pkts_512_1023 += mib[MIB_TX_512_1023]; 1267861cf54cSPyun YongHyeon stats->tx_pkts_1024_max += mib[MIB_TX_1024_MAX]; 1268861cf54cSPyun YongHyeon stats->tx_jabbers += mib[MIB_TX_JABBER]; 1269861cf54cSPyun YongHyeon stats->tx_oversize_frames += mib[MIB_TX_OSIZE]; 1270861cf54cSPyun YongHyeon stats->tx_frag_frames += mib[MIB_TX_FRAG]; 1271861cf54cSPyun YongHyeon stats->tx_underruns += mib[MIB_TX_URUNS]; 1272861cf54cSPyun YongHyeon stats->tx_colls += mib[MIB_TX_TCOLS]; 1273861cf54cSPyun YongHyeon stats->tx_single_colls += mib[MIB_TX_SCOLS]; 1274861cf54cSPyun YongHyeon stats->tx_multi_colls += mib[MIB_TX_MCOLS]; 1275861cf54cSPyun YongHyeon stats->tx_excess_colls += mib[MIB_TX_ECOLS]; 1276861cf54cSPyun YongHyeon stats->tx_late_colls += mib[MIB_TX_LCOLS]; 1277861cf54cSPyun YongHyeon stats->tx_deferrals += mib[MIB_TX_DEFERED]; 1278861cf54cSPyun YongHyeon stats->tx_carrier_losts += mib[MIB_TX_CLOST]; 1279861cf54cSPyun YongHyeon stats->tx_pause_frames += mib[MIB_TX_PAUSE]; 1280861cf54cSPyun YongHyeon /* Rx stat. */ 1281861cf54cSPyun YongHyeon stats->rx_good_octets += mib[MIB_RX_GOOD_O]; 1282861cf54cSPyun YongHyeon stats->rx_good_frames += mib[MIB_RX_GOOD_P]; 1283861cf54cSPyun YongHyeon stats->rx_octets += mib[MIB_RX_O]; 1284861cf54cSPyun YongHyeon stats->rx_frames += mib[MIB_RX_P]; 1285861cf54cSPyun YongHyeon stats->rx_bcast_frames += mib[MIB_RX_BCAST]; 1286861cf54cSPyun YongHyeon stats->rx_mcast_frames += mib[MIB_RX_MCAST]; 1287861cf54cSPyun YongHyeon stats->rx_pkts_64 += mib[MIB_RX_64]; 1288861cf54cSPyun YongHyeon stats->rx_pkts_65_127 += mib[MIB_RX_65_127]; 1289861cf54cSPyun YongHyeon stats->rx_pkts_128_255 += mib[MIB_RX_128_255]; 1290861cf54cSPyun YongHyeon stats->rx_pkts_256_511 += mib[MIB_RX_256_511]; 1291861cf54cSPyun YongHyeon stats->rx_pkts_512_1023 += mib[MIB_RX_512_1023]; 1292861cf54cSPyun YongHyeon stats->rx_pkts_1024_max += mib[MIB_RX_1024_MAX]; 1293861cf54cSPyun YongHyeon stats->rx_jabbers += mib[MIB_RX_JABBER]; 1294861cf54cSPyun YongHyeon stats->rx_oversize_frames += mib[MIB_RX_OSIZE]; 1295861cf54cSPyun YongHyeon stats->rx_frag_frames += mib[MIB_RX_FRAG]; 1296861cf54cSPyun YongHyeon stats->rx_missed_frames += mib[MIB_RX_MISS]; 1297861cf54cSPyun YongHyeon stats->rx_crc_align_errs += mib[MIB_RX_CRCA]; 1298861cf54cSPyun YongHyeon stats->rx_runts += mib[MIB_RX_USIZE]; 1299861cf54cSPyun YongHyeon stats->rx_crc_errs += mib[MIB_RX_CRC]; 1300861cf54cSPyun YongHyeon stats->rx_align_errs += mib[MIB_RX_ALIGN]; 1301861cf54cSPyun YongHyeon stats->rx_symbol_errs += mib[MIB_RX_SYM]; 1302861cf54cSPyun YongHyeon stats->rx_pause_frames += mib[MIB_RX_PAUSE]; 1303861cf54cSPyun YongHyeon stats->rx_control_frames += mib[MIB_RX_NPAUSE]; 1304861cf54cSPyun YongHyeon 1305861cf54cSPyun YongHyeon /* Update counters in ifnet. */ 130610b77d66SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, (u_long)mib[MIB_TX_GOOD_P]); 130710b77d66SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, (u_long)mib[MIB_TX_TCOLS]); 130810b77d66SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, (u_long)mib[MIB_TX_URUNS] + 1309861cf54cSPyun YongHyeon (u_long)mib[MIB_TX_ECOLS] + 1310861cf54cSPyun YongHyeon (u_long)mib[MIB_TX_DEFERED] + 131110b77d66SGleb Smirnoff (u_long)mib[MIB_TX_CLOST]); 1312861cf54cSPyun YongHyeon 131310b77d66SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, (u_long)mib[MIB_RX_GOOD_P]); 1314861cf54cSPyun YongHyeon 131510b77d66SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, mib[MIB_RX_JABBER] + 1316861cf54cSPyun YongHyeon mib[MIB_RX_MISS] + 1317861cf54cSPyun YongHyeon mib[MIB_RX_CRCA] + 1318861cf54cSPyun YongHyeon mib[MIB_RX_USIZE] + 1319861cf54cSPyun YongHyeon mib[MIB_RX_CRC] + 1320861cf54cSPyun YongHyeon mib[MIB_RX_ALIGN] + 132110b77d66SGleb Smirnoff mib[MIB_RX_SYM]); 1322b9f78d2bSBill Paul } 1323b9f78d2bSBill Paul 1324b9f78d2bSBill Paul static void 1325b9f78d2bSBill Paul bfe_txeof(struct bfe_softc *sc) 1326b9f78d2bSBill Paul { 132796ee09c5SPyun YongHyeon struct bfe_tx_data *r; 1328c0e5e270SJustin Hibbits if_t ifp; 1329b9f78d2bSBill Paul int i, chipidx; 1330b9f78d2bSBill Paul 1331f16b4811SMike Makonnen BFE_LOCK_ASSERT(sc); 1332b9f78d2bSBill Paul 1333fc74a9f9SBrooks Davis ifp = sc->bfe_ifp; 1334b9f78d2bSBill Paul 1335b9f78d2bSBill Paul chipidx = CSR_READ_4(sc, BFE_DMATX_STAT) & BFE_STAT_CDMASK; 1336b9f78d2bSBill Paul chipidx /= sizeof(struct bfe_desc); 1337b9f78d2bSBill Paul 1338b9f78d2bSBill Paul i = sc->bfe_tx_cons; 133996ee09c5SPyun YongHyeon if (i == chipidx) 134096ee09c5SPyun YongHyeon return; 134196ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 134296ee09c5SPyun YongHyeon BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1343b9f78d2bSBill Paul /* Go through the mbufs and free those that have been transmitted */ 134496ee09c5SPyun YongHyeon for (; i != chipidx; BFE_INC(i, BFE_TX_LIST_CNT)) { 134596ee09c5SPyun YongHyeon r = &sc->bfe_tx_ring[i]; 134696ee09c5SPyun YongHyeon sc->bfe_tx_cnt--; 134796ee09c5SPyun YongHyeon if (r->bfe_mbuf == NULL) 134896ee09c5SPyun YongHyeon continue; 134996ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_txmbuf_tag, r->bfe_map, 135096ee09c5SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 135196ee09c5SPyun YongHyeon bus_dmamap_unload(sc->bfe_txmbuf_tag, r->bfe_map); 135296ee09c5SPyun YongHyeon 1353b9f78d2bSBill Paul m_freem(r->bfe_mbuf); 1354b9f78d2bSBill Paul r->bfe_mbuf = NULL; 1355b9f78d2bSBill Paul } 1356b9f78d2bSBill Paul 1357b9f78d2bSBill Paul if (i != sc->bfe_tx_cons) { 1358b9f78d2bSBill Paul /* we freed up some mbufs */ 1359b9f78d2bSBill Paul sc->bfe_tx_cons = i; 1360c0e5e270SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 1361b9f78d2bSBill Paul } 13626ceb40baSPyun YongHyeon 1363b9f78d2bSBill Paul if (sc->bfe_tx_cnt == 0) 13646ceb40baSPyun YongHyeon sc->bfe_watchdog_timer = 0; 1365b9f78d2bSBill Paul } 1366b9f78d2bSBill Paul 1367b9f78d2bSBill Paul /* Pass a received packet up the stack */ 1368b9f78d2bSBill Paul static void 1369b9f78d2bSBill Paul bfe_rxeof(struct bfe_softc *sc) 1370b9f78d2bSBill Paul { 1371b9f78d2bSBill Paul struct mbuf *m; 1372c0e5e270SJustin Hibbits if_t ifp; 1373b9f78d2bSBill Paul struct bfe_rxheader *rxheader; 137496ee09c5SPyun YongHyeon struct bfe_rx_data *r; 137596ee09c5SPyun YongHyeon int cons, prog; 1376b9f78d2bSBill Paul u_int32_t status, current, len, flags; 1377b9f78d2bSBill Paul 1378f16b4811SMike Makonnen BFE_LOCK_ASSERT(sc); 1379b9f78d2bSBill Paul cons = sc->bfe_rx_cons; 1380b9f78d2bSBill Paul status = CSR_READ_4(sc, BFE_DMARX_STAT); 1381b9f78d2bSBill Paul current = (status & BFE_STAT_CDMASK) / sizeof(struct bfe_desc); 1382b9f78d2bSBill Paul 1383fc74a9f9SBrooks Davis ifp = sc->bfe_ifp; 1384b9f78d2bSBill Paul 138596ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 138696ee09c5SPyun YongHyeon BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 138796ee09c5SPyun YongHyeon 138896ee09c5SPyun YongHyeon for (prog = 0; current != cons; prog++, 138996ee09c5SPyun YongHyeon BFE_INC(cons, BFE_RX_LIST_CNT)) { 1390b9f78d2bSBill Paul r = &sc->bfe_rx_ring[cons]; 1391b9f78d2bSBill Paul m = r->bfe_mbuf; 139296ee09c5SPyun YongHyeon /* 139396ee09c5SPyun YongHyeon * Rx status should be read from mbuf such that we can't 139496ee09c5SPyun YongHyeon * delay bus_dmamap_sync(9). This hardware limiation 1395f697fe65SGordon Bergling * results in inefficient mbuf usage as bfe(4) couldn't 139696ee09c5SPyun YongHyeon * reuse mapped buffer from errored frame. 139796ee09c5SPyun YongHyeon */ 139896ee09c5SPyun YongHyeon if (bfe_list_newbuf(sc, cons) != 0) { 139910b77d66SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 140096ee09c5SPyun YongHyeon bfe_discard_buf(sc, cons); 140196ee09c5SPyun YongHyeon continue; 140296ee09c5SPyun YongHyeon } 1403b9f78d2bSBill Paul rxheader = mtod(m, struct bfe_rxheader*); 140496ee09c5SPyun YongHyeon len = le16toh(rxheader->len); 140596ee09c5SPyun YongHyeon flags = le16toh(rxheader->flags); 1406b9f78d2bSBill Paul 140796ee09c5SPyun YongHyeon /* Remove CRC bytes. */ 1408b9f78d2bSBill Paul len -= ETHER_CRC_LEN; 1409b9f78d2bSBill Paul 1410b9f78d2bSBill Paul /* flag an error and try again */ 1411b9f78d2bSBill Paul if ((len > ETHER_MAX_LEN+32) || (flags & BFE_RX_FLAG_ERRORS)) { 141296ee09c5SPyun YongHyeon m_freem(m); 1413b9f78d2bSBill Paul continue; 1414b9f78d2bSBill Paul } 1415b9f78d2bSBill Paul 141696ee09c5SPyun YongHyeon /* Make sure to skip header bytes written by hardware. */ 1417b9f78d2bSBill Paul m_adj(m, BFE_RX_OFFSET); 1418b9f78d2bSBill Paul m->m_len = m->m_pkthdr.len = len; 1419b9f78d2bSBill Paul 1420b9f78d2bSBill Paul m->m_pkthdr.rcvif = ifp; 14215120abbfSSam Leffler BFE_UNLOCK(sc); 1422c0e5e270SJustin Hibbits if_input(ifp, m); 14235120abbfSSam Leffler BFE_LOCK(sc); 1424b9f78d2bSBill Paul } 142596ee09c5SPyun YongHyeon 142696ee09c5SPyun YongHyeon if (prog > 0) { 1427b9f78d2bSBill Paul sc->bfe_rx_cons = cons; 142896ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, 142996ee09c5SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 143096ee09c5SPyun YongHyeon } 1431b9f78d2bSBill Paul } 1432b9f78d2bSBill Paul 1433b9f78d2bSBill Paul static void 1434b9f78d2bSBill Paul bfe_intr(void *xsc) 1435b9f78d2bSBill Paul { 1436b9f78d2bSBill Paul struct bfe_softc *sc = xsc; 1437c0e5e270SJustin Hibbits if_t ifp; 1438861cf54cSPyun YongHyeon u_int32_t istat; 1439b9f78d2bSBill Paul 1440fc74a9f9SBrooks Davis ifp = sc->bfe_ifp; 1441b9f78d2bSBill Paul 1442b9f78d2bSBill Paul BFE_LOCK(sc); 1443b9f78d2bSBill Paul 1444b9f78d2bSBill Paul istat = CSR_READ_4(sc, BFE_ISTAT); 1445b9f78d2bSBill Paul 1446b9f78d2bSBill Paul /* 1447b9f78d2bSBill Paul * Defer unsolicited interrupts - This is necessary because setting the 1448b9f78d2bSBill Paul * chips interrupt mask register to 0 doesn't actually stop the 1449b9f78d2bSBill Paul * interrupts 1450b9f78d2bSBill Paul */ 14512be30c0dSPyun YongHyeon istat &= BFE_IMASK_DEF; 1452b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_ISTAT, istat); 1453b9f78d2bSBill Paul CSR_READ_4(sc, BFE_ISTAT); 1454b9f78d2bSBill Paul 1455b9f78d2bSBill Paul /* not expecting this interrupt, disregard it */ 1456c0e5e270SJustin Hibbits if (istat == 0 || (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { 1457b9f78d2bSBill Paul BFE_UNLOCK(sc); 1458b9f78d2bSBill Paul return; 1459b9f78d2bSBill Paul } 1460b9f78d2bSBill Paul 1461861cf54cSPyun YongHyeon /* A packet was received */ 1462861cf54cSPyun YongHyeon if (istat & BFE_ISTAT_RX) 1463861cf54cSPyun YongHyeon bfe_rxeof(sc); 1464861cf54cSPyun YongHyeon 1465861cf54cSPyun YongHyeon /* A packet was sent */ 1466861cf54cSPyun YongHyeon if (istat & BFE_ISTAT_TX) 1467861cf54cSPyun YongHyeon bfe_txeof(sc); 1468861cf54cSPyun YongHyeon 1469b9f78d2bSBill Paul if (istat & BFE_ISTAT_ERRORS) { 1470678d2a9aSMike Silbersack if (istat & BFE_ISTAT_DSCE) { 1471be280562SPyun YongHyeon device_printf(sc->bfe_dev, "Descriptor Error\n"); 1472678d2a9aSMike Silbersack bfe_stop(sc); 1473678d2a9aSMike Silbersack BFE_UNLOCK(sc); 1474678d2a9aSMike Silbersack return; 1475678d2a9aSMike Silbersack } 1476678d2a9aSMike Silbersack 1477678d2a9aSMike Silbersack if (istat & BFE_ISTAT_DPE) { 1478be280562SPyun YongHyeon device_printf(sc->bfe_dev, 1479be280562SPyun YongHyeon "Descriptor Protocol Error\n"); 1480678d2a9aSMike Silbersack bfe_stop(sc); 1481678d2a9aSMike Silbersack BFE_UNLOCK(sc); 1482678d2a9aSMike Silbersack return; 1483678d2a9aSMike Silbersack } 1484c0e5e270SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1485f16b4811SMike Makonnen bfe_init_locked(sc); 1486b9f78d2bSBill Paul } 1487b9f78d2bSBill Paul 1488b9f78d2bSBill Paul /* We have packets pending, fire them out */ 1489c0e5e270SJustin Hibbits if (!if_sendq_empty(ifp)) 1490f16b4811SMike Makonnen bfe_start_locked(ifp); 1491b9f78d2bSBill Paul 1492b9f78d2bSBill Paul BFE_UNLOCK(sc); 1493b9f78d2bSBill Paul } 1494b9f78d2bSBill Paul 1495b9f78d2bSBill Paul static int 149696ee09c5SPyun YongHyeon bfe_encap(struct bfe_softc *sc, struct mbuf **m_head) 1497b9f78d2bSBill Paul { 149896ee09c5SPyun YongHyeon struct bfe_desc *d; 149996ee09c5SPyun YongHyeon struct bfe_tx_data *r, *r1; 1500b9f78d2bSBill Paul struct mbuf *m; 150196ee09c5SPyun YongHyeon bus_dmamap_t map; 150296ee09c5SPyun YongHyeon bus_dma_segment_t txsegs[BFE_MAXTXSEGS]; 150396ee09c5SPyun YongHyeon uint32_t cur, si; 150496ee09c5SPyun YongHyeon int error, i, nsegs; 1505b9f78d2bSBill Paul 150696ee09c5SPyun YongHyeon BFE_LOCK_ASSERT(sc); 1507b9f78d2bSBill Paul 150896ee09c5SPyun YongHyeon M_ASSERTPKTHDR((*m_head)); 1509b9f78d2bSBill Paul 151096ee09c5SPyun YongHyeon si = cur = sc->bfe_tx_prod; 151196ee09c5SPyun YongHyeon r = &sc->bfe_tx_ring[cur]; 151296ee09c5SPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->bfe_txmbuf_tag, r->bfe_map, *m_head, 151396ee09c5SPyun YongHyeon txsegs, &nsegs, 0); 151496ee09c5SPyun YongHyeon if (error == EFBIG) { 1515c6499eccSGleb Smirnoff m = m_collapse(*m_head, M_NOWAIT, BFE_MAXTXSEGS); 151696ee09c5SPyun YongHyeon if (m == NULL) { 151796ee09c5SPyun YongHyeon m_freem(*m_head); 151896ee09c5SPyun YongHyeon *m_head = NULL; 151996ee09c5SPyun YongHyeon return (ENOMEM); 152096ee09c5SPyun YongHyeon } 15215511c4d6SMike Silbersack *m_head = m; 152296ee09c5SPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->bfe_txmbuf_tag, r->bfe_map, 152396ee09c5SPyun YongHyeon *m_head, txsegs, &nsegs, 0); 152496ee09c5SPyun YongHyeon if (error != 0) { 152596ee09c5SPyun YongHyeon m_freem(*m_head); 152696ee09c5SPyun YongHyeon *m_head = NULL; 152796ee09c5SPyun YongHyeon return (error); 152896ee09c5SPyun YongHyeon } 152996ee09c5SPyun YongHyeon } else if (error != 0) 153096ee09c5SPyun YongHyeon return (error); 153196ee09c5SPyun YongHyeon if (nsegs == 0) { 153296ee09c5SPyun YongHyeon m_freem(*m_head); 153396ee09c5SPyun YongHyeon *m_head = NULL; 153496ee09c5SPyun YongHyeon return (EIO); 1535b9f78d2bSBill Paul } 1536b9f78d2bSBill Paul 153796ee09c5SPyun YongHyeon if (sc->bfe_tx_cnt + nsegs > BFE_TX_LIST_CNT - 1) { 153896ee09c5SPyun YongHyeon bus_dmamap_unload(sc->bfe_txmbuf_tag, r->bfe_map); 1539b9f78d2bSBill Paul return (ENOBUFS); 154096ee09c5SPyun YongHyeon } 1541b9f78d2bSBill Paul 154296ee09c5SPyun YongHyeon for (i = 0; i < nsegs; i++) { 1543b9f78d2bSBill Paul d = &sc->bfe_tx_list[cur]; 154496ee09c5SPyun YongHyeon d->bfe_ctrl = htole32(txsegs[i].ds_len & BFE_DESC_LEN); 154596ee09c5SPyun YongHyeon d->bfe_ctrl |= htole32(BFE_DESC_IOC); 1546b9f78d2bSBill Paul if (cur == BFE_TX_LIST_CNT - 1) 1547f2b1c158SJulian Elischer /* 1548f2b1c158SJulian Elischer * Tell the chip to wrap to the start of 154996ee09c5SPyun YongHyeon * the descriptor list. 1550f2b1c158SJulian Elischer */ 155196ee09c5SPyun YongHyeon d->bfe_ctrl |= htole32(BFE_DESC_EOT); 155296ee09c5SPyun YongHyeon /* The chip needs all addresses to be added to BFE_PCI_DMA. */ 155396ee09c5SPyun YongHyeon d->bfe_addr = htole32(BFE_ADDR_LO(txsegs[i].ds_addr) + 155496ee09c5SPyun YongHyeon BFE_PCI_DMA); 1555b9f78d2bSBill Paul BFE_INC(cur, BFE_TX_LIST_CNT); 1556b9f78d2bSBill Paul } 1557b9f78d2bSBill Paul 155896ee09c5SPyun YongHyeon /* Update producer index. */ 155996ee09c5SPyun YongHyeon sc->bfe_tx_prod = cur; 1560b9f78d2bSBill Paul 156196ee09c5SPyun YongHyeon /* Set EOF on the last descriptor. */ 156296ee09c5SPyun YongHyeon cur = (cur + BFE_TX_LIST_CNT - 1) % BFE_TX_LIST_CNT; 156396ee09c5SPyun YongHyeon d = &sc->bfe_tx_list[cur]; 156496ee09c5SPyun YongHyeon d->bfe_ctrl |= htole32(BFE_DESC_EOF); 1565b9f78d2bSBill Paul 156696ee09c5SPyun YongHyeon /* Lastly set SOF on the first descriptor to avoid races. */ 156796ee09c5SPyun YongHyeon d = &sc->bfe_tx_list[si]; 156896ee09c5SPyun YongHyeon d->bfe_ctrl |= htole32(BFE_DESC_SOF); 156996ee09c5SPyun YongHyeon 157096ee09c5SPyun YongHyeon r1 = &sc->bfe_tx_ring[cur]; 157196ee09c5SPyun YongHyeon map = r->bfe_map; 157296ee09c5SPyun YongHyeon r->bfe_map = r1->bfe_map; 157396ee09c5SPyun YongHyeon r1->bfe_map = map; 157496ee09c5SPyun YongHyeon r1->bfe_mbuf = *m_head; 157596ee09c5SPyun YongHyeon sc->bfe_tx_cnt += nsegs; 157696ee09c5SPyun YongHyeon 157796ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_txmbuf_tag, map, BUS_DMASYNC_PREWRITE); 157896ee09c5SPyun YongHyeon 1579b9f78d2bSBill Paul return (0); 1580b9f78d2bSBill Paul } 1581b9f78d2bSBill Paul 1582b9f78d2bSBill Paul /* 1583f16b4811SMike Makonnen * Set up to transmit a packet. 1584b9f78d2bSBill Paul */ 1585b9f78d2bSBill Paul static void 1586c0e5e270SJustin Hibbits bfe_start(if_t ifp) 1587b9f78d2bSBill Paul { 1588c0e5e270SJustin Hibbits BFE_LOCK((struct bfe_softc *)if_getsoftc(ifp)); 1589f16b4811SMike Makonnen bfe_start_locked(ifp); 1590c0e5e270SJustin Hibbits BFE_UNLOCK((struct bfe_softc *)if_getsoftc(ifp)); 1591f16b4811SMike Makonnen } 1592f16b4811SMike Makonnen 1593f16b4811SMike Makonnen /* 1594f16b4811SMike Makonnen * Set up to transmit a packet. The softc is already locked. 1595f16b4811SMike Makonnen */ 1596f16b4811SMike Makonnen static void 1597c0e5e270SJustin Hibbits bfe_start_locked(if_t ifp) 1598f16b4811SMike Makonnen { 1599b9f78d2bSBill Paul struct bfe_softc *sc; 160096ee09c5SPyun YongHyeon struct mbuf *m_head; 160196ee09c5SPyun YongHyeon int queued; 1602b9f78d2bSBill Paul 1603c0e5e270SJustin Hibbits sc = if_getsoftc(ifp); 1604b9f78d2bSBill Paul 1605f16b4811SMike Makonnen BFE_LOCK_ASSERT(sc); 1606b9f78d2bSBill Paul 1607b9f78d2bSBill Paul /* 1608f2b1c158SJulian Elischer * Not much point trying to send if the link is down 1609f2b1c158SJulian Elischer * or we have nothing to send. 1610b9f78d2bSBill Paul */ 1611c0e5e270SJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 161249bbfbc5SPyun YongHyeon IFF_DRV_RUNNING || (sc->bfe_flags & BFE_FLAG_LINK) == 0) 1613b9f78d2bSBill Paul return; 1614b9f78d2bSBill Paul 1615c0e5e270SJustin Hibbits for (queued = 0; !if_sendq_empty(ifp) && 161696ee09c5SPyun YongHyeon sc->bfe_tx_cnt < BFE_TX_LIST_CNT - 1;) { 1617c0e5e270SJustin Hibbits m_head = if_dequeue(ifp); 1618b9f78d2bSBill Paul if (m_head == NULL) 1619b9f78d2bSBill Paul break; 1620b9f78d2bSBill Paul 1621b9f78d2bSBill Paul /* 1622f2b1c158SJulian Elischer * Pack the data into the tx ring. If we dont have 1623f2b1c158SJulian Elischer * enough room, let the chip drain the ring. 1624b9f78d2bSBill Paul */ 162596ee09c5SPyun YongHyeon if (bfe_encap(sc, &m_head)) { 162696ee09c5SPyun YongHyeon if (m_head == NULL) 162796ee09c5SPyun YongHyeon break; 1628c0e5e270SJustin Hibbits if_sendq_prepend(ifp, m_head); 1629c0e5e270SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 1630b9f78d2bSBill Paul break; 1631b9f78d2bSBill Paul } 1632b9f78d2bSBill Paul 163322d0ab2eSMax Laier queued++; 163422d0ab2eSMax Laier 1635b9f78d2bSBill Paul /* 1636b9f78d2bSBill Paul * If there's a BPF listener, bounce a copy of this frame 1637b9f78d2bSBill Paul * to him. 1638b9f78d2bSBill Paul */ 1639b9f78d2bSBill Paul BPF_MTAP(ifp, m_head); 1640b9f78d2bSBill Paul } 1641b9f78d2bSBill Paul 164222d0ab2eSMax Laier if (queued) { 164396ee09c5SPyun YongHyeon bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, 164496ee09c5SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1645b9f78d2bSBill Paul /* Transmit - twice due to apparent hardware bug */ 164696ee09c5SPyun YongHyeon CSR_WRITE_4(sc, BFE_DMATX_PTR, 164796ee09c5SPyun YongHyeon sc->bfe_tx_prod * sizeof(struct bfe_desc)); 164896ee09c5SPyun YongHyeon /* 164996ee09c5SPyun YongHyeon * XXX It seems the following write is not necessary 165096ee09c5SPyun YongHyeon * to kick Tx command. What might be required would be 165196ee09c5SPyun YongHyeon * a way flushing PCI posted write. Reading the register 165296ee09c5SPyun YongHyeon * back ensures the flush operation. In addition, 165396ee09c5SPyun YongHyeon * hardware will execute PCI posted write in the long 165496ee09c5SPyun YongHyeon * run and watchdog timer for the kick command was set 165596ee09c5SPyun YongHyeon * to 5 seconds. Therefore I think the second write 165696ee09c5SPyun YongHyeon * access is not necessary or could be replaced with 165796ee09c5SPyun YongHyeon * read operation. 165896ee09c5SPyun YongHyeon */ 165996ee09c5SPyun YongHyeon CSR_WRITE_4(sc, BFE_DMATX_PTR, 166096ee09c5SPyun YongHyeon sc->bfe_tx_prod * sizeof(struct bfe_desc)); 1661b9f78d2bSBill Paul 1662b9f78d2bSBill Paul /* 1663b9f78d2bSBill Paul * Set a timeout in case the chip goes out to lunch. 1664b9f78d2bSBill Paul */ 16656ceb40baSPyun YongHyeon sc->bfe_watchdog_timer = 5; 166622d0ab2eSMax Laier } 1667b9f78d2bSBill Paul } 1668b9f78d2bSBill Paul 1669b9f78d2bSBill Paul static void 1670b9f78d2bSBill Paul bfe_init(void *xsc) 1671b9f78d2bSBill Paul { 1672f16b4811SMike Makonnen BFE_LOCK((struct bfe_softc *)xsc); 1673f16b4811SMike Makonnen bfe_init_locked(xsc); 1674f16b4811SMike Makonnen BFE_UNLOCK((struct bfe_softc *)xsc); 1675f16b4811SMike Makonnen } 1676f16b4811SMike Makonnen 1677f16b4811SMike Makonnen static void 1678f16b4811SMike Makonnen bfe_init_locked(void *xsc) 1679f16b4811SMike Makonnen { 1680b9f78d2bSBill Paul struct bfe_softc *sc = (struct bfe_softc*)xsc; 1681c0e5e270SJustin Hibbits if_t ifp = sc->bfe_ifp; 16826ceb40baSPyun YongHyeon struct mii_data *mii; 1683b9f78d2bSBill Paul 1684f16b4811SMike Makonnen BFE_LOCK_ASSERT(sc); 1685b9f78d2bSBill Paul 16866ceb40baSPyun YongHyeon mii = device_get_softc(sc->bfe_miibus); 16876ceb40baSPyun YongHyeon 1688c0e5e270SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 1689b9f78d2bSBill Paul return; 1690b9f78d2bSBill Paul 1691b9f78d2bSBill Paul bfe_stop(sc); 1692b9f78d2bSBill Paul bfe_chip_reset(sc); 1693b9f78d2bSBill Paul 1694b9f78d2bSBill Paul if (bfe_list_rx_init(sc) == ENOBUFS) { 1695be280562SPyun YongHyeon device_printf(sc->bfe_dev, 1696be280562SPyun YongHyeon "%s: Not enough memory for list buffers\n", __func__); 1697b9f78d2bSBill Paul bfe_stop(sc); 1698b9f78d2bSBill Paul return; 1699b9f78d2bSBill Paul } 170096ee09c5SPyun YongHyeon bfe_list_tx_init(sc); 1701b9f78d2bSBill Paul 1702b9f78d2bSBill Paul bfe_set_rx_mode(sc); 1703b9f78d2bSBill Paul 1704b9f78d2bSBill Paul /* Enable the chip and core */ 1705b9f78d2bSBill Paul BFE_OR(sc, BFE_ENET_CTRL, BFE_ENET_ENABLE); 1706b9f78d2bSBill Paul /* Enable interrupts */ 1707b9f78d2bSBill Paul CSR_WRITE_4(sc, BFE_IMASK, BFE_IMASK_DEF); 1708b9f78d2bSBill Paul 17096ceb40baSPyun YongHyeon /* Clear link state and change media. */ 171049bbfbc5SPyun YongHyeon sc->bfe_flags &= ~BFE_FLAG_LINK; 17116ceb40baSPyun YongHyeon mii_mediachg(mii); 17126ceb40baSPyun YongHyeon 1713c0e5e270SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 1714c0e5e270SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 1715b9f78d2bSBill Paul 17166ceb40baSPyun YongHyeon callout_reset(&sc->bfe_stat_co, hz, bfe_tick, sc); 1717b9f78d2bSBill Paul } 1718b9f78d2bSBill Paul 1719b9f78d2bSBill Paul /* 1720b9f78d2bSBill Paul * Set media options. 1721b9f78d2bSBill Paul */ 1722b9f78d2bSBill Paul static int 1723c0e5e270SJustin Hibbits bfe_ifmedia_upd(if_t ifp) 1724b9f78d2bSBill Paul { 1725b9f78d2bSBill Paul struct bfe_softc *sc; 1726b9f78d2bSBill Paul struct mii_data *mii; 17273fcb7a53SMarius Strobl struct mii_softc *miisc; 17286ceb40baSPyun YongHyeon int error; 1729b9f78d2bSBill Paul 1730c0e5e270SJustin Hibbits sc = if_getsoftc(ifp); 17316ceb40baSPyun YongHyeon BFE_LOCK(sc); 1732b9f78d2bSBill Paul 1733b9f78d2bSBill Paul mii = device_get_softc(sc->bfe_miibus); 17343fcb7a53SMarius Strobl LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 17353fcb7a53SMarius Strobl PHY_RESET(miisc); 17366ceb40baSPyun YongHyeon error = mii_mediachg(mii); 17376ceb40baSPyun YongHyeon BFE_UNLOCK(sc); 1738b9f78d2bSBill Paul 17396ceb40baSPyun YongHyeon return (error); 1740b9f78d2bSBill Paul } 1741b9f78d2bSBill Paul 1742b9f78d2bSBill Paul /* 1743b9f78d2bSBill Paul * Report current media status. 1744b9f78d2bSBill Paul */ 1745b9f78d2bSBill Paul static void 1746c0e5e270SJustin Hibbits bfe_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 1747b9f78d2bSBill Paul { 1748c0e5e270SJustin Hibbits struct bfe_softc *sc = if_getsoftc(ifp); 1749b9f78d2bSBill Paul struct mii_data *mii; 1750b9f78d2bSBill Paul 17516ceb40baSPyun YongHyeon BFE_LOCK(sc); 1752b9f78d2bSBill Paul mii = device_get_softc(sc->bfe_miibus); 1753b9f78d2bSBill Paul mii_pollstat(mii); 1754b9f78d2bSBill Paul ifmr->ifm_active = mii->mii_media_active; 1755b9f78d2bSBill Paul ifmr->ifm_status = mii->mii_media_status; 17566ceb40baSPyun YongHyeon BFE_UNLOCK(sc); 1757b9f78d2bSBill Paul } 1758b9f78d2bSBill Paul 1759b9f78d2bSBill Paul static int 1760c0e5e270SJustin Hibbits bfe_ioctl(if_t ifp, u_long command, caddr_t data) 1761b9f78d2bSBill Paul { 1762c0e5e270SJustin Hibbits struct bfe_softc *sc = if_getsoftc(ifp); 1763b9f78d2bSBill Paul struct ifreq *ifr = (struct ifreq *) data; 1764b9f78d2bSBill Paul struct mii_data *mii; 1765b9f78d2bSBill Paul int error = 0; 1766b9f78d2bSBill Paul 1767b9f78d2bSBill Paul switch (command) { 1768b9f78d2bSBill Paul case SIOCSIFFLAGS: 1769f16b4811SMike Makonnen BFE_LOCK(sc); 1770c0e5e270SJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 1771c0e5e270SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 1772b9f78d2bSBill Paul bfe_set_rx_mode(sc); 177349bbfbc5SPyun YongHyeon else if ((sc->bfe_flags & BFE_FLAG_DETACH) == 0) 1774f16b4811SMike Makonnen bfe_init_locked(sc); 1775c0e5e270SJustin Hibbits } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 1776b9f78d2bSBill Paul bfe_stop(sc); 1777f16b4811SMike Makonnen BFE_UNLOCK(sc); 1778b9f78d2bSBill Paul break; 1779b9f78d2bSBill Paul case SIOCADDMULTI: 1780b9f78d2bSBill Paul case SIOCDELMULTI: 1781f16b4811SMike Makonnen BFE_LOCK(sc); 1782c0e5e270SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 1783b9f78d2bSBill Paul bfe_set_rx_mode(sc); 1784f16b4811SMike Makonnen BFE_UNLOCK(sc); 1785b9f78d2bSBill Paul break; 1786b9f78d2bSBill Paul case SIOCGIFMEDIA: 1787b9f78d2bSBill Paul case SIOCSIFMEDIA: 1788b9f78d2bSBill Paul mii = device_get_softc(sc->bfe_miibus); 1789cde25118SPyun YongHyeon error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1790b9f78d2bSBill Paul break; 1791b9f78d2bSBill Paul default: 1792b9f78d2bSBill Paul error = ether_ioctl(ifp, command, data); 1793b9f78d2bSBill Paul break; 1794b9f78d2bSBill Paul } 1795b9f78d2bSBill Paul 179627de24a7SDag-Erling Smørgrav return (error); 1797b9f78d2bSBill Paul } 1798b9f78d2bSBill Paul 1799b9f78d2bSBill Paul static void 18006ceb40baSPyun YongHyeon bfe_watchdog(struct bfe_softc *sc) 1801b9f78d2bSBill Paul { 1802c0e5e270SJustin Hibbits if_t ifp; 1803b9f78d2bSBill Paul 18046ceb40baSPyun YongHyeon BFE_LOCK_ASSERT(sc); 1805b9f78d2bSBill Paul 18066ceb40baSPyun YongHyeon if (sc->bfe_watchdog_timer == 0 || --sc->bfe_watchdog_timer) 18076ceb40baSPyun YongHyeon return; 18086ceb40baSPyun YongHyeon 18096ceb40baSPyun YongHyeon ifp = sc->bfe_ifp; 1810b9f78d2bSBill Paul 1811be280562SPyun YongHyeon device_printf(sc->bfe_dev, "watchdog timeout -- resetting\n"); 1812b9f78d2bSBill Paul 181310b77d66SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1814c0e5e270SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1815f16b4811SMike Makonnen bfe_init_locked(sc); 1816b9f78d2bSBill Paul 1817c0e5e270SJustin Hibbits if (!if_sendq_empty(ifp)) 18186ceb40baSPyun YongHyeon bfe_start_locked(ifp); 1819b9f78d2bSBill Paul } 1820b9f78d2bSBill Paul 1821b9f78d2bSBill Paul static void 1822b9f78d2bSBill Paul bfe_tick(void *xsc) 1823b9f78d2bSBill Paul { 1824b9f78d2bSBill Paul struct bfe_softc *sc = xsc; 1825b9f78d2bSBill Paul struct mii_data *mii; 1826b9f78d2bSBill Paul 18276ceb40baSPyun YongHyeon BFE_LOCK_ASSERT(sc); 1828b9f78d2bSBill Paul 1829b9f78d2bSBill Paul mii = device_get_softc(sc->bfe_miibus); 1830b9f78d2bSBill Paul mii_tick(mii); 18316ceb40baSPyun YongHyeon bfe_stats_update(sc); 18326ceb40baSPyun YongHyeon bfe_watchdog(sc); 18336ceb40baSPyun YongHyeon callout_reset(&sc->bfe_stat_co, hz, bfe_tick, sc); 1834b9f78d2bSBill Paul } 1835b9f78d2bSBill Paul 1836b9f78d2bSBill Paul /* 1837b9f78d2bSBill Paul * Stop the adapter and free any mbufs allocated to the 1838b9f78d2bSBill Paul * RX and TX lists. 1839b9f78d2bSBill Paul */ 1840b9f78d2bSBill Paul static void 1841b9f78d2bSBill Paul bfe_stop(struct bfe_softc *sc) 1842b9f78d2bSBill Paul { 1843c0e5e270SJustin Hibbits if_t ifp; 1844b9f78d2bSBill Paul 1845f16b4811SMike Makonnen BFE_LOCK_ASSERT(sc); 1846b9f78d2bSBill Paul 1847fc74a9f9SBrooks Davis ifp = sc->bfe_ifp; 1848c0e5e270SJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 184949bbfbc5SPyun YongHyeon sc->bfe_flags &= ~BFE_FLAG_LINK; 18506ceb40baSPyun YongHyeon callout_stop(&sc->bfe_stat_co); 18516ceb40baSPyun YongHyeon sc->bfe_watchdog_timer = 0; 1852b9f78d2bSBill Paul 1853b9f78d2bSBill Paul bfe_chip_halt(sc); 1854b9f78d2bSBill Paul bfe_tx_ring_free(sc); 1855b9f78d2bSBill Paul bfe_rx_ring_free(sc); 1856b9f78d2bSBill Paul } 1857861cf54cSPyun YongHyeon 1858861cf54cSPyun YongHyeon static int 1859861cf54cSPyun YongHyeon sysctl_bfe_stats(SYSCTL_HANDLER_ARGS) 1860861cf54cSPyun YongHyeon { 1861861cf54cSPyun YongHyeon struct bfe_softc *sc; 1862861cf54cSPyun YongHyeon struct bfe_hw_stats *stats; 1863861cf54cSPyun YongHyeon int error, result; 1864861cf54cSPyun YongHyeon 1865861cf54cSPyun YongHyeon result = -1; 1866861cf54cSPyun YongHyeon error = sysctl_handle_int(oidp, &result, 0, req); 1867861cf54cSPyun YongHyeon 1868861cf54cSPyun YongHyeon if (error != 0 || req->newptr == NULL) 1869861cf54cSPyun YongHyeon return (error); 1870861cf54cSPyun YongHyeon 1871861cf54cSPyun YongHyeon if (result != 1) 1872861cf54cSPyun YongHyeon return (error); 1873861cf54cSPyun YongHyeon 1874861cf54cSPyun YongHyeon sc = (struct bfe_softc *)arg1; 1875861cf54cSPyun YongHyeon stats = &sc->bfe_stats; 1876861cf54cSPyun YongHyeon 1877861cf54cSPyun YongHyeon printf("%s statistics:\n", device_get_nameunit(sc->bfe_dev)); 1878861cf54cSPyun YongHyeon printf("Transmit good octets : %ju\n", 1879861cf54cSPyun YongHyeon (uintmax_t)stats->tx_good_octets); 1880861cf54cSPyun YongHyeon printf("Transmit good frames : %ju\n", 1881861cf54cSPyun YongHyeon (uintmax_t)stats->tx_good_frames); 1882861cf54cSPyun YongHyeon printf("Transmit octets : %ju\n", 1883861cf54cSPyun YongHyeon (uintmax_t)stats->tx_octets); 1884861cf54cSPyun YongHyeon printf("Transmit frames : %ju\n", 1885861cf54cSPyun YongHyeon (uintmax_t)stats->tx_frames); 1886861cf54cSPyun YongHyeon printf("Transmit broadcast frames : %ju\n", 1887861cf54cSPyun YongHyeon (uintmax_t)stats->tx_bcast_frames); 1888861cf54cSPyun YongHyeon printf("Transmit multicast frames : %ju\n", 1889861cf54cSPyun YongHyeon (uintmax_t)stats->tx_mcast_frames); 1890861cf54cSPyun YongHyeon printf("Transmit frames 64 bytes : %ju\n", 1891861cf54cSPyun YongHyeon (uint64_t)stats->tx_pkts_64); 1892861cf54cSPyun YongHyeon printf("Transmit frames 65 to 127 bytes : %ju\n", 1893861cf54cSPyun YongHyeon (uint64_t)stats->tx_pkts_65_127); 1894861cf54cSPyun YongHyeon printf("Transmit frames 128 to 255 bytes : %ju\n", 1895861cf54cSPyun YongHyeon (uint64_t)stats->tx_pkts_128_255); 1896861cf54cSPyun YongHyeon printf("Transmit frames 256 to 511 bytes : %ju\n", 1897861cf54cSPyun YongHyeon (uint64_t)stats->tx_pkts_256_511); 1898861cf54cSPyun YongHyeon printf("Transmit frames 512 to 1023 bytes : %ju\n", 1899861cf54cSPyun YongHyeon (uint64_t)stats->tx_pkts_512_1023); 1900861cf54cSPyun YongHyeon printf("Transmit frames 1024 to max bytes : %ju\n", 1901861cf54cSPyun YongHyeon (uint64_t)stats->tx_pkts_1024_max); 1902861cf54cSPyun YongHyeon printf("Transmit jabber errors : %u\n", stats->tx_jabbers); 1903861cf54cSPyun YongHyeon printf("Transmit oversized frames : %ju\n", 1904861cf54cSPyun YongHyeon (uint64_t)stats->tx_oversize_frames); 1905861cf54cSPyun YongHyeon printf("Transmit fragmented frames : %ju\n", 1906861cf54cSPyun YongHyeon (uint64_t)stats->tx_frag_frames); 1907861cf54cSPyun YongHyeon printf("Transmit underruns : %u\n", stats->tx_colls); 1908861cf54cSPyun YongHyeon printf("Transmit total collisions : %u\n", stats->tx_single_colls); 1909861cf54cSPyun YongHyeon printf("Transmit single collisions : %u\n", stats->tx_single_colls); 1910861cf54cSPyun YongHyeon printf("Transmit multiple collisions : %u\n", stats->tx_multi_colls); 1911861cf54cSPyun YongHyeon printf("Transmit excess collisions : %u\n", stats->tx_excess_colls); 1912861cf54cSPyun YongHyeon printf("Transmit late collisions : %u\n", stats->tx_late_colls); 1913861cf54cSPyun YongHyeon printf("Transmit deferrals : %u\n", stats->tx_deferrals); 1914861cf54cSPyun YongHyeon printf("Transmit carrier losts : %u\n", stats->tx_carrier_losts); 1915861cf54cSPyun YongHyeon printf("Transmit pause frames : %u\n", stats->tx_pause_frames); 1916861cf54cSPyun YongHyeon 1917861cf54cSPyun YongHyeon printf("Receive good octets : %ju\n", 1918861cf54cSPyun YongHyeon (uintmax_t)stats->rx_good_octets); 1919861cf54cSPyun YongHyeon printf("Receive good frames : %ju\n", 1920861cf54cSPyun YongHyeon (uintmax_t)stats->rx_good_frames); 1921861cf54cSPyun YongHyeon printf("Receive octets : %ju\n", 1922861cf54cSPyun YongHyeon (uintmax_t)stats->rx_octets); 1923861cf54cSPyun YongHyeon printf("Receive frames : %ju\n", 1924861cf54cSPyun YongHyeon (uintmax_t)stats->rx_frames); 1925861cf54cSPyun YongHyeon printf("Receive broadcast frames : %ju\n", 1926861cf54cSPyun YongHyeon (uintmax_t)stats->rx_bcast_frames); 1927861cf54cSPyun YongHyeon printf("Receive multicast frames : %ju\n", 1928861cf54cSPyun YongHyeon (uintmax_t)stats->rx_mcast_frames); 1929861cf54cSPyun YongHyeon printf("Receive frames 64 bytes : %ju\n", 1930861cf54cSPyun YongHyeon (uint64_t)stats->rx_pkts_64); 1931861cf54cSPyun YongHyeon printf("Receive frames 65 to 127 bytes : %ju\n", 1932861cf54cSPyun YongHyeon (uint64_t)stats->rx_pkts_65_127); 1933861cf54cSPyun YongHyeon printf("Receive frames 128 to 255 bytes : %ju\n", 1934861cf54cSPyun YongHyeon (uint64_t)stats->rx_pkts_128_255); 1935861cf54cSPyun YongHyeon printf("Receive frames 256 to 511 bytes : %ju\n", 1936861cf54cSPyun YongHyeon (uint64_t)stats->rx_pkts_256_511); 1937861cf54cSPyun YongHyeon printf("Receive frames 512 to 1023 bytes : %ju\n", 1938861cf54cSPyun YongHyeon (uint64_t)stats->rx_pkts_512_1023); 1939861cf54cSPyun YongHyeon printf("Receive frames 1024 to max bytes : %ju\n", 1940861cf54cSPyun YongHyeon (uint64_t)stats->rx_pkts_1024_max); 1941861cf54cSPyun YongHyeon printf("Receive jabber errors : %u\n", stats->rx_jabbers); 1942861cf54cSPyun YongHyeon printf("Receive oversized frames : %ju\n", 1943861cf54cSPyun YongHyeon (uint64_t)stats->rx_oversize_frames); 1944861cf54cSPyun YongHyeon printf("Receive fragmented frames : %ju\n", 1945861cf54cSPyun YongHyeon (uint64_t)stats->rx_frag_frames); 1946861cf54cSPyun YongHyeon printf("Receive missed frames : %u\n", stats->rx_missed_frames); 1947861cf54cSPyun YongHyeon printf("Receive CRC align errors : %u\n", stats->rx_crc_align_errs); 1948861cf54cSPyun YongHyeon printf("Receive undersized frames : %u\n", stats->rx_runts); 1949861cf54cSPyun YongHyeon printf("Receive CRC errors : %u\n", stats->rx_crc_errs); 1950861cf54cSPyun YongHyeon printf("Receive align errors : %u\n", stats->rx_align_errs); 1951861cf54cSPyun YongHyeon printf("Receive symbol errors : %u\n", stats->rx_symbol_errs); 1952861cf54cSPyun YongHyeon printf("Receive pause frames : %u\n", stats->rx_pause_frames); 1953861cf54cSPyun YongHyeon printf("Receive control frames : %u\n", stats->rx_control_frames); 1954861cf54cSPyun YongHyeon 1955861cf54cSPyun YongHyeon return (error); 1956861cf54cSPyun YongHyeon } 1957