summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2003-09-09 18:17:23 +0000
committerwpaul <wpaul@FreeBSD.org>2003-09-09 18:17:23 +0000
commitfc3a8934ee799891fce3717b06b9a7d3e5530c1e (patch)
treee411fd06681e58e4a398845eb6bba9231c7b4a12
parent16a69608057239baa70babc08a9145399430407c (diff)
downloadFreeBSD-src-fc3a8934ee799891fce3717b06b9a7d3e5530c1e.zip
FreeBSD-src-fc3a8934ee799891fce3717b06b9a7d3e5530c1e.tar.gz
Add a device driver for the Broadcom BCM4401 ethernet controller,
written by Stuart Walsh and Duncan Barclay (with some kibbitzing by me). I'm checking it in on Stuart's behalf. The BCM4401 is built into several x86 laptop and desktop systems. For the moment, I have only enabled it in the x86 kernel config because although it's a PCI device, I haven't heard of any standalone NICs that use it. If somebody knows of one, we can easily add it to the other arches. This driver uses register/structure data gleaned from the Linux driver released by Broadcom, but does not contain any of the code from the Linux driver itself. It uses busdma.
-rw-r--r--etc/devd.conf4
-rw-r--r--share/man/man4/Makefile1
-rw-r--r--share/man/man4/bfe.499
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/bfe/if_bfe.c1557
-rw-r--r--sys/dev/bfe/if_bfereg.h512
-rw-r--r--sys/dev/mii/bmtphy.c3
-rw-r--r--sys/dev/mii/miidevs1
-rw-r--r--sys/i386/conf/GENERIC1
-rw-r--r--sys/modules/Makefile1
-rw-r--r--sys/modules/bfe/Makefile8
-rw-r--r--usr.sbin/sade/devices.c1
-rw-r--r--usr.sbin/sysinstall/devices.c1
13 files changed, 2188 insertions, 2 deletions
diff --git a/etc/devd.conf b/etc/devd.conf
index 2cc0586..2999115 100644
--- a/etc/devd.conf
+++ b/etc/devd.conf
@@ -18,8 +18,8 @@ options {
# Setup some shorthand for regex that we use later in the file.
set ethernet-nic-regex
- "(an|ar|ath|aue|awi|bge|cm|cnw|cs|cue|dc|de|ed|el|em|ep|ex|\
- fe|fxp|gem|gx|hme|ie|kue|lge|lnc|my|nge|pcn|ray|re|rl|rue|\
+ "(an|ar|ath|aue|awi|bfe|bge|cm|cnw|cs|cue|dc|de|ed|el|em|ep|\
+ ex|fe|fxp|gem|gx|hme|ie|kue|lge|lnc|my|nge|pcn|ray|re|rl|rue|\
sf|sis|sk|sn|snc|ste|ti|tl|tx|txp|vr|vx|wb|wi|xe|xl)[0-9]+";
set scsi-controller-regex
"(adv|advw|aic|aha|ahb|ahc|ahd|bt|ct|iir|isp|mly|mpt|ncv|nsp|\
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index bf6ac4a6..4674b17 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -24,6 +24,7 @@ MAN= aac.4 \
aue.4 \
awi.4 \
axe.4 \
+ bfe.4 \
bge.4 \
bktr.4 \
blackhole.4 \
diff --git a/share/man/man4/bfe.4 b/share/man/man4/bfe.4
new file mode 100644
index 0000000..72d8f77
--- /dev/null
+++ b/share/man/man4/bfe.4
@@ -0,0 +1,99 @@
+.\"
+.\" Copyright (c) 2003 Stuart Walsh
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 4, 2003
+.Dt BFE 4
+.Os
+.Sh NAME
+.Nm bfe
+.Nd Broadcom BCM4401 Ethernet Device Driver
+.Sh SYNOPSIS
+.Cd "device miibus"
+.Cd "device bfe"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the Broadcom BCM4401 based Fast Ethernet adapters.
+.Pp
+The
+.Nm
+driver supports the following media types:
+.Pp
+.Bl -tag -width xxxxxxxxxxxxxxxxxxxx
+.It autoselect
+Enable autoselection of the media type and options
+.It 10baseT/UTP
+Set 10Mbps operation
+.It 100baseTX
+Set 100Mbps (fast ethernet) operation
+.El
+.Pp
+The
+.Nm
+driver supports the following media options:
+.Pp
+.Bl -tag -width xxxxxxxxxxxxxxxxxxxx
+.It full-duplex
+Set full duplex operation
+.El
+.Pp
+For further information on configuring this device, see
+.Xr ifconfig 8 .
+.Pp
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "bfe%d: couldn't map memory"
+A fatal initialization error has occurred.
+.It "bfe%d: couldn't map interrupt"
+A fatal initialization error has occurred.
+.It "bfe%d: failed to allocate DMA resources"
+There are not enough mbuf's available for allocation.
+.It "bfe%d: watchdog timeout -- resetting"
+The device has stopped responding to the network, or there is a problem with
+the network connection (cable).
+.El
+.Sh SEE ALSO
+.Xr arp 4 ,
+.Xr miibus 4 ,
+.Xr netintro 4 ,
+.Xr ng_ether 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 5.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+device driver was written by
+.An Stuart Walsh
+and
+.An Duncan Barclay .
+This manual page was written by
+.An Stuart Walsh .
diff --git a/sys/conf/files b/sys/conf/files
index adf18b0..3931160 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -325,6 +325,7 @@ dev/awi/awi_wep.c optional awi
dev/awi/awi_wicfg.c optional awi
dev/awi/if_awi_pccard.c optional awi card
dev/awi/if_awi_pccard.c optional awi pccard
+dev/bfe/if_bfe.c optional bfe
dev/bge/if_bge.c optional bge
dev/bktr/bktr_audio.c optional bktr pci
dev/bktr/bktr_card.c optional bktr pci
diff --git a/sys/dev/bfe/if_bfe.c b/sys/dev/bfe/if_bfe.c
new file mode 100644
index 0000000..7160626
--- /dev/null
+++ b/sys/dev/bfe/if_bfe.c
@@ -0,0 +1,1557 @@
+/*
+ * Copyright (c) 2003 Stuart Walsh<stu@ipng.org.uk>
+ * and Duncan Barclay<dmlb@dmlb.org>
+ */
+
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <machine/clock.h> /* for DELAY */
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include "miidevs.h"
+#include <dev/mii/brgphyreg.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/bfe/if_bfereg.h>
+
+MODULE_DEPEND(bfe, pci, 1, 1, 1);
+MODULE_DEPEND(bfe, ether, 1, 1, 1);
+MODULE_DEPEND(bfe, miibus, 1, 1, 1);
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#define BFE_DEVDESC_MAX 64 /* Maximum device description length */
+
+static struct bfe_type bfe_devs[] = {
+ { BCOM_VENDORID, BCOM_DEVICEID_BCM4401,
+ "Broadcom BCM4401 Fast Ethernet" },
+ { 0, 0, NULL }
+};
+
+static int bfe_probe (device_t);
+static int bfe_attach (device_t);
+static int bfe_detach (device_t);
+static void bfe_release_resources (struct bfe_softc *);
+static void bfe_intr (void *);
+static void bfe_start (struct ifnet *);
+static int bfe_ioctl (struct ifnet *, u_long, caddr_t);
+static void bfe_init (void *);
+static void bfe_stop (struct bfe_softc *);
+static void bfe_watchdog (struct ifnet *);
+static void bfe_shutdown (device_t);
+static void bfe_tick (void *);
+static void bfe_txeof (struct bfe_softc *);
+static void bfe_rxeof (struct bfe_softc *);
+static void bfe_set_rx_mode (struct bfe_softc *);
+static int bfe_list_rx_init (struct bfe_softc *);
+static int bfe_list_newbuf (struct bfe_softc *, int, struct mbuf*);
+static void bfe_rx_ring_free (struct bfe_softc *);
+
+static void bfe_pci_setup (struct bfe_softc *, u_int32_t);
+static int bfe_ifmedia_upd (struct ifnet *);
+static void bfe_ifmedia_sts (struct ifnet *, struct ifmediareq *);
+static int bfe_miibus_readreg (device_t, int, int);
+static int bfe_miibus_writereg (device_t, int, int, int);
+static void bfe_miibus_statchg (device_t);
+static int bfe_wait_bit (struct bfe_softc *, u_int32_t, u_int32_t,
+ u_long, const int);
+static void bfe_get_config (struct bfe_softc *sc);
+static void bfe_read_eeprom (struct bfe_softc *, u_int8_t *);
+static void bfe_stats_update (struct bfe_softc *);
+static void bfe_clear_stats (struct bfe_softc *);
+static int bfe_readphy (struct bfe_softc *, u_int32_t, u_int32_t*);
+static int bfe_writephy (struct bfe_softc *, u_int32_t, u_int32_t);
+static int bfe_resetphy (struct bfe_softc *);
+static int bfe_setupphy (struct bfe_softc *);
+static void bfe_chip_reset (struct bfe_softc *);
+static void bfe_chip_halt (struct bfe_softc *);
+static void bfe_core_reset (struct bfe_softc *);
+static void bfe_core_disable (struct bfe_softc *);
+static int bfe_dma_alloc (device_t);
+static void bfe_dma_map_desc (void *, bus_dma_segment_t *, int, int);
+static void bfe_dma_map (void *, bus_dma_segment_t *, int, int);
+static void bfe_cam_write (struct bfe_softc *, u_char *, int);
+
+static device_method_t bfe_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bfe_probe),
+ DEVMETHOD(device_attach, bfe_attach),
+ DEVMETHOD(device_detach, bfe_detach),
+ DEVMETHOD(device_shutdown, bfe_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, bfe_miibus_readreg),
+ DEVMETHOD(miibus_writereg, bfe_miibus_writereg),
+ DEVMETHOD(miibus_statchg, bfe_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t bfe_driver = {
+ "bfe",
+ bfe_methods,
+ sizeof(struct bfe_softc)
+};
+
+static devclass_t bfe_devclass;
+
+DRIVER_MODULE(bfe, pci, bfe_driver, bfe_devclass, 0, 0);
+DRIVER_MODULE(miibus, bfe, miibus_driver, miibus_devclass, 0, 0);
+
+/*
+ * Probe for a Broadcom 4401 chip.
+ */
+static int
+bfe_probe(device_t dev)
+{
+ struct bfe_type *t;
+ struct bfe_softc *sc;
+
+ t = bfe_devs;
+
+ sc = device_get_softc(dev);
+ bzero(sc, sizeof(struct bfe_softc));
+ sc->bfe_unit = device_get_unit(dev);
+ sc->bfe_dev = dev;
+
+ while(t->bfe_name != NULL) {
+ if ((pci_get_vendor(dev) == t->bfe_vid) &&
+ (pci_get_device(dev) == t->bfe_did)) {
+ device_set_desc_copy(dev, t->bfe_name);
+ return(0);
+ }
+ t++;
+ }
+
+ return(ENXIO);
+}
+
+static int
+bfe_dma_alloc(device_t dev)
+{
+ struct bfe_softc *sc;
+ int error, i;
+
+ sc = device_get_softc(dev);
+
+ /* parent tag */
+ error = bus_dma_tag_create(NULL, /* parent */
+ PAGE_SIZE, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR_32BIT, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MAXBSIZE, /* maxsize */
+ BUS_SPACE_UNRESTRICTED, /* num of segments */
+ BUS_SPACE_MAXSIZE_32BIT, /* max segment size */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->bfe_parent_tag);
+
+ /* tag for TX ring */
+ error = bus_dma_tag_create(sc->bfe_parent_tag, BFE_TX_LIST_SIZE,
+ BFE_TX_LIST_SIZE, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
+ NULL, NULL, BFE_TX_LIST_SIZE, 1, BUS_SPACE_MAXSIZE_32BIT,
+ 0, NULL, NULL, &sc->bfe_tx_tag);
+
+ if (error) {
+ device_printf(dev, "could not allocate dma tag\n");
+ return(ENOMEM);
+ }
+
+ /* tag for RX ring */
+ error = bus_dma_tag_create(sc->bfe_parent_tag, BFE_RX_LIST_SIZE,
+ BFE_RX_LIST_SIZE, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
+ NULL, NULL, BFE_RX_LIST_SIZE, 1, BUS_SPACE_MAXSIZE_32BIT,
+ 0, NULL, NULL, &sc->bfe_rx_tag);
+
+ if (error) {
+ device_printf(dev, "could not allocate dma tag\n");
+ return(ENOMEM);
+ }
+
+ /* tag for mbufs */
+ error = bus_dma_tag_create(sc->bfe_parent_tag, ETHER_ALIGN, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
+ 1, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, &sc->bfe_tag);
+
+ if (error) {
+ device_printf(dev, "could not allocate dma tag\n");
+ return(ENOMEM);
+ }
+
+ /* pre allocate dmamaps for RX list */
+ for (i = 0; i < BFE_RX_LIST_CNT; i++) {
+ error = bus_dmamap_create(sc->bfe_tag, 0, &sc->bfe_rx_ring[i].bfe_map);
+ if (error) {
+ device_printf(dev, "cannot create DMA map for RX\n");
+ return(ENOMEM);
+ }
+ }
+
+ /* pre allocate dmamaps for TX list */
+ for (i = 0; i < BFE_TX_LIST_CNT; i++) {
+ error = bus_dmamap_create(sc->bfe_tag, 0, &sc->bfe_tx_ring[i].bfe_map);
+ if (error) {
+ device_printf(dev, "cannot create DMA map for TX\n");
+ return(ENOMEM);
+ }
+ }
+
+ /* Alloc dma for rx ring */
+ error = bus_dmamem_alloc(sc->bfe_rx_tag, (void *)&sc->bfe_rx_list,
+ BUS_DMA_NOWAIT, &sc->bfe_rx_map);
+
+ if(error)
+ return(ENOMEM);
+
+ bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE);
+ error = bus_dmamap_load(sc->bfe_rx_tag, sc->bfe_rx_map,
+ sc->bfe_rx_list, sizeof(struct bfe_desc),
+ bfe_dma_map, &sc->bfe_rx_dma, 0);
+
+ if(error)
+ return(ENOMEM);
+
+ bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
+
+ error = bus_dmamem_alloc(sc->bfe_tx_tag, (void *)&sc->bfe_tx_list,
+ BUS_DMA_NOWAIT, &sc->bfe_tx_map);
+ if (error)
+ return(ENOMEM);
+
+
+ error = bus_dmamap_load(sc->bfe_tx_tag, sc->bfe_tx_map,
+ sc->bfe_tx_list, sizeof(struct bfe_desc),
+ bfe_dma_map, &sc->bfe_tx_dma, 0);
+ if(error)
+ return(ENOMEM);
+
+ bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE);
+ bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
+
+ return(0);
+}
+
+static int
+bfe_attach(device_t dev)
+{
+ struct ifnet *ifp;
+ struct bfe_softc *sc;
+ int unit, error = 0, rid;
+
+ sc = device_get_softc(dev);
+ mtx_init(&sc->bfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+
+ unit = device_get_unit(dev);
+ sc->bfe_dev = dev;
+ sc->bfe_unit = unit;
+
+ /*
+ * Handle power management nonsense.
+ */
+ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+ u_int32_t membase, irq;
+
+ /* Save important PCI config data. */
+ membase = pci_read_config(dev, BFE_PCI_MEMLO, 4);
+ irq = pci_read_config(dev, BFE_PCI_INTLINE, 4);
+
+ /* Reset the power state. */
+ printf("bfe%d: chip is is in D%d power mode -- setting to D0\n",
+ sc->bfe_unit, pci_get_powerstate(dev));
+
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, BFE_PCI_MEMLO, membase, 4);
+ pci_write_config(dev, BFE_PCI_INTLINE, irq, 4);
+ }
+
+ /*
+ * Map control/status registers.
+ */
+ pci_enable_busmaster(dev);
+
+ rid = BFE_PCI_MEMLO;
+ sc->bfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1,
+ RF_ACTIVE);
+ if (sc->bfe_res == NULL) {
+ printf ("bfe%d: couldn't map memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->bfe_btag = rman_get_bustag(sc->bfe_res);
+ sc->bfe_bhandle = rman_get_bushandle(sc->bfe_res);
+ sc->bfe_vhandle = (vm_offset_t)rman_get_virtual(sc->bfe_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+
+ sc->bfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (sc->bfe_irq == NULL) {
+ printf("bfe%d: couldn't map interrupt\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ if (bfe_dma_alloc(dev)) {
+ printf("bfe%d: failed to allocate DMA resources\n", sc->bfe_unit);
+ bfe_release_resources(sc);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Set up ifnet structure */
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = sc->bfe_unit;
+ ifp->if_name = "bfe";
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = bfe_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = bfe_start;
+ ifp->if_watchdog = bfe_watchdog;
+ ifp->if_init = bfe_init;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = BFE_TX_QLEN;
+
+ bfe_get_config(sc);
+
+ printf("bfe%d: Ethernet address: %6D\n", unit, sc->arpcom.ac_enaddr, ":");
+
+ /* Reset the chip and turn on the PHY */
+ bfe_chip_reset(sc);
+
+ if (mii_phy_probe(dev, &sc->bfe_miibus,
+ bfe_ifmedia_upd, bfe_ifmedia_sts)) {
+ printf("bfe%d: MII without any PHY!\n", sc->bfe_unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ ether_ifattach(ifp, sc->arpcom.ac_enaddr);
+ callout_handle_init(&sc->bfe_stat_ch);
+
+ /*
+ * Hook interrupt last to avoid having to lock softc
+ */
+ error = bus_setup_intr(dev, sc->bfe_irq, INTR_TYPE_NET,
+ bfe_intr, sc, &sc->bfe_intrhand);
+
+ if (error) {
+ bfe_release_resources(sc);
+ printf("bfe%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+fail:
+ if(error)
+ bfe_release_resources(sc);
+ return(error);
+}
+
+static int
+bfe_detach(device_t dev)
+{
+ struct bfe_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+
+ KASSERT(mtx_initialized(&sc->bfe_mtx), ("bfe mutex not initialized"));
+ BFE_LOCK(scp);
+
+ ifp = &sc->arpcom.ac_if;
+
+ if (device_is_attached(dev)) {
+ bfe_stop(sc);
+ ether_ifdetach(ifp);
+ }
+
+ bfe_chip_reset(sc);
+
+ bus_generic_detach(dev);
+ if(sc->bfe_miibus != NULL)
+ device_delete_child(dev, sc->bfe_miibus);
+
+ bfe_release_resources(sc);
+ BFE_UNLOCK(sc);
+ mtx_destroy(&sc->bfe_mtx);
+
+ return(0);
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void
+bfe_shutdown(device_t dev)
+{
+ struct bfe_softc *sc;
+
+ sc = device_get_softc(dev);
+ BFE_LOCK(sc);
+ bfe_stop(sc);
+
+ BFE_UNLOCK(sc);
+ return;
+}
+
+static int
+bfe_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct bfe_softc *sc;
+ u_int32_t ret;
+
+ sc = device_get_softc(dev);
+ if(phy != sc->bfe_phyaddr)
+ return(0);
+ bfe_readphy(sc, reg, &ret);
+
+ return(ret);
+}
+
+static int
+bfe_miibus_writereg(device_t dev, int phy, int reg, int val)
+{
+ struct bfe_softc *sc;
+
+ sc = device_get_softc(dev);
+ if(phy != sc->bfe_phyaddr)
+ return(0);
+ bfe_writephy(sc, reg, val);
+
+ return(0);
+}
+
+static void
+bfe_miibus_statchg(device_t dev)
+{
+ return;
+}
+
+static void
+bfe_tx_ring_free(struct bfe_softc *sc)
+{
+ int i;
+
+ for(i = 0; i < BFE_TX_LIST_CNT; i++) {
+ if(sc->bfe_tx_ring[i].bfe_mbuf != NULL) {
+ m_freem(sc->bfe_tx_ring[i].bfe_mbuf);
+ sc->bfe_tx_ring[i].bfe_mbuf = NULL;
+ bus_dmamap_unload(sc->bfe_tag,
+ sc->bfe_tx_ring[i].bfe_map);
+ bus_dmamap_destroy(sc->bfe_tag,
+ sc->bfe_tx_ring[i].bfe_map);
+ }
+ }
+ bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE);
+ bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
+}
+
+static void
+bfe_rx_ring_free(struct bfe_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < BFE_RX_LIST_CNT; i++) {
+ if (sc->bfe_rx_ring[i].bfe_mbuf != NULL) {
+ m_freem(sc->bfe_rx_ring[i].bfe_mbuf);
+ sc->bfe_rx_ring[i].bfe_mbuf = NULL;
+ bus_dmamap_unload(sc->bfe_tag,
+ sc->bfe_rx_ring[i].bfe_map);
+ bus_dmamap_destroy(sc->bfe_tag,
+ sc->bfe_rx_ring[i].bfe_map);
+ }
+ }
+ bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE);
+ bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
+}
+
+
+static int
+bfe_list_rx_init(struct bfe_softc *sc)
+{
+ int i;
+
+ for(i = 0; i < BFE_RX_LIST_CNT; i++) {
+ if(bfe_list_newbuf(sc, i, NULL) == ENOBUFS)
+ return ENOBUFS;
+ }
+
+ bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
+ CSR_WRITE_4(sc, BFE_DMARX_PTR, (i * sizeof(struct bfe_desc)));
+
+ sc->bfe_rx_cons = 0;
+
+ return(0);
+}
+
+static int
+bfe_list_newbuf(struct bfe_softc *sc, int c, struct mbuf *m)
+{
+ struct bfe_rxheader *rx_header;
+ struct bfe_desc *d;
+ struct bfe_data *r;
+ u_int32_t ctrl;
+
+ if ((c < 0) || (c >= BFE_RX_LIST_CNT))
+ return(EINVAL);
+
+ if(m == NULL) {
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if(m == NULL)
+ return(ENOBUFS);
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+ }
+ else
+ m->m_data = m->m_ext.ext_buf;
+
+ rx_header = mtod(m, struct bfe_rxheader *);
+ rx_header->len = 0;
+ rx_header->flags = 0;
+
+ /* Map the mbuf into DMA */
+ sc->bfe_rx_cnt = c;
+ d = &sc->bfe_rx_list[c];
+ r = &sc->bfe_rx_ring[c];
+ bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void *),
+ MCLBYTES, bfe_dma_map_desc, d, 0);
+ bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_PREWRITE);
+
+ ctrl = ETHER_MAX_LEN + 32;
+
+ if(c == BFE_RX_LIST_CNT - 1)
+ ctrl |= BFE_DESC_EOT;
+
+ d->bfe_ctrl = ctrl;
+ r->bfe_mbuf = m;
+ bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
+ return(0);
+}
+
+static void
+bfe_get_config(struct bfe_softc *sc)
+{
+ u_int8_t eeprom[128];
+
+ bfe_read_eeprom(sc, eeprom);
+
+ sc->arpcom.ac_enaddr[0] = eeprom[79];
+ sc->arpcom.ac_enaddr[1] = eeprom[78];
+ sc->arpcom.ac_enaddr[2] = eeprom[81];
+ sc->arpcom.ac_enaddr[3] = eeprom[80];
+ sc->arpcom.ac_enaddr[4] = eeprom[83];
+ sc->arpcom.ac_enaddr[5] = eeprom[82];
+
+ sc->bfe_phyaddr = eeprom[90] & 0x1f;
+ sc->bfe_mdc_port = (eeprom[90] >> 14) & 0x1;
+
+ sc->bfe_core_unit = 0;
+ sc->bfe_dma_offset = BFE_PCI_DMA;
+}
+
+static void
+bfe_pci_setup(struct bfe_softc *sc, u_int32_t cores)
+{
+ u_int32_t bar_orig, pci_rev, val;
+
+ bar_orig = pci_read_config(sc->bfe_dev, BFE_BAR0_WIN, 4);
+ pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, BFE_REG_PCI, 4);
+ pci_rev = CSR_READ_4(sc, BFE_SBIDHIGH) & BFE_RC_MASK;
+
+ val = CSR_READ_4(sc, BFE_SBINTVEC);
+ val |= cores;
+ CSR_WRITE_4(sc, BFE_SBINTVEC, val);
+
+ val = CSR_READ_4(sc, BFE_SSB_PCI_TRANS_2);
+ val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST;
+ CSR_WRITE_4(sc, BFE_SSB_PCI_TRANS_2, val);
+
+ pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, bar_orig, 4);
+}
+
+static void
+bfe_clear_stats(struct bfe_softc *sc)
+{
+ u_long reg;
+
+ BFE_LOCK(sc);
+
+ CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ);
+ for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4)
+ CSR_READ_4(sc, reg);
+ for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4)
+ CSR_READ_4(sc, reg);
+
+ BFE_UNLOCK(sc);
+}
+
+static int
+bfe_resetphy(struct bfe_softc *sc)
+{
+ u_int32_t val;
+
+ BFE_LOCK(sc);
+ bfe_writephy(sc, 0, BMCR_RESET);
+ DELAY(100);
+ bfe_readphy(sc, 0, &val);
+ if (val & BMCR_RESET) {
+ printf("bfe%d: PHY Reset would not complete.\n", sc->bfe_unit);
+ BFE_UNLOCK(sc);
+ return ENXIO;
+ }
+ BFE_UNLOCK(sc);
+ return 0;
+}
+
+static void
+bfe_chip_halt(struct bfe_softc *sc)
+{
+ BFE_LOCK(sc);
+ /* disable interrupts - not that it actually does..*/
+ CSR_WRITE_4(sc, BFE_IMASK, 0);
+ CSR_READ_4(sc, BFE_IMASK);
+
+ CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE);
+ bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 200, 1);
+
+ CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0);
+ CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0);
+ DELAY(10);
+
+ BFE_UNLOCK(sc);
+}
+
+static void
+bfe_chip_reset(struct bfe_softc *sc)
+{
+ u_int32_t val;
+
+ BFE_LOCK(sc);
+
+ /* Set the interrupt vector for the enet core */
+ bfe_pci_setup(sc, BFE_INTVEC_ENET0);
+
+ /* is core up? */
+ val = CSR_READ_4(sc, BFE_SBTMSLOW) & (BFE_RESET | BFE_REJECT | BFE_CLOCK);
+ if (val == BFE_CLOCK) {
+ /* It is, so shut it down */
+ CSR_WRITE_4(sc, BFE_RCV_LAZY, 0);
+ CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE);
+ bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 100, 1);
+ CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0);
+ sc->bfe_tx_cnt = sc->bfe_tx_prod = sc->bfe_tx_cons = 0;
+ if (CSR_READ_4(sc, BFE_DMARX_STAT) & BFE_STAT_EMASK)
+ bfe_wait_bit(sc, BFE_DMARX_STAT, BFE_STAT_SIDLE, 100, 0);
+ CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0);
+ sc->bfe_rx_prod = sc->bfe_rx_cons = 0;
+ }
+
+ bfe_core_reset(sc);
+ bfe_clear_stats(sc);
+
+ /*
+ * We want the phy registers to be accessible even when
+ * the driver is "downed" so initialize MDC preamble, frequency,
+ * and whether internal or external phy here.
+ */
+
+ /* 4402 has 62.5Mhz SB clock and internal phy */
+ CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d);
+
+ /* Internal or external PHY? */
+ val = CSR_READ_4(sc, BFE_DEVCTRL);
+ if(!(val & BFE_IPP))
+ CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_EPSEL);
+ else if(CSR_READ_4(sc, BFE_DEVCTRL) & BFE_EPR) {
+ BFE_AND(sc, BFE_DEVCTRL, ~BFE_EPR);
+ DELAY(100);
+ }
+
+ BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB);
+ CSR_WRITE_4(sc, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) &
+ BFE_LAZY_FC_MASK));
+
+ /*
+ * We don't want lazy interrupts, so just send them at the end of a frame,
+ * please
+ */
+ BFE_OR(sc, BFE_RCV_LAZY, 0);
+
+ /* Set max lengths, accounting for VLAN tags */
+ CSR_WRITE_4(sc, BFE_RXMAXLEN, ETHER_MAX_LEN+32);
+ CSR_WRITE_4(sc, BFE_TXMAXLEN, ETHER_MAX_LEN+32);
+
+ /* Set watermark XXX - magic */
+ CSR_WRITE_4(sc, BFE_TX_WMARK, 56);
+
+ /*
+ * Initialise DMA channels - not forgetting dma addresses need to be added
+ * to BFE_PCI_DMA
+ */
+ CSR_WRITE_4(sc, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE);
+ CSR_WRITE_4(sc, BFE_DMATX_ADDR, sc->bfe_tx_dma + BFE_PCI_DMA);
+
+ CSR_WRITE_4(sc, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) |
+ BFE_RX_CTRL_ENABLE);
+ CSR_WRITE_4(sc, BFE_DMARX_ADDR, sc->bfe_rx_dma + BFE_PCI_DMA);
+
+ bfe_resetphy(sc);
+ bfe_setupphy(sc);
+
+ BFE_UNLOCK(sc);
+}
+
+static void
+bfe_core_disable(struct bfe_softc *sc)
+{
+ if((CSR_READ_4(sc, BFE_SBTMSLOW)) & BFE_RESET)
+ return;
+
+ /*
+ * Set reject, wait for it set, then wait for the core to stop being busy
+ * Then set reset and reject and enable the clocks
+ */
+ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK));
+ bfe_wait_bit(sc, BFE_SBTMSLOW, BFE_REJECT, 1000, 0);
+ bfe_wait_bit(sc, BFE_SBTMSHIGH, BFE_BUSY, 1000, 1);
+ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT |
+ BFE_RESET));
+ CSR_READ_4(sc, BFE_SBTMSLOW);
+ DELAY(10);
+ /* Leave reset and reject set */
+ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET));
+ DELAY(10);
+}
+
+static void
+bfe_core_reset(struct bfe_softc *sc)
+{
+ u_int32_t val;
+
+ /* Disable the core */
+ bfe_core_disable(sc);
+
+ /* and bring it back up */
+ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC));
+ CSR_READ_4(sc, BFE_SBTMSLOW);
+ DELAY(10);
+
+ /* Chip bug, clear SERR, IB and TO if they are set. */
+ if (CSR_READ_4(sc, BFE_SBTMSHIGH) & BFE_SERR)
+ CSR_WRITE_4(sc, BFE_SBTMSHIGH, 0);
+ val = CSR_READ_4(sc, BFE_SBIMSTATE);
+ if (val & (BFE_IBE | BFE_TO))
+ CSR_WRITE_4(sc, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO));
+
+ /* Clear reset and allow it to move through the core */
+ CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC));
+ CSR_READ_4(sc, BFE_SBTMSLOW);
+ DELAY(10);
+
+ /* Leave the clock set */
+ CSR_WRITE_4(sc, BFE_SBTMSLOW, BFE_CLOCK);
+ CSR_READ_4(sc, BFE_SBTMSLOW);
+ DELAY(10);
+}
+
+static void
+bfe_cam_write(struct bfe_softc *sc, u_char *data, int index)
+{
+ u_int32_t val;
+
+ val = ((u_int32_t) data[2]) << 24;
+ val |= ((u_int32_t) data[3]) << 16;
+ val |= ((u_int32_t) data[4]) << 8;
+ val |= ((u_int32_t) data[5]);
+ CSR_WRITE_4(sc, BFE_CAM_DATA_LO, val);
+ val = (BFE_CAM_HI_VALID |
+ (((u_int32_t) data[0]) << 8) |
+ (((u_int32_t) data[1])));
+ CSR_WRITE_4(sc, BFE_CAM_DATA_HI, val);
+ CSR_WRITE_4(sc, BFE_CAM_CTRL, (BFE_CAM_WRITE |
+ (index << BFE_CAM_INDEX_SHIFT)));
+ bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1);
+}
+
+static void
+bfe_set_rx_mode(struct bfe_softc *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifmultiaddr *ifma;
+ u_int32_t val;
+ int i = 0;
+
+ val = CSR_READ_4(sc, BFE_RXCONF);
+
+ if (ifp->if_flags & IFF_PROMISC)
+ val |= BFE_RXCONF_PROMISC;
+ else
+ val &= ~BFE_RXCONF_PROMISC;
+
+ if (ifp->if_flags & IFF_BROADCAST)
+ val &= ~BFE_RXCONF_DBCAST;
+ else
+ val |= BFE_RXCONF_DBCAST;
+
+
+ CSR_WRITE_4(sc, BFE_CAM_CTRL, 0);
+ bfe_cam_write(sc, sc->arpcom.ac_enaddr, i++);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ val |= BFE_RXCONF_ALLMULTI;
+ else {
+ val &= ~BFE_RXCONF_ALLMULTI;
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ bfe_cam_write(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ i++);
+ }
+ }
+
+ CSR_WRITE_4(sc, BFE_RXCONF, val);
+ BFE_OR(sc, BFE_CAM_CTRL, BFE_CAM_ENABLE);
+}
+
+static void
+bfe_dma_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ u_int32_t *ptr;
+
+ ptr = arg;
+ *ptr = segs->ds_addr;
+}
+
+static void
+bfe_dma_map_desc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct bfe_desc *d;
+
+ d = arg;
+ /* The chip needs all addresses to be added to BFE_PCI_DMA */
+ d->bfe_addr = segs->ds_addr + BFE_PCI_DMA;
+}
+
+static void
+bfe_release_resources(struct bfe_softc *sc)
+{
+ device_t dev;
+ int i;
+
+ dev = sc->bfe_dev;
+
+ if (sc->bfe_vpd_prodname != NULL)
+ free(sc->bfe_vpd_prodname, M_DEVBUF);
+
+ if (sc->bfe_vpd_readonly != NULL)
+ free(sc->bfe_vpd_readonly, M_DEVBUF);
+
+ if (sc->bfe_intrhand != NULL)
+ bus_teardown_intr(dev, sc->bfe_irq, sc->bfe_intrhand);
+
+ if (sc->bfe_irq != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->bfe_irq);
+
+ if (sc->bfe_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0x10, sc->bfe_res);
+
+ if(sc->bfe_tx_tag != NULL) {
+ bus_dmamap_unload(sc->bfe_tx_tag, sc->bfe_tx_map);
+ bus_dmamem_free(sc->bfe_tx_tag, sc->bfe_tx_list, sc->bfe_tx_map);
+ bus_dma_tag_destroy(sc->bfe_tx_tag);
+ sc->bfe_tx_tag = NULL;
+ }
+
+ if(sc->bfe_rx_tag != NULL) {
+ bus_dmamap_unload(sc->bfe_rx_tag, sc->bfe_rx_map);
+ bus_dmamem_free(sc->bfe_rx_tag, sc->bfe_rx_list, sc->bfe_rx_map);
+ bus_dma_tag_destroy(sc->bfe_rx_tag);
+ sc->bfe_rx_tag = NULL;
+ }
+
+ if(sc->bfe_tag != NULL) {
+ for(i = 0; i < BFE_TX_LIST_CNT; i++) {
+ bus_dmamap_destroy(sc->bfe_tag, sc->bfe_tx_ring[i].bfe_map);
+ }
+ bus_dma_tag_destroy(sc->bfe_tag);
+ sc->bfe_tag = NULL;
+ }
+
+ if(sc->bfe_parent_tag != NULL)
+ bus_dma_tag_destroy(sc->bfe_parent_tag);
+
+ return;
+}
+
+static void
+bfe_read_eeprom(struct bfe_softc *sc, u_int8_t *data)
+{
+ long i;
+ u_int16_t *ptr = (u_int16_t *)data;
+
+ for(i = 0; i < 128; i += 2)
+ ptr[i/2] = CSR_READ_4(sc, 4096 + i);
+}
+
+static int
+bfe_wait_bit(struct bfe_softc *sc, u_int32_t reg, u_int32_t bit,
+ u_long timeout, const int clear)
+{
+ u_long i;
+
+ for (i = 0; i < timeout; i++) {
+ u_int32_t val = CSR_READ_4(sc, reg);
+
+ if (clear && !(val & bit))
+ break;
+ if (!clear && (val & bit))
+ break;
+ DELAY(10);
+ }
+ if (i == timeout) {
+ printf("bfe%d: BUG! Timeout waiting for bit %08x of register "
+ "%x to %s.\n", sc->bfe_unit, bit, reg,
+ (clear ? "clear" : "set"));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+bfe_readphy(struct bfe_softc *sc, u_int32_t reg, u_int32_t *val)
+{
+ int err;
+
+ BFE_LOCK(sc);
+ /* Clear MII ISR */
+ CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
+ CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
+ (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) |
+ (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) |
+ (reg << BFE_MDIO_RA_SHIFT) |
+ (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT)));
+ err = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0);
+ *val = CSR_READ_4(sc, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA;
+
+ BFE_UNLOCK(sc);
+ return err;
+}
+
+static int
+bfe_writephy(struct bfe_softc *sc, u_int32_t reg, u_int32_t val)
+{
+ int status;
+
+ BFE_LOCK(sc);
+ CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
+ CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
+ (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) |
+ (sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) |
+ (reg << BFE_MDIO_RA_SHIFT) |
+ (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) |
+ (val & BFE_MDIO_DATA_DATA)));
+ status = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0);
+ BFE_UNLOCK(sc);
+
+ return status;
+}
+
+/*
+ * XXX - I think this is handled by the PHY driver, but it can't hurt to do it
+ * twice
+ */
+static int
+bfe_setupphy(struct bfe_softc *sc)
+{
+ u_int32_t val;
+ BFE_LOCK(sc);
+
+ /* Enable activity LED */
+ bfe_readphy(sc, 26, &val);
+ bfe_writephy(sc, 26, val & 0x7fff);
+ bfe_readphy(sc, 26, &val);
+
+ /* Enable traffic meter LED mode */
+ bfe_readphy(sc, 27, &val);
+ bfe_writephy(sc, 27, val | (1 << 6));
+
+ BFE_UNLOCK(sc);
+ return 0;
+}
+
+static void
+bfe_stats_update(struct bfe_softc *sc)
+{
+ u_long reg;
+ u_int32_t *val;
+
+ val = &sc->bfe_hwstats.tx_good_octets;
+ for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) {
+ *val++ += CSR_READ_4(sc, reg);
+ }
+ val = &sc->bfe_hwstats.rx_good_octets;
+ for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) {
+ *val++ += CSR_READ_4(sc, reg);
+ }
+}
+
+static void
+bfe_txeof(struct bfe_softc *sc)
+{
+ struct ifnet *ifp;
+ int i, chipidx;
+
+ BFE_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+
+ chipidx = CSR_READ_4(sc, BFE_DMATX_STAT) & BFE_STAT_CDMASK;
+ chipidx /= sizeof(struct bfe_desc);
+
+ i = sc->bfe_tx_cons;
+ /* Go through the mbufs and free those that have been transmitted */
+ while(i != chipidx) {
+ struct bfe_data *r = &sc->bfe_tx_ring[i];
+ if(r->bfe_mbuf != NULL) {
+ ifp->if_opackets++;
+ m_freem(r->bfe_mbuf);
+ r->bfe_mbuf = NULL;
+ bus_dmamap_unload(sc->bfe_tag, r->bfe_map);
+ }
+ sc->bfe_tx_cnt--;
+ BFE_INC(i, BFE_TX_LIST_CNT);
+ }
+
+ if(i != sc->bfe_tx_cons) {
+ /* we freed up some mbufs */
+ sc->bfe_tx_cons = i;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+ if(sc->bfe_tx_cnt == 0)
+ ifp->if_timer = 0;
+ else
+ ifp->if_timer = 5;
+
+ BFE_UNLOCK(sc);
+}
+
+/* Pass a received packet up the stack */
+static void
+bfe_rxeof(struct bfe_softc *sc)
+{
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct bfe_rxheader *rxheader;
+ struct bfe_data *r;
+ int cons;
+ u_int32_t status, current, len, flags;
+
+ BFE_LOCK(sc);
+ cons = sc->bfe_rx_cons;
+ status = CSR_READ_4(sc, BFE_DMARX_STAT);
+ current = (status & BFE_STAT_CDMASK) / sizeof(struct bfe_desc);
+
+ ifp = &sc->arpcom.ac_if;
+
+ while(current != cons) {
+ r = &sc->bfe_rx_ring[cons];
+ m = r->bfe_mbuf;
+ rxheader = mtod(m, struct bfe_rxheader*);
+ bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_POSTWRITE);
+ len = rxheader->len;
+ r->bfe_mbuf = NULL;
+
+ bus_dmamap_unload(sc->bfe_tag, r->bfe_map);
+ flags = rxheader->flags;
+
+ len -= ETHER_CRC_LEN;
+
+ /* flag an error and try again */
+ if ((len > ETHER_MAX_LEN+32) || (flags & BFE_RX_FLAG_ERRORS)) {
+ ifp->if_ierrors++;
+ if (flags & BFE_RX_FLAG_SERR)
+ ifp->if_collisions++;
+ bfe_list_newbuf(sc, cons, m);
+ continue;
+ }
+
+ /* Go past the rx header */
+ if (bfe_list_newbuf(sc, cons, NULL) == 0) {
+ m_adj(m, BFE_RX_OFFSET);
+ m->m_len = m->m_pkthdr.len = len;
+ } else {
+ bfe_list_newbuf(sc, cons, m);
+ ifp->if_ierrors++;
+ continue;
+ }
+
+ ifp->if_ipackets++;
+ m->m_pkthdr.rcvif = ifp;
+ (*ifp->if_input)(ifp, m);
+
+ BFE_INC(cons, BFE_RX_LIST_CNT);
+ }
+ sc->bfe_rx_cons = cons;
+ BFE_UNLOCK(sc);
+}
+
+static void
+bfe_intr(void *xsc)
+{
+ struct bfe_softc *sc = xsc;
+ struct ifnet *ifp;
+ u_int32_t istat, imask, flag;
+
+ ifp = &sc->arpcom.ac_if;
+
+ BFE_LOCK(sc);
+
+ istat = CSR_READ_4(sc, BFE_ISTAT);
+ imask = CSR_READ_4(sc, BFE_IMASK);
+
+ /*
+ * Defer unsolicited interrupts - This is necessary because setting the
+ * chips interrupt mask register to 0 doesn't actually stop the
+ * interrupts
+ */
+ istat &= imask;
+ CSR_WRITE_4(sc, BFE_ISTAT, istat);
+ CSR_READ_4(sc, BFE_ISTAT);
+
+ /* not expecting this interrupt, disregard it */
+ if(istat == 0) {
+ BFE_UNLOCK(sc);
+ return;
+ }
+
+ if(istat & BFE_ISTAT_ERRORS) {
+ flag = CSR_READ_4(sc, BFE_DMATX_STAT);
+ if(flag & BFE_STAT_EMASK)
+ ifp->if_oerrors++;
+
+ flag = CSR_READ_4(sc, BFE_DMARX_STAT);
+ if(flag & BFE_RX_FLAG_ERRORS)
+ ifp->if_ierrors++;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+ bfe_init(sc);
+ }
+
+ /* A packet was received */
+ if(istat & BFE_ISTAT_RX)
+ bfe_rxeof(sc);
+
+ /* A packet was sent */
+ if(istat & BFE_ISTAT_TX)
+ bfe_txeof(sc);
+
+ /* We have packets pending, fire them out */
+ if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
+ bfe_start(ifp);
+
+ BFE_UNLOCK(sc);
+}
+
+static int
+bfe_encap(struct bfe_softc *sc, struct mbuf *m_head, u_int32_t *txidx)
+{
+ struct bfe_desc *d = NULL;
+ struct bfe_data *r = NULL;
+ struct mbuf *m;
+ u_int32_t frag, cur, cnt = 0;
+ int chainlen = 0;
+
+ if(BFE_TX_LIST_CNT - sc->bfe_tx_cnt < 2)
+ return(ENOBUFS);
+
+ /*
+ * Count the number of frags in this chain to see if
+ * we need to m_defrag. Since the descriptor list is shared
+ * by all packets, we'll m_defrag long chains so that they
+ * do not use up the entire list, even if they would fit.
+ */
+ for(m = m_head; m != NULL; m = m->m_next)
+ chainlen++;
+
+
+ if ((chainlen > BFE_TX_LIST_CNT / 4) ||
+ ((BFE_TX_LIST_CNT - (chainlen + sc->bfe_tx_cnt)) < 2)) {
+ m = m_defrag(m_head, M_DONTWAIT);
+ if (m == NULL)
+ return(ENOBUFS);
+ m_head = m;
+ }
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ cur = frag = *txidx;
+ cnt = 0;
+
+ for(m = m_head; m != NULL; m = m->m_next) {
+ if(m->m_len != 0) {
+ if((BFE_TX_LIST_CNT - (sc->bfe_tx_cnt + cnt)) < 2)
+ return(ENOBUFS);
+
+ d = &sc->bfe_tx_list[cur];
+ r = &sc->bfe_tx_ring[cur];
+ d->bfe_ctrl = BFE_DESC_LEN & m->m_len;
+ /* always intterupt on completion */
+ d->bfe_ctrl |= BFE_DESC_IOC;
+ if(cnt == 0)
+ /* Set start of frame */
+ d->bfe_ctrl |= BFE_DESC_SOF;
+ if(cur == BFE_TX_LIST_CNT - 1)
+ /* Tell the chip to wrap to the start of the descriptor list */
+ d->bfe_ctrl |= BFE_DESC_EOT;
+
+ bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void*), m->m_len,
+ bfe_dma_map_desc, d, 0);
+ bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_PREREAD);
+
+ frag = cur;
+ BFE_INC(cur, BFE_TX_LIST_CNT);
+ cnt++;
+ }
+ }
+
+ if (m != NULL)
+ return(ENOBUFS);
+
+ sc->bfe_tx_list[frag].bfe_ctrl |= BFE_DESC_EOF;
+ sc->bfe_tx_ring[frag].bfe_mbuf = m_head;
+ bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
+
+ *txidx = cur;
+ sc->bfe_tx_cnt += cnt;
+ return (0);
+}
+
+/*
+ * Set up to transmit a packet
+ */
+static void
+bfe_start(struct ifnet *ifp)
+{
+ struct bfe_softc *sc;
+ struct mbuf *m_head = NULL;
+ int idx;
+
+ sc = ifp->if_softc;
+ idx = sc->bfe_tx_prod;
+
+ BFE_LOCK(sc);
+
+ /*
+ * not much point trying to send if the link is down or we have nothing to
+ * send
+ */
+ if (!sc->bfe_link && ifp->if_snd.ifq_len < 10) {
+ BFE_UNLOCK(sc);
+ return;
+ }
+
+ if (ifp->if_flags & IFF_OACTIVE) {
+ BFE_UNLOCK(sc);
+ return;
+ }
+
+ while(sc->bfe_tx_ring[idx].bfe_mbuf == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if(m_head == NULL)
+ break;
+
+ /*
+ * Pack the data into the tx ring. If we dont have enough room, let
+ * the chip drain the ring
+ */
+ if(bfe_encap(sc, m_head, &idx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ BPF_MTAP(ifp, m_head);
+ }
+
+ sc->bfe_tx_prod = idx;
+ /* Transmit - twice due to apparent hardware bug */
+ CSR_WRITE_4(sc, BFE_DMATX_PTR, idx * sizeof(struct bfe_desc));
+ CSR_WRITE_4(sc, BFE_DMATX_PTR, idx * sizeof(struct bfe_desc));
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+ BFE_UNLOCK(sc);
+}
+
+static void
+bfe_init(void *xsc)
+{
+ struct bfe_softc *sc = (struct bfe_softc*)xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ BFE_LOCK(sc);
+
+ if (ifp->if_flags & IFF_RUNNING) {
+ BFE_UNLOCK(sc);
+ return;
+ }
+
+ bfe_stop(sc);
+ bfe_chip_reset(sc);
+
+ if (bfe_list_rx_init(sc) == ENOBUFS) {
+ printf("bfe%d: bfe_init failed. Not enough memory for list buffers\n",
+ sc->bfe_unit);
+ bfe_stop(sc);
+ return;
+ }
+
+ bfe_set_rx_mode(sc);
+
+ /* Enable the chip and core */
+ BFE_OR(sc, BFE_ENET_CTRL, BFE_ENET_ENABLE);
+ /* Enable interrupts */
+ CSR_WRITE_4(sc, BFE_IMASK, BFE_IMASK_DEF);
+
+ bfe_ifmedia_upd(ifp);
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ sc->bfe_stat_ch = timeout(bfe_tick, sc, hz);
+ BFE_UNLOCK(sc);
+}
+
+/*
+ * Set media options.
+ */
+static int
+bfe_ifmedia_upd(struct ifnet *ifp)
+{
+ struct bfe_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+
+ BFE_LOCK(sc);
+
+ mii = device_get_softc(sc->bfe_miibus);
+ sc->bfe_link = 0;
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+ for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
+ miisc = LIST_NEXT(miisc, mii_list))
+ mii_phy_reset(miisc);
+ }
+ mii_mediachg(mii);
+
+ BFE_UNLOCK(sc);
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void
+bfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct bfe_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ BFE_LOCK(sc);
+
+ mii = device_get_softc(sc->bfe_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ BFE_UNLOCK(sc);
+}
+
+static int
+bfe_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct bfe_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error = 0;
+
+ BFE_LOCK(sc);
+
+ switch(command) {
+ case SIOCSIFFLAGS:
+ if(ifp->if_flags & IFF_UP)
+ if(ifp->if_flags & IFF_RUNNING)
+ bfe_set_rx_mode(sc);
+ else
+ bfe_init(sc);
+ else if(ifp->if_flags & IFF_RUNNING)
+ bfe_stop(sc);
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if(ifp->if_flags & IFF_RUNNING)
+ bfe_set_rx_mode(sc);
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->bfe_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ BFE_UNLOCK(sc);
+ return error;
+}
+
+static void
+bfe_watchdog(struct ifnet *ifp)
+{
+ struct bfe_softc *sc;
+
+ sc = ifp->if_softc;
+
+ BFE_LOCK(sc);
+
+ printf("bfe%d: watchdog timeout -- resetting\n", sc->bfe_unit);
+
+ ifp->if_flags &= ~IFF_RUNNING;
+ bfe_init(sc);
+
+ ifp->if_oerrors++;
+
+ BFE_UNLOCK(sc);
+}
+
+static void
+bfe_tick(void *xsc)
+{
+ struct bfe_softc *sc = xsc;
+ struct mii_data *mii;
+
+ if (sc == NULL)
+ return;
+
+ BFE_LOCK(sc);
+
+ mii = device_get_softc(sc->bfe_miibus);
+
+ bfe_stats_update(sc);
+ sc->bfe_stat_ch = timeout(bfe_tick, sc, hz);
+
+ if(sc->bfe_link) {
+ BFE_UNLOCK(sc);
+ return;
+ }
+
+ mii_tick(mii);
+ if (!sc->bfe_link && mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+ sc->bfe_link++;
+
+ BFE_UNLOCK(sc);
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void
+bfe_stop(struct bfe_softc *sc)
+{
+ struct ifnet *ifp;
+
+ BFE_LOCK(sc);
+
+ untimeout(bfe_tick, sc, sc->bfe_stat_ch);
+
+ ifp = &sc->arpcom.ac_if;
+
+ bfe_chip_halt(sc);
+ bfe_tx_ring_free(sc);
+ bfe_rx_ring_free(sc);
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ BFE_UNLOCK(sc);
+}
diff --git a/sys/dev/bfe/if_bfereg.h b/sys/dev/bfe/if_bfereg.h
new file mode 100644
index 0000000..8590061
--- /dev/null
+++ b/sys/dev/bfe/if_bfereg.h
@@ -0,0 +1,512 @@
+/* Copyright (c) 2003 Stuart Walsh */
+/* $FreeBSD$ */
+
+#ifndef _BFE_H
+#define _BFE_H
+
+/* PCI registers */
+#define BFE_PCI_MEMLO 0x10
+#define BFE_PCI_MEMHIGH 0x14
+#define BFE_PCI_INTLINE 0x3C
+
+/* Register layout. */
+#define BFE_DEVCTRL 0x00000000 /* Device Control */
+#define BFE_PFE 0x00000080 /* Pattern Filtering Enable */
+#define BFE_IPP 0x00000400 /* Internal EPHY Present */
+#define BFE_EPR 0x00008000 /* EPHY Reset */
+#define BFE_PME 0x00001000 /* PHY Mode Enable */
+#define BFE_PMCE 0x00002000 /* PHY Mode Clocks Enable */
+#define BFE_PADDR 0x0007c000 /* PHY Address */
+#define BFE_PADDR_SHIFT 18
+
+#define BFE_BIST_STAT 0x0000000C /* Built-In Self-Test Status */
+#define BFE_WKUP_LEN 0x00000010 /* Wakeup Length */
+
+#define BFE_ISTAT 0x00000020 /* Interrupt Status */
+#define BFE_ISTAT_PME 0x00000040 /* Power Management Event */
+#define BFE_ISTAT_TO 0x00000080 /* General Purpose Timeout */
+#define BFE_ISTAT_DSCE 0x00000400 /* Descriptor Error */
+#define BFE_ISTAT_DATAE 0x00000800 /* Data Error */
+#define BFE_ISTAT_DPE 0x00001000 /* Descr. Protocol Error */
+#define BFE_ISTAT_RDU 0x00002000 /* Receive Descr. Underflow */
+#define BFE_ISTAT_RFO 0x00004000 /* Receive FIFO Overflow */
+#define BFE_ISTAT_TFU 0x00008000 /* Transmit FIFO Underflow */
+#define BFE_ISTAT_RX 0x00010000 /* RX Interrupt */
+#define BFE_ISTAT_TX 0x01000000 /* TX Interrupt */
+#define BFE_ISTAT_EMAC 0x04000000 /* EMAC Interrupt */
+#define BFE_ISTAT_MII_WRITE 0x08000000 /* MII Write Interrupt */
+#define BFE_ISTAT_MII_READ 0x10000000 /* MII Read Interrupt */
+#define BFE_ISTAT_ERRORS (BFE_ISTAT_DSCE | BFE_ISTAT_DATAE | BFE_ISTAT_DPE |\
+ BFE_ISTAT_RDU | BFE_ISTAT_RFO | BFE_ISTAT_TFU)
+
+#define BFE_IMASK 0x00000024 /* Interrupt Mask */
+#define BFE_IMASK_DEF (BFE_ISTAT_ERRORS | BFE_ISTAT_TO | BFE_ISTAT_RX | \
+ BFE_ISTAT_TX)
+
+#define BFE_MAC_CTRL 0x000000A8 /* MAC Control */
+#define BFE_CTRL_CRC32_ENAB 0x00000001 /* CRC32 Generation Enable */
+#define BFE_CTRL_PDOWN 0x00000004 /* Onchip EPHY Powerdown */
+#define BFE_CTRL_EDET 0x00000008 /* Onchip EPHY Energy Detected */
+#define BFE_CTRL_LED 0x000000e0 /* Onchip EPHY LED Control */
+#define BFE_CTRL_LED_SHIFT 5
+
+#define BFE_RCV_LAZY 0x00000100 /* Lazy Interrupt Control */
+#define BFE_LAZY_TO_MASK 0x00ffffff /* Timeout */
+#define BFE_LAZY_FC_MASK 0xff000000 /* Frame Count */
+#define BFE_LAZY_FC_SHIFT 24
+
+#define BFE_DMATX_CTRL 0x00000200 /* DMA TX Control */
+#define BFE_TX_CTRL_ENABLE 0x00000001 /* Enable */
+#define BFE_TX_CTRL_SUSPEND 0x00000002 /* Suepend Request */
+#define BFE_TX_CTRL_LPBACK 0x00000004 /* Loopback Enable */
+#define BFE_TX_CTRL_FAIRPRI 0x00000008 /* Fair Priority */
+#define BFE_TX_CTRL_FLUSH 0x00000010 /* Flush Request */
+
+#define BFE_DMATX_ADDR 0x00000204 /* DMA TX Descriptor Ring Address */
+#define BFE_DMATX_PTR 0x00000208 /* DMA TX Last Posted Descriptor */
+#define BFE_DMATX_STAT 0x0000020C /* DMA TX Current Active Desc. + Status */
+#define BFE_STAT_CDMASK 0x00000fff /* Current Descriptor Mask */
+#define BFE_STAT_SMASK 0x0000f000 /* State Mask */
+#define BFE_STAT_DISABLE 0x00000000 /* State Disabled */
+#define BFE_STAT_SACTIVE 0x00001000 /* State Active */
+#define BFE_STAT_SIDLE 0x00002000 /* State Idle Wait */
+#define BFE_STAT_STOPPED 0x00003000 /* State Stopped */
+#define BFE_STAT_SSUSP 0x00004000 /* State Suspend Pending */
+#define BFE_STAT_EMASK 0x000f0000 /* Error Mask */
+#define BFE_STAT_ENONE 0x00000000 /* Error None */
+#define BFE_STAT_EDPE 0x00010000 /* Error Desc. Protocol Error */
+#define BFE_STAT_EDFU 0x00020000 /* Error Data FIFO Underrun */
+#define BFE_STAT_EBEBR 0x00030000 /* Error Bus Error on Buffer Read */
+#define BFE_STAT_EBEDA 0x00040000 /* Error Bus Error on Desc. Access */
+#define BFE_STAT_FLUSHED 0x00100000 /* Flushed */
+
+#define BFE_DMARX_CTRL 0x00000210 /* DMA RX Control */
+#define BFE_RX_CTRL_ENABLE 0x00000001 /* Enable */
+#define BFE_RX_CTRL_ROMASK 0x000000fe /* Receive Offset Mask */
+#define BFE_RX_CTRL_ROSHIFT 1 /* Receive Offset Shift */
+
+#define BFE_DMARX_ADDR 0x00000214 /* DMA RX Descriptor Ring Address */
+#define BFE_DMARX_PTR 0x00000218 /* DMA RX Last Posted Descriptor */
+#define BFE_DMARX_STAT 0x0000021C /* DMA RX Current Active Desc. + Status */
+
+#define BFE_RXCONF 0x00000400 /* EMAC RX Config */
+#define BFE_RXCONF_DBCAST 0x00000001 /* Disable Broadcast */
+#define BFE_RXCONF_ALLMULTI 0x00000002 /* Accept All Multicast */
+#define BFE_RXCONF_NORXTX 0x00000004 /* Receive Disable While Transmitting */
+#define BFE_RXCONF_PROMISC 0x00000008 /* Promiscuous Enable */
+#define BFE_RXCONF_LPBACK 0x00000010 /* Loopback Enable */
+#define BFE_RXCONF_FLOW 0x00000020 /* Flow Control Enable */
+#define BFE_RXCONF_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */
+#define BFE_RXCONF_RFILT 0x00000080 /* Reject Filter */
+
+#define BFE_RXMAXLEN 0x00000404 /* EMAC RX Max Packet Length */
+#define BFE_TXMAXLEN 0x00000408 /* EMAC TX Max Packet Length */
+
+#define BFE_MDIO_CTRL 0x00000410 /* EMAC MDIO Control */
+#define BFE_MDIO_MAXF_MASK 0x0000007f /* MDC Frequency */
+#define BFE_MDIO_PREAMBLE 0x00000080 /* MII Preamble Enable */
+
+#define BFE_MDIO_DATA 0x00000414 /* EMAC MDIO Data */
+#define BFE_MDIO_DATA_DATA 0x0000ffff /* R/W Data */
+#define BFE_MDIO_TA_MASK 0x00030000 /* Turnaround Value */
+#define BFE_MDIO_TA_SHIFT 16
+#define BFE_MDIO_TA_VALID 2
+
+#define BFE_MDIO_RA_MASK 0x007c0000 /* Register Address */
+#define BFE_MDIO_PMD_MASK 0x0f800000 /* Physical Media Device */
+#define BFE_MDIO_OP_MASK 0x30000000 /* Opcode */
+#define BFE_MDIO_SB_MASK 0xc0000000 /* Start Bits */
+#define BFE_MDIO_SB_START 0x40000000 /* Start Of Frame */
+#define BFE_MDIO_RA_SHIFT 18
+#define BFE_MDIO_PMD_SHIFT 23
+#define BFE_MDIO_OP_SHIFT 28
+#define BFE_MDIO_OP_WRITE 1
+#define BFE_MDIO_OP_READ 2
+#define BFE_MDIO_SB_SHIFT 30
+
+#define BFE_EMAC_IMASK 0x00000418 /* EMAC Interrupt Mask */
+#define BFE_EMAC_ISTAT 0x0000041C /* EMAC Interrupt Status */
+#define BFE_EMAC_INT_MII 0x00000001 /* MII MDIO Interrupt */
+#define BFE_EMAC_INT_MIB 0x00000002 /* MIB Interrupt */
+#define BFE_EMAC_INT_FLOW 0x00000003 /* Flow Control Interrupt */
+
+#define BFE_CAM_DATA_LO 0x00000420 /* EMAC CAM Data Low */
+#define BFE_CAM_DATA_HI 0x00000424 /* EMAC CAM Data High */
+#define BFE_CAM_HI_VALID 0x00010000 /* Valid Bit */
+
+#define BFE_CAM_CTRL 0x00000428 /* EMAC CAM Control */
+#define BFE_CAM_ENABLE 0x00000001 /* CAM Enable */
+#define BFE_CAM_MSEL 0x00000002 /* Mask Select */
+#define BFE_CAM_READ 0x00000004 /* Read */
+#define BFE_CAM_WRITE 0x00000008 /* Read */
+#define BFE_CAM_INDEX_MASK 0x003f0000 /* Index Mask */
+#define BFE_CAM_BUSY 0x80000000 /* CAM Busy */
+#define BFE_CAM_INDEX_SHIFT 16
+
+#define BFE_ENET_CTRL 0x0000042C /* EMAC ENET Control */
+#define BFE_ENET_ENABLE 0x00000001 /* EMAC Enable */
+#define BFE_ENET_DISABLE 0x00000002 /* EMAC Disable */
+#define BFE_ENET_SRST 0x00000004 /* EMAC Soft Reset */
+#define BFE_ENET_EPSEL 0x00000008 /* External PHY Select */
+
+#define BFE_TX_CTRL 0x00000430 /* EMAC TX Control */
+#define BFE_TX_DUPLEX 0x00000001 /* Full Duplex */
+#define BFE_TX_FMODE 0x00000002 /* Flow Mode */
+#define BFE_TX_SBENAB 0x00000004 /* Single Backoff Enable */
+#define BFE_TX_SMALL_SLOT 0x00000008 /* Small Slottime */
+
+#define BFE_TX_WMARK 0x00000434 /* EMAC TX Watermark */
+
+#define BFE_MIB_CTRL 0x00000438 /* EMAC MIB Control */
+#define BFE_MIB_CLR_ON_READ 0x00000001 /* Autoclear on Read */
+
+/* Status registers */
+#define BFE_TX_GOOD_O 0x00000500 /* MIB TX Good Octets */
+#define BFE_TX_GOOD_P 0x00000504 /* MIB TX Good Packets */
+#define BFE_TX_O 0x00000508 /* MIB TX Octets */
+#define BFE_TX_P 0x0000050C /* MIB TX Packets */
+#define BFE_TX_BCAST 0x00000510 /* MIB TX Broadcast Packets */
+#define BFE_TX_MCAST 0x00000514 /* MIB TX Multicast Packets */
+#define BFE_TX_64 0x00000518 /* MIB TX <= 64 byte Packets */
+#define BFE_TX_65_127 0x0000051C /* MIB TX 65 to 127 byte Packets */
+#define BFE_TX_128_255 0x00000520 /* MIB TX 128 to 255 byte Packets */
+#define BFE_TX_256_511 0x00000524 /* MIB TX 256 to 511 byte Packets */
+#define BFE_TX_512_1023 0x00000528 /* MIB TX 512 to 1023 byte Packets */
+#define BFE_TX_1024_MAX 0x0000052C /* MIB TX 1024 to max byte Packets */
+#define BFE_TX_JABBER 0x00000530 /* MIB TX Jabber Packets */
+#define BFE_TX_OSIZE 0x00000534 /* MIB TX Oversize Packets */
+#define BFE_TX_FRAG 0x00000538 /* MIB TX Fragment Packets */
+#define BFE_TX_URUNS 0x0000053C /* MIB TX Underruns */
+#define BFE_TX_TCOLS 0x00000540 /* MIB TX Total Collisions */
+#define BFE_TX_SCOLS 0x00000544 /* MIB TX Single Collisions */
+#define BFE_TX_MCOLS 0x00000548 /* MIB TX Multiple Collisions */
+#define BFE_TX_ECOLS 0x0000054C /* MIB TX Excessive Collisions */
+#define BFE_TX_LCOLS 0x00000550 /* MIB TX Late Collisions */
+#define BFE_TX_DEFERED 0x00000554 /* MIB TX Defered Packets */
+#define BFE_TX_CLOST 0x00000558 /* MIB TX Carrier Lost */
+#define BFE_TX_PAUSE 0x0000055C /* MIB TX Pause Packets */
+#define BFE_RX_GOOD_O 0x00000580 /* MIB RX Good Octets */
+#define BFE_RX_GOOD_P 0x00000584 /* MIB RX Good Packets */
+#define BFE_RX_O 0x00000588 /* MIB RX Octets */
+#define BFE_RX_P 0x0000058C /* MIB RX Packets */
+#define BFE_RX_BCAST 0x00000590 /* MIB RX Broadcast Packets */
+#define BFE_RX_MCAST 0x00000594 /* MIB RX Multicast Packets */
+#define BFE_RX_64 0x00000598 /* MIB RX <= 64 byte Packets */
+#define BFE_RX_65_127 0x0000059C /* MIB RX 65 to 127 byte Packets */
+#define BFE_RX_128_255 0x000005A0 /* MIB RX 128 to 255 byte Packets */
+#define BFE_RX_256_511 0x000005A4 /* MIB RX 256 to 511 byte Packets */
+#define BFE_RX_512_1023 0x000005A8 /* MIB RX 512 to 1023 byte Packets */
+#define BFE_RX_1024_MAX 0x000005AC /* MIB RX 1024 to max byte Packets */
+#define BFE_RX_JABBER 0x000005B0 /* MIB RX Jabber Packets */
+#define BFE_RX_OSIZE 0x000005B4 /* MIB RX Oversize Packets */
+#define BFE_RX_FRAG 0x000005B8 /* MIB RX Fragment Packets */
+#define BFE_RX_MISS 0x000005BC /* MIB RX Missed Packets */
+#define BFE_RX_CRCA 0x000005C0 /* MIB RX CRC Align Errors */
+#define BFE_RX_USIZE 0x000005C4 /* MIB RX Undersize Packets */
+#define BFE_RX_CRC 0x000005C8 /* MIB RX CRC Errors */
+#define BFE_RX_ALIGN 0x000005CC /* MIB RX Align Errors */
+#define BFE_RX_SYM 0x000005D0 /* MIB RX Symbol Errors */
+#define BFE_RX_PAUSE 0x000005D4 /* MIB RX Pause Packets */
+#define BFE_RX_NPAUSE 0x000005D8 /* MIB RX Non-Pause Packets */
+
+#define BFE_SBIMSTATE 0x00000F90 /* BFE_SB Initiator Agent State */
+#define BFE_PC 0x0000000f /* Pipe Count */
+#define BFE_AP_MASK 0x00000030 /* Arbitration Priority */
+#define BFE_AP_BOTH 0x00000000 /* Use both timeslices and token */
+#define BFE_AP_TS 0x00000010 /* Use timeslices only */
+#define BFE_AP_TK 0x00000020 /* Use token only */
+#define BFE_AP_RSV 0x00000030 /* Reserved */
+#define BFE_IBE 0x00020000 /* In Band Error */
+#define BFE_TO 0x00040000 /* Timeout */
+
+
+/* Seems the bcm440x has a fairly generic core, we only need be concerned with
+ * a couple of these
+ */
+#define BFE_SBINTVEC 0x00000F94 /* BFE_SB Interrupt Mask */
+#define BFE_INTVEC_PCI 0x00000001 /* Enable interrupts for PCI */
+#define BFE_INTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */
+#define BFE_INTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */
+#define BFE_INTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */
+#define BFE_INTVEC_USB 0x00000010 /* Enable interrupts for usb */
+#define BFE_INTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */
+#define BFE_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */
+
+#define BFE_SBTMSLOW 0x00000F98 /* BFE_SB Target State Low */
+#define BFE_RESET 0x00000001 /* Reset */
+#define BFE_REJECT 0x00000002 /* Reject */
+#define BFE_CLOCK 0x00010000 /* Clock Enable */
+#define BFE_FGC 0x00020000 /* Force Gated Clocks On */
+#define BFE_PE 0x40000000 /* Power Management Enable */
+#define BFE_BE 0x80000000 /* BIST Enable */
+
+#define BFE_SBTMSHIGH 0x00000F9C /* BFE_SB Target State High */
+#define BFE_SERR 0x00000001 /* S-error */
+#define BFE_INT 0x00000002 /* Interrupt */
+#define BFE_BUSY 0x00000004 /* Busy */
+#define BFE_GCR 0x20000000 /* Gated Clock Request */
+#define BFE_BISTF 0x40000000 /* BIST Failed */
+#define BFE_BISTD 0x80000000 /* BIST Done */
+
+#define BFE_SBBWA0 0x00000FA0 /* BFE_SB Bandwidth Allocation Table 0 */
+#define BFE_TAB0_MASK 0x0000ffff /* Lookup Table 0 */
+#define BFE_TAB1_MASK 0xffff0000 /* Lookup Table 0 */
+#define BFE_TAB0_SHIFT 0
+#define BFE_TAB1_SHIFT 16
+
+#define BFE_SBIMCFGLOW 0x00000FA8 /* BFE_SB Initiator Configuration Low */
+#define BFE_STO_MASK 0x00000003 /* Service Timeout */
+#define BFE_RTO_MASK 0x00000030 /* Request Timeout */
+#define BFE_CID_MASK 0x00ff0000 /* Connection ID */
+#define BFE_RTO_SHIFT 4
+#define BFE_CID_SHIFT 16
+
+#define BFE_SBIMCFGHIGH 0x00000FAC /* BFE_SB Initiator Configuration High */
+#define BFE_IEM_MASK 0x0000000c /* Inband Error Mode */
+#define BFE_TEM_MASK 0x00000030 /* Timeout Error Mode */
+#define BFE_BEM_MASK 0x000000c0 /* Bus Error Mode */
+#define BFE_TEM_SHIFT 4
+#define BFE_BEM_SHIFT 6
+
+#define BFE_SBTMCFGLOW 0x00000FB8 /* BFE_SB Target Configuration Low */
+#define BFE_LOW_CD_MASK 0x000000ff /* Clock Divide Mask */
+#define BFE_LOW_CO_MASK 0x0000f800 /* Clock Offset Mask */
+#define BFE_LOW_IF_MASK 0x00fc0000 /* Interrupt Flags Mask */
+#define BFE_LOW_IM_MASK 0x03000000 /* Interrupt Mode Mask */
+#define BFE_LOW_CO_SHIFT 11
+#define BFE_LOW_IF_SHIFT 18
+#define BFE_LOW_IM_SHIFT 24
+
+#define BFE_SBTMCFGHIGH 0x00000FBC /* BFE_SB Target Configuration High */
+#define BFE_HIGH_BM_MASK 0x00000003 /* Busy Mode */
+#define BFE_HIGH_RM_MASK 0x0000000C /* Retry Mode */
+#define BFE_HIGH_SM_MASK 0x00000030 /* Stop Mode */
+#define BFE_HIGH_EM_MASK 0x00000300 /* Error Mode */
+#define BFE_HIGH_IM_MASK 0x00000c00 /* Interrupt Mode */
+#define BFE_HIGH_RM_SHIFT 2
+#define BFE_HIGH_SM_SHIFT 4
+#define BFE_HIGH_EM_SHIFT 8
+#define BFE_HIGH_IM_SHIFT 10
+
+#define BFE_SBBCFG 0x00000FC0 /* BFE_SB Broadcast Configuration */
+#define BFE_LAT_MASK 0x00000003 /* BFE_SB Latency */
+#define BFE_MAX0_MASK 0x000f0000 /* MAX Counter 0 */
+#define BFE_MAX1_MASK 0x00f00000 /* MAX Counter 1 */
+#define BFE_MAX0_SHIFT 16
+#define BFE_MAX1_SHIFT 20
+
+#define BFE_SBBSTATE 0x00000FC8 /* BFE_SB Broadcast State */
+#define BFE_SBBSTATE_SRD 0x00000001 /* ST Reg Disable */
+#define BFE_SBBSTATE_HRD 0x00000002 /* Hold Reg Disable */
+
+#define BFE_SBACTCNFG 0x00000FD8 /* BFE_SB Activate Configuration */
+#define BFE_SBFLAGST 0x00000FE8 /* BFE_SB Current BFE_SBFLAGS */
+
+#define BFE_SBIDLOW 0x00000FF8 /* BFE_SB Identification Low */
+#define BFE_CS_MASK 0x00000003 /* Config Space Mask */
+#define BFE_AR_MASK 0x00000038 /* Num Address Ranges Supported */
+#define BFE_SYNCH 0x00000040 /* Sync */
+#define BFE_INIT 0x00000080 /* Initiator */
+#define BFE_MINLAT_MASK 0x00000f00 /* Minimum Backplane Latency */
+#define BFE_MAXLAT_MASK 0x0000f000 /* Maximum Backplane Latency */
+#define BFE_FIRST 0x00010000 /* This Initiator is First */
+#define BFE_CW_MASK 0x000c0000 /* Cycle Counter Width */
+#define BFE_TP_MASK 0x00f00000 /* Target Ports */
+#define BFE_IP_MASK 0x0f000000 /* Initiator Ports */
+#define BFE_AR_SHIFT 3
+#define BFE_MINLAT_SHIFT 8
+#define BFE_MAXLAT_SHIFT 12
+#define BFE_CW_SHIFT 18
+#define BFE_TP_SHIFT 20
+#define BFE_IP_SHIFT 24
+
+#define BFE_SBIDHIGH 0x00000FFC /* BFE_SB Identification High */
+#define BFE_RC_MASK 0x0000000f /* Revision Code */
+#define BFE_CC_MASK 0x0000fff0 /* Core Code */
+#define BFE_VC_MASK 0xffff0000 /* Vendor Code */
+#define BFE_CC_SHIFT 4
+#define BFE_VC_SHIFT 16
+
+#define BFE_CORE_ILINE20 0x801
+#define BFE_CORE_SDRAM 0x803
+#define BFE_CORE_PCI 0x804
+#define BFE_CORE_MIPS 0x805
+#define BFE_CORE_ENET 0x806
+#define BFE_CORE_CODEC 0x807
+#define BFE_CORE_USB 0x808
+#define BFE_CORE_ILINE100 0x80a
+#define BFE_CORE_EXTIF 0x811
+
+/* SSB PCI config space registers. */
+#define BFE_BAR0_WIN 0x80
+#define BFE_BAR1_WIN 0x84
+#define BFE_SPROM_CONTROL 0x88
+#define BFE_BAR1_CONTROL 0x8c
+
+/* SSB core and hsot control registers. */
+#define BFE_SSB_CONTROL 0x00000000
+#define BFE_SSB_ARBCONTROL 0x00000010
+#define BFE_SSB_ISTAT 0x00000020
+#define BFE_SSB_IMASK 0x00000024
+#define BFE_SSB_MBOX 0x00000028
+#define BFE_SSB_BCAST_ADDR 0x00000050
+#define BFE_SSB_BCAST_DATA 0x00000054
+#define BFE_SSB_PCI_TRANS_0 0x00000100
+#define BFE_SSB_PCI_TRANS_1 0x00000104
+#define BFE_SSB_PCI_TRANS_2 0x00000108
+#define BFE_SSB_SPROM 0x00000800
+
+#define BFE_SSB_PCI_MEM 0x00000000
+#define BFE_SSB_PCI_IO 0x00000001
+#define BFE_SSB_PCI_CFG0 0x00000002
+#define BFE_SSB_PCI_CFG1 0x00000003
+#define BFE_SSB_PCI_PREF 0x00000004
+#define BFE_SSB_PCI_BURST 0x00000008
+#define BFE_SSB_PCI_MASK0 0xfc000000
+#define BFE_SSB_PCI_MASK1 0xfc000000
+#define BFE_SSB_PCI_MASK2 0xc0000000
+
+#define BFE_DESC_LEN 0x00001fff
+#define BFE_DESC_CMASK 0x0ff00000 /* Core specific bits */
+#define BFE_DESC_EOT 0x10000000 /* End of Table */
+#define BFE_DESC_IOC 0x20000000 /* Interrupt On Completion */
+#define BFE_DESC_EOF 0x40000000 /* End of Frame */
+#define BFE_DESC_SOF 0x80000000 /* Start of Frame */
+
+#define BFE_RX_CP_THRESHOLD 256
+#define BFE_RX_HEADER_LEN 28
+
+#define BFE_RX_FLAG_OFIFO 0x00000001 /* FIFO Overflow */
+#define BFE_RX_FLAG_CRCERR 0x00000002 /* CRC Error */
+#define BFE_RX_FLAG_SERR 0x00000004 /* Receive Symbol Error */
+#define BFE_RX_FLAG_ODD 0x00000008 /* Frame has odd number of nibbles */
+#define BFE_RX_FLAG_LARGE 0x00000010 /* Frame is > RX MAX Length */
+#define BFE_RX_FLAG_MCAST 0x00000020 /* Dest is Multicast Address */
+#define BFE_RX_FLAG_BCAST 0x00000040 /* Dest is Broadcast Address */
+#define BFE_RX_FLAG_MISS 0x00000080 /* Received due to promisc mode */
+#define BFE_RX_FLAG_LAST 0x00000800 /* Last buffer in frame */
+#define BFE_RX_FLAG_ERRORS (BFE_RX_FLAG_ODD | BFE_RX_FLAG_SERR | \
+ BFE_RX_FLAG_CRCERR | BFE_RX_FLAG_OFIFO)
+
+#define BFE_MCAST_TBL_SIZE 32
+#define BFE_PCI_DMA 0x40000000
+#define BFE_REG_PCI 0x18002000
+
+#define BCOM_VENDORID 0x14E4
+#define BCOM_DEVICEID_BCM4401 0x4401
+
+#define PCI_SETBIT(dev, reg, x, s) \
+ pci_write_config(dev, reg, (pci_read_config(dev, reg, s) | (x)), s)
+#define PCI_CLRBIT(dev, reg, x, s) \
+ pci_write_config(dev, reg, (pci_read_config(dev, reg, s) & ~(x)), s)
+
+#define BFE_RX_RING_SIZE 512
+#define BFE_TX_RING_SIZE 512
+#define BFE_LINK_DOWN 5
+#define BFE_TX_LIST_CNT 511
+#define BFE_RX_LIST_CNT 511
+#define BFE_TX_LIST_SIZE BFE_TX_LIST_CNT * sizeof(struct bfe_desc)
+#define BFE_RX_LIST_SIZE BFE_RX_LIST_CNT * sizeof(struct bfe_desc)
+#define BFE_RX_OFFSET 30
+#define BFE_TX_QLEN 256
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->bfe_btag, sc->bfe_bhandle, reg)
+
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->bfe_btag, sc->bfe_bhandle, reg, val)
+
+#define BFE_OR(sc, name, val) \
+ CSR_WRITE_4(sc, name, CSR_READ_4(sc, name) | val)
+
+#define BFE_AND(sc, name, val) \
+ CSR_WRITE_4(sc, name, CSR_READ_4(sc, name) & val)
+
+#define BFE_LOCK(scp) mtx_lock(&sc->bfe_mtx)
+#define BFE_UNLOCK(scp) mtx_unlock(&sc->bfe_mtx)
+
+#define BFE_INC(x, y) (x) = ((x) == ((y)-1)) ? 0 : (x)+1
+
+struct bfe_data {
+ struct mbuf *bfe_mbuf;
+ bus_dmamap_t bfe_map;
+};
+
+struct bfe_desc {
+ u_int32_t bfe_ctrl;
+ u_int32_t bfe_addr;
+};
+
+struct bfe_rxheader {
+ u_int16_t len;
+ u_int16_t flags;
+ u_int16_t pad[12];
+};
+
+struct bfe_hw_stats {
+ u_int32_t tx_good_octets, tx_good_pkts, tx_octets;
+ u_int32_t tx_pkts, tx_broadcast_pkts, tx_multicast_pkts;
+ u_int32_t tx_len_64, tx_len_65_to_127, tx_len_128_to_255;
+ u_int32_t tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max;
+ u_int32_t tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts;
+ u_int32_t tx_underruns, tx_total_cols, tx_single_cols;
+ u_int32_t tx_multiple_cols, tx_excessive_cols, tx_late_cols;
+ u_int32_t tx_defered, tx_carrier_lost, tx_pause_pkts;
+ u_int32_t __pad1[8];
+
+ u_int32_t rx_good_octets, rx_good_pkts, rx_octets;
+ u_int32_t rx_pkts, rx_broadcast_pkts, rx_multicast_pkts;
+ u_int32_t rx_len_64, rx_len_65_to_127, rx_len_128_to_255;
+ u_int32_t rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max;
+ u_int32_t rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts;
+ u_int32_t rx_missed_pkts, rx_crc_align_errs, rx_undersize;
+ u_int32_t rx_crc_errs, rx_align_errs, rx_symbol_errs;
+ u_int32_t rx_pause_pkts, rx_nonpause_pkts;
+};
+
+struct bfe_softc
+{
+ struct arpcom arpcom; /* interface info */
+ device_t bfe_dev;
+ device_t bfe_miibus;
+ bus_space_handle_t bfe_bhandle;
+ vm_offset_t bfe_vhandle;
+ bus_space_tag_t bfe_btag;
+ bus_dma_tag_t bfe_tag;
+ bus_dma_tag_t bfe_parent_tag;
+ bus_dma_tag_t bfe_tx_tag, bfe_rx_tag;
+ bus_dmamap_t bfe_tx_map, bfe_rx_map;
+ void *bfe_intrhand;
+ struct resource *bfe_irq;
+ struct resource *bfe_res;
+ struct callout_handle bfe_stat_ch;
+ struct bfe_hw_stats bfe_hwstats;
+ struct bfe_desc *bfe_tx_list, *bfe_rx_list;
+ struct bfe_data bfe_tx_ring[BFE_TX_LIST_CNT]; /* XXX */
+ struct bfe_data bfe_rx_ring[BFE_RX_LIST_CNT]; /* XXX */
+ struct mtx bfe_mtx;
+ u_int32_t bfe_flags;
+ u_int32_t bfe_imask;
+ u_int32_t bfe_dma_offset;
+ u_int32_t bfe_tx_cnt, bfe_tx_cons, bfe_tx_prod;
+ u_int32_t bfe_rx_cnt, bfe_rx_prod, bfe_rx_cons;
+ u_int32_t bfe_tx_dma, bfe_rx_dma;
+ u_int32_t bfe_link;
+ u_int8_t bfe_phyaddr; /* Address of the card's PHY */
+ u_int8_t bfe_mdc_port;
+ u_int8_t bfe_unit; /* interface number */
+ u_int8_t bfe_core_unit;
+ u_int8_t bfe_up;
+ int bfe_if_flags;
+ char *bfe_vpd_prodname;
+ char *bfe_vpd_readonly;
+};
+
+struct bfe_type
+{
+ u_int16_t bfe_vid;
+ u_int16_t bfe_did;
+ char *bfe_name;
+};
+
+#endif /* _BFE_H */
diff --git a/sys/dev/mii/bmtphy.c b/sys/dev/mii/bmtphy.c
index 988793e..df5bdc5 100644
--- a/sys/dev/mii/bmtphy.c
+++ b/sys/dev/mii/bmtphy.c
@@ -146,6 +146,9 @@ bmtphy_probe(device_t dev)
case MII_MODEL_BROADCOM_BCM5221:
device_set_desc(dev, MII_STR_BROADCOM_BCM5221);
break;
+ case MII_MODEL_BROADCOM_BCM4401:
+ device_set_desc(dev, MII_STR_BROADCOM_BCM4401);
+ break;
default:
return (ENXIO);
}
diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs
index d57c890..cf86bef 100644
--- a/sys/dev/mii/miidevs
+++ b/sys/dev/mii/miidevs
@@ -110,6 +110,7 @@ model BROADCOM 3C905B 0x0012 3c905B 10/100 internal PHY
model BROADCOM 3C905C 0x0017 3c905C 10/100 internal PHY
model BROADCOM BCM5201 0x0021 BCM5201 10/100baseTX PHY
model BROADCOM BCM5221 0x001e BCM5221 10/100baseTX PHY
+model BROADCOM BCM4401 0x0036 BCM4401 10/100baseTX PHY
model xxBROADCOM BCM5400 0x0004 Broadcom 1000baseTX PHY
model xxBROADCOM BCM5401 0x0005 BCM5401 10/100/1000baseTX PHY
model xxBROADCOM BCM5411 0x0007 BCM5411 10/100/1000baseTX PHY
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index 22c704e..a6ca703 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -187,6 +187,7 @@ device vx # 3Com 3c590, 3c595 (``Vortex'')
# PCI Ethernet NICs that use the common MII bus controller code.
# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
device miibus # MII bus support
+device bfe # Broadcom BCM440x 10/100 ethernet
device dc # DEC/Intel 21143 and various workalikes
device fxp # Intel EtherExpress PRO/100B (82557, 82558)
device pcn # AMD Am79C97x PCI 10/100 (precedence over 'lnc')
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 4904bbd..914b737 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -20,6 +20,7 @@ SUBDIR= accf_data \
ath \
aue \
axe \
+ bfe \
bge \
bridge \
cam \
diff --git a/sys/modules/bfe/Makefile b/sys/modules/bfe/Makefile
new file mode 100644
index 0000000..6fbe93a
--- /dev/null
+++ b/sys/modules/bfe/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/bfe
+
+KMOD= if_bfe
+SRCS= if_bfe.c miibus_if.h miidevs.h opt_bdg.h device_if.h bus_if.h pci_if.h
+
+.include <bsd.kmod.mk>
diff --git a/usr.sbin/sade/devices.c b/usr.sbin/sade/devices.c
index 5319f69..c34c0bc 100644
--- a/usr.sbin/sade/devices.c
+++ b/usr.sbin/sade/devices.c
@@ -85,6 +85,7 @@ static struct _devname {
{ DEVICE_TYPE_NETWORK, "an", "Aironet 4500/4800 802.11 wireless adapter" },
{ DEVICE_TYPE_NETWORK, "aue", "ADMtek USB ethernet adapter" },
{ DEVICE_TYPE_NETWORK, "axe", "ASIX Electronics USB ethernet adapter" },
+ { DEVICE_TYPE_NETWORK, "bfe", "Broadcom BCM440x PCI ethernet card" },
{ DEVICE_TYPE_NETWORK, "bge", "Broadcom BCM570x PCI gigabit ethernet card" },
{ DEVICE_TYPE_NETWORK, "cue", "CATC USB ethernet adapter" },
{ DEVICE_TYPE_NETWORK, "fpa", "DEC DEFPA PCI FDDI card" },
diff --git a/usr.sbin/sysinstall/devices.c b/usr.sbin/sysinstall/devices.c
index 5319f69..c34c0bc 100644
--- a/usr.sbin/sysinstall/devices.c
+++ b/usr.sbin/sysinstall/devices.c
@@ -85,6 +85,7 @@ static struct _devname {
{ DEVICE_TYPE_NETWORK, "an", "Aironet 4500/4800 802.11 wireless adapter" },
{ DEVICE_TYPE_NETWORK, "aue", "ADMtek USB ethernet adapter" },
{ DEVICE_TYPE_NETWORK, "axe", "ASIX Electronics USB ethernet adapter" },
+ { DEVICE_TYPE_NETWORK, "bfe", "Broadcom BCM440x PCI ethernet card" },
{ DEVICE_TYPE_NETWORK, "bge", "Broadcom BCM570x PCI gigabit ethernet card" },
{ DEVICE_TYPE_NETWORK, "cue", "CATC USB ethernet adapter" },
{ DEVICE_TYPE_NETWORK, "fpa", "DEC DEFPA PCI FDDI card" },
OpenPOWER on IntegriCloud