split fxp into bus independent and dependent (pci) parts (cardbus to come)
authorjason <jason@openbsd.org>
Tue, 18 Apr 2000 18:44:22 +0000 (18:44 +0000)
committerjason <jason@openbsd.org>
Tue, 18 Apr 2000 18:44:22 +0000 (18:44 +0000)
sys/conf/files
sys/dev/ic/fxp.c [new file with mode: 0644]
sys/dev/ic/fxpreg.h [new file with mode: 0644]
sys/dev/ic/fxpvar.h [new file with mode: 0644]
sys/dev/pci/files.pci
sys/dev/pci/if_fxp.c [deleted file]
sys/dev/pci/if_fxp_pci.c [new file with mode: 0644]
sys/dev/pci/if_fxpreg.h [deleted file]
sys/dev/pci/if_fxpvar.h [deleted file]

index 6715a32..3ad86bd 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.157 2000/04/08 05:50:50 aaron Exp $
+#      $OpenBSD: files,v 1.158 2000/04/18 18:44:22 jason Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -116,9 +116,14 @@ file       dev/ic/rlnsubr.c        rln
 device le: ether, ifnet, ifmedia
 file   dev/ic/am7990.c         le
 
+# 3Com 3c9xx
 device xl: ether, ifnet, ifmedia, mii
 file   dev/ic/xl.c             xl
 
+# Intel EtherExpress PRO 10/100B
+device fxp: ether, ifnet, ifmedia, mii
+file   dev/ic/fxp.c            fxp
+
 # SMC 91Cxx Ethernet Controller
 device sm: ether, ifnet, ifmedia
 file   dev/ic/smc91cxx.c       sm
