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
bfe_probe(device_t dev)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
bfe_dma_alloc(struct bfe_softc * sc)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
bfe_dma_free(struct bfe_softc * sc)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
bfe_attach(device_t dev)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
bfe_detach(device_t dev)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
bfe_shutdown(device_t dev)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
bfe_suspend(device_t dev)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
bfe_resume(device_t dev)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
bfe_miibus_readreg(device_t dev,int phy,int reg)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
bfe_miibus_writereg(device_t dev,int phy,int reg,int val)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
bfe_miibus_statchg(device_t dev)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
bfe_tx_ring_free(struct bfe_softc * sc)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
bfe_rx_ring_free(struct bfe_softc * sc)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
bfe_list_rx_init(struct bfe_softc * sc)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
bfe_list_tx_init(struct bfe_softc * sc)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
bfe_discard_buf(struct bfe_softc * sc,int c)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
bfe_list_newbuf(struct bfe_softc * sc,int c)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
bfe_get_config(struct bfe_softc * sc)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
bfe_pci_setup(struct bfe_softc * sc,u_int32_t cores)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
bfe_clear_stats(struct bfe_softc * sc)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
bfe_resetphy(struct bfe_softc * sc)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
bfe_chip_halt(struct bfe_softc * sc)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
bfe_chip_reset(struct bfe_softc * sc)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
bfe_core_disable(struct bfe_softc * sc)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
bfe_core_reset(struct bfe_softc * sc)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
bfe_cam_write(struct bfe_softc * sc,u_char * data,int index)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
bfe_write_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)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
bfe_set_rx_mode(struct bfe_softc * sc)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
bfe_dma_map(void * arg,bus_dma_segment_t * segs,int nseg,int error)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
bfe_release_resources(struct bfe_softc * sc)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
bfe_read_eeprom(struct bfe_softc * sc,u_int8_t * data)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
bfe_wait_bit(struct bfe_softc * sc,u_int32_t reg,u_int32_t bit,u_long timeout,const int clear)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
bfe_readphy(struct bfe_softc * sc,u_int32_t reg,u_int32_t * val)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
bfe_writephy(struct bfe_softc * sc,u_int32_t reg,u_int32_t val)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
bfe_setupphy(struct bfe_softc * sc)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
bfe_stats_update(struct bfe_softc * sc)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
bfe_txeof(struct bfe_softc * sc)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
bfe_rxeof(struct bfe_softc * sc)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
bfe_intr(void * xsc)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
bfe_encap(struct bfe_softc * sc,struct mbuf ** m_head)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
bfe_start(if_t ifp)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
bfe_start_locked(if_t ifp)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
bfe_init(void * xsc)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
bfe_init_locked(void * xsc)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
bfe_ifmedia_upd(if_t ifp)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
bfe_ifmedia_sts(if_t ifp,struct ifmediareq * ifmr)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
bfe_ioctl(if_t ifp,u_long command,caddr_t data)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
bfe_watchdog(struct bfe_softc * sc)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
bfe_tick(void * xsc)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
bfe_stop(struct bfe_softc * sc)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
sysctl_bfe_stats(SYSCTL_HANDLER_ARGS)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