summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2000-02-11 14:51:51 +0000
committerJason Wright <jason@cvs.openbsd.org>2000-02-11 14:51:51 +0000
commit2c59e8bb062bad25fc115176aedafdea6ccd8da1 (patch)
tree3537f0fc36975d6625cac01420592953e907c93b /sys/dev
parent73e27c34052e023e34bf368c4d3aa63e8e0ad7fb (diff)
Intel 82452 (Pro/1000) driver from mjacob@feral.com
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/files.pci7
-rw-r--r--sys/dev/pci/if_wx.c1991
-rw-r--r--sys/dev/pci/if_wxreg.h317
-rw-r--r--sys/dev/pci/if_wxvar.h407
4 files changed, 2721 insertions, 1 deletions
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 9bdf34912f7..0f2731a08f5 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.63 2000/02/07 00:33:03 niklas Exp $
+# $OpenBSD: files.pci,v 1.64 2000/02/11 14:51:50 jason Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -238,6 +238,11 @@ device sk: ether, ifnet, ifmedia
attach sk at skc
file dev/pci/if_sk.c skc | sk
+# Intel 82452 (Pro/1000 gigabit server adapter)
+device wx: ether, ifnet, ifmedia
+attach wx at pci
+file dev/pci/if_wx.c wx
+
# PCI "universal" communication device driver, for PCI com, lpt, etc. ports
# (see documentation in the driver for what, exactly, should be supported)
device puc { port = -1 }
diff --git a/sys/dev/pci/if_wx.c b/sys/dev/pci/if_wx.c
new file mode 100644
index 00000000000..4984c0da2b9
--- /dev/null
+++ b/sys/dev/pci/if_wx.c
@@ -0,0 +1,1991 @@
+/* $OpenBSD: if_wx.c,v 1.1 2000/02/11 14:51:50 jason Exp $ */
+
+/*
+ * Copyright (c) 1999, Traakan Software
+ * 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 unmodified, 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.
+ *
+ * $FreeBSD: src/sys/pci/if_wx.c,v 1.5 2000/01/25 06:09:53 mjacob Exp $
+ */
+
+/*
+ * Intel Gigabit Ethernet (82452) Driver.
+ * Inspired by fxp driver by David Greenman for FreeBSD, and by
+ * Bill Paul's work in other FreeBSD network drivers.
+ */
+
+/*
+ * Options
+ */
+
+/*
+ * Use only every other 16 byte receive descriptor, leaving the ones
+ * in between empty. This card is most efficient at reading/writing
+ * 32 byte cache lines, so avoid all the (not working for early rev
+ * cards) MWI and/or READ/MODIFY/WRITE cycles updating one descriptor
+ * would have you do.
+ *
+ * This isn't debugged yet.
+ */
+/* #define PADDED_CELL 1 */
+/*
+ * Enable JumboGrams. This seems to work.
+ */
+/* #define WX_JUMBO 1 */
+
+/*
+ * Since the includes are a mess, they'll all be in if_wxvar.h
+ */
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <dev/pci/if_wxvar.h>
+#elif defined(__FreeBSD__)
+#include <pci/if_wxvar.h>
+#endif
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
+#endif /* __alpha__ */
+
+/*
+ * Function Prototpes, yadda yadda...
+ */
+
+static int wx_intr __P((void *));
+static void wx_handle_link_intr __P((wx_softc_t *));
+static void wx_handle_rxint __P((wx_softc_t *));
+static void wx_gc __P((wx_softc_t *));
+static void wx_start __P((struct ifnet *));
+static int wx_ioctl __P((struct ifnet *, IOCTL_CMD_TYPE, caddr_t));
+static int wx_ifmedia_upd __P((struct ifnet *));
+static void wx_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
+static int wx_init __P((void *));
+static void wx_hw_stop __P((wx_softc_t *));
+static void wx_set_addr __P((wx_softc_t *, int, u_int8_t *));
+static int wx_hw_initialize __P((wx_softc_t *));
+static void wx_stop __P((wx_softc_t *));
+static void wx_watchdog __P((struct ifnet *));
+static int wx_get_rbuf __P((wx_softc_t *, rxpkt_t *));
+static void wx_rxdma_map __P((wx_softc_t *, rxpkt_t *, struct mbuf *));
+
+static INLINE void wx_eeprom_raise_clk __P((wx_softc_t *, u_int32_t));
+static INLINE void wx_eeprom_lower_clk __P((wx_softc_t *, u_int32_t));
+static INLINE void wx_eeprom_sobits __P((wx_softc_t *, u_int16_t, u_int16_t));
+static INLINE u_int16_t wx_eeprom_sibits __P((wx_softc_t *));
+static INLINE void wx_eeprom_cleanup __P((wx_softc_t *));
+static INLINE u_int16_t wx_read_eeprom_word __P((wx_softc_t *, int));
+static void wx_read_eeprom __P((wx_softc_t *, u_int16_t *, int, int));
+
+static int wx_attach_common __P((wx_softc_t *));
+static void wx_stats_update __P((void *));
+
+static INLINE void wx_mwi_whackon __P((wx_softc_t *));
+static INLINE void wx_mwi_unwhack __P((wx_softc_t *));
+static int wx_dring_setup __P((wx_softc_t *));
+static void wx_dring_teardown __P((wx_softc_t *));
+
+#define WX_DISABLE_INT(sc) WRITE_CSR(sc, WXREG_IMCLR, WXDISABLE)
+#define WX_ENABLE_INT(sc) WRITE_CSR(sc, WXREG_IMASK, sc->wx_ienable)
+
+#define JUMBOMTU (WX_MAX_PKT_SIZE_JUMBO - sizeof (struct ether_header))
+#ifdef WX_JUMBO
+#define WX_MAXMTU JUMBOMTU
+#else
+#define WX_MAXMTU ETHERMTU
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(__BROKEN_INDIRECT_CONFIG) || defined(__OpenBSD__)
+#define MATCHARG void *
+#else
+#define MATCHARG struct cfdata *
+#endif
+
+static int wx_match __P((struct device *, MATCHARG, void *));
+static void wx_attach __P((struct device *, struct device *, void *));
+static void wx_shutdown __P((void *));
+static int wx_ether_ioctl __P((struct ifnet *, IOCTL_CMD_TYPE, caddr_t));
+static int wx_mc_setup __P((wx_softc_t *));
+#define ether_ioctl wx_ether_ioctl
+
+/*
+ * Life *should* be simple- we only read/write 32 bit values in registers.
+ * Unfortunately, some platforms define bus_space functions in a fashion
+ * such that they cannot be used as part of a for loop, for example.
+ */
+
+static INLINE u_int32_t _read_csr __P((struct wx_softc *, u_int32_t));
+static INLINE void _write_csr __P((struct wx_softc *, u_int32_t, u_int32_t));
+
+static INLINE u_int32_t _read_csr(sc, reg)
+ struct wx_softc *sc;
+ u_int32_t reg;
+{
+ return bus_space_read_4(sc->w.st, sc->w.sh, reg);
+}
+
+static INLINE void _write_csr(sc, reg, val)
+ struct wx_softc *sc;
+ u_int32_t reg;
+ u_int32_t val;
+{
+ bus_space_write_4(sc->w.st, sc->w.sh, reg, val);
+}
+
+
+
+static wx_softc_t *wxlist;
+
+struct cfattach wx_ca = {
+ sizeof (wx_softc_t), wx_match, wx_attach
+};
+
+#ifdef __OpenBSD__
+struct cfdriver wx_cd = {
+ 0, "wx", DV_IFNET
+};
+#endif
+
+/*
+ * Check if a device is an 82452.
+ */
+static int
+wx_match(parent, match, aux)
+ struct device *parent;
+ MATCHARG match;
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+ if (PCI_VENDOR(pa->pa_id) != WX_VENDOR_INTEL) {
+ return (0);
+ }
+ if (PCI_PRODUCT(pa->pa_id) != WX_PRODUCT_82452) {
+ return (0);
+ }
+ return (1);
+}
+
+static void
+wx_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ wx_softc_t *tmp, *sc = (wx_softc_t *)self;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ u_int32_t data;
+ struct ifnet *ifp;
+
+ sc->w.pci_pc = pa->pa_pc;
+ sc->w.pci_tag = pa->pa_tag;
+
+ /*
+ * Map control/status registers.
+ */
+ if (pci_mapreg_map(pa, WX_MMBA, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->w.st, &sc->w.sh, NULL, NULL)) {
+ printf(": can't map registers\n");
+ return;
+ }
+ printf(": Intel GigaBit Ethernet\n");
+
+ /*
+ * Allocate our interrupt.
+ */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: couldn't map interrupt\n", sc->wx_name);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+#if defined(__OpenBSD__)
+ sc->w.ih = pci_intr_establish(pc, ih, IPL_NET, wx_intr, sc,
+ self->dv_xname);
+#else
+ sc->w.ih = pci_intr_establish(pc, ih, IPL_NET, wx_intr, sc);
+#endif
+ if (sc->w.ih == NULL) {
+ printf("%s: couldn't establish interrupt", sc->wx_name);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ printf("%s: interrupting at %s\n", sc->wx_name, intrstr);
+ sc->revision =
+ pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0xff;
+
+ data = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
+ data &= ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT);
+ data |= (WX_CACHELINE_SIZE << PCI_CACHELINE_SHIFT);
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, data);
+
+ if (wx_attach_common(sc)) {
+ return;
+ }
+
+ printf("%s: Ethernet address %s\n",
+ sc->wx_name, ether_sprintf(sc->wx_enaddr));
+
+ ifp = &sc->wx_if;
+ bcopy(sc->wx_name, ifp->if_xname, IFNAMSIZ);
+ ifp->if_mtu = WX_MAXMTU;
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = wx_ioctl;
+ ifp->if_start = wx_start;
+ ifp->if_watchdog = wx_watchdog;
+
+ /*
+ * Attach the interface.
+ */
+ if_attach(ifp);
+#ifdef __OpenBSD__
+ ether_ifattach(ifp);
+#else
+ ether_ifattach(ifp, sc->wx_enaddr);
+#endif
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB,
+ sizeof (struct ether_header));
+#endif
+ /*
+ * Add shutdown hook so that DMA is disabled prior to reboot. Not
+ * doing do could allow DMA to corrupt kernel memory during the
+ * reboot before the driver initializes.
+ */
+ shutdownhook_establish(wx_shutdown, sc);
+
+ tmp = wxlist;
+ if (tmp) {
+ while (tmp->wx_next)
+ tmp = tmp->wx_next;
+ tmp->wx_next = sc;
+ } else {
+ wxlist = sc;
+ }
+}
+
+/*
+ * Device shutdown routine. Called at system shutdown after sync. The
+ * main purpose of this routine is to shut off receiver DMA so that
+ * kernel memory doesn't get clobbered during warmboot.
+ */
+static void
+wx_shutdown(sc)
+ void *sc;
+{
+ wx_hw_stop((wx_softc_t *) sc);
+}
+
+static int
+wx_ether_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ IOCTL_CMD_TYPE cmd;
+ caddr_t data;
+{
+ struct ifaddr *ifa = (struct ifaddr *) data;
+ int error = 0;
+ wx_softc_t *sc = SOFTC_IFP(ifp);
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ error = wx_init(sc);
+ if (error) {
+ ifp->if_flags &= ~IFF_UP;
+ break;
+ }
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+#ifdef __OpenBSD__
+ arp_ifinit(&sc->w.arpcom, ifa);
+#else
+ arp_ifinit(ifp, ifa);
+#endif
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+ if (ns_nullhost(*ina))
+ ina->x_host = *(union ns_host *)
+ LLADDR(ifp->if_sadl);
+ else
+ bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
+ ifp->if_addrlen);
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Program multicast addresses.
+ *
+ * This function must be called at splimp, but it may sleep.
+ */
+static int
+wx_mc_setup(sc)
+ wx_softc_t *sc;
+{
+ struct ifnet *ifp = &sc->wx_if;
+ struct ether_multistep step;
+ struct ether_multi *enm;
+
+ /*
+ * XXX: drain TX queue- use a tsleep/wakeup until done.
+ */
+ if (sc->tactive) {
+ return (EBUSY);
+ }
+
+ wx_stop(sc);
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ sc->all_mcasts = 1;
+ return (wx_init(sc));
+ }
+
+#ifdef __OpenBSD__
+ ETHER_FIRST_MULTI(step, &sc->w.arpcom, enm);
+#else
+ ETHER_FIRST_MULTI(step, &sc->w.ethercom, enm);
+#endif
+
+ while (enm != NULL) {
+ if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0)
+ continue;
+ if (sc->wx_nmca >= WX_RAL_TAB_SIZE-1) {
+ sc->wx_nmca = 0;
+ sc->all_mcasts = 1;
+ break;
+ }
+ bcopy(enm->enm_addrlo,
+ (void *) &sc->wx_mcaddr[sc->wx_nmca++][0], 6);
+ ETHER_NEXT_MULTI(step, enm);
+ }
+ return (wx_init(sc));
+}
+
+static INLINE void
+wx_mwi_whackon(sc)
+ wx_softc_t *sc;
+{
+ sc->wx_cmdw =
+ pci_conf_read(sc->w.pci_pc, sc->w.pci_tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(sc->w.pci_pc, sc->w.pci_tag,
+ PCI_COMMAND_STATUS_REG, sc->wx_cmdw & ~MWI);
+}
+
+static INLINE void
+wx_mwi_unwhack(sc)
+ wx_softc_t *sc;
+{
+ if (sc->wx_cmdw & MWI) {
+ pci_conf_write(sc->w.pci_pc, sc->w.pci_tag,
+ PCI_COMMAND_STATUS_REG, sc->wx_cmdw & ~MWI);
+ }
+}
+
+static int
+wx_dring_setup(sc)
+ wx_softc_t *sc;
+{
+ size_t len;
+
+ len = sizeof (wxrd_t) * WX_MAX_RDESC;
+ if (len > NBPG) {
+ printf("%s: len (%lx) over a page for the receive ring\n",
+ sc->wx_name, len);
+ return (-1);
+ }
+ len = NBPG;
+ sc->rdescriptors = (wxrd_t *) WXMALLOC(len);
+ if (sc->rdescriptors == NULL) {
+ printf("%s: could not allocate rcv descriptors\n", sc->wx_name);
+ return (-1);
+ }
+
+ if (((u_long)sc->rdescriptors) & 0xfff) {
+ printf("%s: rcv descriptors not 4KB aligned\n", sc->wx_name);
+ return (-1);
+ }
+ bzero(sc->rdescriptors, len);
+
+ len = sizeof (wxtd_t) * WX_MAX_TDESC;
+ if (len > NBPG) {
+ printf("%s: len (%lx) over a page for the xmit ring\n",
+ sc->wx_name, len);
+ return (-1);
+ }
+ len = NBPG;
+ sc->tdescriptors = (wxtd_t *) WXMALLOC(len);
+ if (sc->tdescriptors == NULL) {
+ printf("%s: could not allocate xmt descriptors\n", sc->wx_name);
+ return (-1);
+ }
+ if (((u_long)sc->tdescriptors) & 0xfff) {
+ printf("%s: xmt descriptors not 4KB aligned\n", sc->wx_name);
+ return (-1);
+ }
+ bzero(sc->tdescriptors, len);
+ return (0);
+}
+
+static void
+wx_dring_teardown(sc)
+ wx_softc_t *sc;
+{
+ if (sc->rdescriptors) {
+ WXFREE(sc->rdescriptors);
+ sc->rdescriptors = NULL;
+ }
+ if (sc->tdescriptors) {
+ WXFREE(sc->tdescriptors);
+ sc->tdescriptors = NULL;
+ }
+}
+
+#elif defined(__FreeBSD__)
+static int wx_mc_setup __P((wx_softc_t *));
+/*
+ * Program multicast addresses.
+ *
+ * This function must be called at splimp, but it may sleep.
+ */
+static int
+wx_mc_setup(sc)
+ wx_softc_t *sc;
+{
+ struct ifnet *ifp = &sc->wx_if;
+ struct ifmultiaddr *ifma;
+
+ /*
+ * XXX: drain TX queue- use a tsleep/wakeup until done.
+ */
+ if (sc->tactive) {
+ return (EBUSY);
+ }
+
+ wx_stop(sc);
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ sc->all_mcasts = 1;
+ return (wx_init(sc));
+ }
+
+ for (ifma = ifp->if_multiaddrs.lh_first, sc->wx_nmca = 0;
+ ifma != NULL; ifma = ifma->ifma_link.le_next) {
+ if (ifma->ifma_addr->sa_family != AF_LINK) {
+ continue;
+ }
+ if (sc->wx_nmca >= WX_RAL_TAB_SIZE-1) {
+ sc->wx_nmca = 0;
+ sc->all_mcasts = 1;
+ break;
+ }
+ bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ (void *) &sc->wx_mcaddr[sc->wx_nmca++][0], 6);
+ }
+ return (wx_init(sc));
+}
+
+/*
+ * Return identification string if this is device is ours.
+ */
+static wx_softc_t *wxlist;
+static int
+wx_probe(device_t dev)
+{
+ if ((pci_get_vendor(dev) == WX_VENDOR_INTEL) &&
+ (pci_get_device(dev) == WX_PRODUCT_82452)) {
+ device_set_desc(dev, "Intel GigaBit Ethernet");
+ return 0;
+ }
+ return (ENXIO);
+}
+
+static int
+wx_attach(device_t dev)
+{
+ int error = 0;
+ wx_softc_t *tmp, *sc = device_get_softc(dev);
+ struct ifnet *ifp;
+ int s;
+ u_long val;
+ int rid;
+
+ bzero(sc, sizeof (wx_softc_t));
+
+ callout_handle_init(&sc->w.sch);
+ sc->w.dev = dev;
+
+ if (getenv_int("wx_debug", &rid)) {
+ if (rid & (1 << device_get_unit(dev))) {
+ sc->wx_debug = 1;
+ }
+ }
+
+ if (getenv_int("wx_no_ilos", &rid)) {
+ if (rid & (1 << device_get_unit(dev))) {
+ sc->wx_no_ilos = 1;
+ }
+ }
+
+ if (getenv_int("wx_ilos", &rid)) {
+ if (rid & (1 << device_get_unit(dev))) {
+ sc->wx_ilos = 1;
+ }
+ }
+
+ if (getenv_int("wx_no_flow", &rid)) {
+ if (rid & (1 << device_get_unit(dev))) {
+ sc->wx_no_flow = 1;
+ }
+ }
+
+ s = splimp();
+ /*
+ * Enable bus mastering, make sure that the cache line size is right.
+ */
+ val = pci_read_config(dev, PCIR_COMMAND, 2);
+ val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
+ pci_write_config(dev, PCIR_COMMAND, val, 2);
+
+ val = pci_read_config(dev, PCIR_CACHELNSZ, 1);
+ if (val != 0x10) {
+ pci_write_config(dev, PCIR_CACHELNSZ, 0x10, 1);
+ }
+
+ /*
+ * get revision
+ */
+ sc->revision = pci_read_config(dev, PCIR_CLASS, 1);
+
+ /*
+ * Map control/status registers.
+ */
+ rid = WX_MMBA;
+ sc->w.mem = bus_alloc_resource(dev, SYS_RES_MEMORY,
+ &rid, 0, ~0, 1, RF_ACTIVE);
+ if (!sc->w.mem) {
+ device_printf(dev, "could not map memory\n");
+ error = ENXIO;
+ goto out;
+ }
+ sc->w.st = rman_get_bustag(sc->w.mem);
+ sc->w.sh = rman_get_bushandle(sc->w.mem);
+
+ rid = 0;
+ sc->w.irq = bus_alloc_resource(dev, SYS_RES_IRQ,
+ &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
+ if (sc->w.irq == NULL) {
+ device_printf(dev, "could not map interrupt\n");
+ error = ENXIO;
+ goto out;
+ }
+ error = bus_setup_intr(dev, sc->w.irq, INTR_TYPE_NET,
+ (void (*)(void *))wx_intr, sc, &sc->w.ih);
+ if (error) {
+ device_printf(dev, "could not setup irq\n");
+ goto out;
+ }
+ if (wx_attach_common(sc)) {
+ bus_teardown_intr(dev, sc->w.irq, sc->w.ih);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->w.irq);
+ bus_release_resource(dev, SYS_RES_MEMORY, WX_MMBA, sc->w.mem);
+ error = ENXIO;
+ goto out;
+ }
+ device_printf(dev, "Ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ sc->w.arpcom.ac_enaddr[0], sc->w.arpcom.ac_enaddr[1],
+ sc->w.arpcom.ac_enaddr[2], sc->w.arpcom.ac_enaddr[3],
+ sc->w.arpcom.ac_enaddr[4], sc->w.arpcom.ac_enaddr[5]);
+ (void) snprintf(sc->wx_name, sizeof (sc->wx_name) - 1, "wx%d",
+ device_get_unit(dev));
+ ifp = &sc->w.arpcom.ac_if;
+ ifp->if_unit = device_get_unit(dev);
+ ifp->if_name = "wx";
+ ifp->if_mtu = WX_MAXMTU;
+ ifp->if_output = ether_output;
+ ifp->if_baudrate = 1000000000;
+ ifp->if_init = (void (*)(void *))wx_init;
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = wx_ioctl;
+ ifp->if_start = wx_start;
+ ifp->if_watchdog = wx_watchdog;
+ if_attach(ifp);
+ ifp->if_snd.ifq_maxlen = WX_MAX_TDESC - 1;
+ ether_ifattach(ifp);
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+ tmp = wxlist;
+ if (tmp) {
+ while (tmp->wx_next)
+ tmp = tmp->wx_next;
+ tmp->wx_next = sc;
+ } else {
+ wxlist = sc;
+ }
+out:
+ splx(s);
+ return (error);
+}
+
+static int
+wx_detach(device_t dev)
+{
+ wx_softc_t *sc = device_get_softc(dev);
+ int s = splimp();
+ if_detach(&sc->w.arpcom.ac_if);
+ wx_stop(sc);
+ bus_teardown_intr(dev, sc->w.irq, sc->w.ih);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->w.irq);
+ bus_release_resource(dev, SYS_RES_MEMORY, WX_MMBA, sc->w.mem);
+ splx(s);
+ return (0);
+}
+
+static int
+wx_shutdown(device_t dev)
+{
+ wx_hw_stop((wx_softc_t *) device_get_softc(dev));
+ return (0);
+}
+
+static INLINE void
+wx_mwi_whackon(sc)
+ wx_softc_t *sc;
+{
+ sc->wx_cmdw = pci_read_config(sc->w.dev, PCIR_COMMAND, 2);
+ pci_write_config(sc->w.dev, PCIR_COMMAND, sc->wx_cmdw & ~MWI, 2);
+}
+
+static INLINE void
+wx_mwi_unwhack(sc)
+ wx_softc_t *sc;
+{
+ if (sc->wx_cmdw & MWI) {
+ pci_write_config(sc->w.dev, PCIR_COMMAND, sc->wx_cmdw, 2);
+ }
+}
+
+static int
+wx_dring_setup(sc)
+ wx_softc_t *sc;
+{
+ size_t len;
+
+ len = sizeof (wxrd_t) * WX_MAX_RDESC;
+ sc->rdescriptors = (wxrd_t *)
+ contigmalloc(len, M_DEVBUF, M_NOWAIT, 0, ~0, 4096, 0);
+ if (sc->rdescriptors == NULL) {
+ printf("%s: could not allocate rcv descriptors\n", sc->wx_name);
+ return (-1);
+ }
+ if (((u_long)sc->rdescriptors) & 0xfff) {
+ printf("%s: rcv descriptors not 4KB aligned\n", sc->wx_name);
+ return (-1);
+ }
+ bzero(sc->rdescriptors, len);
+
+ len = sizeof (wxtd_t) * WX_MAX_TDESC;
+ sc->tdescriptors = (wxtd_t *)
+ contigmalloc(len, M_DEVBUF, M_NOWAIT, 0, ~0, 4096, 0);
+ if (sc->tdescriptors == NULL) {
+ printf("%s: could not allocate xmt descriptors\n", sc->wx_name);
+ return (-1);
+ }
+ if (((u_long)sc->tdescriptors) & 0xfff) {
+ printf("%s: xmt descriptors not 4KB aligned\n", sc->wx_name);
+ return (-1);
+ }
+ bzero(sc->tdescriptors, len);
+ return (0);
+}
+
+static void
+wx_dring_teardown(sc)
+ wx_softc_t *sc;
+{
+ if (sc->rdescriptors) {
+ WXFREE(sc->rdescriptors);
+ sc->rdescriptors = NULL;
+ }
+ if (sc->tdescriptors) {
+ WXFREE(sc->tdescriptors);
+ sc->tdescriptors = NULL;
+ }
+}
+
+static device_method_t wx_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, wx_probe),
+ DEVMETHOD(device_attach, wx_attach),
+ DEVMETHOD(device_detach, wx_detach),
+ DEVMETHOD(device_shutdown, wx_shutdown),
+ { 0, 0 }
+};
+
+static driver_t wx_driver = {
+ "wx", wx_methods, sizeof(wx_softc_t),
+};
+static devclass_t wx_devclass;
+DRIVER_MODULE(if_wx, pci, wx_driver, wx_devclass, 0, 0);
+
+#endif
+
+/*
+ * Do generic parts of attach. Our registers have been mapped
+ * and our interrupt registered.
+ */
+static int
+wx_attach_common(sc)
+ wx_softc_t *sc;
+{
+ size_t len;
+ u_int32_t tmp;
+ int ll = 0;
+
+ /*
+ * First, reset the chip.
+ */
+ wx_hw_stop(sc);
+
+ /*
+ * Second, validate our EEPROM.
+ */
+
+ /* TBD */
+
+ /*
+ * Third, read eeprom for our MAC address and other things.
+ */
+ wx_read_eeprom(sc, (u_int16_t *)sc->wx_enaddr, WX_EEPROM_MAC_OFF, 3);
+
+ /*
+ * Fourth, establish some adapter parameters.
+ */
+ sc->wx_txint_delay = 128;
+ ifmedia_init(&sc->wx_media, IFM_IMASK, wx_ifmedia_upd, wx_ifmedia_sts);
+ ifmedia_add(&sc->wx_media, IFM_ETHER|IFM_1000_SX, 0, NULL);
+ ifmedia_add(&sc->wx_media, IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL);
+ ifmedia_set(&sc->wx_media, IFM_ETHER|IFM_1000_SX|IFM_FDX);
+ sc->wx_media.ifm_media = sc->wx_media.ifm_cur->ifm_media;
+ ll += 1;
+
+ /*
+ * Fifth, establish a default device control register word.
+ */
+ sc->wx_dcr = 0;
+ if (sc->wx_cfg1 & WX_EEPROM_CTLR1_FD)
+ sc->wx_dcr |= WXDCR_FD;
+ if (sc->wx_cfg1 & WX_EEPROM_CTLR1_ILOS)
+ sc->wx_dcr |= WXDCR_ILOS;
+
+ tmp = (sc->wx_cfg1 >> WX_EEPROM_CTLR1_SWDPIO_SHIFT) & WXDCR_SWDPIO_MASK;
+ sc->wx_dcr |= (tmp << WXDCR_SWDPIO_SHIFT);
+
+ if (sc->wx_no_ilos)
+ sc->wx_dcr &= ~WXDCR_ILOS;
+ if (sc->wx_ilos)
+ sc->wx_dcr |= WXDCR_ILOS;
+ if (sc->wx_no_flow == 0)
+ sc->wx_dcr |= WXDCR_RFCE | WXDCR_TFCE;
+
+
+ /*
+ * Sixth, allocate various sw structures...
+ */
+ len = sizeof (rxpkt_t) * WX_MAX_RDESC;
+ sc->rbase = (rxpkt_t *) WXMALLOC(len);
+ if (sc->rbase == NULL) {
+ goto fail;
+ }
+ bzero(sc->rbase, len);
+ ll += 1;
+
+ len = sizeof (txpkt_t) * WX_MAX_TDESC;
+ sc->tbase = (txpkt_t *) WXMALLOC(len);
+ if (sc->tbase == NULL) {
+ goto fail;
+ }
+ bzero(sc->tbase, len);
+ ll += 1;
+
+ /*
+ * Seventh, allocate and dma map (platform dependent) descriptor rings.
+ * They have to be aligned on a 4KB boundary.
+ */
+ if (wx_dring_setup(sc) == 0) {
+ return (0);
+ }
+
+fail:
+ printf("%s: failed to do common attach (%d)\n", sc->wx_name, ll);
+ wx_dring_teardown(sc);
+ if (sc->rbase) {
+ WXFREE(sc->rbase);
+ sc->rbase = NULL;
+ }
+ if (sc->tbase) {
+ WXFREE(sc->tbase);
+ sc->tbase = NULL;
+ }
+ return (ENOMEM);
+}
+
+/*
+ * EEPROM functions.
+ */
+
+static INLINE void
+wx_eeprom_raise_clk(sc, regval)
+ wx_softc_t *sc;
+ u_int32_t regval;
+{
+ WRITE_CSR(sc, WXREG_EECDR, regval | WXEECD_SK);
+ DELAY(50);
+}
+
+static INLINE void
+wx_eeprom_lower_clk(sc, regval)
+ wx_softc_t *sc;
+ u_int32_t regval;
+{
+ WRITE_CSR(sc, WXREG_EECDR, regval & ~WXEECD_SK);
+ DELAY(50);
+}
+
+static INLINE void
+wx_eeprom_sobits(sc, data, count)
+ wx_softc_t *sc;
+ u_int16_t data;
+ u_int16_t count;
+{
+ u_int32_t regval, mask;
+
+ mask = 1 << (count - 1);
+ regval = READ_CSR(sc, WXREG_EECDR) & ~(WXEECD_DI|WXEECD_DO);
+
+ do {
+ if (data & mask)
+ regval |= WXEECD_DI;
+ else
+ regval &= ~WXEECD_DI;
+ WRITE_CSR(sc, WXREG_EECDR, regval); DELAY(50);
+ wx_eeprom_raise_clk(sc, regval);
+ wx_eeprom_lower_clk(sc, regval);
+ mask >>= 1;
+ } while (mask != 0);
+ WRITE_CSR(sc, WXREG_EECDR, regval & ~WXEECD_DI);
+}
+
+
+static INLINE u_int16_t
+wx_eeprom_sibits(sc)
+ wx_softc_t *sc;
+{
+ unsigned int regval, i;
+ u_int16_t data;
+
+ data = 0;
+ regval = READ_CSR(sc, WXREG_EECDR) & ~(WXEECD_DI|WXEECD_DO);
+ for (i = 0; i != 16; i++) {
+ data <<= 1;
+ wx_eeprom_raise_clk(sc, regval);
+ regval = READ_CSR(sc, WXREG_EECDR) & ~WXEECD_DI;
+ if (regval & WXEECD_DO) {
+ data |= 1;
+ }
+ wx_eeprom_lower_clk(sc, regval);
+ }
+ return (data);
+}
+
+
+
+static INLINE void
+wx_eeprom_cleanup(sc)
+ wx_softc_t *sc;
+{
+ u_int32_t regval;
+ regval = READ_CSR(sc, WXREG_EECDR) & ~(WXEECD_DI|WXEECD_CS);
+ WRITE_CSR(sc, WXREG_EECDR, regval); DELAY(50);
+ wx_eeprom_raise_clk(sc, regval);
+ wx_eeprom_lower_clk(sc, regval);
+}
+
+static u_int16_t INLINE
+wx_read_eeprom_word(sc, offset)
+ wx_softc_t *sc;
+ int offset;
+{
+ u_int16_t data;
+ WRITE_CSR(sc, WXREG_EECDR, WXEECD_CS);
+ wx_eeprom_sobits(sc, EEPROM_READ_OPCODE, 3);
+ wx_eeprom_sobits(sc, offset, 6);
+ data = wx_eeprom_sibits(sc);
+ wx_eeprom_cleanup(sc);
+ return (data);
+}
+
+static void
+wx_read_eeprom(sc, data, offset, words)
+ wx_softc_t *sc;
+ u_int16_t *data;
+ int offset;
+ int words;
+{
+ int i;
+ for (i = 0; i < words; i++) {
+ *data++ = wx_read_eeprom_word(sc, offset++);
+ }
+ sc->wx_cfg1 = wx_read_eeprom_word(sc, WX_EEPROM_CTLR1_OFF);
+}
+
+/*
+ * Start packet transmission on the interface.
+ */
+
+static void
+wx_start(ifp)
+ struct ifnet *ifp;
+{
+ wx_softc_t *sc = SOFTC_IFP(ifp);
+ u_int16_t cidx, nactv;
+
+ nactv = sc->tactive;
+ while (nactv < WX_MAX_TDESC) {
+ int ndesc;
+ int gctried = 0;
+ struct mbuf *m, *mb_head;
+
+ IF_DEQUEUE(&ifp->if_snd, mb_head);
+ if (mb_head == NULL) {
+ break;
+ }
+ sc->wx_xmitwanted++;
+
+ /*
+ * If we have a packet less than ethermin, pad it out.
+ */
+ if (mb_head->m_pkthdr.len < WX_MIN_RPKT_SIZE) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ m_freem(mb_head);
+ break;
+ }
+ m_copydata(mb_head, 0, mb_head->m_pkthdr.len,
+ mtod(m, caddr_t));
+ m->m_pkthdr.len = m->m_len = WX_MIN_RPKT_SIZE;
+ bzero(mtod(m, char *) + mb_head->m_pkthdr.len,
+ WX_MIN_RPKT_SIZE - mb_head->m_pkthdr.len);
+ sc->wx_xmitpullup++;
+ m_freem(mb_head);
+ mb_head = m;
+ }
+again:
+ cidx = sc->tnxtfree;
+ nactv = sc->tactive;
+
+
+ /*
+ * Go through each of the mbufs in the chain and initialize
+ * the transmit buffer descriptors with the physical address
+ * and size of that mbuf. If we have a length less than our
+ * minimum transmit size, we bail (to do a pullup). If we run
+ * out of descriptors, we also bail and try and do a pullup.
+ */
+ for (ndesc = 0, m = mb_head; m != NULL; m = m->m_next) {
+ vm_offset_t vptr;
+ wxtd_t *td;
+
+ /*
+ * If this mbuf has no data, skip it.
+ */
+ if (m->m_len == 0) {
+ continue;
+ }
+
+ /*
+ * If this packet is too small for the chip's minimum,
+ * break out to to cluster it.
+ */
+ if (m->m_len < WX_MIN_RPKT_SIZE) {
+ sc->wx_xmitrunt++;
+ break;
+ }
+
+ /*
+ * Do we have a descriptor available for this mbuf?
+ */
+ if (++nactv == WX_MAX_TDESC) {
+ if (gctried++ == 0) {
+ sc->wx_xmitgc++;
+ wx_gc(sc);
+ goto again;
+ }
+ break;
+ }
+ sc->tbase[cidx].dptr = m;
+ td = &sc->tdescriptors[cidx];
+ td->length = m->m_len;
+
+ vptr = mtod(m, vm_offset_t);
+ td->address.highpart = 0;
+ td->address.lowpart = vtophys(vptr);
+
+ td->cso = 0;
+ td->status = 0;
+ td->special = 0;
+ td->cmd = 0;
+ td->css = 0;
+
+ if (sc->wx_debug) {
+ printf("%s: XMIT[%d] %p vptr %lx (length %d "
+ "DMA addr %x) idx %d\n", sc->wx_name,
+ ndesc, m, (long) vptr, td->length,
+ td->address.lowpart, cidx);
+ }
+ ndesc++;
+ cidx = T_NXT_IDX(cidx);
+ }
+
+ /*
+ * If we get here and m is NULL, we can send
+ * the the packet chain described by mb_head.
+ */
+ if (m == NULL) {
+ /*
+ * Mark the last descriptor with EOP and tell the
+ * chip to insert a final checksum.
+ */
+ wxtd_t *td = &sc->tdescriptors[T_PREV_IDX(cidx)];
+ td->cmd = TXCMD_EOP|TXCMD_IFCS;
+
+ sc->tbase[sc->tnxtfree].sidx = sc->tnxtfree;
+ sc->tbase[sc->tnxtfree].eidx = cidx;
+ sc->tbase[sc->tnxtfree].next = NULL;
+ if (sc->tbsyf) {
+ sc->tbsyl->next = &sc->tbase[sc->tnxtfree];
+ } else {
+ sc->tbsyf = &sc->tbase[sc->tnxtfree];
+ }
+ sc->tbsyl = &sc->tbase[sc->tnxtfree];
+ sc->tnxtfree = cidx;
+ sc->tactive = nactv;
+ ifp->if_timer = 10;
+ WRITE_CSR(sc, WXREG_TDT, cidx);
+ if (ifp->if_bpf)
+ bpf_mtap(WX_BPFTAP_ARG(ifp), mb_head);
+ continue;
+ }
+
+ /*
+ * Otherwise, we couldn't send this packet for some reason.
+ *
+ * If don't have a descriptor available, and this is a
+ * single mbuf packet, freeze output so that later we
+ * can restart when we have more room. Otherwise, we'll
+ * try and cluster the request. We've already tried to
+ * garbage collect completed descriptors.
+ */
+ if (nactv == WX_MAX_TDESC && mb_head->m_next == NULL) {
+ sc->wx_xmitputback++;
+ ifp->if_flags |= IFF_OACTIVE;
+ IF_PREPEND(&ifp->if_snd, mb_head);
+ break;
+ }
+
+ /*
+ * Otherwise, it's either a fragment length somewhere in the
+ * chain that isn't at least WX_MIN_XPKT_SIZE in length or
+ * the number of fragments exceeds the number of descriptors
+ * available.
+ *
+ * We could try a variety of strategies here- if this is
+ * a length problem for single mbuf packet or a length problem
+ * for the last mbuf in a chain (we could just try and adjust
+ * it), but it's just simpler to try and cluster it.
+ */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ m_freem(mb_head);
+ break;
+ }
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ m_freem(mb_head);
+ break;
+ }
+ m_copydata(mb_head, 0, mb_head->m_pkthdr.len, mtod(m, caddr_t));
+ m->m_pkthdr.len = m->m_len = mb_head->m_pkthdr.len;
+ m_freem(mb_head);
+ mb_head = m;
+ sc->wx_xmitcluster++;
+ goto again;
+ }
+
+ if (sc->tactive == WX_MAX_TDESC) {
+ sc->wx_xmitblocked++;
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+}
+
+/*
+ * Process interface interrupts.
+ */
+static int
+wx_intr(arg)
+ void *arg;
+{
+ wx_softc_t *sc = arg;
+ int claimed = 0;
+
+ /*
+ * Read interrupt cause register. Reading it clears bits.
+ */
+ sc->wx_icr = READ_CSR(sc, WXREG_ICR);
+ if (sc->wx_icr) {
+ claimed++;
+ WX_DISABLE_INT(sc);
+ sc->wx_intr++;
+ if (sc->wx_icr & (WXISR_LSC|WXISR_RXSEQ)) {
+ wx_handle_link_intr(sc);
+ }
+ wx_handle_rxint(sc);
+ if (sc->tactive) {
+ wx_gc(sc);
+ }
+ if (sc->wx_if.if_snd.ifq_head != NULL) {
+ wx_start(&sc->wx_if);
+ }
+ WX_ENABLE_INT(sc);
+ }
+ return (claimed);
+}
+
+static void
+wx_handle_link_intr(sc)
+ wx_softc_t *sc;
+{
+ sc->wx_linkintr++;
+ printf("%s: link intr 0x%x\n", sc->wx_name, sc->wx_icr);
+}
+
+static void
+wx_handle_rxint(sc)
+ wx_softc_t *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m0, *mb, *pending[WX_MAX_RDESC];
+ struct ifnet *ifp = &sc->wx_if;
+ int npkts, ndesc, lidx, idx, tlen;
+
+ for (m0 = sc->rpending, tlen = ndesc = npkts = 0, idx = sc->rnxt,
+ lidx = R_PREV_IDX(idx); ndesc < WX_MAX_RDESC;
+ ndesc++, lidx = idx, idx = R_NXT_IDX(idx)) {
+ wxrd_t *rd;
+ rxpkt_t *rxpkt;
+ int length, offset, lastframe;
+
+ rd = &sc->rdescriptors[idx];
+ if ((rd->status & RDSTAT_DD) == 0) {
+ if (m0) {
+ if (sc->rpending == NULL) {
+ m0->m_pkthdr.len = tlen;
+ sc->rpending = m0;
+ } else {
+ m_freem(m0);
+ }
+ m0 = NULL;
+ }
+ if (sc->wx_debug) {
+ printf("WXRX: ndesc %d idx %d lidx %d\n",
+ ndesc, idx, lidx);
+ }
+ break;
+ }
+
+ if (rd->errors != 0) {
+ printf("%s: packet with errors (%x)\n",
+ sc->wx_name, rd->errors);
+ rd->status = 0;
+ ifp->if_ierrors++;
+ if (m0) {
+ m_freem(m0);
+ m0 = NULL;
+ if (sc->rpending) {
+ m_freem(sc->rpending);
+ sc->rpending = NULL;
+ }
+ }
+ continue;
+ }
+
+
+ rxpkt = &sc->rbase[idx];
+ mb = rxpkt->dptr;
+ if (mb == NULL) {
+ printf("%s: receive descriptor with no mbuf\n",
+ sc->wx_name);
+ (void) wx_get_rbuf(sc, rxpkt);
+ rd->status = 0;
+ ifp->if_ierrors++;
+ if (m0) {
+ m_freem(m0);
+ m0 = NULL;
+ if (sc->rpending) {
+ m_freem(sc->rpending);
+ sc->rpending = NULL;
+ }
+ }
+ continue;
+ }
+
+ /* XXX: Flush DMA for rxpkt */
+
+ if (wx_get_rbuf(sc, rxpkt)) {
+ sc->wx_rxnobuf++;
+ wx_rxdma_map(sc, rxpkt, mb);
+ ifp->if_ierrors++;
+ rd->status = 0;
+ if (m0) {
+ m_freem(m0);
+ m0 = NULL;
+ if (sc->rpending) {
+ m_freem(sc->rpending);
+ sc->rpending = NULL;
+ }
+ }
+ continue;
+ }
+
+ /*
+ * Save the completing packet's offset value and length
+ * and install the new one into the descriptor.
+ */
+ lastframe = (rd->status & RDSTAT_EOP) != 0;
+ length = rd->length;
+ offset = rd->address.lowpart & 0xff;
+ bzero (rd, sizeof (*rd));
+ rd->address.lowpart = rxpkt->dma_addr + WX_RX_OFFSET_VALUE;
+
+ mb->m_len = length;
+ mb->m_data += offset;
+ mb->m_next = NULL;
+ if (m0 == NULL) {
+ m0 = mb;
+ tlen = length;
+ } else if (m0 == sc->rpending) {
+ /*
+ * Pick up where we left off before. If
+ * we have an offset (we're assuming the
+ * first frame has an offset), then we've
+ * lost sync somewhere along the line.
+ */
+ if (offset) {
+ printf("%s: lost sync with partial packet\n",
+ sc->wx_name);
+ m_freem(sc->rpending);
+ sc->rpending = NULL;
+ m0 = mb;
+ tlen = length;
+ } else {
+ sc->rpending = NULL;
+ tlen = m0->m_pkthdr.len;
+ }
+ } else {
+ tlen += length;
+ }
+
+ if (sc->wx_debug) {
+ printf("%s: RDESC[%d] len %d off %d lastframe %d\n",
+ sc->wx_name, idx, mb->m_len, offset, lastframe);
+ }
+ if (m0 != mb)
+ m_cat(m0, mb);
+ if (lastframe == 0) {
+ continue;
+ }
+ m0->m_pkthdr.rcvif = ifp;
+ m0->m_pkthdr.len = tlen - WX_CRC_LENGTH;
+ mb->m_len -= WX_CRC_LENGTH;
+
+#ifdef __OpenBSD__
+ pending[npkts++] = m0;
+#else
+ eh = mtod(m0, struct ether_header *);
+ if ((ifp->if_flags & IFF_PROMISC) &&
+ (bcmp(eh->ether_dhost, sc->wx_enaddr, ETHER_ADDR_LEN) &&
+ (eh->ether_dhost[0] & 1) == 0)) {
+ m_freem(m0);
+ if (sc->rpending) {
+ m_freem(sc->rpending);
+ sc->rpending = NULL;
+ }
+ } else {
+ pending[npkts++] = m0;
+ }
+#endif
+ m0 = NULL;
+ tlen = 0;
+ }
+
+ if (ndesc) {
+ WRITE_CSR(sc, WXREG_RDT0, lidx);
+ sc->rnxt = idx;
+ }
+
+ if (npkts) {
+ sc->wx_rxintr++;
+ }
+
+ for (idx = 0; idx < npkts; idx++) {
+ mb = pending[idx];
+ if (ifp->if_bpf) {
+ bpf_mtap(WX_BPFTAP_ARG(ifp), mb);
+ }
+ ifp->if_ipackets++;
+ if (sc->wx_debug) {
+ printf("%s: RECV packet length %d\n",
+ sc->wx_name, mb->m_pkthdr.len);
+ }
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ eh = mtod(mb, struct ether_header *);
+ m_adj(mb, sizeof (struct ether_header));
+ ether_input(ifp, eh, mb);
+#else
+ (*ifp->if_input)(ifp, mb);
+#endif
+ }
+}
+
+static void
+wx_gc(sc)
+ wx_softc_t *sc;
+{
+ struct ifnet *ifp = &sc->wx_if;
+ txpkt_t *txpkt = sc->tbsyf;
+ u_int32_t tdh = READ_CSR(sc, WXREG_TDH);
+ int s;
+
+ s = splimp();
+ while (txpkt != NULL) {
+ u_int32_t end = txpkt->eidx, cidx = tdh;
+
+ /*
+ * Normalize start..end indices to 2 *
+ * WX_MAX_TDESC range to eliminate wrap.
+ */
+ if (txpkt->eidx < txpkt->sidx) {
+ end += WX_MAX_TDESC;
+ }
+
+ /*
+ * Normalize current chip index to 2 *
+ * WX_MAX_TDESC range to eliminate wrap.
+ */
+ if (cidx < txpkt->sidx) {
+ cidx += WX_MAX_TDESC;
+ }
+
+ /*
+ * If the current chip index is between low and
+ * high indices for this packet, it's not finished
+ * transmitting yet. Because transmits are done FIFO,
+ * this means we're done garbage collecting too.
+ */
+
+ if (txpkt->sidx <= cidx && cidx < txpkt->eidx) {
+ if (sc->wx_debug) {
+ printf("%s: TXGC %d..%d TDH %d\n", sc->wx_name,
+ txpkt->sidx, txpkt->eidx, tdh);
+ }
+ break;
+ }
+ ifp->if_opackets++;
+
+ if (txpkt->dptr) {
+ (void) m_freem(txpkt->dptr);
+ } else {
+ printf("%s: null mbuf in gc\n", sc->wx_name);
+ }
+
+ for (cidx = txpkt->sidx; cidx != txpkt->eidx;
+ cidx = T_NXT_IDX(cidx)) {
+ txpkt_t *tmp;
+ wxtd_t *td;
+
+ td = &sc->tdescriptors[cidx];
+ if (td->status & TXSTS_EC) {
+ printf("%s: excess collisions\n", sc->wx_name);
+ ifp->if_collisions++;
+ ifp->if_oerrors++;
+ }
+ if (td->status & TXSTS_LC) {
+ printf("%s: lost carrier\n", sc->wx_name);
+ ifp->if_oerrors++;
+ }
+ tmp = &sc->tbase[cidx];
+ if (sc->wx_debug) {
+ printf("%s: TXGC[%d] %p %d..%d done nact %d "
+ "TDH %d\n", sc->wx_name, cidx, tmp->dptr,
+ txpkt->sidx, txpkt->eidx, sc->tactive, tdh);
+ }
+ tmp->dptr = NULL;
+ if (sc->tactive == 0) {
+ printf("%s: nactive < 0?\n", sc->wx_name);
+ } else {
+ sc->tactive -= 1;
+ }
+ bzero(td, sizeof (*td));
+ }
+ sc->tbsyf = txpkt->next;
+ txpkt = sc->tbsyf;
+ }
+ if (sc->tactive < WX_MAX_TDESC) {
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+ splx(s);
+}
+
+/*
+ * Update packet in/out/collision statistics.
+ */
+static void
+wx_stats_update(arg)
+ void *arg;
+{
+ wx_softc_t *sc = arg;
+ int s;
+
+ s = splimp();
+ wx_gc(sc);
+ splx(s);
+
+ /*
+ * Schedule another timeout one second from now.
+ */
+ TIMEOUT(sc, wx_stats_update, sc, hz);
+}
+
+/*
+ * Stop and reinitialize the hardware
+ */
+static void
+wx_hw_stop(sc)
+ wx_softc_t *sc;
+{
+ u_int32_t icr;
+ if (sc->revision == 2) {
+ wx_mwi_whackon(sc);
+ }
+ WRITE_CSR(sc, WXREG_DCR, WXDCR_RST);
+ DELAY(20 * 1000);
+ WRITE_CSR(sc, WXREG_IMASK, ~0);
+ icr = READ_CSR(sc, WXREG_ICR);
+ if (sc->revision == 2) {
+ wx_mwi_unwhack(sc);
+ }
+ WX_DISABLE_INT(sc);
+}
+
+static void
+wx_set_addr(sc, idx, mac)
+ wx_softc_t *sc;
+ int idx;
+ u_int8_t *mac;
+{
+ u_int32_t t0, t1;
+ t0 = (mac[0]) | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
+ t1 = (mac[4] << 0) | (mac[5] << 8);
+ t1 |= WX_RAL_AV;
+ WRITE_CSR(sc, WXREG_RAL_LO(idx), t0);
+ WRITE_CSR(sc, WXREG_RAL_HI(idx), t1);
+}
+
+static int
+wx_hw_initialize(sc)
+ wx_softc_t *sc;
+{
+ int i;
+
+ WRITE_CSR(sc, WXREG_VET, 0);
+ for (i = 0; i < (WX_VLAN_TAB_SIZE << 2); i += 4) {
+ WRITE_CSR(sc, (WXREG_VFTA + i), 0);
+ }
+ if (sc->revision == 2) {
+ wx_mwi_whackon(sc);
+ WRITE_CSR(sc, WXREG_RCTL, WXRCTL_RST);
+ DELAY(5 * 1000);
+ }
+ /*
+ * Load the first receiver address with our MAC address,
+ * and load as many multicast addresses as can fit into
+ * the receive address array.
+ */
+ wx_set_addr(sc, 0, sc->wx_enaddr);
+ for (i = 1; i <= sc->wx_nmca; i++) {
+ if (i >= WX_RAL_TAB_SIZE) {
+ break;
+ } else {
+ wx_set_addr(sc, i, sc->wx_mcaddr[i-1]);
+ }
+ }
+
+ while (i < WX_RAL_TAB_SIZE) {
+ WRITE_CSR(sc, WXREG_RAL_LO(i), 0);
+ WRITE_CSR(sc, WXREG_RAL_HI(i), 0);
+ i++;
+ }
+
+ if (sc->revision == 2) {
+ WRITE_CSR(sc, WXREG_RCTL, 0);
+ DELAY(1 * 1000);
+ wx_mwi_unwhack(sc);
+ }
+
+ /*
+ * Clear out the hashed multicast table array.
+ */
+ for (i = 0; i < WX_MC_TAB_SIZE; i++) {
+ WRITE_CSR(sc, WXREG_MTA + (sizeof (u_int32_t) * 4), 0);
+ }
+ if (sc->wx_dcr & (WXDCR_RFCE|WXDCR_TFCE)) {
+ WRITE_CSR(sc, WXREG_FCAL, FC_FRM_CONST_LO);
+ WRITE_CSR(sc, WXREG_FCAH, FC_FRM_CONST_HI);
+ WRITE_CSR(sc, WXREG_FCT, FC_TYP_CONST);
+ } else {
+ WRITE_CSR(sc, WXREG_FCAL, 0);
+ WRITE_CSR(sc, WXREG_FCAH, 0);
+ WRITE_CSR(sc, WXREG_FCT, 0);
+ }
+ WRITE_CSR(sc, WXREG_FLOW_XTIMER, WX_XTIMER_DFLT);
+ if (sc->revision == 2) {
+ WRITE_CSR(sc, WXREG_FLOW_RCV_HI, 0);
+ WRITE_CSR(sc, WXREG_FLOW_RCV_LO, 0);
+ } else {
+ WRITE_CSR(sc, WXREG_FLOW_RCV_HI, WX_RCV_FLOW_HI_DFLT);
+ WRITE_CSR(sc, WXREG_FLOW_RCV_LO, WX_RCV_FLOW_LO_DFLT);
+ }
+ WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT);
+ WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr);
+ DELAY(50 * 1000);
+
+ /*
+ * The pin stuff is all FM from the Linux driver.
+ */
+ if ((READ_CSR(sc, WXREG_DCR) & WXDCR_SWDPIN1) == 0) {
+ for (i = 0; i < 500; i++) {
+ DELAY(10 * 1000);
+ if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) {
+ sc->linkup = 1;
+ break;
+ }
+ }
+ } else {
+ printf("%s: swdpio did not clear\n", sc->wx_name);
+ return (-1);
+ }
+ if (sc->linkup == 0) {
+ printf("%s: link never came up\n", sc->wx_name);
+ return (-1);
+ }
+ sc->wx_ienable = WXIENABLE_DEFAULT;
+ return (0);
+}
+
+/*
+ * Stop the interface. Cancels the statistics updater and resets the interface.
+ */
+static void
+wx_stop(sc)
+ wx_softc_t *sc;
+{
+ txpkt_t *txp;
+ rxpkt_t *rxp;
+ struct ifnet *ifp = &sc->wx_if;
+
+ /*
+ * Cancel stats updater.
+ */
+ UNTIMEOUT(wx_stats_update, sc, sc);
+
+ /*
+ * Reset the chip
+ */
+ wx_hw_stop(sc);
+
+ /*
+ * Release any xmit buffers.
+ */
+ for (txp = sc->tbase; txp && txp < &sc->tbase[WX_MAX_TDESC]; txp++) {
+ if (txp->dptr) {
+ m_free(txp->dptr);
+ txp->dptr = NULL;
+ }
+ }
+
+ /*
+ * Free all the receive buffers.
+ */
+ for (rxp = sc->rbase; rxp && rxp < &sc->rbase[WX_MAX_RDESC]; rxp++) {
+ if (rxp->dptr) {
+ m_free(rxp->dptr);
+ rxp->dptr = NULL;
+ }
+ }
+
+ if (sc->rpending) {
+ m_freem(sc->rpending);
+ sc->rpending = NULL;
+ }
+
+ /*
+ * And we're outta here...
+ */
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ ifp->if_timer = 0;
+}
+
+/*
+ * Watchdog/transmission transmit timeout handler.
+ */
+static void
+wx_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ wx_softc_t *sc = SOFTC_IFP(ifp);
+ printf("%s: device timeout\n", sc->wx_name);
+ ifp->if_oerrors++;
+ if (wx_init(sc)) {
+ printf("%s: could not re-init device\n", sc->wx_name);
+ VTIMEOUT(sc, (void (*)(void *))wx_init, sc, hz);
+ }
+}
+
+static int
+wx_init(xsc)
+ void *xsc;
+{
+ struct ifmedia *ifm;
+ wx_softc_t *sc = xsc;
+ struct ifnet *ifp = &sc->wx_if;
+ rxpkt_t *rxpkt;
+ wxrd_t *rd;
+ size_t len;
+ int s, i, bflags;
+
+ s = splimp();
+
+ /*
+ * Cancel any pending I/O by resetting things.
+ * wx_stop will free any allocated mbufs.
+ */
+ wx_stop(sc);
+
+ /*
+ * Reset the hardware. All network addresses loaded here, but
+ * neither the receiver nor the transmitter are enabled.
+ */
+
+ if (wx_hw_initialize(sc)) {
+ return (EIO);
+ }
+
+ /*
+ * Set up the receive ring stuff.
+ */
+ len = sizeof (wxrd_t) * WX_MAX_RDESC;
+ bzero(sc->rdescriptors, len);
+ for (rxpkt = sc->rbase, i = 0; rxpkt != NULL && i < WX_MAX_RDESC;
+ i += RXINCR, rxpkt++) {
+ rd = &sc->rdescriptors[i];
+ if (wx_get_rbuf(sc, rxpkt)) {
+ break;
+ }
+ rd->address.lowpart = rxpkt->dma_addr + WX_RX_OFFSET_VALUE;
+ }
+ if (i != WX_MAX_RDESC) {
+ printf("%s: could not set up rbufs\n", sc->wx_name);
+ wx_stop(sc);
+ return (ENOMEM);
+ }
+
+ /*
+ * Set up transmit parameters and enable the transmitter.
+ */
+ sc->tnxtfree = sc->tactive = 0;
+ sc->tbsyf = sc->tbsyl = NULL;
+ WRITE_CSR(sc, WXREG_TCTL, 0);
+ DELAY(5 * 1000);
+ WRITE_CSR(sc, WXREG_TDBA_LO,
+ vtophys((vm_offset_t)&sc->tdescriptors[0]));
+ WRITE_CSR(sc, WXREG_TDBA_HI, 0);
+ WRITE_CSR(sc, WXREG_TDLEN, WX_MAX_TDESC * sizeof (wxtd_t));
+ WRITE_CSR(sc, WXREG_TDH, 0);
+ WRITE_CSR(sc, WXREG_TDT, 0);
+ WRITE_CSR(sc, WXREG_TQSA_HI, 0);
+ WRITE_CSR(sc, WXREG_TQSA_LO, 0);
+ WRITE_CSR(sc, WXREG_TIPG, WX_TIPG_DFLT);
+ WRITE_CSR(sc, WXREG_TIDV, sc->wx_txint_delay);
+ WRITE_CSR(sc, WXREG_TCTL, (WXTCTL_CT(WX_COLLISION_THRESHOLD) |
+ WXTCTL_COLD(WX_FDX_COLLISION_DX) | WXTCTL_EN));
+ /*
+ * Set up receive parameters and enable the receiver.
+ */
+
+ sc->rnxt = 0;
+ WRITE_CSR(sc, WXREG_RCTL, 0);
+ DELAY(5 * 1000);
+ WRITE_CSR(sc, WXREG_RDTR0, WXRDTR_FPD);
+ WRITE_CSR(sc, WXREG_RDBA0_LO,
+ vtophys((vm_offset_t)&sc->rdescriptors[0]));
+ WRITE_CSR(sc, WXREG_RDBA0_HI, 0);
+ WRITE_CSR(sc, WXREG_RDLEN0, WX_MAX_RDESC * sizeof (wxrd_t));
+ WRITE_CSR(sc, WXREG_RDH0, 0);
+ WRITE_CSR(sc, WXREG_RDT0, (WX_MAX_RDESC - RXINCR));
+ WRITE_CSR(sc, WXREG_RDTR1, 0);
+ WRITE_CSR(sc, WXREG_RDBA1_LO, 0);
+ WRITE_CSR(sc, WXREG_RDBA1_HI, 0);
+ WRITE_CSR(sc, WXREG_RDLEN1, 0);
+ WRITE_CSR(sc, WXREG_RDH1, 0);
+ WRITE_CSR(sc, WXREG_RDT1, 0);
+
+ if (ifp->if_mtu > ETHERMTU) {
+ printf("%s: enabling for jumbo packets\n", sc->wx_name);
+ bflags = WXRCTL_EN | WXRCTL_LPE | WXRCTL_2KRBUF;
+ } else {
+ bflags = WXRCTL_EN | WXRCTL_2KRBUF;
+ }
+
+ WRITE_CSR(sc, WXREG_RCTL, bflags |
+ ((ifp->if_flags & IFF_BROADCAST) ? WXRCTL_BAM : 0) |
+ ((ifp->if_flags & IFF_PROMISC) ? WXRCTL_UPE : 0) |
+ ((sc->all_mcasts) ? WXRCTL_MPE : 0));
+
+ /*
+ * Enable Interrupts
+ */
+ WX_ENABLE_INT(sc);
+
+ /*
+ * Mark that we're up and running...
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ ifm = &sc->wx_media;
+ i = ifm->ifm_media;
+ ifm->ifm_media = ifm->ifm_cur->ifm_media;
+ wx_ifmedia_upd(ifp);
+ ifm->ifm_media = i;
+ splx(s);
+
+ /*
+ * Start stats updater.
+ */
+ TIMEOUT(sc, wx_stats_update, sc, hz);
+
+ /*
+ * And we're outta here...
+ */
+ return (0);
+}
+
+/*
+ * Get a receive buffer for our use (and dma map the data area).
+ *
+ * This chip can have buffers be 256, 512, 1024 or 2048 bytes in size.
+ * It wants them aligned on 256 byte boundaries, but can actually cope
+ * with an offset in the first 255 bytes of the head of a receive frame.
+ *
+ * We'll allocate a MCLBYTE sized cluster but *not* adjust the data pointer
+ * by any alignment value. Instead, we'll tell the chip to offset by any
+ * alignment and we'll catch the alignment on the backend at interrupt time.
+ */
+static void
+wx_rxdma_map(sc, rxpkt, mb)
+ wx_softc_t *sc;
+ rxpkt_t *rxpkt;
+ struct mbuf *mb;
+{
+ rxpkt->dptr = mb;
+ rxpkt->dma_addr = vtophys(mtod(mb, vm_offset_t));
+}
+
+static int
+wx_get_rbuf(sc, rxpkt)
+ wx_softc_t *sc;
+ rxpkt_t *rxpkt;
+{
+ struct mbuf *mb;
+ MGETHDR(mb, M_DONTWAIT, MT_DATA);
+ if (mb == NULL) {
+ rxpkt->dptr = NULL;
+ return (-1);
+ }
+ MCLGET(mb, M_DONTWAIT);
+ if ((mb->m_flags & M_EXT) == 0) {
+ m_freem(mb);
+ rxpkt->dptr = NULL;
+ return (-1);
+ }
+ wx_rxdma_map(sc, rxpkt, mb);
+ return (0);
+}
+
+static int
+wx_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ IOCTL_CMD_TYPE command;
+ caddr_t data;
+{
+ wx_softc_t *sc = SOFTC_IFP(ifp);
+ struct ifreq *ifr = (struct ifreq *) data;
+ int s, error = 0;
+
+ s = splimp();
+ switch (command) {
+ case SIOCSIFADDR:
+#if !defined(__NetBSD__) && !defined(__OpenBSD__)
+ case SIOCGIFADDR:
+#endif
+ error = ether_ioctl(ifp, command, data);
+ break;
+
+#if defined(SIOCSIFMTU) && !defined(__OpenBSD__)
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu > WX_MAXMTU || ifr->ifr_mtu < ETHERMIN) {
+ error = EINVAL;
+ } else if (ifp->if_mtu != ifr->ifr_mtu) {
+ ifp->if_mtu = ifr->ifr_mtu;
+ error = wx_init(sc);
+ }
+ break;
+#endif
+
+ case SIOCSIFFLAGS:
+ sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
+
+ /*
+ * If interface is marked up and not running, then start it.
+ * If it is marked down and running, stop it.
+ * If it's up then re-initialize it. This is so flags
+ * such as IFF_PROMISC are handled.
+ */
+ if (ifp->if_flags & IFF_UP) {
+ error = wx_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING) {
+ wx_stop(sc);
+ }
+ }
+ break;
+
+#ifdef SIOCADDMULTI
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+#if defined(__NetBSD__)
+ {
+ int all_mc_change = (sc->all_mcasts ==
+ ((ifp->if_flags & IFF_ALLMULTI) ? 1 : 0));
+ error = (command == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->w.ethercom) :
+ ether_delmulti(ifr, &sc->w.ethercom);
+ if (error != ENETRESET && all_mc_change == 0) {
+ break;
+ }
+ }
+#endif
+ sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
+ error = wx_mc_setup(sc);
+ break;
+#endif
+#ifdef SIOCGIFMEDIA
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->wx_media, command);
+ break;
+#endif
+ default:
+ error = EINVAL;
+ }
+
+ (void) splx(s);
+ return (error);
+}
+
+static int
+wx_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct wx_softc *sc = SOFTC_IFP(ifp);
+ struct ifmedia *ifm = &sc->wx_media;
+
+ if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+ return (EINVAL);
+ return (0);
+}
+
+static void
+wx_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct wx_softc *sc = SOFTC_IFP(ifp);
+
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER;
+
+ if (sc->linkup == 0)
+ return;
+
+ ifmr->ifm_status |= IFM_ACTIVE|IFM_1000_SX;
+ if (READ_CSR(sc, WXREG_DSR) & WXDSR_FD)
+ ifmr->ifm_active |= IFM_FDX;
+}
diff --git a/sys/dev/pci/if_wxreg.h b/sys/dev/pci/if_wxreg.h
new file mode 100644
index 00000000000..a19c855fd1d
--- /dev/null
+++ b/sys/dev/pci/if_wxreg.h
@@ -0,0 +1,317 @@
+/* $OpenBSD: if_wxreg.h,v 1.1 2000/02/11 14:51:50 jason Exp $ */
+
+/*
+ * Copyright (c) 1999, Traakan Software
+ * 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 unmodified, 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.
+ *
+ * $FreeBSD: src/sys/pci/if_wxreg.h,v 1.3 2000/01/25 04:11:33 mjacob Exp $
+ */
+
+#define WX_VENDOR_INTEL 0x8086
+#define WX_PRODUCT_82452 0x1000
+#define WX_MMBA 0x10
+#define MWI 0x10 /* Memory Write Invalidate */
+#define WX_CACHELINE_SIZE 0x20
+
+/*
+ * Information about this chipset gathered from a released Intel Linux driver,
+ * which was clearly a port of an NT driver.
+ */
+
+/*
+ * Various Descriptor Structures.
+ * These are all in little endian format (for now).
+ */
+
+typedef struct {
+ u_int32_t lowpart;
+ u_int32_t highpart;
+} wxpa_t, wxrp_t;
+
+/*
+ * Receive Descriptor.
+ * The base address of a receive descriptor ring must be on a 4KB boundary,
+ * and they must be allocated in multiples of 8.
+ */
+typedef struct {
+ wxpa_t address; /* physical address of buffer */
+ u_int16_t length;
+ u_int16_t csum;
+ u_int8_t status;
+ u_int8_t errors;
+ u_int16_t special;
+} wxrd_t;
+
+#define RDSTAT_DD 0x1 /* descriptor done */
+#define RDSTAT_EOP 0x2 /* end of packet */
+#define RDSTAT_RSVD 0x74 /* reserved bits */
+
+#define RDERR_CRC 0x1 /* CRC Error */
+#define RDERR_SE 0x2 /* Symbol Error */
+#define RDERR_SEQ 0x4 /* Sequence Error */
+
+/*
+ * Transmit Descriptor
+ * The base address of a transmit descriptor ring must be on a 4KB boundary,
+ * and they must be allocated in multiples of 8.
+ */
+typedef struct {
+ wxpa_t address;
+ u_int16_t length;
+ u_int8_t cso; /* checksum offset */
+ u_int8_t cmd; /* cmd */
+ u_int8_t status; /* status */
+ u_int8_t css; /* checksum start */
+ u_int16_t special;
+} wxtd_t;
+
+#define TXCMD_EOP 0x1 /* last packet */
+#define TXCMD_IFCS 0x2 /* insert FCS */
+#define TXCMD_IC 0x4 /* insert checksum */
+#define TXCMD_RS 0x8 /* report status */
+#define TXCMD_RPS 0x10 /* report packet sent */
+#define TXCMD_SM 0x20 /* symbol mode */
+#define TXCMD_IDE 0x80 /* interrupt delay enable */
+
+#define TXSTS_DD 0x1 /* descriptor done */
+#define TXSTS_EC 0x2 /* excess collisions */
+#define TXSTS_LC 0x4 /* late collision */
+
+/*
+ * This device can only be accessed via memory space.
+ */
+/*
+ * Register access via offsets.
+ */
+
+#define WXREG_DCR 0x00000000
+#define WXREG_DSR 0x00000008
+#define WXREG_EECDR 0x00000010
+#define WXREG_FCAL 0x00000028
+#define WXREG_FCAH 0x0000002C
+#define WXREG_FCT 0x00000030
+#define WXREG_VET 0x00000038
+#define WXREG_RAL_BASE 0x00000040
+#define WXREG_RAL_LO(x) (WXREG_RAL_BASE + ((x) << 3))
+#define WXREG_RAL_HI(x) (WXREG_RAL_LO(x) + 4)
+#define WXREG_ICR 0x000000c0
+#define WXREG_ICS 0x000000c8
+#define WXREG_IMASK 0x000000d0
+#define WXREG_IMCLR 0x000000d8
+#define WXREG_RCTL 0x00000100
+#define WXREG_RDTR0 0x00000108
+#define WXREG_RDBA0_LO 0x00000110
+#define WXREG_RDBA0_HI 0x00000114
+#define WXREG_RDLEN0 0x00000118
+#define WXREG_RDH0 0x00000120
+#define WXREG_RDT0 0x00000128
+#define WXREG_RDTR1 0x00000130
+#define WXREG_RDBA1_LO 0x00000138
+#define WXREG_RDBA1_HI 0x0000013C
+#define WXREG_RDLEN1 0x00000140
+#define WXREG_RDH1 0x00000148
+#define WXREG_RDT1 0x00000150
+#define WXREG_FLOW_RCV_HI 0x00000160
+#define WXREG_FLOW_RCV_LO 0x00000168
+#define WXREG_FLOW_XTIMER 0x00000170
+#define WXREG_XMIT_CFGW 0x00000178
+#define WXREG_RECV_CFGW 0x00000180
+#define WXREG_MTA 0x00000200
+#define WXREG_TCTL 0x00000400
+#define WXREG_TQSA_LO 0x00000408
+#define WXREG_TQSA_HI 0x0000040C
+#define WXREG_TIPG 0x00000410
+#define WXREG_TQC 0x00000418
+#define WXREG_TDBA_LO 0x00000420
+#define WXREG_TDBA_HI 0x00000424
+#define WXREG_TDLEN 0x00000428
+#define WXREG_TDH 0x00000430
+#define WXREG_TDT 0x00000438
+#define WXREG_TIDV 0x00000440
+#define WXREG_VFTA 0x00000600
+
+#define WX_RAL_TAB_SIZE 16
+#define WX_RAL_AV 0x80000000
+
+#define WX_MC_TAB_SIZE 128
+#define WX_VLAN_TAB_SIZE 128
+
+/*
+ * Device Control Register Defines
+ */
+#define WXDCR_FD 0x1 /* full duplex */
+#define WXDCR_BEM 0x2 /* big endian mode */
+#define WXDCR_FAIR 0x4 /* 1->Fairness, 0->Receive Priority */
+#define WXDCR_LRST 0x8 /* Link Reset */
+#define WXDCR_SLU 0x40 /* Set Link Up */
+#define WXDCR_ILOS 0x80 /* Invert Loss-of-Signal */
+
+#define WXDCR_SWDPINS_SHIFT 18
+#define WXDCR_SWDPINS_MASK 0xf
+#define WXDCR_SWDPIN0 (1 << 18)
+#define WXDCR_SWDPIN1 (1 << 19)
+#define WXDCR_SWDPIN2 (1 << 20)
+#define WXDCR_SWDPIN3 (1 << 21)
+#define WXDCR_SWDPIO_SHIFT 22
+#define WXDCR_SWDPIO_MASK 0xf
+#define WXDCR_SWDPIO0 (1 << 22)
+#define WXDCR_SWDPIO1 (1 << 23)
+#define WXDCR_SWDPIO2 (1 << 24)
+#define WXDCR_SWDPIO3 (1 << 25)
+
+#define WXDCR_RST 0x04000000 /* Device Reset (self clearing) */
+#define WXDCR_RFCE 0x08000000 /* Receive Flow Control Enable */
+#define WXDCR_TFCE 0x10000000 /* Transmit Flow Control Enable */
+#define WXDCR_RTE 0x20000000 /* Routing Tag Enable */
+#define WXDCR_VME 0x40000000 /* VLAN Mode Enable */
+
+/*
+ * Device Status Register Defines
+ */
+#define WXDSR_FD 0x1 /* full duplex */
+#define WXDSR_LU 0x2 /* link up */
+#define WXDSR_TXCLK 0x4 /* transmit clock running */
+#define WXDSR_RBCLK 0x8 /* receive clock running */
+#define WXDSR_TXOFF 0x10 /* transmit paused */
+
+/*
+ * EEPROM Register Defines
+ */
+#define WXEECD_SK 0x1 /* enable clock */
+#define WXEECD_CS 0x2 /* chip select */
+#define WXEECD_DI 0x4 /* data input */
+#define WXEECD_DO 0x8 /* data output */
+
+#define EEPROM_READ_OPCODE 0x6
+
+/*
+ * Constant Flow Control Frame MAC Address and Type values.
+ */
+#define FC_FRM_CONST_LO 0x00C28001
+#define FC_FRM_CONST_HI 0x0100
+#define FC_TYP_CONST 0x8808
+
+/*
+ * Bits pertinent for the Receive Address register pairs. The low address
+ * is the low 32 bits of a 48 bit MAC address. The high address contains
+ * bits 32-47 of the 48 bit MAC address. The top bit in the high address
+ * is a 'valid' bit.
+ */
+#define WXRAH_RDR1 0x40000000 /* second receive descriptor ring */
+#define WXRAH_VALID 0x80000000
+
+/*
+ * Interrupt Cause Bits
+ */
+#define WXISR_TXDW 0x1 /* transmit descriptor written back */
+#define WXISR_TXQE 0x2 /* transmit queue empty */
+#define WXISR_LSC 0x4 /* link status change */
+#define WXISR_RXSEQ 0x8 /* receive sequence error */
+#define WXISR_RXDMT0 0x10 /* receiver ring 0 getting empty */
+#define WXISR_RXO 0x40 /* receiver overrun */
+#define WXISR_RXT0 0x80 /* ring 0 receiver timer interrupt */
+#define WXISR_PCIE 0x200 /* ?? Probably PCI interface error... */
+
+#define WXIENABLE_DEFAULT \
+ (WXISR_RXO|WXISR_RXT0|WXISR_RXDMT0|WXISR_RXSEQ|WXISR_LSC|WXISR_PCIE)
+
+#define WXDISABLE 0xffffffff
+
+/*
+ * Receive Control Register bits.
+ */
+
+#define WXRCTL_RST 0x1 /* receiver reset */
+#define WXRCTL_EN 0x2 /* receiver enable */
+#define WXRCTL_SBP 0x4 /* store bad packets */
+#define WXRCTL_UPE 0x8 /* unicast promiscuos mode */
+#define WXRCTL_MPE 0x10 /* multicast promiscuous mode */
+#define WXRCTL_LPE 0x20 /* large packet enable */
+#define WXRCTL_BAM 0x8000 /* broadcast accept mode */
+
+#define WXRCTL_2KRBUF (0 << 16) /* 2-Kbyte Receive Buffers */
+#define WXRCTL_1KRBUF (1 << 16) /* 1-Kbyte Receive Buffers */
+#define WXRCTL_512BRBUF (2 << 16) /* 512 Byte Receive Buffers */
+#define WXRCTL_256BRBUF (3 << 16) /* 256 Byte Receive Buffers */
+
+
+/*
+ * Receive Delay Timer Register bits.
+ */
+#define WXRDTR_FPD 0x80000000 /* flush partial descriptor */
+
+/*
+ * Transmit Configuration Word defines
+ */
+#define WXTXCW_FD 0x00000020 /* Full Duplex */
+#define WXTXCW_PMASK 0x00000180 /* pause mask */
+#define WXTXCW_ANE 0x80000000 /* AutoNegotiate */
+#define WXTXCW_DEFAULT 0x800001A0
+
+/*
+ * Transmit Control Register defines.
+ */
+#define WXTCTL_RST 0x1 /* transmitter reset */
+#define WXTCTL_EN 0x2 /* transmitter enable */
+#define WXTCTL_PSP 0x8 /* pad short packets */
+#define WXTCTL_CT(x) (((x) & 0xff) << 4) /* 4:11 - Collision Threshold */
+#define WXTCTL_COLD(x) (((x) & 0x3ff) << 12) /* 12:21 - Collision Distance */
+#define WXTCTL_SWXOFF (1 << 22) /* Software XOFF */
+
+#define WX_COLLISION_THRESHOLD 15
+#define WX_FDX_COLLISION_DX 64
+#define WX_HDX_COLLISION_DX 512
+
+/*
+ * Miscellaneous
+ */
+#define WX_EEPROM_MAC_OFF 0
+
+/*
+ * Offset for Initialization Control Word #1
+ */
+#define WX_EEPROM_CTLR1_OFF 0xA
+#define WX_EEPROM_CTLR1_FD (1 << 10)
+#define WX_EEPROM_CTLR1_SWDPIO_SHIFT 5
+#define WX_EEPROM_CTLR1_ILOS (1 << 4)
+
+
+#define WX_XTIMER_DFLT 0x100
+#define WX_RCV_FLOW_HI_DFLT 0x8000
+#define WX_RCV_FLOW_LO_DFLT 0x4000
+
+#define WX_TIPG_DFLT (10 | (2 << 10) | (10 << 20))
+
+#define WX_CRC_LENGTH 4
+
+
+/*
+ * Hardware cannot transmit less than 16 bytes. It also cannot
+ * successfully receive less than 60 bytes.
+ */
+#define WX_MIN_XPKT_SIZE 16
+#define WX_MIN_RPKT_SIZE 60
+#define WX_MAX_PKT_SIZE 1514
+#define WX_MAX_PKT_SIZE_JUMBO 9014
diff --git a/sys/dev/pci/if_wxvar.h b/sys/dev/pci/if_wxvar.h
new file mode 100644
index 00000000000..ece97e9eb73
--- /dev/null
+++ b/sys/dev/pci/if_wxvar.h
@@ -0,0 +1,407 @@
+/* $OpenBSD: if_wxvar.h,v 1.1 2000/02/11 14:51:50 jason Exp $ */
+
+/*
+ * Copyright (c) 1999, Traakan Software
+ * 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 unmodified, 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.
+ *
+ * $FreeBSD: src/sys/pci/if_wxvar.h,v 1.4 2000/01/23 03:18:14 mjacob Exp $
+ */
+
+/*
+ * Softc definitions for the Intel Gigabit Ethernet driver.
+ *
+ * Guidance and inspiration from David Greenman's
+ * if_fxp driver gratefully acknowledged here.
+ */
+
+/*
+ * Platform specific defines and inline functions go here.
+ * Look further below for more generic structures.
+ */
+
+#if defined(__NetBSD__)
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <net/if.h>
+#if defined(SIOCSIFMEDIA)
+#include <net/if_media.h>
+#endif
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <net/if_ether.h>
+#if defined(INET)
+#include <netinet/if_inarp.h>
+#endif
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/if_wxreg.h>
+
+struct wxmdvar {
+ struct device dev; /* generic device structures */
+ void * ih; /* interrupt handler cookie */
+ struct ethercom ethercom; /* ethernet common part */
+ pci_chipset_tag_t pci_pc;
+ pcitag_t pci_tag;
+ u_int8_t enaddr[6]; /* our mac address */
+ u_int32_t cmdw;
+ bus_space_tag_t st; /* bus space tag */
+ bus_space_handle_t sh; /* bus space handle */
+ struct ifmedia ifm;
+ struct wx_softc * next;
+};
+#define wx_dev w.dev
+#define wx_enaddr w.enaddr
+#define wx_cmdw w.cmdw
+#define wx_media w.ifm
+#define wx_next w.next
+
+#define wx_if w.ethercom.ec_if
+#define wx_name w.dev.dv_xname
+
+#define IOCTL_CMD_TYPE u_long
+#define WXMALLOC(len) malloc(len, M_DEVBUF, M_NOWAIT)
+#define WXFREE(ptr) free(ptr, M_DEVBUF)
+#define SOFTC_IFP(ifp) ifp->if_softc
+#define WX_BPFTAP_ARG(ifp) (ifp)->if_bpf
+#define TIMEOUT(sc, func, arg, time) timeout(func, arg, time)
+#define VTIMEOUT(sc, func, arg, time) timeout(func, arg, time)
+#define UNTIMEOUT(f, arg, sc) untimeout(f, arg)
+#define INLINE inline
+
+#define vm_offset_t vaddr_t
+#ifndef IFM_1000_SX
+#define IFM_1000_SX IFM_1000_FX
+#endif
+#define READ_CSR _read_csr
+#define WRITE_CSR _write_csr
+
+#elif defined(__FreeBSD__)
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+#include <net/bpf.h>
+#include <sys/sockio.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/clock.h>
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/if_wxreg.h>
+
+#include "opt_bdg.h"
+#ifdef BRIDGE
+#include <net/if_types.h>
+#include <net/bridge.h>
+#endif
+
+struct wxmdvar {
+ struct device * dev; /* backpointer to device */
+ struct arpcom arpcom; /* per-interface network data */
+ struct resource * mem; /* resource descriptor for registers */
+ struct resource * irq; /* resource descriptor for interrupt */
+ void * ih; /* interrupt handler cookie */
+ u_int16_t cmdw;
+ struct callout_handle sch; /* handle for timeouts */
+ char name[8];
+ bus_space_tag_t st; /* bus space tag */
+ bus_space_handle_t sh; /* bus space handle */
+ struct ifmedia ifm;
+ struct wx_softc * next;
+};
+#define wx_dev w.dev
+#define wx_enaddr w.arpcom.ac_enaddr
+#define wx_cmdw w.cmdw
+#define wx_media w.ifm
+#define wx_next w.next
+
+#define wx_if w.arpcom.ac_if
+#define wx_name w.name
+
+#define IOCTL_CMD_TYPE u_long
+#define WXMALLOC(len) malloc(len, M_DEVBUF, M_NOWAIT)
+#define WXFREE(ptr) free(ptr, M_DEVBUF)
+#define SOFTC_IFP(ifp) ifp->if_softc
+#define WX_BPFTAP_ARG(ifp) ifp
+#define VTIMEOUT(sc, func, arg, time) (void) timeout(func, arg, time)
+#define TIMEOUT(sc, func, arg, time) (sc)->w.sch = timeout(func, arg, time)
+#define UNTIMEOUT(f, arg, sc) untimeout(f, arg, (sc)->w.sch)
+#define INLINE __inline
+
+#define READ_CSR(sc, reg) \
+ bus_space_read_4((sc)->w.st, (sc)->w.sh, (reg))
+#define WRITE_CSR(sc, reg, val) \
+ bus_space_write_4((sc)->w.st, (sc)->w.sh, (reg), (val))
+
+#elif defined(__OpenBSD__)
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/if_wxreg.h>
+
+struct wxmdvar {
+ struct device dev; /* generic device structures */
+ void * ih; /* interrupt handler cookie */
+ struct arpcom arpcom; /* ethernet common part */
+ pci_chipset_tag_t pci_pc;
+ pcitag_t pci_tag;
+ u_int32_t cmdw;
+ bus_space_tag_t st; /* bus space tag */
+ bus_space_handle_t sh; /* bus space handle */
+ struct ifmedia ifm;
+ struct wx_softc * next;
+};
+#define wx_dev w.dev
+#define wx_enaddr w.arpcom.ac_enaddr
+#define wx_cmdw w.cmdw
+#define wx_media w.ifm
+#define wx_next w.next
+
+#define wx_if w.arpcom.ac_if
+#define wx_name w.dev.dv_xname
+
+#define IOCTL_CMD_TYPE u_long
+#define WXMALLOC(len) malloc(len, M_DEVBUF, M_NOWAIT)
+#define WXFREE(ptr) free(ptr, M_DEVBUF)
+#define SOFTC_IFP(ifp) ifp->if_softc
+#define WX_BPFTAP_ARG(ifp) (ifp)->if_bpf
+#define TIMEOUT(sc, func, arg, time) timeout(func, arg, time)
+#define VTIMEOUT(sc, func, arg, time) timeout(func, arg, time)
+#define UNTIMEOUT(f, arg, sc) untimeout(f, arg)
+#define INLINE inline
+
+#define vm_offset_t vaddr_t
+#define READ_CSR _read_csr
+#define WRITE_CSR _write_csr
+
+#endif
+
+
+/*
+ * Transmit soft descriptor, used to manage packets as they come in.
+ */
+typedef struct rxpkt {
+ struct mbuf *dptr; /* pointer to receive frame */
+ u_int32_t dma_addr; /* dma address */
+} rxpkt_t;
+
+
+/*
+ * Transmit soft descriptor, used to manage packets as they are transmitted.
+ */
+typedef struct txpkt {
+ struct txpkt *next; /* next in a chain */
+ struct mbuf *dptr; /* pointer to mbuf being sent */
+ u_int32_t sidx; /* start index */
+ u_int32_t eidx; /* end index */
+} txpkt_t;
+
+
+typedef struct wx_softc {
+ /*
+ * OS dependent storage... must be first...
+ */
+ struct wxmdvar w;
+
+ /*
+ * misc goodies
+ */
+ u_int32_t : 18,
+ wx_no_flow : 1,
+ wx_ilos : 1,
+ wx_no_ilos : 1,
+ wx_debug : 1,
+ linkup : 1,
+ all_mcasts : 1,
+ revision : 8; /* chip revision */
+
+ u_int16_t wx_cfg1;
+ u_int16_t wx_txint_delay;
+ u_int32_t wx_ienable; /* current ienable to use */
+ u_int32_t wx_dcr; /* dcr used */
+ u_int32_t wx_icr; /* last icr */
+
+ /*
+ * Statistics, soft && hard
+ */
+ u_int32_t wx_intr;
+ u_int32_t wx_linkintr;
+ u_int32_t wx_rxintr;
+ u_int32_t wx_xmitgc;
+ u_int32_t wx_xmitpullup;
+ u_int32_t wx_xmitcluster;
+ u_int32_t wx_xmitputback;
+ u_int32_t wx_xmitwanted;
+ u_int32_t wx_xmitblocked;
+ u_int32_t wx_xmitblocked1;
+ u_int32_t wx_xmitrunt;
+ u_int32_t wx_rxnobuf;
+
+ /*
+ * Soft copies of multicast addresses. We're only
+ * using (right now) the rest of the receive address
+ * registers- not the hashed multicast table.
+ */
+ u_int8_t wx_mcaddr[WX_RAL_TAB_SIZE-1][6];
+ u_int8_t wx_nmca; /* # active multicast addrs */
+
+
+ /*
+ * Receive Management
+ * We have software and shared memory rings in a buddy store format.
+ */
+ wxrd_t *rdescriptors; /* receive descriptor ring */
+ rxpkt_t *rbase; /* base of soft rdesc list */
+ u_int16_t rnxt; /* next descriptor to check */
+ u_int16_t _pad;
+ struct mbuf *rpending; /* pending partial packet */
+
+ /*
+ * Transmit Management
+ * We have software and shared memory rings in a buddy store format.
+ */
+ txpkt_t *tbase; /* base of soft soft management */
+ txpkt_t *tbsyf, *tbsyl; /* linked busy list */
+ wxtd_t *tdescriptors; /* transmit descriptor ring */
+ u_int16_t tnxtfree; /* next free index (circular) */
+ u_int16_t tactive; /* # active */
+} wx_softc_t;
+
+/*
+ * We offset the the receive frame header by two bytes so that the actual
+ * payload is 32 bit aligned. On platforms that require strict structure
+ * alignment, this means that the ethernet frame header may have to be shifted
+ * to align it at interrupt time, but because it's such a small amount
+ * (fourteen bytes) and processors have gotten pretty fast, that's okay.
+ * It may even turn out on some platforms that this doesn't have to happen.
+ */
+#define WX_RX_OFFSET_VALUE 2
+
+/*
+ * Tunable Parameters.
+ *
+ * Descriptor lengths must be in multiples of 8.
+ */
+#define WX_MAX_TDESC 256 /* number of transmit descriptors */
+#define T_NXT_IDX(x) ((x + 1) & (WX_MAX_TDESC - 1))
+#define T_PREV_IDX(x) ((x - 1) & (WX_MAX_TDESC - 1))
+#define WX_MAX_RDESC 64 /* number of receive descriptors */
+#ifdef PADDED_CELL
+#define RXINCR 2
+#else
+#define RXINCR 1
+#endif
+#define R_NXT_IDX(x) ((x + RXINCR) & (WX_MAX_RDESC - 1))
+#define R_PREV_IDX(x) ((x - RXINCR) & (WX_MAX_RDESC - 1))