diff --git a/sys/dev/ic/fxp.c b/sys/dev/ic/fxp.c
new file mode 100644 (file)
index 0000000..a5adc1d
--- /dev/null
@@ -0,0 +1,1596 @@
+/*     $OpenBSD: fxp.c,v 1.1 2000/04/18 18:44:26 jason Exp $   */
+/*     $NetBSD: if_fxp.c,v 1.2 1997/06/05 02:01:55 thorpej Exp $       */
+
+/*
+ * Copyright (c) 1995, David Greenman
+ * All rights reserved.
+ *
+ * Modifications to support NetBSD:
+ * Copyright (c) 1997 Jason R. Thorpe.  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.
+ *
+ *     Id: if_fxp.c,v 1.55 1998/08/04 08:53:12 dg Exp
+ */
+
+/*
+ * Intel EtherExpress Pro/100B PCI Fast Ethernet driver
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <netinet/if_ether.h>
+
+#include <vm/vm.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/ic/fxpreg.h>
+#include <dev/ic/fxpvar.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#ifdef __alpha__               /* XXX */
+/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
+#undef vtophys
+#define        vtophys(va)     alpha_XXX_dmamap((vm_offset_t)(va))
+#endif /* __alpha__ */
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/*
+ * NOTE!  On the Alpha, we have an alignment constraint.  The
+ * card DMAs the packet immediately following the RFA.  However,
+ * the first thing in the packet is a 14-byte Ethernet header.
+ * This means that the packet is misaligned.  To compensate,
+ * we actually offset the RFA 2 bytes into the cluster.  This
+ * aligns the packet after the Ethernet header at a 32-bit
+ * boundary.  HOWEVER!  This means that the RFA is misaligned!
+ */
+#define        RFA_ALIGNMENT_FUDGE     2
+
+/*
+ * Inline function to copy a 16-bit aligned 32-bit quantity.
+ */
+static __inline void fxp_lwcopy __P((volatile u_int32_t *,
+       volatile u_int32_t *));
+static __inline void
+fxp_lwcopy(src, dst)
+       volatile u_int32_t *src, *dst;
+{
+       volatile u_int16_t *a = (u_int16_t *)src;
+       volatile u_int16_t *b = (u_int16_t *)dst;
+
+       b[0] = a[0];
+       b[1] = a[1];
+}
+
+/*
+ * Template for default configuration parameters.
+ * See struct fxp_cb_config for the bit definitions.
+ */
+static u_char fxp_cb_config_template[] = {
+       0x0, 0x0,               /* cb_status */
+       0x80, 0x2,              /* cb_command */
+       0xff, 0xff, 0xff, 0xff, /* link_addr */
+       0x16,   /*  0 */
+       0x8,    /*  1 */
+       0x0,    /*  2 */
+       0x0,    /*  3 */
+       0x0,    /*  4 */
+       0x80,   /*  5 */
+       0xb2,   /*  6 */
+       0x3,    /*  7 */
+       0x1,    /*  8 */
+       0x0,    /*  9 */
+       0x26,   /* 10 */
+       0x0,    /* 11 */
+       0x60,   /* 12 */
+       0x0,    /* 13 */
+       0xf2,   /* 14 */
+       0x48,   /* 15 */
+       0x0,    /* 16 */
+       0x40,   /* 17 */
+       0xf3,   /* 18 */
+       0x0,    /* 19 */
+       0x3f,   /* 20 */
+       0x5     /* 21 */
+};
+
+/* Supported media types. */
+struct fxp_supported_media {
+       const int       fsm_phy;        /* PHY type */
+       const int       *fsm_media;     /* the media array */
+       const int       fsm_nmedia;     /* the number of supported media */
+       const int       fsm_defmedia;   /* default media for this PHY */
+};
+
+int fxp_mediachange            __P((struct ifnet *));
+void fxp_mediastatus           __P((struct ifnet *, struct ifmediareq *));
+static inline void fxp_scb_wait        __P((struct fxp_softc *));
+void fxp_start                 __P((struct ifnet *));
+int fxp_ioctl                  __P((struct ifnet *, u_long, caddr_t));
+void fxp_init                  __P((void *));
+void fxp_stop                  __P((struct fxp_softc *, int));
+void fxp_watchdog              __P((struct ifnet *));
+int fxp_add_rfabuf             __P((struct fxp_softc *, struct mbuf *));
+int fxp_mdi_read               __P((struct device *, int, int));
+void fxp_mdi_write             __P((struct device *, int, int, int));
+void fxp_autosize_eeprom       __P((struct fxp_softc *));
+void fxp_statchg               __P((struct device *));
+void fxp_read_eeprom           __P((struct fxp_softc *, u_int16_t *,
+                                   int, int));
+void fxp_stats_update          __P((void *));
+void fxp_mc_setup              __P((struct fxp_softc *));
+
+/*
+ * Set initial transmit threshold at 64 (512 bytes). This is
+ * increased by 64 (512 bytes) at a time, to maximum of 192
+ * (1536 bytes), if an underrun occurs.
+ */
+static int tx_threshold = 64;
+
+/*
+ * Number of transmit control blocks. This determines the number
+ * of transmit buffers that can be chained in the CB list.
+ * This must be a power of two.
+ */
+#define FXP_NTXCB      128
+
+/*
+ * Number of completed TX commands at which point an interrupt
+ * will be generated to garbage collect the attached buffers.
+ * Must be at least one less than FXP_NTXCB, and should be
+ * enough less so that the transmitter doesn't becomes idle
+ * during the buffer rundown (which would reduce performance).
+ */
+#define FXP_CXINT_THRESH 120
+
+/*
+ * TxCB list index mask. This is used to do list wrap-around.
+ */
+#define FXP_TXCB_MASK  (FXP_NTXCB - 1)
+
+/*
+ * Number of receive frame area buffers. These are large so chose
+ * wisely.
+ */
+#define FXP_NRFABUFS   64
+
+/*
+ * Maximum number of seconds that the receiver can be idle before we
+ * assume it's dead and attempt to reset it by reprogramming the
+ * multicast filter. This is part of a work-around for a bug in the
+ * NIC. See fxp_stats_update().
+ */
+#define FXP_MAX_RX_IDLE        15
+
+/*
+ * Wait for the previous command to be accepted (but not necessarily
+ * completed).
+ */
+static inline void
+fxp_scb_wait(sc)
+       struct fxp_softc *sc;
+{
+       int i = 10000;
+
+       while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
+}
+
+/*************************************************************
+ * Operating system-specific autoconfiguration glue
+ *************************************************************/
+
+void fxp_attach __P((struct device *, struct device *, void *));
+
+void   fxp_shutdown __P((void *));
+void   fxp_power __P((int, void *));
+
+/* Compensate for lack of a generic ether_ioctl() */
+int    fxp_ether_ioctl __P((struct ifnet *, u_long, caddr_t));
+#define        ether_ioctl     fxp_ether_ioctl
+
+struct cfdriver fxp_cd = {
+       NULL, "fxp", DV_IFNET
+};
+
+/*
+ * 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.
+ */
+void
+fxp_shutdown(sc)
+       void *sc;
+{
+       fxp_stop((struct fxp_softc *) sc, 0);
+}
+
+/*
+ * Power handler routine. Called when the system is transitioning
+ * into/out of power save modes.  As with fxp_shutdown, the main
+ * purpose of this routine is to shut off receiver DMA so it doesn't
+ * clobber kernel memory at the wrong time.
+ */
+void
+fxp_power(why, arg)
+       int why;
+       void *arg;
+{
+       struct fxp_softc *sc = arg;
+       struct ifnet *ifp;
+       int s;
+
+       s = splnet();
+       if (why != PWR_RESUME)
+               fxp_stop(sc, 0);
+       else {
+               ifp = &sc->arpcom.ac_if;
+               if (ifp->if_flags & IFF_UP)
+                       fxp_init(sc);
+       }
+       splx(s);
+}
+
+int
+fxp_ether_ioctl(ifp, cmd, data)
+       struct ifnet *ifp;
+       u_long cmd;
+       caddr_t data;
+{
+       struct ifaddr *ifa = (struct ifaddr *) data;
+       struct fxp_softc *sc = ifp->if_softc;
+
+       switch (cmd) {
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+
+               switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       fxp_init(sc);
+                       arp_ifinit(&sc->arpcom, ifa);
+                       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);
+                        /* Set new address. */
+                        fxp_init(sc);
+                        break;
+                   }
+#endif
+               default:
+                       fxp_init(sc);
+                       break;
+               }
+               break;
+
+       default:
+               return (EINVAL);
+       }
+
+       return (0);
+}
+
+/*************************************************************
+ * End of operating system-specific autoconfiguration glue
+ *************************************************************/
+
+/*
+ * Do generic parts of attach.
+ */
+int
+fxp_attach_common(sc, enaddr, intrstr)
+       struct fxp_softc *sc;
+       u_int8_t *enaddr;
+       const char *intrstr;
+{
+       struct ifnet *ifp;
+       u_int16_t data;
+       int i;
+
+       /*
+        * Reset to a stable state.
+        */
+       CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
+       DELAY(10);
+
+       sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB,
+           M_DEVBUF, M_NOWAIT);
+       if (sc->cbl_base == NULL)
+               goto fail;
+
+       sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT);
+       if (sc->fxp_stats == NULL)
+               goto fail;
+       bzero(sc->fxp_stats, sizeof(struct fxp_stats));
+
+       sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT);
+       if (sc->mcsp == NULL)
+               goto fail;
+
+       /*
+        * Pre-allocate our receive buffers.
+        */
+       for (i = 0; i < FXP_NRFABUFS; i++) {
+               if (fxp_add_rfabuf(sc, NULL) != 0) {
+                       goto fail;
+               }
+       }
+
+       /*
+        * Find out how large of an SEEPROM we have.
+        */
+       fxp_autosize_eeprom(sc);
+
+       /*
+        * Get info about the primary PHY
+        */
+       fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);
+       sc->phy_primary_addr = data & 0xff;
+       sc->phy_primary_device = (data >> 8) & 0x3f;
+       sc->phy_10Mbps_only = data >> 15;
+
+       /*
+        * Read MAC address.
+        */
+       fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3);
+
+       ifp = &sc->arpcom.ac_if;
+       bcopy(enaddr, sc->arpcom.ac_enaddr, sizeof(enaddr));
+       bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+       ifp->if_softc = sc;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_ioctl = fxp_ioctl;
+       ifp->if_start = fxp_start;
+       ifp->if_watchdog = fxp_watchdog;
+
+       printf(": %s, address %s\n", intrstr,
+           ether_sprintf(sc->arpcom.ac_enaddr));
+
+       /*
+        * Initialize our media structures and probe the MII.
+        */
+       sc->sc_mii.mii_ifp = ifp;
+       sc->sc_mii.mii_readreg = fxp_mdi_read;
+       sc->sc_mii.mii_writereg = fxp_mdi_write;
+       sc->sc_mii.mii_statchg = fxp_statchg;
+       ifmedia_init(&sc->sc_mii.mii_media, 0, fxp_mediachange,
+           fxp_mediastatus);
+       mii_phy_probe(&sc->sc_dev, &sc->sc_mii, 0xffffffff);
+       /* If no phy found, just use auto mode */
+       if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
+               ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL,
+                   0, NULL);
+               printf("%s: no phy found, using manual mode\n",
+                   sc->sc_dev.dv_xname);
+       }
+
+       if (ifmedia_match(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL, 0))
+               ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
+       else if (ifmedia_match(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO, 0))
+               ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
+       else
+               ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_10_T);
+
+       /*
+        * Attach the interface.
+        */
+       if_attach(ifp);
+       /*
+        * Let the system queue as many packets as we have available
+        * TX descriptors.
+        */
+       ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1;
+       ether_ifattach(ifp);
+#if NBPFILTER > 0
+       bpfattach(&sc->arpcom.ac_if.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(fxp_shutdown, sc);
+
+       /*
+        * Add suspend hook, for similiar reasons..
+        */
+       powerhook_establish(fxp_power, sc);
+
+       return (0);
+
+ fail:
+       printf("%s: Failed to malloc memory\n", sc->sc_dev.dv_xname);
+       if (sc->cbl_base)
+               free(sc->cbl_base, M_DEVBUF);
+       if (sc->fxp_stats)
+               free(sc->fxp_stats, M_DEVBUF);
+       if (sc->mcsp)
+               free(sc->mcsp, M_DEVBUF);
+       /* frees entire chain */
+       if (sc->rfa_headm)
+               m_freem(sc->rfa_headm);
+
+       return (ENOMEM);
+}
+
+/*
+ * From NetBSD:
+ *
+ * Figure out EEPROM size.
+ *
+ * 559's can have either 64-word or 256-word EEPROMs, the 558
+ * datasheet only talks about 64-word EEPROMs, and the 557 datasheet
+ * talks about the existance of 16 to 256 word EEPROMs.
+ *
+ * The only known sizes are 64 and 256, where the 256 version is used
+ * by CardBus cards to store CIS information.
+ *
+ * The address is shifted in msb-to-lsb, and after the last
+ * address-bit the EEPROM is supposed to output a `dummy zero' bit,
+ * after which follows the actual data. We try to detect this zero, by
+ * probing the data-out bit in the EEPROM control register just after
+ * having shifted in a bit. If the bit is zero, we assume we've
+ * shifted enough address bits. The data-out should be tri-state,
+ * before this, which should translate to a logical one.
+ *
+ * Other ways to do this would be to try to read a register with known
+ * contents with a varying number of address bits, but no such
+ * register seem to be available. The high bits of register 10 are 01
+ * on the 558 and 559, but apparently not on the 557.
+ * 
+ * The Linux driver computes a checksum on the EEPROM data, but the
+ * value of this checksum is not very well documented.
+ */
+void
+fxp_autosize_eeprom(sc)
+       struct fxp_softc *sc;
+{
+       u_int16_t reg;
+       int x;
+
+       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+       /*
+        * Shift in read opcode.
+        */
+       for (x = 3; x > 0; x--) {
+               if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
+                       reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
+               } else {
+                       reg = FXP_EEPROM_EECS;
+               }
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+                   reg | FXP_EEPROM_EESK);
+               DELAY(1);
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+               DELAY(1);
+       }
+       /*
+        * Shift in address.
+        * Wait for the dummy zero following a correct address shift.
+        */
+       for (x = 1; x <= 8; x++) {
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+                       FXP_EEPROM_EECS | FXP_EEPROM_EESK);
+               DELAY(1);
+               if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) == 0)
+                       break;
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+               DELAY(1);
+       }
+       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+       DELAY(1);
+       sc->eeprom_size = x;
+}
+/*
+ * Read from the serial EEPROM. Basically, you manually shift in
+ * the read opcode (one bit at a time) and then shift in the address,
+ * and then you shift out the data (all of this one bit at a time).
+ * The word size is 16 bits, so you have to provide the address for
+ * every 16 bits of data.
+ */
+void
+fxp_read_eeprom(sc, data, offset, words)
+       struct fxp_softc *sc;
+       u_short *data;
+       int offset;
+       int words;
+{
+       u_int16_t reg;
+       int i, x;
+
+       for (i = 0; i < words; i++) {
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+               /*
+                * Shift in read opcode.
+                */
+               for (x = 3; x > 0; x--) {
+                       if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
+                               reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
+                       } else {
+                               reg = FXP_EEPROM_EECS;
+                       }
+                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+                           reg | FXP_EEPROM_EESK);
+                       DELAY(1);
+                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+                       DELAY(1);
+               }
+               /*
+                * Shift in address.
+                */
+               for (x = sc->eeprom_size; x > 0; x--) {
+                       if ((i + offset) & (1 << (x - 1))) {
+                               reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
+                       } else {
+                               reg = FXP_EEPROM_EECS;
+                       }
+                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+                           reg | FXP_EEPROM_EESK);
+                       DELAY(1);
+                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+                       DELAY(1);
+               }
+               reg = FXP_EEPROM_EECS;
+               data[i] = 0;
+               /*
+                * Shift out data.
+                */
+               for (x = 16; x > 0; x--) {
+                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+                           reg | FXP_EEPROM_EESK);
+                       DELAY(1);
+                       if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
+                           FXP_EEPROM_EEDO)
+                               data[i] |= (1 << (x - 1));
+                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+                       DELAY(1);
+               }
+               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+               DELAY(1);
+       }
+}
+
+/*
+ * Start packet transmission on the interface.
+ */
+void
+fxp_start(ifp)
+       struct ifnet *ifp;
+{
+       struct fxp_softc *sc = ifp->if_softc;
+       struct fxp_cb_tx *txp;
+
+       /*
+        * See if we need to suspend xmit until the multicast filter
+        * has been reprogrammed (which can only be done at the head
+        * of the command chain).
+        */
+       if (sc->need_mcsetup)
+               return;
+
+       txp = NULL;
+
+       /*
+        * We're finished if there is nothing more to add to the list or if
+        * we're all filled up with buffers to transmit.
+        * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add
+        *       a NOP command when needed.
+        */
+       while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB - 1) {
+               struct mbuf *m, *mb_head;
+               int segment;
+
+               /*
+                * Grab a packet to transmit.
+                */
+               IF_DEQUEUE(&ifp->if_snd, mb_head);
+
+               /*
+                * Get pointer to next available tx desc.
+                */
+               txp = sc->cbl_last->next;
+
+               /*
+                * Go through each of the mbufs in the chain and initialize
+                * the transmit buffer descriptors with the physical address
+                * and size of the mbuf.
+                */
+tbdinit:
+               for (m = mb_head, segment = 0; m != NULL; m = m->m_next) {
+                       if (m->m_len != 0) {
+                               if (segment == FXP_NTXSEG)
+                                       break;
+                               txp->tbd[segment].tb_addr =
+                                   vtophys(mtod(m, vm_offset_t));
+                               txp->tbd[segment].tb_size = m->m_len;
+                               segment++;
+                       }
+               }
+               if (m != NULL) {
+                       struct mbuf *mn;
+
+                       /*
+                        * We ran out of segments. We have to recopy this mbuf
+                        * chain first. Bail out if we can't get the new buffers.
+                        */
+                       MGETHDR(mn, M_DONTWAIT, MT_DATA);
+                       if (mn == NULL) {
+                               m_freem(mb_head);
+                               break;
+                       }
+                       if (mb_head->m_pkthdr.len > MHLEN) {
+                               MCLGET(mn, M_DONTWAIT);
+                               if ((mn->m_flags & M_EXT) == 0) {
+                                       m_freem(mn);
+                                       m_freem(mb_head);
+                                       break;
+                               }
+                       }
+                       m_copydata(mb_head, 0, mb_head->m_pkthdr.len,
+                           mtod(mn, caddr_t));
+                       mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len;
+                       m_freem(mb_head);
+                       mb_head = mn;
+                       goto tbdinit;
+               }
+
+               txp->tbd_number = segment;
+               txp->mb_head = mb_head;
+               txp->cb_status = 0;
+               if (sc->tx_queued != FXP_CXINT_THRESH - 1) {
+                       txp->cb_command =
+                           FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S;
+               } else {
+                       txp->cb_command =
+                           FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;
+                       /*
+                        * Set a 5 second timer just in case we don't hear from the
+                        * card again.
+                        */
+                       ifp->if_timer = 5;
+               }
+               txp->tx_threshold = tx_threshold;
+       
+               /*
+                * Advance the end of list forward.
+                */
+               sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;
+               sc->cbl_last = txp;
+
+               /*
+                * Advance the beginning of the list forward if there are
+                * no other packets queued (when nothing is queued, cbl_first
+                * sits on the last TxCB that was sent out).
+                */
+               if (sc->tx_queued == 0)
+                       sc->cbl_first = txp;
+
+               sc->tx_queued++;
+
+#if NBPFILTER > 0
+               /*
+                * Pass packet to bpf if there is a listener.
+                */
+               if (ifp->if_bpf)
+                       bpf_mtap(ifp->if_bpf, mb_head);
+#endif
+       }
+
+       /*
+        * We're finished. If we added to the list, issue a RESUME to get DMA
+        * going again if suspended.
+        */
+       if (txp != NULL) {
+               fxp_scb_wait(sc);
+               CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
+       }
+}
+
+/*
+ * Process interface interrupts.
+ */
+int
+fxp_intr(arg)
+       void *arg;
+{
+       struct fxp_softc *sc = arg;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       u_int8_t statack;
+       int claimed = 0;
+
+       /*
+        * If the interface isn't running, don't try to
+        * service the interrupt.. just ack it and bail.
+        */
+       if ((ifp->if_flags & IFF_RUNNING) == 0) {
+               statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK);
+               if (statack) {
+                       claimed = 1;
+                       CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
+               }
+               return claimed;
+       }
+
+       while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
+               claimed = 1;
+               /*
+                * First ACK all the interrupts in this pass.
+                */
+               CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
+
+               /*
+                * Free any finished transmit mbuf chains.
+                */
+               if (statack & FXP_SCB_STATACK_CXTNO) {
+                       struct fxp_cb_tx *txp;
+
+                       for (txp = sc->cbl_first; sc->tx_queued &&
+                           (txp->cb_status & FXP_CB_STATUS_C) != 0;
+                           txp = txp->next) {
+                               if (txp->mb_head != NULL) {
+                                       m_freem(txp->mb_head);
+                                       txp->mb_head = NULL;
+                               }
+                               sc->tx_queued--;
+                       }
+                       sc->cbl_first = txp;
+                       ifp->if_timer = 0;
+                       if (sc->tx_queued == 0) {
+                               if (sc->need_mcsetup)
+                                       fxp_mc_setup(sc);
+                       }
+                       /*
+                        * Try to start more packets transmitting.
+                        */
+                       if (ifp->if_snd.ifq_head != NULL)
+                               fxp_start(ifp);
+               }
+               /*
+                * Process receiver interrupts. If a no-resource (RNR)
+                * condition exists, get whatever packets we can and
+                * re-start the receiver.
+                */
+               if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) {
+                       struct mbuf *m;
+                       u_int8_t *rfap;
+rcvloop:
+                       m = sc->rfa_headm;
+                       rfap = m->m_ext.ext_buf + RFA_ALIGNMENT_FUDGE;
+
+                       if (*(u_int16_t *)(rfap +
+                           offsetof(struct fxp_rfa, rfa_status)) &
+                           FXP_RFA_STATUS_C) {
+                               /*
+                                * Remove first packet from the chain.
+                                */
+                               sc->rfa_headm = m->m_next;
+                               m->m_next = NULL;
+
+                               /*
+                                * Add a new buffer to the receive chain.
+                                * If this fails, the old buffer is recycled
+                                * instead.
+                                */
+                               if (fxp_add_rfabuf(sc, m) == 0) {
+                                       struct ether_header *eh;
+                                       u_int16_t total_len;
+
+                                       total_len = *(u_int16_t *)(rfap +
+                                           offsetof(struct fxp_rfa,
+                                           actual_size)) &
+                                           (MCLBYTES - 1);
+                                       if (total_len <
+                                           sizeof(struct ether_header)) {
+                                               m_freem(m);
+                                               goto rcvloop;
+                                       }
+                                       m->m_pkthdr.rcvif = ifp;
+                                       m->m_pkthdr.len = m->m_len =
+                                           total_len -
+                                           sizeof(struct ether_header);
+                                       eh = mtod(m, struct ether_header *);
+#if NBPFILTER > 0
+                                       if (ifp->if_bpf)
+                                               bpf_tap(ifp->if_bpf,
+                                                   mtod(m, caddr_t),
+                                                   total_len); 
+#endif /* NBPFILTER > 0 */
+                                       m->m_data +=
+                                           sizeof(struct ether_header);
+                                       ether_input(ifp, eh, m);
+                               }
+                               goto rcvloop;
+                       }
+                       if (statack & FXP_SCB_STATACK_RNR) {
+                               fxp_scb_wait(sc);
+                               CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
+                                   vtophys(sc->rfa_headm->m_ext.ext_buf) +
+                                       RFA_ALIGNMENT_FUDGE);
+                               CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
+                                   FXP_SCB_COMMAND_RU_START);
+                       }
+               }
+       }
+       return (claimed);
+}
+
+/*
+ * Update packet in/out/collision statistics. The i82557 doesn't
+ * allow you to access these counters without doing a fairly
+ * expensive DMA to get _all_ of the statistics it maintains, so
+ * we do this operation here only once per second. The statistics
+ * counters in the kernel are updated from the previous dump-stats
+ * DMA and then a new dump-stats DMA is started. The on-chip
+ * counters are zeroed when the DMA completes. If we can't start
+ * the DMA immediately, we don't wait - we just prepare to read
+ * them again next time.
+ */
+void
+fxp_stats_update(arg)
+       void *arg;
+{
+       struct fxp_softc *sc = arg;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       struct fxp_stats *sp = sc->fxp_stats;
+       int s;
+
+       ifp->if_opackets += sp->tx_good;
+       ifp->if_collisions += sp->tx_total_collisions;
+       if (sp->rx_good) {
+               ifp->if_ipackets += sp->rx_good;
+               sc->rx_idle_secs = 0;
+       } else {
+               sc->rx_idle_secs++;
+       }
+       ifp->if_ierrors +=
+           sp->rx_crc_errors +
+           sp->rx_alignment_errors +
+           sp->rx_rnr_errors +
+           sp->rx_overrun_errors;
+       /*
+        * If any transmit underruns occured, bump up the transmit
+        * threshold by another 512 bytes (64 * 8).
+        */
+       if (sp->tx_underruns) {
+               ifp->if_oerrors += sp->tx_underruns;
+               if (tx_threshold < 192)
+                       tx_threshold += 64;
+       }
+       s = splimp();
+       /*
+        * If we haven't received any packets in FXP_MAC_RX_IDLE seconds,
+        * then assume the receiver has locked up and attempt to clear
+        * the condition by reprogramming the multicast filter. This is
+        * a work-around for a bug in the 82557 where the receiver locks
+        * up if it gets certain types of garbage in the syncronization
+        * bits prior to the packet header. This bug is supposed to only
+        * occur in 10Mbps mode, but has been seen to occur in 100Mbps
+        * mode as well (perhaps due to a 10/100 speed transition).
+        */
+       if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) {
+               sc->rx_idle_secs = 0;
+               fxp_mc_setup(sc);
+       }
+       /*
+        * If there is no pending command, start another stats
+        * dump. Otherwise punt for now.
+        */
+       if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) {
+               /*
+                * Start another stats dump.
+                */
+               CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
+                   FXP_SCB_COMMAND_CU_DUMPRESET);
+       } else {
+               /*
+                * A previous command is still waiting to be accepted.
+                * Just zero our copy of the stats and wait for the
+                * next timer event to update them.
+                */
+               sp->tx_good = 0;
+               sp->tx_underruns = 0;
+               sp->tx_total_collisions = 0;
+
+               sp->rx_good = 0;
+               sp->rx_crc_errors = 0;
+               sp->rx_alignment_errors = 0;
+               sp->rx_rnr_errors = 0;
+               sp->rx_overrun_errors = 0;
+       }
+
+       /* Tick the MII clock. */
+       mii_tick(&sc->sc_mii);
+
+       splx(s);
+       /*
+        * Schedule another timeout one second from now.
+        */
+       timeout(fxp_stats_update, sc, hz);
+}
+
+/*
+ * Stop the interface. Cancels the statistics updater and resets
+ * the interface.
+ */
+void
+fxp_stop(sc, drain)
+       struct fxp_softc *sc;
+       int drain;
+{
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       struct fxp_cb_tx *txp;
+       int i;
+
+       /*
+        * Turn down interface (done early to avoid bad interactions
+        * between panics, shutdown hooks, and the watchdog timer)
+        */
+       ifp->if_timer = 0;
+       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+       /*
+        * Cancel stats updater.
+        */
+       untimeout(fxp_stats_update, sc);
+
+       /*
+        * Issue software reset
+        */
+       CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
+       DELAY(10);
+
+       /*
+        * Release any xmit buffers.
+        */
+       for (txp = sc->cbl_first; txp != NULL && txp->mb_head != NULL;
+           txp = txp->next) {
+               m_freem(txp->mb_head);
+               txp->mb_head = NULL;
+       }
+       sc->tx_queued = 0;
+
+       if (drain) {
+               /*
+                * Free all the receive buffers then reallocate/reinitialize
+                */
+               if (sc->rfa_headm != NULL)
+                       m_freem(sc->rfa_headm);
+               sc->rfa_headm = NULL;
+               sc->rfa_tailm = NULL;
+               for (i = 0; i < FXP_NRFABUFS; i++) {
+                       if (fxp_add_rfabuf(sc, NULL) != 0) {
+                               /*
+                                * This "can't happen" - we're at splimp()
+                                * and we just freed all the buffers we need
+                                * above.
+                                */
+                               panic("fxp_stop: no buffers!");
+                       }
+               }
+       }
+
+}
+
+/*
+ * Watchdog/transmission transmit timeout handler. Called when a
+ * transmission is started on the interface, but no interrupt is
+ * received before the timeout. This usually indicates that the
+ * card has wedged for some reason.
+ */
+void
+fxp_watchdog(ifp)
+       struct ifnet *ifp;
+{
+       struct fxp_softc *sc = ifp->if_softc;
+
+       log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
+       ifp->if_oerrors++;
+
+       fxp_init(sc);
+}
+
+void
+fxp_init(xsc)
+       void *xsc;
+{
+       struct fxp_softc *sc = xsc;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       struct fxp_cb_config *cbp;
+       struct fxp_cb_ias *cb_ias;
+       struct fxp_cb_tx *txp;
+       int i, s, prm;
+
+       s = splimp();
+       /*
+        * Cancel any pending I/O
+        */
+       fxp_stop(sc, 0);
+
+       prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
+
+       /*
+        * Initialize base of CBL and RFA memory. Loading with zero
+        * sets it up for regular linear addressing.
+        */
+       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
+       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
+
+       fxp_scb_wait(sc);
+       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
+
+       /*
+        * Initialize base of dump-stats buffer.
+        */
+       fxp_scb_wait(sc);
+       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats));
+       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR);
+
+       /*
+        * We temporarily use memory that contains the TxCB list to
+        * construct the config CB. The TxCB list memory is rebuilt
+        * later.
+        */
+       cbp = (struct fxp_cb_config *) sc->cbl_base;
+
+       /*
+        * This bcopy is kind of disgusting, but there are a bunch of must be
+        * zero and must be one bits in this structure and this is the easiest
+        * way to initialize them all to proper values.
+        */
+       bcopy(fxp_cb_config_template, (void *)&cbp->cb_status,
+               sizeof(fxp_cb_config_template));
+
+       cbp->cb_status =        0;
+       cbp->cb_command =       FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
+       cbp->link_addr =        -1;     /* (no) next command */
+       cbp->byte_count =       22;     /* (22) bytes to config */
+       cbp->rx_fifo_limit =    8;      /* rx fifo threshold (32 bytes) */
+       cbp->tx_fifo_limit =    0;      /* tx fifo threshold (0 bytes) */
+       cbp->adaptive_ifs =     0;      /* (no) adaptive interframe spacing */
+       cbp->rx_dma_bytecount = 0;      /* (no) rx DMA max */
+       cbp->tx_dma_bytecount = 0;      /* (no) tx DMA max */
+       cbp->dma_bce =          0;      /* (disable) dma max counters */
+       cbp->late_scb =         0;      /* (don't) defer SCB update */
+       cbp->tno_int =          0;      /* (disable) tx not okay interrupt */
+       cbp->ci_int =           1;      /* interrupt on CU idle */
+       cbp->save_bf =          prm;    /* save bad frames */
+       cbp->disc_short_rx =    !prm;   /* discard short packets */
+       cbp->underrun_retry =   1;      /* retry mode (1) on DMA underrun */
+       cbp->mediatype =        !sc->phy_10Mbps_only; /* interface mode */
+       cbp->nsai =             1;      /* (don't) disable source addr insert */
+       cbp->preamble_length =  2;      /* (7 byte) preamble */
+       cbp->loopback =         0;      /* (don't) loopback */
+       cbp->linear_priority =  0;      /* (normal CSMA/CD operation) */
+       cbp->linear_pri_mode =  0;      /* (wait after xmit only) */
+       cbp->interfrm_spacing = 6;      /* (96 bits of) interframe spacing */
+       cbp->promiscuous =      prm;    /* promiscuous mode */
+       cbp->bcast_disable =    0;      /* (don't) disable broadcasts */
+       cbp->crscdt =           0;      /* (CRS only) */
+       cbp->stripping =        !prm;   /* truncate rx packet to byte count */
+       cbp->padding =          1;      /* (do) pad short tx packets */
+       cbp->rcv_crc_xfer =     0;      /* (don't) xfer CRC to host */
+       cbp->force_fdx =        0;      /* (don't) force full duplex */
+       cbp->fdx_pin_en =       1;      /* (enable) FDX# pin */
+       cbp->multi_ia =         0;      /* (don't) accept multiple IAs */
+       cbp->mc_all =           sc->all_mcasts;/* accept all multicasts */
+
+       /*
+        * Start the config command/DMA.
+        */
+       fxp_scb_wait(sc);
+       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
+       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
+       /* ...and wait for it to complete. */
+       while (!(cbp->cb_status & FXP_CB_STATUS_C));
+
+       /*
+        * Now initialize the station address. Temporarily use the TxCB
+        * memory area like we did above for the config CB.
+        */
+       cb_ias = (struct fxp_cb_ias *) sc->cbl_base;
+       cb_ias->cb_status = 0;
+       cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
+       cb_ias->link_addr = -1;
+       bcopy(sc->arpcom.ac_enaddr, (void *)cb_ias->macaddr,
+           sizeof(sc->arpcom.ac_enaddr));
+
+       /*
+        * Start the IAS (Individual Address Setup) command/DMA.
+        */
+       fxp_scb_wait(sc);
+       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
+       /* ...and wait for it to complete. */
+       while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
+
+       /*
+        * Initialize transmit control block (TxCB) list.
+        */
+
+       txp = sc->cbl_base;
+       bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB);
+       for (i = 0; i < FXP_NTXCB; i++) {
+               txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
+               txp[i].cb_command = FXP_CB_COMMAND_NOP;
+               txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status);
+               txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]);
+               txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK];
+       }
+       /*
+        * Set the suspend flag on the first TxCB and start the control
+        * unit. It will execute the NOP and then suspend.
+        */
+       txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
+       sc->cbl_first = sc->cbl_last = txp;
+       sc->tx_queued = 1;
+
+       fxp_scb_wait(sc);
+       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
+
+       /*
+        * Initialize receiver buffer area - RFA.
+        */
+       fxp_scb_wait(sc);
+       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
+           vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE);
+       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
+
+       /*
+        * Set current media.
+        */
+       mii_mediachg(&sc->sc_mii);
+
+       ifp->if_flags |= IFF_RUNNING;
+       ifp->if_flags &= ~IFF_OACTIVE;
+       splx(s);
+
+       /*
+        * Start stats updater.
+        */
+       timeout(fxp_stats_update, sc, hz);
+}
+
+/*
+ * Change media according to request.
+ */
+int
+fxp_mediachange(ifp)
+       struct ifnet *ifp;
+{
+
+       if (ifp->if_flags & IFF_UP)
+               fxp_init(ifp->if_softc);
+       return (0);
+}
+
+/*
+ * Notify the world which media we're using.
+ */
+void
+fxp_mediastatus(ifp, ifmr)
+       struct ifnet *ifp;
+       struct ifmediareq *ifmr;
+{
+       struct fxp_softc *sc = ifp->if_softc;
+
+       mii_pollstat(&sc->sc_mii);
+       ifmr->ifm_status = sc->sc_mii.mii_media_status;
+       ifmr->ifm_active = sc->sc_mii.mii_media_active;
+}
+
+/*
+ * Add a buffer to the end of the RFA buffer list.
+ * Return 0 if successful, 1 for failure. A failure results in
+ * adding the 'oldm' (if non-NULL) on to the end of the list -
+ * tossing out its old contents and recycling it.
+ * The RFA struct is stuck at the beginning of mbuf cluster and the
+ * data pointer is fixed up to point just past it.
+ */
+int
+fxp_add_rfabuf(sc, oldm)
+       struct fxp_softc *sc;
+       struct mbuf *oldm;
+{
+       u_int32_t v;
+       struct mbuf *m;
+       u_int8_t *rfap;
+
+       MGETHDR(m, M_DONTWAIT, MT_DATA);
+       if (m != NULL) {
+               MCLGET(m, M_DONTWAIT);
+               if ((m->m_flags & M_EXT) == 0) {
+                       m_freem(m);
+                       if (oldm == NULL)
+                               return 1;
+                       m = oldm;
+                       m->m_data = m->m_ext.ext_buf;
+               }
+       } else {
+               if (oldm == NULL)
+                       return 1;
+               m = oldm;
+               m->m_data = m->m_ext.ext_buf;
+       }
+
+       /*
+        * Move the data pointer up so that the incoming data packet
+        * will be 32-bit aligned.
+        */
+       m->m_data += RFA_ALIGNMENT_FUDGE;
+
+       /*
+        * Get a pointer to the base of the mbuf cluster and move
+        * data start past it.
+        */
+       rfap = m->m_data;
+       m->m_data += sizeof(struct fxp_rfa);
+       *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, size)) =
+           MCLBYTES - sizeof(struct fxp_rfa) - RFA_ALIGNMENT_FUDGE;
+
+       /*
+        * Initialize the rest of the RFA.  Note that since the RFA
+        * is misaligned, we cannot store values directly.  Instead,
+        * we use an optimized, inline copy.
+        */
+       *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_status)) = 0;
+       *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_control)) =
+           FXP_RFA_CONTROL_EL;
+       *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, actual_size)) = 0;
+
+       v = -1;
+       fxp_lwcopy(&v,
+           (u_int32_t *)(rfap + offsetof(struct fxp_rfa, link_addr)));
+       fxp_lwcopy(&v,
+           (u_int32_t *)(rfap + offsetof(struct fxp_rfa, rbd_addr)));
+
+       /*
+        * If there are other buffers already on the list, attach this
+        * one to the end by fixing up the tail to point to this one.
+        */
+       if (sc->rfa_headm != NULL) {
+               sc->rfa_tailm->m_next = m;
+               v = vtophys(rfap);
+               rfap = sc->rfa_tailm->m_ext.ext_buf + RFA_ALIGNMENT_FUDGE;
+               fxp_lwcopy(&v,
+                   (u_int32_t *)(rfap + offsetof(struct fxp_rfa, link_addr)));
+               *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_control)) &=
+                   ~FXP_RFA_CONTROL_EL;
+       } else {
+               sc->rfa_headm = m;
+       }
+       sc->rfa_tailm = m;
+
+       return (m == oldm);
+}
+
+volatile int
+fxp_mdi_read(self, phy, reg)
+       struct device *self;
+       int phy;
+       int reg;
+{
+       struct fxp_softc *sc = (struct fxp_softc *)self;
+       int count = 10000;
+       int value;
+
+       CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
+           (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));
+
+       while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0
+           && count--)
+               DELAY(10);
+
+       if (count <= 0)
+               printf("%s: fxp_mdi_read: timed out\n", sc->sc_dev.dv_xname);
+
+       return (value & 0xffff);
+}
+
+void
+fxp_statchg(self)
+       struct device *self;
+{
+
+       /* XXX Update ifp->if_baudrate */
+}
+
+void
+fxp_mdi_write(self, phy, reg, value)
+       struct device *self;
+       int phy;
+       int reg;
+       int value;
+{
+       struct fxp_softc *sc = (struct fxp_softc *)self;
+       int count = 10000;
+
+       CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
+           (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) |
+           (value & 0xffff));
+
+       while((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 &&
+           count--)
+               DELAY(10);
+
+       if (count <= 0)
+               printf("%s: fxp_mdi_write: timed out\n", sc->sc_dev.dv_xname);
+}
+
+int
+fxp_ioctl(ifp, command, data)
+       struct ifnet *ifp;
+       u_long command;
+       caddr_t data;
+{
+       struct fxp_softc *sc = ifp->if_softc;
+       struct ifreq *ifr = (struct ifreq *)data;
+       int s, error = 0;
+
+       s = splimp();
+
+       switch (command) {
+
+       case SIOCSIFADDR:
+       case SIOCGIFADDR:
+       case SIOCSIFMTU:
+               error = ether_ioctl(ifp, command, data);
+               break;
+
+       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.
+                * XXX If it's up then re-initialize it. This is so flags
+                * such as IFF_PROMISC are handled.
+                */
+               if (ifp->if_flags & IFF_UP) {
+                       fxp_init(sc);
+               } else {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               fxp_stop(sc, 1);
+               }
+               break;
+
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+               sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
+               error = (command == SIOCADDMULTI) ?
+                   ether_addmulti(ifr, &sc->arpcom) :
+                   ether_delmulti(ifr, &sc->arpcom);
+               if (error == ENETRESET) {
+                       /*
+                        * Multicast list has changed; set the hardware
+                        * filter accordingly.
+                        */
+                       if (!sc->all_mcasts)
+                               fxp_mc_setup(sc);
+                       /*
+                        * fxp_mc_setup() can turn on all_mcasts if we run
+                        * out of space, so check it again rather than else {}.
+                        */
+                       if (sc->all_mcasts)
+                               fxp_init(sc);
+                       error = 0;
+               }
+               break;
+
+       case SIOCSIFMEDIA:
+       case SIOCGIFMEDIA:
+               error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       (void) splx(s);
+       return (error);
+}
+
+/*
+ * Program the multicast filter.
+ *
+ * We have an artificial restriction that the multicast setup command
+ * must be the first command in the chain, so we take steps to ensure
+ * this. By requiring this, it allows us to keep up the performance of
+ * the pre-initialized command ring (esp. link pointers) by not actually
+ * inserting the mcsetup command in the ring - i.e. its link pointer
+ * points to the TxCB ring, but the mcsetup descriptor itself is not part
+ * of it. We then can do 'CU_START' on the mcsetup descriptor and have it
+ * lead into the regular TxCB ring when it completes.
+ *
+ * This function must be called at splimp.
+ */
+void
+fxp_mc_setup(sc)
+       struct fxp_softc *sc;
+{
+       struct fxp_cb_mcs *mcsp = sc->mcsp;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       struct ether_multistep step;
+       struct ether_multi *enm;
+       int nmcasts;
+
+       /*
+        * If there are queued commands, we must wait until they are all
+        * completed. If we are already waiting, then add a NOP command
+        * with interrupt option so that we're notified when all commands
+        * have been completed - fxp_start() ensures that no additional
+        * TX commands will be added when need_mcsetup is true.
+        */
+       if (sc->tx_queued) {
+               struct fxp_cb_tx *txp;
+
+               /*
+                * need_mcsetup will be true if we are already waiting for the
+                * NOP command to be completed (see below). In this case, bail.
+                */
+               if (sc->need_mcsetup)
+                       return;
+               sc->need_mcsetup = 1;
+
+               /*
+                * Add a NOP command with interrupt so that we are notified when all
+                * TX commands have been processed.
+                */
+               txp = sc->cbl_last->next;
+               txp->mb_head = NULL;
+               txp->cb_status = 0;
+               txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;
+               /*
+                * Advance the end of list forward.
+                */
+               sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;
+               sc->cbl_last = txp;
+               sc->tx_queued++;
+               /*
+                * Issue a resume in case the CU has just suspended.
+                */
+               fxp_scb_wait(sc);
+               CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
+               /*
+                * Set a 5 second timer just in case we don't hear from the
+                * card again.
+                */
+               ifp->if_timer = 5;
+
+               return;
+       }
+       sc->need_mcsetup = 0;
+
+       /*
+        * Initialize multicast setup descriptor.
+        */
+       mcsp->next = sc->cbl_base;
+       mcsp->mb_head = NULL;
+       mcsp->cb_status = 0;
+       mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;
+       mcsp->link_addr = vtophys(&sc->cbl_base->cb_status);
+
+       nmcasts = 0;
+       if (!sc->all_mcasts) {
+               ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
+               while (enm != NULL) {
+                       if (nmcasts >= MAXMCADDR) {
+                               sc->all_mcasts = 1;
+                               nmcasts = 0;
+                               break;
+                       }
+
+                       /* Punt on ranges. */
+                       if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
+                           sizeof(enm->enm_addrlo)) != 0) {
+                               sc->all_mcasts = 1;
+                               nmcasts = 0;
+                               break;
+                       }
+                       bcopy(enm->enm_addrlo,
+                           (void *) &sc->mcsp->mc_addr[nmcasts][0], 6);
+                       nmcasts++;
+                       ETHER_NEXT_MULTI(step, enm);
+               }
+       }
+       mcsp->mc_cnt = nmcasts * 6;
+       sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp;
+       sc->tx_queued = 1;
+
+       /*
+        * Wait until command unit is not active. This should never
+        * be the case when nothing is queued, but make sure anyway.
+        */
+       while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
+           FXP_SCB_CUS_ACTIVE) ;
+
+       /*
+        * Start the multicast setup command.
+        */
+       fxp_scb_wait(sc);
+       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status));
+       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
+
+       ifp->if_timer = 2;
+       return;
+}
diff --git a/sys/dev/ic/fxpreg.h b/sys/dev/ic/fxpreg.h
new file mode 100644 (file)
index 0000000..68cbd61
--- /dev/null
@@ -0,0 +1,349 @@
+/*     $OpenBSD: fxpreg.h,v 1.1 2000/04/18 18:44:27 jason Exp $        */
+
+/*
+ * Copyright (c) 1995, David Greenman
+ * 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: if_fxpreg.h,v 1.13 1998/06/08 09:47:46 bde Exp $
+ */
+
+#define FXP_VENDORID_INTEL     0x8086
+#define FXP_DEVICEID_i82557    0x1229
+
+#define FXP_PCI_MMBA   0x10
+#define FXP_PCI_IOBA   0x14
+
+/*
+ * Control/status registers.
+ */
+#define        FXP_CSR_SCB_RUSCUS      0       /* scb_rus/scb_cus (1 byte) */
+#define        FXP_CSR_SCB_STATACK     1       /* scb_statack (1 byte) */
+#define        FXP_CSR_SCB_COMMAND     2       /* scb_command (1 byte) */
+#define        FXP_CSR_SCB_INTRCNTL    3       /* scb_intrcntl (1 byte) */
+#define        FXP_CSR_SCB_GENERAL     4       /* scb_general (4 bytes) */
+#define        FXP_CSR_PORT            8       /* port (4 bytes) */
+#define        FXP_CSR_FLASHCONTROL    12      /* flash control (2 bytes) */
+#define        FXP_CSR_EEPROMCONTROL   14      /* eeprom control (2 bytes) */
+#define        FXP_CSR_MDICONTROL      16      /* mdi control (4 bytes) */
+
+/*
+ * FOR REFERENCE ONLY, the old definition of FXP_CSR_SCB_RUSCUS:
+ *
+ *     volatile u_int8_t       :2,
+ *                             scb_rus:4,
+ *                             scb_cus:2;
+ */
+
+#define FXP_PORT_SOFTWARE_RESET                0
+#define FXP_PORT_SELFTEST              1
+#define FXP_PORT_SELECTIVE_RESET       2
+#define FXP_PORT_DUMP                  3
+
+#define FXP_SCB_RUS_IDLE               0
+#define FXP_SCB_RUS_SUSPENDED          1
+#define FXP_SCB_RUS_NORESOURCES                2
+#define FXP_SCB_RUS_READY              4
+#define FXP_SCB_RUS_SUSP_NORBDS                9
+#define FXP_SCB_RUS_NORES_NORBDS       10
+#define FXP_SCB_RUS_READY_NORBDS       12
+
+#define FXP_SCB_CUS_IDLE               0
+#define FXP_SCB_CUS_SUSPENDED          1
+#define FXP_SCB_CUS_ACTIVE             2
+
+#define FXP_SCB_STATACK_SWI            0x04
+#define FXP_SCB_STATACK_MDI            0x08
+#define FXP_SCB_STATACK_RNR            0x10
+#define FXP_SCB_STATACK_CNA            0x20
+#define FXP_SCB_STATACK_FR             0x40
+#define FXP_SCB_STATACK_CXTNO          0x80
+
+#define FXP_SCB_COMMAND_CU_NOP         0x00
+#define FXP_SCB_COMMAND_CU_START       0x10
+#define FXP_SCB_COMMAND_CU_RESUME      0x20
+#define FXP_SCB_COMMAND_CU_DUMP_ADR    0x40
+#define FXP_SCB_COMMAND_CU_DUMP                0x50
+#define FXP_SCB_COMMAND_CU_BASE                0x60
+#define FXP_SCB_COMMAND_CU_DUMPRESET   0x70
+
+#define FXP_SCB_COMMAND_RU_NOP         0
+#define FXP_SCB_COMMAND_RU_START       1
+#define FXP_SCB_COMMAND_RU_RESUME      2
+#define FXP_SCB_COMMAND_RU_ABORT       4
+#define FXP_SCB_COMMAND_RU_LOADHDS     5
+#define FXP_SCB_COMMAND_RU_BASE                6
+#define FXP_SCB_COMMAND_RU_RBDRESUME   7
+
+/*
+ * Command block definitions
+ */
+struct fxp_cb_nop {
+       void *fill[2];
+       volatile u_int16_t cb_status;
+       volatile u_int16_t cb_command;
+       volatile u_int32_t link_addr;
+};
+struct fxp_cb_ias {
+       void *fill[2];
+       volatile u_int16_t cb_status;
+       volatile u_int16_t cb_command;
+       volatile u_int32_t link_addr;
+       volatile u_int8_t macaddr[6];
+};
+/* I hate bit-fields :-( */
+struct fxp_cb_config {
+       void *fill[2];
+       volatile u_int16_t      cb_status;
+       volatile u_int16_t      cb_command;
+       volatile u_int32_t      link_addr;
+       volatile u_int          byte_count:6,
+                               :2;
+       volatile u_int          rx_fifo_limit:4,
+                               tx_fifo_limit:3,
+                               :1;
+       volatile u_int8_t       adaptive_ifs;
+       volatile u_int          :8;
+       volatile u_int          rx_dma_bytecount:7,
+                               :1;
+       volatile u_int          tx_dma_bytecount:7,
+                               dma_bce:1;
+       volatile u_int          late_scb:1,
+                               :1,
+                               tno_int:1,
+                               ci_int:1,
+                               :3,
+                               save_bf:1;
+       volatile u_int          disc_short_rx:1,
+                               underrun_retry:2,
+                               :5;
+       volatile u_int          mediatype:1,
+                               :7;
+       volatile u_int          :8;
+       volatile u_int          :3,
+                               nsai:1,
+                               preamble_length:2,
+                               loopback:2;
+       volatile u_int          linear_priority:3,
+                               :5;
+       volatile u_int          linear_pri_mode:1,
+                               :3,
+                               interfrm_spacing:4;
+       volatile u_int          :8;
+       volatile u_int          :8;
+       volatile u_int          promiscuous:1,
+                               bcast_disable:1,
+                               :5,
+                               crscdt:1;
+       volatile u_int          :8;
+       volatile u_int          :8;
+       volatile u_int          stripping:1,
+                               padding:1,
+                               rcv_crc_xfer:1,
+                               :5;
+       volatile u_int          :6,
+                               force_fdx:1,
+                               fdx_pin_en:1;
+       volatile u_int          :6,
+                               multi_ia:1,
+                               :1;
+       volatile u_int          :3,
+                               mc_all:1,
+                               :4;
+};
+
+#define MAXMCADDR 80
+struct fxp_cb_mcs {
+       struct fxp_cb_tx *next;
+       struct mbuf *mb_head;
+       volatile u_int16_t cb_status;
+       volatile u_int16_t cb_command;
+       volatile u_int32_t link_addr;
+       volatile u_int16_t mc_cnt;
+       volatile u_int8_t mc_addr[MAXMCADDR][6];
+};
+
+/*
+ * Number of DMA segments in a TxCB. Note that this is carefully
+ * chosen to make the total struct size an even power of two. It's
+ * critical that no TxCB be split across a page boundry since
+ * no attempt is made to allocate physically contiguous memory.
+ * 
+ */
+#ifdef __alpha__ /* XXX - should be conditional on pointer size */
+#define FXP_NTXSEG      28
+#else
+#define FXP_NTXSEG      29
+#endif
+
+struct fxp_tbd {
+       volatile u_int32_t tb_addr;
+       volatile u_int32_t tb_size;
+};
+struct fxp_cb_tx {
+       struct fxp_cb_tx *next;
+       struct mbuf *mb_head;
+       volatile u_int16_t cb_status;
+       volatile u_int16_t cb_command;
+       volatile u_int32_t link_addr;
+       volatile u_int32_t tbd_array_addr;
+       volatile u_int16_t byte_count;
+       volatile u_int8_t tx_threshold;
+       volatile u_int8_t tbd_number;
+       /*
+        * The following isn't actually part of the TxCB.
+        */
+       volatile struct fxp_tbd tbd[FXP_NTXSEG];
+};
+
+/*
+ * Control Block (CB) definitions
+ */
+
+/* status */
+#define FXP_CB_STATUS_OK       0x2000
+#define FXP_CB_STATUS_C                0x8000
+/* commands */
+#define FXP_CB_COMMAND_NOP     0x0
+#define FXP_CB_COMMAND_IAS     0x1
+#define FXP_CB_COMMAND_CONFIG  0x2
+#define FXP_CB_COMMAND_MCAS    0x3
+#define FXP_CB_COMMAND_XMIT    0x4
+#define FXP_CB_COMMAND_RESRV   0x5
+#define FXP_CB_COMMAND_DUMP    0x6
+#define FXP_CB_COMMAND_DIAG    0x7
+/* command flags */
+#define FXP_CB_COMMAND_SF      0x0008  /* simple/flexible mode */
+#define FXP_CB_COMMAND_I       0x2000  /* generate interrupt on completion */
+#define FXP_CB_COMMAND_S       0x4000  /* suspend on completion */
+#define FXP_CB_COMMAND_EL      0x8000  /* end of list */
+
+/*
+ * RFA definitions
+ */
+
+struct fxp_rfa {
+       volatile u_int16_t rfa_status;
+       volatile u_int16_t rfa_control;
+       volatile u_int32_t link_addr;
+       volatile u_int32_t rbd_addr;
+       volatile u_int16_t actual_size;
+       volatile u_int16_t size;
+};
+#define FXP_RFA_STATUS_RCOL    0x0001  /* receive collision */
+#define FXP_RFA_STATUS_IAMATCH 0x0002  /* 0 = matches station address */
+#define FXP_RFA_STATUS_S4      0x0010  /* receive error from PHY */
+#define FXP_RFA_STATUS_TL      0x0020  /* type/length */
+#define FXP_RFA_STATUS_FTS     0x0080  /* frame too short */
+#define FXP_RFA_STATUS_OVERRUN 0x0100  /* DMA overrun */
+#define FXP_RFA_STATUS_RNR     0x0200  /* no resources */
+#define FXP_RFA_STATUS_ALIGN   0x0400  /* alignment error */
+#define FXP_RFA_STATUS_CRC     0x0800  /* CRC error */
+#define FXP_RFA_STATUS_OK      0x2000  /* packet received okay */
+#define FXP_RFA_STATUS_C       0x8000  /* packet reception complete */
+#define FXP_RFA_CONTROL_SF     0x08    /* simple/flexible memory mode */
+#define FXP_RFA_CONTROL_H      0x10    /* header RFD */
+#define FXP_RFA_CONTROL_S      0x4000  /* suspend after reception */
+#define FXP_RFA_CONTROL_EL     0x8000  /* end of list */
+
+/*
+ * Statistics dump area definitions
+ */
+struct fxp_stats {
+       volatile u_int32_t tx_good;
+       volatile u_int32_t tx_maxcols;
+       volatile u_int32_t tx_latecols;
+       volatile u_int32_t tx_underruns;
+       volatile u_int32_t tx_lostcrs;
+       volatile u_int32_t tx_deffered;
+       volatile u_int32_t tx_single_collisions;
+       volatile u_int32_t tx_multiple_collisions;
+       volatile u_int32_t tx_total_collisions;
+       volatile u_int32_t rx_good;
+       volatile u_int32_t rx_crc_errors;
+       volatile u_int32_t rx_alignment_errors;
+       volatile u_int32_t rx_rnr_errors;
+       volatile u_int32_t rx_overrun_errors;
+       volatile u_int32_t rx_cdt_errors;
+       volatile u_int32_t rx_shortframes;
+       volatile u_int32_t completion_status;
+};
+#define FXP_STATS_DUMP_COMPLETE        0xa005
+#define FXP_STATS_DR_COMPLETE  0xa007
+       
+/*
+ * Serial EEPROM control register bits
+ */
+/* shift clock */
+#define FXP_EEPROM_EESK                0x01
+/* chip select */
+#define FXP_EEPROM_EECS                0x02
+/* data in */
+#define FXP_EEPROM_EEDI                0x04
+/* data out */
+#define FXP_EEPROM_EEDO                0x08
+
+/*
+ * Serial EEPROM opcodes, including start bit
+ */
+#define FXP_EEPROM_OPC_ERASE   0x4
+#define FXP_EEPROM_OPC_WRITE   0x5
+#define FXP_EEPROM_OPC_READ    0x6
+
+/*
+ * Management Data Interface opcodes
+ */
+#define FXP_MDI_WRITE          0x1
+#define FXP_MDI_READ           0x2
+
+/*
+ * PHY device types
+ */
+#define FXP_PHY_NONE           0
+#define FXP_PHY_82553A         1
+#define FXP_PHY_82553C         2
+#define FXP_PHY_82503          3
+#define FXP_PHY_DP83840                4
+#define FXP_PHY_80C240         5
+#define FXP_PHY_80C24          6
+#define FXP_PHY_82555          7
+#define FXP_PHY_DP83840A       10
+#define FXP_PHY_82555B         11
+
+/*
+ * PHY BMCR Basic Mode Control Register
+ */
+#define FXP_PHY_BMCR                   0x0
+#define FXP_PHY_BMCR_FULLDUPLEX                0x0100
+#define FXP_PHY_BMCR_AUTOEN            0x1000
+#define FXP_PHY_BMCR_SPEED_100M                0x2000
+
+/*
+ * DP84830 PHY, PCS Configuration Register
+ */
+#define FXP_DP83840_PCR                        0x17
+#define FXP_DP83840_PCR_LED4_MODE      0x0002  /* 1 = LED4 always indicates full duplex */
+#define FXP_DP83840_PCR_F_CONNECT      0x0020  /* 1 = force link disconnect function bypass */
+#define FXP_DP83840_PCR_BIT8           0x0100
+#define FXP_DP83840_PCR_BIT10          0x0400
diff --git a/sys/dev/ic/fxpvar.h b/sys/dev/ic/fxpvar.h
new file mode 100644 (file)
index 0000000..4918342
--- /dev/null
@@ -0,0 +1,83 @@
+/*     $OpenBSD: fxpvar.h,v 1.1 2000/04/18 18:44:27 jason Exp $        */
+/*     $NetBSD: if_fxpvar.h,v 1.1 1997/06/05 02:01:58 thorpej Exp $    */
+
+/*                  
+ * Copyright (c) 1995, David Greenman
+ * All rights reserved.
+ *              
+ * Modifications to support NetBSD:
+ * Copyright (c) 1997 Jason R. Thorpe.  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.
+ *
+ *      Id: if_fxpvar.h,v 1.6 1998/08/02 00:29:15 dg Exp
+ */
+
+/*
+ * Misc. defintions for the Intel EtherExpress Pro/100B PCI Fast
+ * Ethernet driver
+ */
+/*
+ * NOTE: Elements are ordered for optimal cacheline behavior, and NOT
+ *      for functional grouping.
+ */
+struct fxp_softc {
+       struct device sc_dev;           /* generic device structures */
+       void *sc_ih;                    /* interrupt handler cookie */
+       bus_space_tag_t sc_st;          /* bus space tag */
+       bus_space_handle_t sc_sh;       /* bus space handle */
+       struct arpcom arpcom;           /* per-interface network data */
+       struct mii_data sc_mii;         /* MII media information */
+       struct mbuf *rfa_headm;         /* first mbuf in receive frame area */
+       struct mbuf *rfa_tailm;         /* last mbuf in receive frame area */
+       struct fxp_cb_tx *cbl_first;    /* first active TxCB in list */
+       int tx_queued;                  /* # of active TxCB's */
+       int need_mcsetup;               /* multicast filter needs programming */
+       struct fxp_cb_tx *cbl_last;     /* last active TxCB in list */
+       struct fxp_stats *fxp_stats;    /* Pointer to interface stats */
+       int rx_idle_secs;               /* # of seconds RX has been idle */
+       struct fxp_cb_tx *cbl_base;     /* base of TxCB list */
+       struct fxp_cb_mcs *mcsp;        /* Pointer to mcast setup descriptor */
+       int all_mcasts;                 /* receive all multicasts */
+       int phy_primary_addr;           /* address of primary PHY */
+       int phy_primary_device;         /* device type of primary PHY */
+       int phy_10Mbps_only;            /* PHY is 10Mbps-only device */
+       int eeprom_size;                /* size of serial EEPROM */
+};
+
+/* Macros to ease CSR access. */
+#define        CSR_READ_1(sc, reg)                                             \
+       bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg))
+#define        CSR_READ_2(sc, reg)                                             \
+       bus_space_read_2((sc)->sc_st, (sc)->sc_sh, (reg))
+#define        CSR_READ_4(sc, reg)                                             \
+       bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
+#define        CSR_WRITE_1(sc, reg, val)                                       \
+       bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#define        CSR_WRITE_2(sc, reg, val)                                       \
+       bus_space_write_2((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#define        CSR_WRITE_4(sc, reg, val)                                       \
+       bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+
+extern int fxp_intr __P((void *));
+extern int fxp_attach_common __P((struct fxp_softc *, u_int8_t *, const char *));
index 16aed13..bda71e4 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.pci,v 1.70 2000/04/13 00:10:52 csapuntz Exp $
+#      $OpenBSD: files.pci,v 1.71 2000/04/18 18:44:31 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.
@@ -130,11 +130,6 @@ file       dev/pci/if_lmc_common.c         lmc
 file   dev/pci/if_lmc_media.c          lmc
 file   dev/pci/if_lmc_obsd.c           lmc
 
-# Intel EtherExpress PRO 10/100B
-device fxp: ether, ifnet, mii, ifmedia
-attach fxp at pci 
-file   dev/pci/if_fxp.c                fxp
-
 # RealTek 8129/8139
 device rl: ether, ifnet, mii, ifmedia
 attach rl at pci
@@ -169,6 +164,10 @@ file       dev/pci/brooktree848.c          bktr    needs-count
 attach xl at pci with xl_pci
 file   dev/pci/if_xl_pci.c             xl_pci
 
+# Intel EtherExpress PRO 10/100B
+attach fxp at pci with fxp_pci
+file   dev/pci/if_fxp_pci.c            fxp_pci
+
 # SMC EPIC, 83c170
 device tx: ether, ifnet, ifmedia
 attach tx at pci
diff --git a/sys/dev/pci/if_fxp.c b/sys/dev/pci/if_fxp.c
deleted file mode 100644 (file)
index 2fa3bce..0000000
+++ /dev/null
@@ -1,1679 +0,0 @@
-/*     $OpenBSD: if_fxp.c,v 1.26 2000/04/18 03:40:55 jason Exp $       */
-/*     $NetBSD: if_fxp.c,v 1.2 1997/06/05 02:01:55 thorpej Exp $       */
-
-/*
- * Copyright (c) 1995, David Greenman
- * All rights reserved.
- *
- * Modifications to support NetBSD:
- * Copyright (c) 1997 Jason R. Thorpe.  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.
- *
- *     Id: if_fxp.c,v 1.55 1998/08/04 08:53:12 dg Exp
- */
-
-/*
- * Intel EtherExpress Pro/100B PCI Fast Ethernet driver
- */
-
-#include "bpfilter.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/socket.h>
-#include <sys/syslog.h>
-
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
-#include <net/if_types.h>
-
-#ifdef INET
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
-#include <netinet/ip.h>
-#endif
-
-#ifdef IPX
-#include <netipx/ipx.h>
-#include <netipx/ipx_if.h>
-#endif
-
-#ifdef NS
-#include <netns/ns.h>
-#include <netns/ns_if.h>
-#endif
-
-#if NBPFILTER > 0
-#include <net/bpf.h>
-#include <net/bpfdesc.h>
-#endif
-
-#include <sys/ioctl.h>
-#include <sys/errno.h>
-#include <sys/device.h>
-
-#include <netinet/if_ether.h>
-
-#include <vm/vm.h>
-
-#include <machine/cpu.h>
-#include <machine/bus.h>
-#include <machine/intr.h>
-
-#include <dev/mii/miivar.h>
-
-#include <dev/pci/if_fxpreg.h>
-#include <dev/pci/if_fxpvar.h>
-
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcidevs.h>
-
-#ifdef __alpha__               /* XXX */
-/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
-#undef vtophys
-#define        vtophys(va)     alpha_XXX_dmamap((vm_offset_t)(va))
-#endif /* __alpha__ */
-
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-/*
- * NOTE!  On the Alpha, we have an alignment constraint.  The
- * card DMAs the packet immediately following the RFA.  However,
- * the first thing in the packet is a 14-byte Ethernet header.
- * This means that the packet is misaligned.  To compensate,
- * we actually offset the RFA 2 bytes into the cluster.  This
- * aligns the packet after the Ethernet header at a 32-bit
- * boundary.  HOWEVER!  This means that the RFA is misaligned!
- */
-#define        RFA_ALIGNMENT_FUDGE     2
-
-/*
- * Inline function to copy a 16-bit aligned 32-bit quantity.
- */
-static __inline void fxp_lwcopy __P((volatile u_int32_t *,
-       volatile u_int32_t *));
-static __inline void
-fxp_lwcopy(src, dst)
-       volatile u_int32_t *src, *dst;
-{
-       volatile u_int16_t *a = (u_int16_t *)src;
-       volatile u_int16_t *b = (u_int16_t *)dst;
-
-       b[0] = a[0];
-       b[1] = a[1];
-}
-
-/*
- * Template for default configuration parameters.
- * See struct fxp_cb_config for the bit definitions.
- */
-static u_char fxp_cb_config_template[] = {
-       0x0, 0x0,               /* cb_status */
-       0x80, 0x2,              /* cb_command */
-       0xff, 0xff, 0xff, 0xff, /* link_addr */
-       0x16,   /*  0 */
-       0x8,    /*  1 */
-       0x0,    /*  2 */
-       0x0,    /*  3 */
-       0x0,    /*  4 */
-       0x80,   /*  5 */
-       0xb2,   /*  6 */
-       0x3,    /*  7 */
-       0x1,    /*  8 */
-       0x0,    /*  9 */
-       0x26,   /* 10 */
-       0x0,    /* 11 */
-       0x60,   /* 12 */
-       0x0,    /* 13 */
-       0xf2,   /* 14 */
-       0x48,   /* 15 */
-       0x0,    /* 16 */
-       0x40,   /* 17 */
-       0xf3,   /* 18 */
-       0x0,    /* 19 */
-       0x3f,   /* 20 */
-       0x5     /* 21 */
-};
-
-/* Supported media types. */
-struct fxp_supported_media {
-       const int       fsm_phy;        /* PHY type */
-       const int       *fsm_media;     /* the media array */
-       const int       fsm_nmedia;     /* the number of supported media */
-       const int       fsm_defmedia;   /* default media for this PHY */
-};
-
-int fxp_mediachange            __P((struct ifnet *));
-void fxp_mediastatus           __P((struct ifnet *, struct ifmediareq *));
-static inline void fxp_scb_wait        __P((struct fxp_softc *));
-int fxp_intr                   __P((void *));
-void fxp_start                 __P((struct ifnet *));
-int fxp_ioctl                  __P((struct ifnet *, u_long, caddr_t));
-void fxp_init                  __P((void *));
-void fxp_stop                  __P((struct fxp_softc *, int));
-void fxp_watchdog              __P((struct ifnet *));
-int fxp_add_rfabuf             __P((struct fxp_softc *, struct mbuf *));
-int fxp_mdi_read               __P((struct device *, int, int));
-void fxp_mdi_write             __P((struct device *, int, int, int));
-void fxp_autosize_eeprom       __P((struct fxp_softc *));
-void fxp_statchg               __P((struct device *));
-void fxp_read_eeprom           __P((struct fxp_softc *, u_int16_t *,
-                                   int, int));
-int fxp_attach_common  __P((struct fxp_softc *, u_int8_t *));
-
-void fxp_stats_update          __P((void *));
-void fxp_mc_setup              __P((struct fxp_softc *));
-
-/*
- * Set initial transmit threshold at 64 (512 bytes). This is
- * increased by 64 (512 bytes) at a time, to maximum of 192
- * (1536 bytes), if an underrun occurs.
- */
-static int tx_threshold = 64;
-
-/*
- * Number of transmit control blocks. This determines the number
- * of transmit buffers that can be chained in the CB list.
- * This must be a power of two.
- */
-#define FXP_NTXCB      128
-
-/*
- * Number of completed TX commands at which point an interrupt
- * will be generated to garbage collect the attached buffers.
- * Must be at least one less than FXP_NTXCB, and should be
- * enough less so that the transmitter doesn't becomes idle
- * during the buffer rundown (which would reduce performance).
- */
-#define FXP_CXINT_THRESH 120
-
-/*
- * TxCB list index mask. This is used to do list wrap-around.
- */
-#define FXP_TXCB_MASK  (FXP_NTXCB - 1)
-
-/*
- * Number of receive frame area buffers. These are large so chose
- * wisely.
- */
-#define FXP_NRFABUFS   64
-
-/*
- * Maximum number of seconds that the receiver can be idle before we
- * assume it's dead and attempt to reset it by reprogramming the
- * multicast filter. This is part of a work-around for a bug in the
- * NIC. See fxp_stats_update().
- */
-#define FXP_MAX_RX_IDLE        15
-
-/*
- * Wait for the previous command to be accepted (but not necessarily
- * completed).
- */
-static inline void
-fxp_scb_wait(sc)
-       struct fxp_softc *sc;
-{
-       int i = 10000;
-
-       while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
-}
-
-/*************************************************************
- * Operating system-specific autoconfiguration glue
- *************************************************************/
-
-int fxp_match __P((struct device *, void *, void *));
-void fxp_attach __P((struct device *, struct device *, void *));
-
-void   fxp_shutdown __P((void *));
-void   fxp_power __P((int, void *));
-
-/* Compensate for lack of a generic ether_ioctl() */
-int    fxp_ether_ioctl __P((struct ifnet *, u_long, caddr_t));
-#define        ether_ioctl     fxp_ether_ioctl
-
-struct cfattach fxp_ca = {
-       sizeof(struct fxp_softc), fxp_match, fxp_attach
-};
-
-struct cfdriver fxp_cd = {
-       NULL, "fxp", DV_IFNET
-};
-
-/*
- * Check if a device is an 82557.
- */
-int
-fxp_match(parent, match, aux)
-       struct device *parent;
-       void *match;
-       void *aux;
-{
-       struct pci_attach_args *pa = aux;
-
-       if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
-               return (0);
-
-       switch (PCI_PRODUCT(pa->pa_id)) {
-       case PCI_PRODUCT_INTEL_82557:
-       case PCI_PRODUCT_INTEL_82559:
-               return (1);
-       }
-
-       return (0);
-}
-
-void
-fxp_attach(parent, self, aux)
-       struct device *parent, *self;
-       void *aux;
-{
-       struct fxp_softc *sc = (struct fxp_softc *)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_int8_t enaddr[6];
-       struct ifnet *ifp;
-       bus_space_tag_t iot = pa->pa_iot;
-       bus_addr_t iobase;
-       bus_size_t iosize;
-
-       if (pci_io_find(pc, pa->pa_tag, FXP_PCI_IOBA, &iobase, &iosize)) {
-               printf(": can't find i/o space\n");
-               return;
-       }
-
-       if (bus_space_map(iot, iobase, iosize, 0, &sc->sc_sh)) {
-               printf(": can't map i/o space\n");
-               return;
-       }
-       sc->sc_st = iot;
-
-       /*
-        * Allocate our interrupt.
-        */
-       if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
-           pa->pa_intrline, &ih)) {
-               printf(": couldn't map interrupt\n");
-               return;
-       }
-
-       intrstr = pci_intr_string(pc, ih);
-       sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, fxp_intr, sc,
-           self->dv_xname);
-       if (sc->sc_ih == NULL) {
-               printf(": couldn't establish interrupt");
-               if (intrstr != NULL)
-                       printf(" at %s", intrstr);
-               printf("\n");
-               return;
-       }
-
-       /* Do generic parts of attach. */
-       if (fxp_attach_common(sc, enaddr)) {
-               /* Failed! */
-               return;
-       }
-
-
-       ifp = &sc->arpcom.ac_if;
-       bcopy(enaddr, sc->arpcom.ac_enaddr, sizeof(enaddr));
-       bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
-       ifp->if_softc = sc;
-       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
-       ifp->if_ioctl = fxp_ioctl;
-       ifp->if_start = fxp_start;
-       ifp->if_watchdog = fxp_watchdog;
-
-       printf(": %s, address %s\n", intrstr,
-           ether_sprintf(sc->arpcom.ac_enaddr));
-
-       /*
-        * Initialize our media structures and probe the MII.
-        */
-       sc->sc_mii.mii_ifp = ifp;
-       sc->sc_mii.mii_readreg = fxp_mdi_read;
-       sc->sc_mii.mii_writereg = fxp_mdi_write;
-       sc->sc_mii.mii_statchg = fxp_statchg;
-       ifmedia_init(&sc->sc_mii.mii_media, 0, fxp_mediachange,
-           fxp_mediastatus);
-       mii_phy_probe(self, &sc->sc_mii, 0xffffffff);
-       /* If no phy found, just use auto mode */
-       if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
-               ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL,
-                   0, NULL);
-               printf("%s: no phy found, using manual mode\n",
-                   sc->sc_dev.dv_xname);
-       }
-
-       if (ifmedia_match(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL, 0))
-               ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
-       else if (ifmedia_match(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO, 0))
-               ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
-       else
-               ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_10_T);
-
-       /*
-        * Attach the interface.
-        */
-       if_attach(ifp);
-       /*
-        * Let the system queue as many packets as we have available
-        * TX descriptors.
-        */
-       ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1;
-       ether_ifattach(ifp);
-#if NBPFILTER > 0
-       bpfattach(&sc->arpcom.ac_if.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(fxp_shutdown, sc);
-
-       /*
-        * Add suspend hook, for similiar reasons..
-        */
-       powerhook_establish(fxp_power, 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.
- */
-void
-fxp_shutdown(sc)
-       void *sc;
-{
-       fxp_stop((struct fxp_softc *) sc, 0);
-}
-
-/*
- * Power handler routine. Called when the system is transitioning
- * into/out of power save modes.  As with fxp_shutdown, the main
- * purpose of this routine is to shut off receiver DMA so it doesn't
- * clobber kernel memory at the wrong time.
- */
-void
-fxp_power(why, arg)
-       int why;
-       void *arg;
-{
-       struct fxp_softc *sc = arg;
-       struct ifnet *ifp;
-       int s;
-
-       s = splnet();
-       if (why != PWR_RESUME)
-               fxp_stop(sc, 0);
-       else {
-               ifp = &sc->arpcom.ac_if;
-               if (ifp->if_flags & IFF_UP)
-                       fxp_init(sc);
-       }
-       splx(s);
-}
-
-int
-fxp_ether_ioctl(ifp, cmd, data)
-       struct ifnet *ifp;
-       u_long cmd;
-       caddr_t data;
-{
-       struct ifaddr *ifa = (struct ifaddr *) data;
-       struct fxp_softc *sc = ifp->if_softc;
-
-       switch (cmd) {
-       case SIOCSIFADDR:
-               ifp->if_flags |= IFF_UP;
-
-               switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
-               case AF_INET:
-                       fxp_init(sc);
-                       arp_ifinit(&sc->arpcom, ifa);
-                       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);
-                        /* Set new address. */
-                        fxp_init(sc);
-                        break;
-                   }
-#endif
-               default:
-                       fxp_init(sc);
-                       break;
-               }
-               break;
-
-       default:
-               return (EINVAL);
-       }
-
-       return (0);
-}
-
-/*************************************************************
- * End of operating system-specific autoconfiguration glue
- *************************************************************/
-
-/*
- * Do generic parts of attach.
- */
-int
-fxp_attach_common(sc, enaddr)
-       struct fxp_softc *sc;
-       u_int8_t *enaddr;
-{
-       u_int16_t data;
-       int i;
-
-       /*
-        * Reset to a stable state.
-        */
-       CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
-       DELAY(10);
-
-       sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB,
-           M_DEVBUF, M_NOWAIT);
-       if (sc->cbl_base == NULL)
-               goto fail;
-
-       sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT);
-       if (sc->fxp_stats == NULL)
-               goto fail;
-       bzero(sc->fxp_stats, sizeof(struct fxp_stats));
-
-       sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT);
-       if (sc->mcsp == NULL)
-               goto fail;
-
-       /*
-        * Pre-allocate our receive buffers.
-        */
-       for (i = 0; i < FXP_NRFABUFS; i++) {
-               if (fxp_add_rfabuf(sc, NULL) != 0) {
-                       goto fail;
-               }
-       }
-
-       /*
-        * Find out how large of an SEEPROM we have.
-        */
-       fxp_autosize_eeprom(sc);
-
-       /*
-        * Get info about the primary PHY
-        */
-       fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);
-       sc->phy_primary_addr = data & 0xff;
-       sc->phy_primary_device = (data >> 8) & 0x3f;
-       sc->phy_10Mbps_only = data >> 15;
-
-       /*
-        * Read MAC address.
-        */
-       fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3);
-       return (0);
-
- fail:
-       printf("%s: Failed to malloc memory\n", sc->sc_dev.dv_xname);
-       if (sc->cbl_base)
-               free(sc->cbl_base, M_DEVBUF);
-       if (sc->fxp_stats)
-               free(sc->fxp_stats, M_DEVBUF);
-       if (sc->mcsp)
-               free(sc->mcsp, M_DEVBUF);
-       /* frees entire chain */
-       if (sc->rfa_headm)
-               m_freem(sc->rfa_headm);
-
-       return (ENOMEM);
-}
-
-/*
- * From NetBSD:
- *
- * Figure out EEPROM size.
- *
- * 559's can have either 64-word or 256-word EEPROMs, the 558
- * datasheet only talks about 64-word EEPROMs, and the 557 datasheet
- * talks about the existance of 16 to 256 word EEPROMs.
- *
- * The only known sizes are 64 and 256, where the 256 version is used
- * by CardBus cards to store CIS information.
- *
- * The address is shifted in msb-to-lsb, and after the last
- * address-bit the EEPROM is supposed to output a `dummy zero' bit,
- * after which follows the actual data. We try to detect this zero, by
- * probing the data-out bit in the EEPROM control register just after
- * having shifted in a bit. If the bit is zero, we assume we've
- * shifted enough address bits. The data-out should be tri-state,
- * before this, which should translate to a logical one.
- *
- * Other ways to do this would be to try to read a register with known
- * contents with a varying number of address bits, but no such
- * register seem to be available. The high bits of register 10 are 01
- * on the 558 and 559, but apparently not on the 557.
- * 
- * The Linux driver computes a checksum on the EEPROM data, but the
- * value of this checksum is not very well documented.
- */
-void
-fxp_autosize_eeprom(sc)
-       struct fxp_softc *sc;
-{
-       u_int16_t reg;
-       int x;
-
-       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
-       /*
-        * Shift in read opcode.
-        */
-       for (x = 3; x > 0; x--) {
-               if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
-                       reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
-               } else {
-                       reg = FXP_EEPROM_EECS;
-               }
-               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
-               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
-                   reg | FXP_EEPROM_EESK);
-               DELAY(1);
-               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
-               DELAY(1);
-       }
-       /*
-        * Shift in address.
-        * Wait for the dummy zero following a correct address shift.
-        */
-       for (x = 1; x <= 8; x++) {
-               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
-               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
-                       FXP_EEPROM_EECS | FXP_EEPROM_EESK);
-               DELAY(1);
-               if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) == 0)
-                       break;
-               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
-               DELAY(1);
-       }
-       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
-       DELAY(1);
-       sc->eeprom_size = x;
-}
-/*
- * Read from the serial EEPROM. Basically, you manually shift in
- * the read opcode (one bit at a time) and then shift in the address,
- * and then you shift out the data (all of this one bit at a time).
- * The word size is 16 bits, so you have to provide the address for
- * every 16 bits of data.
- */
-void
-fxp_read_eeprom(sc, data, offset, words)
-       struct fxp_softc *sc;
-       u_short *data;
-       int offset;
-       int words;
-{
-       u_int16_t reg;
-       int i, x;
-
-       for (i = 0; i < words; i++) {
-               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
-               /*
-                * Shift in read opcode.
-                */
-               for (x = 3; x > 0; x--) {
-                       if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
-                               reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
-                       } else {
-                               reg = FXP_EEPROM_EECS;
-                       }
-                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
-                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
-                           reg | FXP_EEPROM_EESK);
-                       DELAY(1);
-                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
-                       DELAY(1);
-               }
-               /*
-                * Shift in address.
-                */
-               for (x = sc->eeprom_size; x > 0; x--) {
-                       if ((i + offset) & (1 << (x - 1))) {
-                               reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
-                       } else {
-                               reg = FXP_EEPROM_EECS;
-                       }
-                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
-                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
-                           reg | FXP_EEPROM_EESK);
-                       DELAY(1);
-                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
-                       DELAY(1);
-               }
-               reg = FXP_EEPROM_EECS;
-               data[i] = 0;
-               /*
-                * Shift out data.
-                */
-               for (x = 16; x > 0; x--) {
-                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
-                           reg | FXP_EEPROM_EESK);
-                       DELAY(1);
-                       if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
-                           FXP_EEPROM_EEDO)
-                               data[i] |= (1 << (x - 1));
-                       CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
-                       DELAY(1);
-               }
-               CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
-               DELAY(1);
-       }
-}
-
-/*
- * Start packet transmission on the interface.
- */
-void
-fxp_start(ifp)
-       struct ifnet *ifp;
-{
-       struct fxp_softc *sc = ifp->if_softc;
-       struct fxp_cb_tx *txp;
-
-       /*
-        * See if we need to suspend xmit until the multicast filter
-        * has been reprogrammed (which can only be done at the head
-        * of the command chain).
-        */
-       if (sc->need_mcsetup)
-               return;
-
-       txp = NULL;
-
-       /*
-        * We're finished if there is nothing more to add to the list or if
-        * we're all filled up with buffers to transmit.
-        * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add
-        *       a NOP command when needed.
-        */
-       while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB - 1) {
-               struct mbuf *m, *mb_head;
-               int segment;
-
-               /*
-                * Grab a packet to transmit.
-                */
-               IF_DEQUEUE(&ifp->if_snd, mb_head);
-
-               /*
-                * Get pointer to next available tx desc.
-                */
-               txp = sc->cbl_last->next;
-
-               /*
-                * Go through each of the mbufs in the chain and initialize
-                * the transmit buffer descriptors with the physical address
-                * and size of the mbuf.
-                */
-tbdinit:
-               for (m = mb_head, segment = 0; m != NULL; m = m->m_next) {
-                       if (m->m_len != 0) {
-                               if (segment == FXP_NTXSEG)
-                                       break;
-                               txp->tbd[segment].tb_addr =
-                                   vtophys(mtod(m, vm_offset_t));
-                               txp->tbd[segment].tb_size = m->m_len;
-                               segment++;
-                       }
-               }
-               if (m != NULL) {
-                       struct mbuf *mn;
-
-                       /*
-                        * We ran out of segments. We have to recopy this mbuf
-                        * chain first. Bail out if we can't get the new buffers.
-                        */
-                       MGETHDR(mn, M_DONTWAIT, MT_DATA);
-                       if (mn == NULL) {
-                               m_freem(mb_head);
-                               break;
-                       }
-                       if (mb_head->m_pkthdr.len > MHLEN) {
-                               MCLGET(mn, M_DONTWAIT);
-                               if ((mn->m_flags & M_EXT) == 0) {
-                                       m_freem(mn);
-                                       m_freem(mb_head);
-                                       break;
-                               }
-                       }
-                       m_copydata(mb_head, 0, mb_head->m_pkthdr.len,
-                           mtod(mn, caddr_t));
-                       mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len;
-                       m_freem(mb_head);
-                       mb_head = mn;
-                       goto tbdinit;
-               }
-
-               txp->tbd_number = segment;
-               txp->mb_head = mb_head;
-               txp->cb_status = 0;
-               if (sc->tx_queued != FXP_CXINT_THRESH - 1) {
-                       txp->cb_command =
-                           FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S;
-               } else {
-                       txp->cb_command =
-                           FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;
-                       /*
-                        * Set a 5 second timer just in case we don't hear from the
-                        * card again.
-                        */
-                       ifp->if_timer = 5;
-               }
-               txp->tx_threshold = tx_threshold;
-       
-               /*
-                * Advance the end of list forward.
-                */
-               sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;
-               sc->cbl_last = txp;
-
-               /*
-                * Advance the beginning of the list forward if there are
-                * no other packets queued (when nothing is queued, cbl_first
-                * sits on the last TxCB that was sent out).
-                */
-               if (sc->tx_queued == 0)
-                       sc->cbl_first = txp;
-
-               sc->tx_queued++;
-
-#if NBPFILTER > 0
-               /*
-                * Pass packet to bpf if there is a listener.
-                */
-               if (ifp->if_bpf)
-                       bpf_mtap(ifp->if_bpf, mb_head);
-#endif
-       }
-
-       /*
-        * We're finished. If we added to the list, issue a RESUME to get DMA
-        * going again if suspended.
-        */
-       if (txp != NULL) {
-               fxp_scb_wait(sc);
-               CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
-       }
-}
-
-/*
- * Process interface interrupts.
- */
-int
-fxp_intr(arg)
-       void *arg;
-{
-       struct fxp_softc *sc = arg;
-       struct ifnet *ifp = &sc->arpcom.ac_if;
-       u_int8_t statack;
-       int claimed = 0;
-
-       /*
-        * If the interface isn't running, don't try to
-        * service the interrupt.. just ack it and bail.
-        */
-       if ((ifp->if_flags & IFF_RUNNING) == 0) {
-               statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK);
-               if (statack) {
-                       claimed = 1;
-                       CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
-               }
-               return claimed;
-       }
-
-       while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
-               claimed = 1;
-               /*
-                * First ACK all the interrupts in this pass.
-                */
-               CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
-
-               /*
-                * Free any finished transmit mbuf chains.
-                */
-               if (statack & FXP_SCB_STATACK_CXTNO) {
-                       struct fxp_cb_tx *txp;
-
-                       for (txp = sc->cbl_first; sc->tx_queued &&
-                           (txp->cb_status & FXP_CB_STATUS_C) != 0;
-                           txp = txp->next) {
-                               if (txp->mb_head != NULL) {
-                                       m_freem(txp->mb_head);
-                                       txp->mb_head = NULL;
-                               }
-                               sc->tx_queued--;
-                       }
-                       sc->cbl_first = txp;
-                       ifp->if_timer = 0;
-                       if (sc->tx_queued == 0) {
-                               if (sc->need_mcsetup)
-                                       fxp_mc_setup(sc);
-                       }
-                       /*
-                        * Try to start more packets transmitting.
-                        */
-                       if (ifp->if_snd.ifq_head != NULL)
-                               fxp_start(ifp);
-               }
-               /*
-                * Process receiver interrupts. If a no-resource (RNR)
-                * condition exists, get whatever packets we can and
-                * re-start the receiver.
-                */
-               if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) {
-                       struct mbuf *m;
-                       u_int8_t *rfap;
-rcvloop:
-                       m = sc->rfa_headm;
-                       rfap = m->m_ext.ext_buf + RFA_ALIGNMENT_FUDGE;
-
-                       if (*(u_int16_t *)(rfap +
-                           offsetof(struct fxp_rfa, rfa_status)) &
-                           FXP_RFA_STATUS_C) {
-                               /*
-                                * Remove first packet from the chain.
-                                */
-                               sc->rfa_headm = m->m_next;
-                               m->m_next = NULL;
-
-                               /*
-                                * Add a new buffer to the receive chain.
-                                * If this fails, the old buffer is recycled
-                                * instead.
-                                */
-                               if (fxp_add_rfabuf(sc, m) == 0) {
-                                       struct ether_header *eh;
-                                       u_int16_t total_len;
-
-                                       total_len = *(u_int16_t *)(rfap +
-                                           offsetof(struct fxp_rfa,
-                                           actual_size)) &
-                                           (MCLBYTES - 1);
-                                       if (total_len <
-                                           sizeof(struct ether_header)) {
-                                               m_freem(m);
-                                               goto rcvloop;
-                                       }
-                                       m->m_pkthdr.rcvif = ifp;
-                                       m->m_pkthdr.len = m->m_len =
-                                           total_len -
-                                           sizeof(struct ether_header);
-                                       eh = mtod(m, struct ether_header *);
-#if NBPFILTER > 0
-                                       if (ifp->if_bpf)
-                                               bpf_tap(ifp->if_bpf,
-                                                   mtod(m, caddr_t),
-                                                   total_len); 
-#endif /* NBPFILTER > 0 */
-                                       m->m_data +=
-                                           sizeof(struct ether_header);
-                                       ether_input(ifp, eh, m);
-                               }
-                               goto rcvloop;
-                       }
-                       if (statack & FXP_SCB_STATACK_RNR) {
-                               fxp_scb_wait(sc);
-                               CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
-                                   vtophys(sc->rfa_headm->m_ext.ext_buf) +
-                                       RFA_ALIGNMENT_FUDGE);
-                               CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
-                                   FXP_SCB_COMMAND_RU_START);
-                       }
-               }
-       }
-       return (claimed);
-}
-
-/*
- * Update packet in/out/collision statistics. The i82557 doesn't
- * allow you to access these counters without doing a fairly
- * expensive DMA to get _all_ of the statistics it maintains, so
- * we do this operation here only once per second. The statistics
- * counters in the kernel are updated from the previous dump-stats
- * DMA and then a new dump-stats DMA is started. The on-chip
- * counters are zeroed when the DMA completes. If we can't start
- * the DMA immediately, we don't wait - we just prepare to read
- * them again next time.
- */
-void
-fxp_stats_update(arg)
-       void *arg;
-{
-       struct fxp_softc *sc = arg;
-       struct ifnet *ifp = &sc->arpcom.ac_if;
-       struct fxp_stats *sp = sc->fxp_stats;
-       int s;
-
-       ifp->if_opackets += sp->tx_good;
-       ifp->if_collisions += sp->tx_total_collisions;
-       if (sp->rx_good) {
-               ifp->if_ipackets += sp->rx_good;
-               sc->rx_idle_secs = 0;
-       } else {
-               sc->rx_idle_secs++;
-       }
-       ifp->if_ierrors +=
-           sp->rx_crc_errors +
-           sp->rx_alignment_errors +
-           sp->rx_rnr_errors +
-           sp->rx_overrun_errors;
-       /*
-        * If any transmit underruns occured, bump up the transmit
-        * threshold by another 512 bytes (64 * 8).
-        */
-       if (sp->tx_underruns) {
-               ifp->if_oerrors += sp->tx_underruns;
-               if (tx_threshold < 192)
-                       tx_threshold += 64;
-       }
-       s = splimp();
-       /*
-        * If we haven't received any packets in FXP_MAC_RX_IDLE seconds,
-        * then assume the receiver has locked up and attempt to clear
-        * the condition by reprogramming the multicast filter. This is
-        * a work-around for a bug in the 82557 where the receiver locks
-        * up if it gets certain types of garbage in the syncronization
-        * bits prior to the packet header. This bug is supposed to only
-        * occur in 10Mbps mode, but has been seen to occur in 100Mbps
-        * mode as well (perhaps due to a 10/100 speed transition).
-        */
-       if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) {
-               sc->rx_idle_secs = 0;
-               fxp_mc_setup(sc);
-       }
-       /*
-        * If there is no pending command, start another stats
-        * dump. Otherwise punt for now.
-        */
-       if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) {
-               /*
-                * Start another stats dump.
-                */
-               CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
-                   FXP_SCB_COMMAND_CU_DUMPRESET);
-       } else {
-               /*
-                * A previous command is still waiting to be accepted.
-                * Just zero our copy of the stats and wait for the
-                * next timer event to update them.
-                */
-               sp->tx_good = 0;
-               sp->tx_underruns = 0;
-               sp->tx_total_collisions = 0;
-
-               sp->rx_good = 0;
-               sp->rx_crc_errors = 0;
-               sp->rx_alignment_errors = 0;
-               sp->rx_rnr_errors = 0;
-               sp->rx_overrun_errors = 0;
-       }
-
-       /* Tick the MII clock. */
-       mii_tick(&sc->sc_mii);
-
-       splx(s);
-       /*
-        * Schedule another timeout one second from now.
-        */
-       timeout(fxp_stats_update, sc, hz);
-}
-
-/*
- * Stop the interface. Cancels the statistics updater and resets
- * the interface.
- */
-void
-fxp_stop(sc, drain)
-       struct fxp_softc *sc;
-       int drain;
-{
-       struct ifnet *ifp = &sc->arpcom.ac_if;
-       struct fxp_cb_tx *txp;
-       int i;
-
-       /*
-        * Turn down interface (done early to avoid bad interactions
-        * between panics, shutdown hooks, and the watchdog timer)
-        */
-       ifp->if_timer = 0;
-       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-
-       /*
-        * Cancel stats updater.
-        */
-       untimeout(fxp_stats_update, sc);
-
-       /*
-        * Issue software reset
-        */
-       CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
-       DELAY(10);
-
-       /*
-        * Release any xmit buffers.
-        */
-       for (txp = sc->cbl_first; txp != NULL && txp->mb_head != NULL;
-           txp = txp->next) {
-               m_freem(txp->mb_head);
-               txp->mb_head = NULL;
-       }
-       sc->tx_queued = 0;
-
-       if (drain) {
-               /*
-                * Free all the receive buffers then reallocate/reinitialize
-                */
-               if (sc->rfa_headm != NULL)
-                       m_freem(sc->rfa_headm);
-               sc->rfa_headm = NULL;
-               sc->rfa_tailm = NULL;
-               for (i = 0; i < FXP_NRFABUFS; i++) {
-                       if (fxp_add_rfabuf(sc, NULL) != 0) {
-                               /*
-                                * This "can't happen" - we're at splimp()
-                                * and we just freed all the buffers we need
-                                * above.
-                                */
-                               panic("fxp_stop: no buffers!");
-                       }
-               }
-       }
-
-}
-
-/*
- * Watchdog/transmission transmit timeout handler. Called when a
- * transmission is started on the interface, but no interrupt is
- * received before the timeout. This usually indicates that the
- * card has wedged for some reason.
- */
-void
-fxp_watchdog(ifp)
-       struct ifnet *ifp;
-{
-       struct fxp_softc *sc = ifp->if_softc;
-
-       log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
-       ifp->if_oerrors++;
-
-       fxp_init(sc);
-}
-
-void
-fxp_init(xsc)
-       void *xsc;
-{
-       struct fxp_softc *sc = xsc;
-       struct ifnet *ifp = &sc->arpcom.ac_if;
-       struct fxp_cb_config *cbp;
-       struct fxp_cb_ias *cb_ias;
-       struct fxp_cb_tx *txp;
-       int i, s, prm;
-
-       s = splimp();
-       /*
-        * Cancel any pending I/O
-        */
-       fxp_stop(sc, 0);
-
-       prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
-
-       /*
-        * Initialize base of CBL and RFA memory. Loading with zero
-        * sets it up for regular linear addressing.
-        */
-       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
-       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
-
-       fxp_scb_wait(sc);
-       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
-
-       /*
-        * Initialize base of dump-stats buffer.
-        */
-       fxp_scb_wait(sc);
-       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats));
-       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR);
-
-       /*
-        * We temporarily use memory that contains the TxCB list to
-        * construct the config CB. The TxCB list memory is rebuilt
-        * later.
-        */
-       cbp = (struct fxp_cb_config *) sc->cbl_base;
-
-       /*
-        * This bcopy is kind of disgusting, but there are a bunch of must be
-        * zero and must be one bits in this structure and this is the easiest
-        * way to initialize them all to proper values.
-        */
-       bcopy(fxp_cb_config_template, (void *)&cbp->cb_status,
-               sizeof(fxp_cb_config_template));
-
-       cbp->cb_status =        0;
-       cbp->cb_command =       FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
-       cbp->link_addr =        -1;     /* (no) next command */
-       cbp->byte_count =       22;     /* (22) bytes to config */
-       cbp->rx_fifo_limit =    8;      /* rx fifo threshold (32 bytes) */
-       cbp->tx_fifo_limit =    0;      /* tx fifo threshold (0 bytes) */
-       cbp->adaptive_ifs =     0;      /* (no) adaptive interframe spacing */
-       cbp->rx_dma_bytecount = 0;      /* (no) rx DMA max */
-       cbp->tx_dma_bytecount = 0;      /* (no) tx DMA max */
-       cbp->dma_bce =          0;      /* (disable) dma max counters */
-       cbp->late_scb =         0;      /* (don't) defer SCB update */
-       cbp->tno_int =          0;      /* (disable) tx not okay interrupt */
-       cbp->ci_int =           1;      /* interrupt on CU idle */
-       cbp->save_bf =          prm;    /* save bad frames */
-       cbp->disc_short_rx =    !prm;   /* discard short packets */
-       cbp->underrun_retry =   1;      /* retry mode (1) on DMA underrun */
-       cbp->mediatype =        !sc->phy_10Mbps_only; /* interface mode */
-       cbp->nsai =             1;      /* (don't) disable source addr insert */
-       cbp->preamble_length =  2;      /* (7 byte) preamble */
-       cbp->loopback =         0;      /* (don't) loopback */
-       cbp->linear_priority =  0;      /* (normal CSMA/CD operation) */
-       cbp->linear_pri_mode =  0;      /* (wait after xmit only) */
-       cbp->interfrm_spacing = 6;      /* (96 bits of) interframe spacing */
-       cbp->promiscuous =      prm;    /* promiscuous mode */
-       cbp->bcast_disable =    0;      /* (don't) disable broadcasts */
-       cbp->crscdt =           0;      /* (CRS only) */
-       cbp->stripping =        !prm;   /* truncate rx packet to byte count */
-       cbp->padding =          1;      /* (do) pad short tx packets */
-       cbp->rcv_crc_xfer =     0;      /* (don't) xfer CRC to host */
-       cbp->force_fdx =        0;      /* (don't) force full duplex */
-       cbp->fdx_pin_en =       1;      /* (enable) FDX# pin */
-       cbp->multi_ia =         0;      /* (don't) accept multiple IAs */
-       cbp->mc_all =           sc->all_mcasts;/* accept all multicasts */
-
-       /*
-        * Start the config command/DMA.
-        */
-       fxp_scb_wait(sc);
-       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
-       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
-       /* ...and wait for it to complete. */
-       while (!(cbp->cb_status & FXP_CB_STATUS_C));
-
-       /*
-        * Now initialize the station address. Temporarily use the TxCB
-        * memory area like we did above for the config CB.
-        */
-       cb_ias = (struct fxp_cb_ias *) sc->cbl_base;
-       cb_ias->cb_status = 0;
-       cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
-       cb_ias->link_addr = -1;
-       bcopy(sc->arpcom.ac_enaddr, (void *)cb_ias->macaddr,
-           sizeof(sc->arpcom.ac_enaddr));
-
-       /*
-        * Start the IAS (Individual Address Setup) command/DMA.
-        */
-       fxp_scb_wait(sc);
-       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
-       /* ...and wait for it to complete. */
-       while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
-
-       /*
-        * Initialize transmit control block (TxCB) list.
-        */
-
-       txp = sc->cbl_base;
-       bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB);
-       for (i = 0; i < FXP_NTXCB; i++) {
-               txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
-               txp[i].cb_command = FXP_CB_COMMAND_NOP;
-               txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status);
-               txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]);
-               txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK];
-       }
-       /*
-        * Set the suspend flag on the first TxCB and start the control
-        * unit. It will execute the NOP and then suspend.
-        */
-       txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
-       sc->cbl_first = sc->cbl_last = txp;
-       sc->tx_queued = 1;
-
-       fxp_scb_wait(sc);
-       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
-
-       /*
-        * Initialize receiver buffer area - RFA.
-        */
-       fxp_scb_wait(sc);
-       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
-           vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE);
-       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
-
-       /*
-        * Set current media.
-        */
-       mii_mediachg(&sc->sc_mii);
-
-       ifp->if_flags |= IFF_RUNNING;
-       ifp->if_flags &= ~IFF_OACTIVE;
-       splx(s);
-
-       /*
-        * Start stats updater.
-        */
-       timeout(fxp_stats_update, sc, hz);
-}
-
-/*
- * Change media according to request.
- */
-int
-fxp_mediachange(ifp)
-       struct ifnet *ifp;
-{
-
-       if (ifp->if_flags & IFF_UP)
-               fxp_init(ifp->if_softc);
-       return (0);
-}
-
-/*
- * Notify the world which media we're using.
- */
-void
-fxp_mediastatus(ifp, ifmr)
-       struct ifnet *ifp;
-       struct ifmediareq *ifmr;
-{
-       struct fxp_softc *sc = ifp->if_softc;
-
-       mii_pollstat(&sc->sc_mii);
-       ifmr->ifm_status = sc->sc_mii.mii_media_status;
-       ifmr->ifm_active = sc->sc_mii.mii_media_active;
-}
-
-/*
- * Add a buffer to the end of the RFA buffer list.
- * Return 0 if successful, 1 for failure. A failure results in
- * adding the 'oldm' (if non-NULL) on to the end of the list -
- * tossing out its old contents and recycling it.
- * The RFA struct is stuck at the beginning of mbuf cluster and the
- * data pointer is fixed up to point just past it.
- */
-int
-fxp_add_rfabuf(sc, oldm)
-       struct fxp_softc *sc;
-       struct mbuf *oldm;
-{
-       u_int32_t v;
-       struct mbuf *m;
-       u_int8_t *rfap;
-
-       MGETHDR(m, M_DONTWAIT, MT_DATA);
-       if (m != NULL) {
-               MCLGET(m, M_DONTWAIT);
-               if ((m->m_flags & M_EXT) == 0) {
-                       m_freem(m);
-                       if (oldm == NULL)
-                               return 1;
-                       m = oldm;
-                       m->m_data = m->m_ext.ext_buf;
-               }
-       } else {
-               if (oldm == NULL)
-                       return 1;
-               m = oldm;
-               m->m_data = m->m_ext.ext_buf;
-       }
-
-       /*
-        * Move the data pointer up so that the incoming data packet
-        * will be 32-bit aligned.
-        */
-       m->m_data += RFA_ALIGNMENT_FUDGE;
-
-       /*
-        * Get a pointer to the base of the mbuf cluster and move
-        * data start past it.
-        */
-       rfap = m->m_data;
-       m->m_data += sizeof(struct fxp_rfa);
-       *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, size)) =
-           MCLBYTES - sizeof(struct fxp_rfa) - RFA_ALIGNMENT_FUDGE;
-
-       /*
-        * Initialize the rest of the RFA.  Note that since the RFA
-        * is misaligned, we cannot store values directly.  Instead,
-        * we use an optimized, inline copy.
-        */
-       *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_status)) = 0;
-       *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_control)) =
-           FXP_RFA_CONTROL_EL;
-       *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, actual_size)) = 0;
-
-       v = -1;
-       fxp_lwcopy(&v,
-           (u_int32_t *)(rfap + offsetof(struct fxp_rfa, link_addr)));
-       fxp_lwcopy(&v,
-           (u_int32_t *)(rfap + offsetof(struct fxp_rfa, rbd_addr)));
-
-       /*
-        * If there are other buffers already on the list, attach this
-        * one to the end by fixing up the tail to point to this one.
-        */
-       if (sc->rfa_headm != NULL) {
-               sc->rfa_tailm->m_next = m;
-               v = vtophys(rfap);
-               rfap = sc->rfa_tailm->m_ext.ext_buf + RFA_ALIGNMENT_FUDGE;
-               fxp_lwcopy(&v,
-                   (u_int32_t *)(rfap + offsetof(struct fxp_rfa, link_addr)));
-               *(u_int16_t *)(rfap + offsetof(struct fxp_rfa, rfa_control)) &=
-                   ~FXP_RFA_CONTROL_EL;
-       } else {
-               sc->rfa_headm = m;
-       }
-       sc->rfa_tailm = m;
-
-       return (m == oldm);
-}
-
-volatile int
-fxp_mdi_read(self, phy, reg)
-       struct device *self;
-       int phy;
-       int reg;
-{
-       struct fxp_softc *sc = (struct fxp_softc *)self;
-       int count = 10000;
-       int value;
-
-       CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
-           (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));
-
-       while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0
-           && count--)
-               DELAY(10);
-
-       if (count <= 0)
-               printf("%s: fxp_mdi_read: timed out\n", sc->sc_dev.dv_xname);
-
-       return (value & 0xffff);
-}
-
-void
-fxp_statchg(self)
-       struct device *self;
-{
-
-       /* XXX Update ifp->if_baudrate */
-}
-
-void
-fxp_mdi_write(self, phy, reg, value)
-       struct device *self;
-       int phy;
-       int reg;
-       int value;
-{
-       struct fxp_softc *sc = (struct fxp_softc *)self;
-       int count = 10000;
-
-       CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
-           (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) |
-           (value & 0xffff));
-
-       while((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 &&
-           count--)
-               DELAY(10);
-
-       if (count <= 0)
-               printf("%s: fxp_mdi_write: timed out\n", sc->sc_dev.dv_xname);
-}
-
-int
-fxp_ioctl(ifp, command, data)
-       struct ifnet *ifp;
-       u_long command;
-       caddr_t data;
-{
-       struct fxp_softc *sc = ifp->if_softc;
-       struct ifreq *ifr = (struct ifreq *)data;
-       int s, error = 0;
-
-       s = splimp();
-
-       switch (command) {
-
-       case SIOCSIFADDR:
-       case SIOCGIFADDR:
-       case SIOCSIFMTU:
-               error = ether_ioctl(ifp, command, data);
-               break;
-
-       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.
-                * XXX If it's up then re-initialize it. This is so flags
-                * such as IFF_PROMISC are handled.
-                */
-               if (ifp->if_flags & IFF_UP) {
-                       fxp_init(sc);
-               } else {
-                       if (ifp->if_flags & IFF_RUNNING)
-                               fxp_stop(sc, 1);
-               }
-               break;
-
-       case SIOCADDMULTI:
-       case SIOCDELMULTI:
-               sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
-               error = (command == SIOCADDMULTI) ?
-                   ether_addmulti(ifr, &sc->arpcom) :
-                   ether_delmulti(ifr, &sc->arpcom);
-               if (error == ENETRESET) {
-                       /*
-                        * Multicast list has changed; set the hardware
-                        * filter accordingly.
-                        */
-                       if (!sc->all_mcasts)
-                               fxp_mc_setup(sc);
-                       /*
-                        * fxp_mc_setup() can turn on all_mcasts if we run
-                        * out of space, so check it again rather than else {}.
-                        */
-                       if (sc->all_mcasts)
-                               fxp_init(sc);
-                       error = 0;
-               }
-               break;
-
-       case SIOCSIFMEDIA:
-       case SIOCGIFMEDIA:
-               error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
-               break;
-
-       default:
-               error = EINVAL;
-       }
-       (void) splx(s);
-       return (error);
-}
-
-/*
- * Program the multicast filter.
- *
- * We have an artificial restriction that the multicast setup command
- * must be the first command in the chain, so we take steps to ensure
- * this. By requiring this, it allows us to keep up the performance of
- * the pre-initialized command ring (esp. link pointers) by not actually
- * inserting the mcsetup command in the ring - i.e. its link pointer
- * points to the TxCB ring, but the mcsetup descriptor itself is not part
- * of it. We then can do 'CU_START' on the mcsetup descriptor and have it
- * lead into the regular TxCB ring when it completes.
- *
- * This function must be called at splimp.
- */
-void
-fxp_mc_setup(sc)
-       struct fxp_softc *sc;
-{
-       struct fxp_cb_mcs *mcsp = sc->mcsp;
-       struct ifnet *ifp = &sc->arpcom.ac_if;
-       struct ether_multistep step;
-       struct ether_multi *enm;
-       int nmcasts;
-
-       /*
-        * If there are queued commands, we must wait until they are all
-        * completed. If we are already waiting, then add a NOP command
-        * with interrupt option so that we're notified when all commands
-        * have been completed - fxp_start() ensures that no additional
-        * TX commands will be added when need_mcsetup is true.
-        */
-       if (sc->tx_queued) {
-               struct fxp_cb_tx *txp;
-
-               /*
-                * need_mcsetup will be true if we are already waiting for the
-                * NOP command to be completed (see below). In this case, bail.
-                */
-               if (sc->need_mcsetup)
-                       return;
-               sc->need_mcsetup = 1;
-
-               /*
-                * Add a NOP command with interrupt so that we are notified when all
-                * TX commands have been processed.
-                */
-               txp = sc->cbl_last->next;
-               txp->mb_head = NULL;
-               txp->cb_status = 0;
-               txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;
-               /*
-                * Advance the end of list forward.
-                */
-               sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;
-               sc->cbl_last = txp;
-               sc->tx_queued++;
-               /*
-                * Issue a resume in case the CU has just suspended.
-                */
-               fxp_scb_wait(sc);
-               CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
-               /*
-                * Set a 5 second timer just in case we don't hear from the
-                * card again.
-                */
-               ifp->if_timer = 5;
-
-               return;
-       }
-       sc->need_mcsetup = 0;
-
-       /*
-        * Initialize multicast setup descriptor.
-        */
-       mcsp->next = sc->cbl_base;
-       mcsp->mb_head = NULL;
-       mcsp->cb_status = 0;
-       mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;
-       mcsp->link_addr = vtophys(&sc->cbl_base->cb_status);
-
-       nmcasts = 0;
-       if (!sc->all_mcasts) {
-               ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
-               while (enm != NULL) {
-                       if (nmcasts >= MAXMCADDR) {
-                               sc->all_mcasts = 1;
-                               nmcasts = 0;
-                               break;
-                       }
-
-                       /* Punt on ranges. */
-                       if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
-                           sizeof(enm->enm_addrlo)) != 0) {
-                               sc->all_mcasts = 1;
-                               nmcasts = 0;
-                               break;
-                       }
-                       bcopy(enm->enm_addrlo,
-                           (void *) &sc->mcsp->mc_addr[nmcasts][0], 6);
-                       nmcasts++;
-                       ETHER_NEXT_MULTI(step, enm);
-               }
-       }
-       mcsp->mc_cnt = nmcasts * 6;
-       sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp;
-       sc->tx_queued = 1;
-
-       /*
-        * Wait until command unit is not active. This should never
-        * be the case when nothing is queued, but make sure anyway.
-        */
-       while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
-           FXP_SCB_CUS_ACTIVE) ;
-
-       /*
-        * Start the multicast setup command.
-        */
-       fxp_scb_wait(sc);
-       CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status));
-       CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
-
-       ifp->if_timer = 2;
-       return;
-}
diff --git a/sys/dev/pci/if_fxp_pci.c b/sys/dev/pci/if_fxp_pci.c
new file mode 100644 (file)
index 0000000..61b4aa1
--- /dev/null
@@ -0,0 +1,178 @@
+/*     $OpenBSD: if_fxp_pci.c,v 1.1 2000/04/18 18:44:31 jason Exp $    */
+
+/*
+ * Copyright (c) 1995, David Greenman
+ * All rights reserved.
+ *
+ * Modifications to support NetBSD:
+ * Copyright (c) 1997 Jason R. Thorpe.  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.
+ *
+ *     Id: if_fxp.c,v 1.55 1998/08/04 08:53:12 dg Exp
+ */
+
+/*
+ * Intel EtherExpress Pro/100B PCI Fast Ethernet driver
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <netinet/if_ether.h>
+
+#include <vm/vm.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/ic/fxpreg.h>
+#include <dev/ic/fxpvar.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+int fxp_pci_match __P((struct device *, void *, void *));
+void fxp_pci_attach __P((struct device *, struct device *, void *));
+
+struct cfattach fxp_pci_ca = {
+       sizeof(struct fxp_softc), fxp_pci_match, fxp_pci_attach
+};
+
+/*
+ * Check if a device is an 82557.
+ */
+int
+fxp_pci_match(parent, match, aux)
+       struct device *parent;
+       void *match;
+       void *aux;
+{
+       struct pci_attach_args *pa = aux;
+
+       if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
+               return (0);
+
+       switch (PCI_PRODUCT(pa->pa_id)) {
+       case PCI_PRODUCT_INTEL_82557:
+       case PCI_PRODUCT_INTEL_82559:
+               return (1);
+       }
+
+       return (0);
+}
+
+void
+fxp_pci_attach(parent, self, aux)
+       struct device *parent, *self;
+       void *aux;
+{
+       struct fxp_softc *sc = (struct fxp_softc *)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_int8_t enaddr[6];
+       bus_space_tag_t iot = pa->pa_iot;
+       bus_addr_t iobase;
+       bus_size_t iosize;
+
+       if (pci_io_find(pc, pa->pa_tag, FXP_PCI_IOBA, &iobase, &iosize)) {
+               printf(": can't find i/o space\n");
+               return;
+       }
+
+       if (bus_space_map(iot, iobase, iosize, 0, &sc->sc_sh)) {
+               printf(": can't map i/o space\n");
+               return;
+       }
+       sc->sc_st = iot;
+
+       /*
+        * Allocate our interrupt.
+        */
+       if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+           pa->pa_intrline, &ih)) {
+               printf(": couldn't map interrupt\n");
+               return;
+       }
+
+       intrstr = pci_intr_string(pc, ih);
+       sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, fxp_intr, sc,
+           self->dv_xname);
+       if (sc->sc_ih == NULL) {
+               printf(": couldn't establish interrupt");
+               if (intrstr != NULL)
+                       printf(" at %s", intrstr);
+               printf("\n");
+               return;
+       }
+
+       /* Do generic parts of attach. */
+       if (fxp_attach_common(sc, enaddr, intrstr)) {
+               /* Failed! */
+               return;
+       }
+}
diff --git a/sys/dev/pci/if_fxpreg.h b/sys/dev/pci/if_fxpreg.h
deleted file mode 100644 (file)
index 38a2ac5..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-/*     $OpenBSD: if_fxpreg.h,v 1.5 1998/07/02 21:15:46 downsj Exp $    */
-
-/*
- * Copyright (c) 1995, David Greenman
- * 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: if_fxpreg.h,v 1.13 1998/06/08 09:47:46 bde Exp $
- */
-
-#define FXP_VENDORID_INTEL     0x8086
-#define FXP_DEVICEID_i82557    0x1229
-
-#define FXP_PCI_MMBA   0x10
-#define FXP_PCI_IOBA   0x14
-
-/*
- * Control/status registers.
- */
-#define        FXP_CSR_SCB_RUSCUS      0       /* scb_rus/scb_cus (1 byte) */
-#define        FXP_CSR_SCB_STATACK     1       /* scb_statack (1 byte) */
-#define        FXP_CSR_SCB_COMMAND     2       /* scb_command (1 byte) */
-#define        FXP_CSR_SCB_INTRCNTL    3       /* scb_intrcntl (1 byte) */
-#define        FXP_CSR_SCB_GENERAL     4       /* scb_general (4 bytes) */
-#define        FXP_CSR_PORT            8       /* port (4 bytes) */
-#define        FXP_CSR_FLASHCONTROL    12      /* flash control (2 bytes) */
-#define        FXP_CSR_EEPROMCONTROL   14      /* eeprom control (2 bytes) */
-#define        FXP_CSR_MDICONTROL      16      /* mdi control (4 bytes) */
-
-/*
- * FOR REFERENCE ONLY, the old definition of FXP_CSR_SCB_RUSCUS:
- *
- *     volatile u_int8_t       :2,
- *                             scb_rus:4,
- *                             scb_cus:2;
- */
-
-#define FXP_PORT_SOFTWARE_RESET                0
-#define FXP_PORT_SELFTEST              1
-#define FXP_PORT_SELECTIVE_RESET       2
-#define FXP_PORT_DUMP                  3
-
-#define FXP_SCB_RUS_IDLE               0
-#define FXP_SCB_RUS_SUSPENDED          1
-#define FXP_SCB_RUS_NORESOURCES                2
-#define FXP_SCB_RUS_READY              4
-#define FXP_SCB_RUS_SUSP_NORBDS                9
-#define FXP_SCB_RUS_NORES_NORBDS       10
-#define FXP_SCB_RUS_READY_NORBDS       12
-
-#define FXP_SCB_CUS_IDLE               0
-#define FXP_SCB_CUS_SUSPENDED          1
-#define FXP_SCB_CUS_ACTIVE             2
-
-#define FXP_SCB_STATACK_SWI            0x04
-#define FXP_SCB_STATACK_MDI            0x08
-#define FXP_SCB_STATACK_RNR            0x10
-#define FXP_SCB_STATACK_CNA            0x20
-#define FXP_SCB_STATACK_FR             0x40
-#define FXP_SCB_STATACK_CXTNO          0x80
-
-#define FXP_SCB_COMMAND_CU_NOP         0x00
-#define FXP_SCB_COMMAND_CU_START       0x10
-#define FXP_SCB_COMMAND_CU_RESUME      0x20
-#define FXP_SCB_COMMAND_CU_DUMP_ADR    0x40
-#define FXP_SCB_COMMAND_CU_DUMP                0x50
-#define FXP_SCB_COMMAND_CU_BASE                0x60
-#define FXP_SCB_COMMAND_CU_DUMPRESET   0x70
-
-#define FXP_SCB_COMMAND_RU_NOP         0
-#define FXP_SCB_COMMAND_RU_START       1
-#define FXP_SCB_COMMAND_RU_RESUME      2
-#define FXP_SCB_COMMAND_RU_ABORT       4
-#define FXP_SCB_COMMAND_RU_LOADHDS     5
-#define FXP_SCB_COMMAND_RU_BASE                6
-#define FXP_SCB_COMMAND_RU_RBDRESUME   7
-
-/*
- * Command block definitions
- */
-struct fxp_cb_nop {
-       void *fill[2];
-       volatile u_int16_t cb_status;
-       volatile u_int16_t cb_command;
-       volatile u_int32_t link_addr;
-};
-struct fxp_cb_ias {
-       void *fill[2];
-       volatile u_int16_t cb_status;
-       volatile u_int16_t cb_command;
-       volatile u_int32_t link_addr;
-       volatile u_int8_t macaddr[6];
-};
-/* I hate bit-fields :-( */
-struct fxp_cb_config {
-       void *fill[2];
-       volatile u_int16_t      cb_status;
-       volatile u_int16_t      cb_command;
-       volatile u_int32_t      link_addr;
-       volatile u_int          byte_count:6,
-                               :2;
-       volatile u_int          rx_fifo_limit:4,
-                               tx_fifo_limit:3,
-                               :1;
-       volatile u_int8_t       adaptive_ifs;
-       volatile u_int          :8;
-       volatile u_int          rx_dma_bytecount:7,
-                               :1;
-       volatile u_int          tx_dma_bytecount:7,
-                               dma_bce:1;
-       volatile u_int          late_scb:1,
-                               :1,
-                               tno_int:1,
-                               ci_int:1,
-                               :3,
-                               save_bf:1;
-       volatile u_int          disc_short_rx:1,
-                               underrun_retry:2,
-                               :5;
-       volatile u_int          mediatype:1,
-                               :7;
-       volatile u_int          :8;
-       volatile u_int          :3,
-                               nsai:1,
-                               preamble_length:2,
-                               loopback:2;
-       volatile u_int          linear_priority:3,
-                               :5;
-       volatile u_int          linear_pri_mode:1,
-                               :3,
-                               interfrm_spacing:4;
-       volatile u_int          :8;
-       volatile u_int          :8;
-       volatile u_int          promiscuous:1,
-                               bcast_disable:1,
-                               :5,
-                               crscdt:1;
-       volatile u_int          :8;
-       volatile u_int          :8;
-       volatile u_int          stripping:1,
-                               padding:1,
-                               rcv_crc_xfer:1,
-                               :5;
-       volatile u_int          :6,
-                               force_fdx:1,
-                               fdx_pin_en:1;
-       volatile u_int          :6,
-                               multi_ia:1,
-                               :1;
-       volatile u_int          :3,
-                               mc_all:1,
-                               :4;
-};
-
-#define MAXMCADDR 80
-struct fxp_cb_mcs {
-       struct fxp_cb_tx *next;
-       struct mbuf *mb_head;
-       volatile u_int16_t cb_status;
-       volatile u_int16_t cb_command;
-       volatile u_int32_t link_addr;
-       volatile u_int16_t mc_cnt;
-       volatile u_int8_t mc_addr[MAXMCADDR][6];
-};
-
-/*
- * Number of DMA segments in a TxCB. Note that this is carefully
- * chosen to make the total struct size an even power of two. It's
- * critical that no TxCB be split across a page boundry since
- * no attempt is made to allocate physically contiguous memory.
- * 
- */
-#ifdef __alpha__ /* XXX - should be conditional on pointer size */
-#define FXP_NTXSEG      28
-#else
-#define FXP_NTXSEG      29
-#endif
-
-struct fxp_tbd {
-       volatile u_int32_t tb_addr;
-       volatile u_int32_t tb_size;
-};
-struct fxp_cb_tx {
-       struct fxp_cb_tx *next;
-       struct mbuf *mb_head;
-       volatile u_int16_t cb_status;
-       volatile u_int16_t cb_command;
-       volatile u_int32_t link_addr;
-       volatile u_int32_t tbd_array_addr;
-       volatile u_int16_t byte_count;
-       volatile u_int8_t tx_threshold;
-       volatile u_int8_t tbd_number;
-       /*
-        * The following isn't actually part of the TxCB.
-        */
-       volatile struct fxp_tbd tbd[FXP_NTXSEG];
-};
-
-/*
- * Control Block (CB) definitions
- */
-
-/* status */
-#define FXP_CB_STATUS_OK       0x2000
-#define FXP_CB_STATUS_C                0x8000
-/* commands */
-#define FXP_CB_COMMAND_NOP     0x0
-#define FXP_CB_COMMAND_IAS     0x1
-#define FXP_CB_COMMAND_CONFIG  0x2
-#define FXP_CB_COMMAND_MCAS    0x3
-#define FXP_CB_COMMAND_XMIT    0x4
-#define FXP_CB_COMMAND_RESRV   0x5
-#define FXP_CB_COMMAND_DUMP    0x6
-#define FXP_CB_COMMAND_DIAG    0x7
-/* command flags */
-#define FXP_CB_COMMAND_SF      0x0008  /* simple/flexible mode */
-#define FXP_CB_COMMAND_I       0x2000  /* generate interrupt on completion */
-#define FXP_CB_COMMAND_S       0x4000  /* suspend on completion */
-#define FXP_CB_COMMAND_EL      0x8000  /* end of list */
-
-/*
- * RFA definitions
- */
-
-struct fxp_rfa {
-       volatile u_int16_t rfa_status;
-       volatile u_int16_t rfa_control;
-       volatile u_int32_t link_addr;
-       volatile u_int32_t rbd_addr;
-       volatile u_int16_t actual_size;
-       volatile u_int16_t size;
-};
-#define FXP_RFA_STATUS_RCOL    0x0001  /* receive collision */
-#define FXP_RFA_STATUS_IAMATCH 0x0002  /* 0 = matches station address */
-#define FXP_RFA_STATUS_S4      0x0010  /* receive error from PHY */
-#define FXP_RFA_STATUS_TL      0x0020  /* type/length */
-#define FXP_RFA_STATUS_FTS     0x0080  /* frame too short */
-#define FXP_RFA_STATUS_OVERRUN 0x0100  /* DMA overrun */
-#define FXP_RFA_STATUS_RNR     0x0200  /* no resources */
-#define FXP_RFA_STATUS_ALIGN   0x0400  /* alignment error */
-#define FXP_RFA_STATUS_CRC     0x0800  /* CRC error */
-#define FXP_RFA_STATUS_OK      0x2000  /* packet received okay */
-#define FXP_RFA_STATUS_C       0x8000  /* packet reception complete */
-#define FXP_RFA_CONTROL_SF     0x08    /* simple/flexible memory mode */
-#define FXP_RFA_CONTROL_H      0x10    /* header RFD */
-#define FXP_RFA_CONTROL_S      0x4000  /* suspend after reception */
-#define FXP_RFA_CONTROL_EL     0x8000  /* end of list */
-
-/*
- * Statistics dump area definitions
- */
-struct fxp_stats {
-       volatile u_int32_t tx_good;
-       volatile u_int32_t tx_maxcols;
-       volatile u_int32_t tx_latecols;
-       volatile u_int32_t tx_underruns;
-       volatile u_int32_t tx_lostcrs;
-       volatile u_int32_t tx_deffered;
-       volatile u_int32_t tx_single_collisions;
-       volatile u_int32_t tx_multiple_collisions;
-       volatile u_int32_t tx_total_collisions;
-       volatile u_int32_t rx_good;
-       volatile u_int32_t rx_crc_errors;
-       volatile u_int32_t rx_alignment_errors;
-       volatile u_int32_t rx_rnr_errors;
-       volatile u_int32_t rx_overrun_errors;
-       volatile u_int32_t rx_cdt_errors;
-       volatile u_int32_t rx_shortframes;
-       volatile u_int32_t completion_status;
-};
-#define FXP_STATS_DUMP_COMPLETE        0xa005
-#define FXP_STATS_DR_COMPLETE  0xa007
-       
-/*
- * Serial EEPROM control register bits
- */
-/* shift clock */
-#define FXP_EEPROM_EESK                0x01
-/* chip select */
-#define FXP_EEPROM_EECS                0x02
-/* data in */
-#define FXP_EEPROM_EEDI                0x04
-/* data out */
-#define FXP_EEPROM_EEDO                0x08
-
-/*
- * Serial EEPROM opcodes, including start bit
- */
-#define FXP_EEPROM_OPC_ERASE   0x4
-#define FXP_EEPROM_OPC_WRITE   0x5
-#define FXP_EEPROM_OPC_READ    0x6
-
-/*
- * Management Data Interface opcodes
- */
-#define FXP_MDI_WRITE          0x1
-#define FXP_MDI_READ           0x2
-
-/*
- * PHY device types
- */
-#define FXP_PHY_NONE           0
-#define FXP_PHY_82553A         1
-#define FXP_PHY_82553C         2
-#define FXP_PHY_82503          3
-#define FXP_PHY_DP83840                4
-#define FXP_PHY_80C240         5
-#define FXP_PHY_80C24          6
-#define FXP_PHY_82555          7
-#define FXP_PHY_DP83840A       10
-#define FXP_PHY_82555B         11
-
-/*
- * PHY BMCR Basic Mode Control Register
- */
-#define FXP_PHY_BMCR                   0x0
-#define FXP_PHY_BMCR_FULLDUPLEX                0x0100
-#define FXP_PHY_BMCR_AUTOEN            0x1000
-#define FXP_PHY_BMCR_SPEED_100M                0x2000
-
-/*
- * DP84830 PHY, PCS Configuration Register
- */
-#define FXP_DP83840_PCR                        0x17
-#define FXP_DP83840_PCR_LED4_MODE      0x0002  /* 1 = LED4 always indicates full duplex */
-#define FXP_DP83840_PCR_F_CONNECT      0x0020  /* 1 = force link disconnect function bypass */
-#define FXP_DP83840_PCR_BIT8           0x0100
-#define FXP_DP83840_PCR_BIT10          0x0400
diff --git a/sys/dev/pci/if_fxpvar.h b/sys/dev/pci/if_fxpvar.h
deleted file mode 100644 (file)
index 783a091..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*     $OpenBSD: if_fxpvar.h,v 1.8 2000/04/18 03:40:55 jason Exp $     */
-/*     $NetBSD: if_fxpvar.h,v 1.1 1997/06/05 02:01:58 thorpej Exp $    */
-
-/*                  
- * Copyright (c) 1995, David Greenman
- * All rights reserved.
- *              
- * Modifications to support NetBSD:
- * Copyright (c) 1997 Jason R. Thorpe.  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.
- *
- *      Id: if_fxpvar.h,v 1.6 1998/08/02 00:29:15 dg Exp
- */
-
-/*
- * Misc. defintions for the Intel EtherExpress Pro/100B PCI Fast
- * Ethernet driver
- */
-/*
- * NOTE: Elements are ordered for optimal cacheline behavior, and NOT
- *      for functional grouping.
- */
-struct fxp_softc {
-       struct device sc_dev;           /* generic device structures */
-       void *sc_ih;                    /* interrupt handler cookie */
-       bus_space_tag_t sc_st;          /* bus space tag */
-       bus_space_handle_t sc_sh;       /* bus space handle */
-       struct arpcom arpcom;           /* per-interface network data */
-       struct mii_data sc_mii;         /* MII media information */
-       struct mbuf *rfa_headm;         /* first mbuf in receive frame area */
-       struct mbuf *rfa_tailm;         /* last mbuf in receive frame area */
-       struct fxp_cb_tx *cbl_first;    /* first active TxCB in list */
-       int tx_queued;                  /* # of active TxCB's */
-       int need_mcsetup;               /* multicast filter needs programming */
-       struct fxp_cb_tx *cbl_last;     /* last active TxCB in list */
-       struct fxp_stats *fxp_stats;    /* Pointer to interface stats */
-       int rx_idle_secs;               /* # of seconds RX has been idle */
-       struct fxp_cb_tx *cbl_base;     /* base of TxCB list */
-       struct fxp_cb_mcs *mcsp;        /* Pointer to mcast setup descriptor */
-       int all_mcasts;                 /* receive all multicasts */
-       int phy_primary_addr;           /* address of primary PHY */
-       int phy_primary_device;         /* device type of primary PHY */
-       int phy_10Mbps_only;            /* PHY is 10Mbps-only device */
-       int eeprom_size;                /* size of serial EEPROM */
-};
-
-/* Macros to ease CSR access. */
-#define        CSR_READ_1(sc, reg)                                             \
-       bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg))
-#define        CSR_READ_2(sc, reg)                                             \
-       bus_space_read_2((sc)->sc_st, (sc)->sc_sh, (reg))
-#define        CSR_READ_4(sc, reg)                                             \
-       bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
-#define        CSR_WRITE_1(sc, reg, val)                                       \
-       bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val))
-#define        CSR_WRITE_2(sc, reg, val)                                       \
-       bus_space_write_2((sc)->sc_st, (sc)->sc_sh, (reg), (val))
-#define        CSR_WRITE_4(sc, reg, val)                                       \
-       bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))