summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2005-05-10 01:16:33 +0000
committerBrad Smith <brad@cvs.openbsd.org>2005-05-10 01:16:33 +0000
commita2387b97d380c1ff7191a1a57f39092665855d51 (patch)
tree2e3fbb222d0ac1a462be18098e5cf3cdf020196b
parent390474309a49bee35f12d6c59d4382a1c1dfcef8 (diff)
Add epic(4) driver which supersedes tx(4).
This buys us.. - bus_dma - big endian support - multicast - support for another EPIC chipset From NetBSD ok mickey@
-rw-r--r--sys/arch/alpha/conf/GENERIC5
-rw-r--r--sys/arch/alpha/conf/RAMDISKBIG5
-rw-r--r--sys/arch/amd64/conf/GENERIC4
-rw-r--r--sys/arch/amd64/conf/RAMDISK4
-rw-r--r--sys/arch/amd64/conf/RAMDISK_CD4
-rw-r--r--sys/arch/i386/conf/GENERIC4
-rw-r--r--sys/arch/i386/conf/RAMDISK4
-rw-r--r--sys/arch/i386/conf/RAMDISKB4
-rw-r--r--sys/arch/i386/conf/RAMDISKC4
-rw-r--r--sys/arch/i386/conf/RAMDISK_CD4
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/ic/smc83c170.c1608
-rw-r--r--sys/dev/ic/smc83c170reg.h487
-rw-r--r--sys/dev/ic/smc83c170var.h191
-rw-r--r--sys/dev/pci/files.pci9
-rw-r--r--sys/dev/pci/if_epic_pci.c277
16 files changed, 2592 insertions, 28 deletions
diff --git a/sys/arch/alpha/conf/GENERIC b/sys/arch/alpha/conf/GENERIC
index 7f1e849e336..a106e93bf70 100644
--- a/sys/arch/alpha/conf/GENERIC
+++ b/sys/arch/alpha/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.146 2005/05/01 17:19:33 david Exp $
+# $OpenBSD: GENERIC,v 1.147 2005/05/10 01:16:31 brad Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -220,8 +220,7 @@ skc* at pci? # SysKonnect GEnesis 984x
sk* at skc? # each port of above
an* at pci? # Cisco/Aironet 802.11DS
-#BROKEN: The following driver has 64-bit issues
-#tx* at pci? # SMC 83C170 EPIC ethernet
+#epic* at pci? # SMC EPIC/100 ethernet
vga* at pci? # PCI VGA graphics
tga* at pci? # DEC ZLXp-E[123] graphics
diff --git a/sys/arch/alpha/conf/RAMDISKBIG b/sys/arch/alpha/conf/RAMDISKBIG
index 452c985183f..355affc2046 100644
--- a/sys/arch/alpha/conf/RAMDISKBIG
+++ b/sys/arch/alpha/conf/RAMDISKBIG
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISKBIG,v 1.52 2005/05/01 07:54:41 david Exp $
+# $OpenBSD: RAMDISKBIG,v 1.53 2005/05/10 01:16:31 brad Exp $
# $NetBSD: GENERIC,v 1.31 1996/12/03 17:25:29 cgd Exp $
#
# Generic Alpha kernel. Enough to get booted, etc., but not much more.
@@ -201,8 +201,7 @@ skc* at pci? # SysKonnect GEnesis 984x
sk* at skc? # each port of above
an* at pci? # Cisco/Aironet 802.11DS
-#BROKEN: The following driver has 64-bit issues
-#tx* at pci? # SMC 83C170 EPIC ethernet
+#epic* at pci? # SMC EPIC/100 ethernet
vga* at pci? # PCI VGA graphics
tga* at pci? # DEC ZLXp-E[123] graphics
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 29b50f76550..55f3119b1a7 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.63 2005/05/01 07:54:42 david Exp $
+# $OpenBSD: GENERIC,v 1.64 2005/05/10 01:16:31 brad Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -261,7 +261,7 @@ xl* at pci? # 3C9xx ethernet
rl* at pci? # RealTek 81[23]9 ethernet
#rl* at cardbus? # RealTek 81[23]9 ethernet
#mtd* at pci? # Myson MTD800/803/891
-#tx* at pci? # SMC 83C170 EPIC ethernet
+#epic* at pci? # SMC EPIC/100 ethernet
#tl* at pci? # Compaq Thunderlan ethernet
vr* at pci? # VIA Rhine ethernet
#wb* at pci? # Winbond W89C840F ethernet
diff --git a/sys/arch/amd64/conf/RAMDISK b/sys/arch/amd64/conf/RAMDISK
index def55722ad5..433d3f174ce 100644
--- a/sys/arch/amd64/conf/RAMDISK
+++ b/sys/arch/amd64/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.19 2005/01/06 21:32:56 deraadt Exp $
+# $OpenBSD: RAMDISK,v 1.20 2005/05/10 01:16:31 brad Exp $
machine amd64 # architecture, used by config; REQUIRED
@@ -200,7 +200,7 @@ fxp* at pci? # EtherExpress 10/100B ethernet
#xl* at cardbus? # 3C575 ethernet
rl* at pci? # RealTek 81[23]9 ethernet
re* at pci? # Realtek 8169/8169S/8110S
-#tx* at pci? # SMC 83C170 EPIC ethernet
+#epic* at pci? # SMC EPIC/100 ethernet
#tl* at pci? # Compaq Thunderlan ethernet
vr* at pci? # VIA Rhine ethernet
dc* at pci? # 21143, "tulip" clone ethernet
diff --git a/sys/arch/amd64/conf/RAMDISK_CD b/sys/arch/amd64/conf/RAMDISK_CD
index baa2642850b..2a934581a84 100644
--- a/sys/arch/amd64/conf/RAMDISK_CD
+++ b/sys/arch/amd64/conf/RAMDISK_CD
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK_CD,v 1.29 2005/03/30 07:42:13 deraadt Exp $
+# $OpenBSD: RAMDISK_CD,v 1.30 2005/05/10 01:16:31 brad Exp $
machine amd64 # architecture, used by config; REQUIRED
@@ -216,7 +216,7 @@ fxp* at pci? # EtherExpress 10/100B ethernet
#xl* at pci? # 3C9xx ethernet
#xl* at cardbus? # 3C575 ethernet
rl* at pci? # RealTek 81[23]9 ethernet
-#tx* at pci? # SMC 83C170 EPIC ethernet
+#epic* at pci? # SMC EPIC/100 ethernet
#tl* at pci? # Compaq Thunderlan ethernet
vr* at pci? # VIA Rhine ethernet
dc* at pci? # 21143, "tulip" clone ethernet
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index b1002422948..eef8d87d908 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.411 2005/05/02 17:26:00 grange Exp $
+# $OpenBSD: GENERIC,v 1.412 2005/05/10 01:16:31 brad Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -396,7 +396,7 @@ xl* at cardbus? # 3C575/3C656 ethernet
rl* at pci? # RealTek 81[23]9 ethernet
rl* at cardbus? # RealTek 81[23]9 ethernet
mtd* at pci? # Myson MTD800/803/891
-tx* at pci? # SMC 83C170 EPIC ethernet
+epic* at pci? # SMC EPIC/100 ethernet
tl* at pci? # Compaq Thunderlan ethernet
vr* at pci? # VIA Rhine ethernet
wb* at pci? # Winbond W89C840F ethernet
diff --git a/sys/arch/i386/conf/RAMDISK b/sys/arch/i386/conf/RAMDISK
index 2e1b06cb9b1..eae4c6fbabf 100644
--- a/sys/arch/i386/conf/RAMDISK
+++ b/sys/arch/i386/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.137 2005/03/18 19:24:27 deraadt Exp $
+# $OpenBSD: RAMDISK,v 1.138 2005/05/10 01:16:31 brad Exp $
machine i386 # architecture, used by config; REQUIRED
@@ -224,7 +224,7 @@ ep* at pcmcia? # PCMCIA based 3c5xx cards
#fpa* at pci? # DEC DEFPA FDDI cards
xl* at pci? # 3C9xx ethernet cards
rl* at pci? # RealTek 81[23]9 ethernet
-tx* at pci? # SMC 83C170 EPIC ethernet cards
+epic* at pci? # SMC EPIC/100 ethernet
tl* at pci? # Compaq Thunderlan ethernet cards
vr* at pci? # VIA Rhine ethernet
#wb* at pci? # Winbond W89C840F ethernet
diff --git a/sys/arch/i386/conf/RAMDISKB b/sys/arch/i386/conf/RAMDISKB
index dc7f47eac47..55de72f29b8 100644
--- a/sys/arch/i386/conf/RAMDISKB
+++ b/sys/arch/i386/conf/RAMDISKB
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISKB,v 1.80 2005/03/18 22:39:59 deraadt Exp $
+# $OpenBSD: RAMDISKB,v 1.81 2005/05/10 01:16:31 brad Exp $
machine i386 # architecture, used by config; REQUIRED
@@ -247,7 +247,7 @@ ep* at pci? # 3C59x ethernet cards
#fpa* at pci? # DEC DEFPA FDDI cards
xl* at pci? # 3C9xx ethernet cards
#rl* at pci? # RealTek 81[23]9 ethernet
-#tx* at pci? # SMC 83C170 EPIC ethernet cards
+#epic* at pci? # SMC EPIC/100 ethernet
#tl* at pci? # Compaq Thunderlan ethernet cards
vr* at pci? # VIA Rhine ethernet
#wb* at pci? # Winbond W89C840F ethernet
diff --git a/sys/arch/i386/conf/RAMDISKC b/sys/arch/i386/conf/RAMDISKC
index 830e42aff08..e59c54c322b 100644
--- a/sys/arch/i386/conf/RAMDISKC
+++ b/sys/arch/i386/conf/RAMDISKC
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISKC,v 1.56 2005/05/01 07:54:42 david Exp $
+# $OpenBSD: RAMDISKC,v 1.57 2005/05/10 01:16:31 brad Exp $
machine i386 # architecture, used by config; REQUIRED
@@ -263,7 +263,7 @@ xl* at pci? # 3C9xx ethernet
xl* at cardbus? # 3C575 ethernet
rl* at pci? # RealTek 81[23]9 ethernet
rl* at cardbus? # RealTek 81[23]9 ethernet
-#tx* at pci? # SMC 83C170 EPIC ethernet
+#epic* at pci? # SMC EPIC/100 ethernet
#tl* at pci? # Compaq Thunderlan ethernet
#vr* at pci? # VIA Rhine ethernet
#wb* at pci? # Winbond W89C840F ethernet
diff --git a/sys/arch/i386/conf/RAMDISK_CD b/sys/arch/i386/conf/RAMDISK_CD
index 2e51d055305..b9cec934d89 100644
--- a/sys/arch/i386/conf/RAMDISK_CD
+++ b/sys/arch/i386/conf/RAMDISK_CD
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK_CD,v 1.94 2005/04/14 20:21:07 brad Exp $
+# $OpenBSD: RAMDISK_CD,v 1.95 2005/05/10 01:16:31 brad Exp $
machine i386 # architecture, used by config; REQUIRED
@@ -308,7 +308,7 @@ fpa* at pci? # DEC DEFPA FDDI
xl* at pci? # 3C9xx ethernet
xl* at cardbus? # 3C575 ethernet
rl* at pci? # RealTek 81[23]9 ethernet
-tx* at pci? # SMC 83C170 EPIC ethernet
+epic* at pci? # SMC EPIC/100 ethernet
tl* at pci? # Compaq Thunderlan ethernet
vr* at pci? # VIA Rhine ethernet
dc* at pci? # 21143, "tulip" clone ethernet
diff --git a/sys/conf/files b/sys/conf/files
index 4fc7ebff899..1f91d849951 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.335 2005/05/01 21:36:57 brad Exp $
+# $OpenBSD: files,v 1.336 2005/05/10 01:16:31 brad Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -258,6 +258,10 @@ file dev/ic/dc.c dc
device sm: ether, ifnet, ifmedia
file dev/ic/smc91cxx.c sm
+# SMC 83C170 EPIC/100 Fast Ethernet Controller
+device epic: ether, ifnet, ifmedia, mii
+file dev/ic/smc83c170.c epic
+
# Novell NE2000-compatible Ethernet cards, based on the
# National Semiconductor DS8390.
device ne: ether, ifnet, dp8390nic, ifmedia, mii
diff --git a/sys/dev/ic/smc83c170.c b/sys/dev/ic/smc83c170.c
new file mode 100644
index 00000000000..3fcfdc5cd2a
--- /dev/null
+++ b/sys/dev/ic/smc83c170.c
@@ -0,0 +1,1608 @@
+/* $OpenBSD: smc83c170.c,v 1.1 2005/05/10 01:16:32 brad Exp $ */
+/* $NetBSD: smc83c170.c,v 1.59 2005/02/27 00:27:02 perry Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Device driver for the Standard Microsystems Corp. 83C170
+ * Ethernet PCI Integrated Controller (EPIC/100).
+ */
+
+#if 0
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: smc83c170.c,v 1.59 2005/02/27 00:27:02 perry Exp $");
+#endif
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/timeout.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+/* #include <uvm/uvm_extern.h> */
+
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net/if_media.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/mii/miivar.h>
+#include <dev/mii/lxtphyreg.h>
+
+#include <dev/ic/smc83c170reg.h>
+#include <dev/ic/smc83c170var.h>
+
+void epic_start(struct ifnet *);
+void epic_watchdog(struct ifnet *);
+int epic_ioctl(struct ifnet *, u_long, caddr_t);
+int epic_init(struct ifnet *);
+void epic_stop(struct ifnet *, int);
+
+void epic_shutdown(void *);
+
+void epic_reset(struct epic_softc *);
+void epic_rxdrain(struct epic_softc *);
+int epic_add_rxbuf(struct epic_softc *, int);
+void epic_read_eeprom(struct epic_softc *, int, int, u_int16_t *);
+void epic_set_mchash(struct epic_softc *);
+void epic_fixup_clock_source(struct epic_softc *);
+int epic_mii_read(struct device *, int, int);
+void epic_mii_write(struct device *, int, int, int);
+int epic_mii_wait(struct epic_softc *, u_int32_t);
+void epic_tick(void *);
+
+void epic_statchg(struct device *);
+int epic_mediachange(struct ifnet *);
+void epic_mediastatus(struct ifnet *, struct ifmediareq *);
+
+struct cfdriver epic_cd = {
+ 0, "epic", DV_IFNET
+};
+
+#define INTMASK (INTSTAT_FATAL_INT | INTSTAT_TXU | \
+ INTSTAT_TXC | INTSTAT_RXE | INTSTAT_RQE | INTSTAT_RCC)
+
+int epic_copy_small = 0;
+
+#define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN)
+
+/*
+ * Attach an EPIC interface to the system.
+ */
+void
+epic_attach(sc, intrstr)
+ struct epic_softc *sc;
+ const char *intrstr;
+{
+ bus_space_tag_t st = sc->sc_st;
+ bus_space_handle_t sh = sc->sc_sh;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ int rseg, error, miiflags;
+ u_int i;
+ bus_dma_segment_t seg;
+ u_int8_t enaddr[ETHER_ADDR_LEN], devname[12 + 1];
+ u_int16_t myea[ETHER_ADDR_LEN / 2], mydevname[6];
+ char *nullbuf;
+
+ timeout_set(&sc->sc_mii_timeout, epic_tick, sc);
+
+ /*
+ * Allocate the control data structures, and create and load the
+ * DMA map for it.
+ */
+ if ((error = bus_dmamem_alloc(sc->sc_dmat,
+ sizeof(struct epic_control_data) + ETHER_PAD_LEN, PAGE_SIZE, 0,
+ &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
+ printf(
+ "%s: unable to allocate control data, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_0;
+ }
+
+ if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
+ sizeof(struct epic_control_data) + ETHER_PAD_LEN,
+ (caddr_t *)&sc->sc_control_data,
+ BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
+ printf("%s: unable to map control data, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_1;
+ }
+ nullbuf =
+ (char *)sc->sc_control_data + sizeof(struct epic_control_data);
+ memset(nullbuf, 0, ETHER_PAD_LEN);
+
+ if ((error = bus_dmamap_create(sc->sc_dmat,
+ sizeof(struct epic_control_data), 1,
+ sizeof(struct epic_control_data), 0, BUS_DMA_NOWAIT,
+ &sc->sc_cddmamap)) != 0) {
+ printf("%s: unable to create control data DMA map, "
+ "error = %d\n", sc->sc_dev.dv_xname, error);
+ goto fail_2;
+ }
+
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap,
+ sc->sc_control_data, sizeof(struct epic_control_data), NULL,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf(
+ "%s: unable to load control data DMA map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_3;
+ }
+
+ /*
+ * Create the transmit buffer DMA maps.
+ */
+ for (i = 0; i < EPIC_NTXDESC; i++) {
+ if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
+ EPIC_NFRAGS, MCLBYTES, 0, BUS_DMA_NOWAIT,
+ &EPIC_DSTX(sc, i)->ds_dmamap)) != 0) {
+ printf("%s: unable to create tx DMA map %d, "
+ "error = %d\n", sc->sc_dev.dv_xname, i, error);
+ goto fail_4;
+ }
+ }
+
+ /*
+ * Create the receive buffer DMA maps.
+ */
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
+ MCLBYTES, 0, BUS_DMA_NOWAIT,
+ &EPIC_DSRX(sc, i)->ds_dmamap)) != 0) {
+ printf("%s: unable to create rx DMA map %d, "
+ "error = %d\n", sc->sc_dev.dv_xname, i, error);
+ goto fail_5;
+ }
+ EPIC_DSRX(sc, i)->ds_mbuf = NULL;
+ }
+
+ /*
+ * create and map the pad buffer
+ */
+ if ((error = bus_dmamap_create(sc->sc_dmat, ETHER_PAD_LEN, 1,
+ ETHER_PAD_LEN, 0, BUS_DMA_NOWAIT,&sc->sc_nulldmamap)) != 0) {
+ printf("%s: unable to create pad buffer DMA map, "
+ "error = %d\n", sc->sc_dev.dv_xname, error);
+ goto fail_5;
+ }
+
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_nulldmamap,
+ nullbuf, ETHER_PAD_LEN, NULL, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to load pad buffer DMA map, "
+ "error = %d\n", sc->sc_dev.dv_xname, error);
+ goto fail_6;
+ }
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_nulldmamap, 0, ETHER_PAD_LEN,
+ BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Bring the chip out of low-power mode and reset it to a known state.
+ */
+ bus_space_write_4(st, sh, EPIC_GENCTL, 0);
+ epic_reset(sc);
+
+ /*
+ * Read the Ethernet address from the EEPROM.
+ */
+ epic_read_eeprom(sc, 0, (sizeof(myea) / sizeof(myea[0])), myea);
+ for (i = 0; i < sizeof(myea)/ sizeof(myea[0]); i++) {
+ enaddr[i * 2] = myea[i] & 0xff;
+ enaddr[i * 2 + 1] = myea[i] >> 8;
+ }
+
+ /*
+ * ...and the device name.
+ */
+ epic_read_eeprom(sc, 0x2c, (sizeof(mydevname) / sizeof(mydevname[0])),
+ mydevname);
+ for (i = 0; i < sizeof(mydevname) / sizeof(mydevname[0]); i++) {
+ devname[i * 2] = mydevname[i] & 0xff;
+ devname[i * 2 + 1] = mydevname[i] >> 8;
+ }
+
+ devname[sizeof(mydevname)] = '\0';
+ for (i = sizeof(mydevname) - 1; i >= 0; i--) {
+ if (devname[i] == ' ')
+ devname[i] = '\0';
+ else
+ break;
+ }
+
+ printf(": %s, address %s\n", intrstr, ether_sprintf(enaddr));
+
+ miiflags = 0;
+ if (sc->sc_hwflags & EPIC_HAS_MII_FIBER)
+ miiflags |= MIIF_HAVEFIBER;
+
+ /*
+ * Initialize our media structures and probe the MII.
+ */
+ sc->sc_mii.mii_ifp = ifp;
+ sc->sc_mii.mii_readreg = epic_mii_read;
+ sc->sc_mii.mii_writereg = epic_mii_write;
+ sc->sc_mii.mii_statchg = epic_statchg;
+ ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, epic_mediachange,
+ epic_mediastatus);
+ mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
+ MII_OFFSET_ANY, miiflags);
+ if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
+ ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
+ ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
+ } else
+ ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
+
+ if (sc->sc_hwflags & EPIC_HAS_BNC) {
+ /* use the next free media instance */
+ sc->sc_serinst = sc->sc_mii.mii_instance++;
+ ifmedia_add(&sc->sc_mii.mii_media,
+ IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0,
+ sc->sc_serinst),
+ 0, NULL);
+ } else
+ sc->sc_serinst = -1;
+
+ bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
+ 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 = epic_ioctl;
+ ifp->if_start = epic_start;
+ ifp->if_watchdog = epic_watchdog;
+ IFQ_SET_MAXLEN(&ifp->if_snd, EPIC_NTXDESC - 1);
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ifp->if_capabilities = IFCAP_VLAN_MTU;
+
+ /*
+ * Attach the interface.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ /*
+ * Make sure the interface is shutdown during reboot.
+ */
+ sc->sc_sdhook = shutdownhook_establish(epic_shutdown, sc);
+ if (sc->sc_sdhook == NULL)
+ printf("%s: WARNING: unable to establish shutdown hook\n",
+ sc->sc_dev.dv_xname);
+ return;
+
+ /*
+ * Free any resources we've allocated during the failed attach
+ * attempt. Do this in reverse order and fall through.
+ */
+ fail_6:
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_nulldmamap);
+ fail_5:
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ if (EPIC_DSRX(sc, i)->ds_dmamap != NULL)
+ bus_dmamap_destroy(sc->sc_dmat,
+ EPIC_DSRX(sc, i)->ds_dmamap);
+ }
+ fail_4:
+ for (i = 0; i < EPIC_NTXDESC; i++) {
+ if (EPIC_DSTX(sc, i)->ds_dmamap != NULL)
+ bus_dmamap_destroy(sc->sc_dmat,
+ EPIC_DSTX(sc, i)->ds_dmamap);
+ }
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
+ fail_3:
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
+ fail_2:
+ bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_control_data,
+ sizeof(struct epic_control_data));
+ fail_1:
+ bus_dmamem_free(sc->sc_dmat, &seg, rseg);
+ fail_0:
+ return;
+}
+
+/*
+ * Shutdown hook. Make sure the interface is stopped at reboot.
+ */
+void
+epic_shutdown(arg)
+ void *arg;
+{
+ struct epic_softc *sc = arg;
+
+ epic_stop(&sc->sc_arpcom.ac_if, 1);
+}
+
+/*
+ * Start packet transmission on the interface.
+ * [ifnet interface function]
+ */
+void
+epic_start(ifp)
+ struct ifnet *ifp;
+{
+ struct epic_softc *sc = ifp->if_softc;
+ struct mbuf *m0, *m;
+ struct epic_txdesc *txd;
+ struct epic_descsoft *ds;
+ struct epic_fraglist *fr;
+ bus_dmamap_t dmamap;
+ int error, firsttx, nexttx, opending, seg;
+ u_int len;
+
+ /*
+ * Remember the previous txpending and the first transmit
+ * descriptor we use.
+ */
+ opending = sc->sc_txpending;
+ firsttx = EPIC_NEXTTX(sc->sc_txlast);
+
+ /*
+ * Loop through the send queue, setting up transmit descriptors
+ * until we drain the queue, or use up all available transmit
+ * descriptors.
+ */
+ while (sc->sc_txpending < EPIC_NTXDESC) {
+ /*
+ * Grab a packet off the queue.
+ */
+ IFQ_POLL(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+ m = NULL;
+
+ /*
+ * Get the last and next available transmit descriptor.
+ */
+ nexttx = EPIC_NEXTTX(sc->sc_txlast);
+ txd = EPIC_CDTX(sc, nexttx);
+ fr = EPIC_CDFL(sc, nexttx);
+ ds = EPIC_DSTX(sc, nexttx);
+ dmamap = ds->ds_dmamap;
+
+ /*
+ * Load the DMA map. If this fails, the packet either
+ * didn't fit in the alloted number of frags, or we were
+ * short on resources. In this case, we'll copy and try
+ * again.
+ */
+ if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
+ BUS_DMA_WRITE|BUS_DMA_NOWAIT)) != 0 ||
+ (m0->m_pkthdr.len < ETHER_PAD_LEN &&
+ dmamap-> dm_nsegs == EPIC_NFRAGS)) {
+ if (error == 0)
+ bus_dmamap_unload(sc->sc_dmat, dmamap);
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ printf("%s: unable to allocate Tx mbuf\n",
+ sc->sc_dev.dv_xname);
+ break;
+ }
+ if (m0->m_pkthdr.len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ printf("%s: unable to allocate Tx "
+ "cluster\n", sc->sc_dev.dv_xname);
+ m_freem(m);
+ break;
+ }
+ }
+ m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
+ m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap,
+ m, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
+ if (error) {
+ printf("%s: unable to load Tx buffer, "
+ "error = %d\n", sc->sc_dev.dv_xname, error);
+ break;
+ }
+ }
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+ if (m != NULL) {
+ m_freem(m0);
+ m0 = m;
+ }
+
+ /* Initialize the fraglist. */
+ for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
+ fr->ef_frags[seg].ef_addr =
+ dmamap->dm_segs[seg].ds_addr;
+ fr->ef_frags[seg].ef_length =
+ dmamap->dm_segs[seg].ds_len;
+ }
+ len = m0->m_pkthdr.len;
+ if (len < ETHER_PAD_LEN) {
+ fr->ef_frags[seg].ef_addr = sc->sc_nulldma;
+ fr->ef_frags[seg].ef_length = ETHER_PAD_LEN - len;
+ len = ETHER_PAD_LEN;
+ seg++;
+ }
+ fr->ef_nfrags = seg;
+
+ EPIC_CDFLSYNC(sc, nexttx, BUS_DMASYNC_PREWRITE);
+
+ /* Sync the DMA map. */
+ bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Store a pointer to the packet so we can free it later.
+ */
+ ds->ds_mbuf = m0;
+
+ /*
+ * Fill in the transmit descriptor.
+ */
+ txd->et_control = ET_TXCTL_LASTDESC | ET_TXCTL_FRAGLIST;
+
+ /*
+ * If this is the first descriptor we're enqueueing,
+ * don't give it to the EPIC yet. That could cause
+ * a race condition. We'll do it below.
+ */
+ if (nexttx == firsttx)
+ txd->et_txstatus = TXSTAT_TXLENGTH(len);
+ else
+ txd->et_txstatus =
+ TXSTAT_TXLENGTH(len) | ET_TXSTAT_OWNER;
+
+ EPIC_CDTXSYNC(sc, nexttx,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /* Advance the tx pointer. */
+ sc->sc_txpending++;
+ sc->sc_txlast = nexttx;
+
+#if NBPFILTER > 0
+ /*
+ * Pass the packet to any BPF listeners.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0);
+#endif
+ }
+
+ if (sc->sc_txpending == EPIC_NTXDESC) {
+ /* No more slots left; notify upper layer. */
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+
+ if (sc->sc_txpending != opending) {
+ /*
+ * We enqueued packets. If the transmitter was idle,
+ * reset the txdirty pointer.
+ */
+ if (opending == 0)
+ sc->sc_txdirty = firsttx;
+
+ /*
+ * Cause a transmit interrupt to happen on the
+ * last packet we enqueued.
+ */
+ EPIC_CDTX(sc, sc->sc_txlast)->et_control |= ET_TXCTL_IAF;
+ EPIC_CDTXSYNC(sc, sc->sc_txlast,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /*
+ * The entire packet chain is set up. Give the
+ * first descriptor to the EPIC now.
+ */
+ EPIC_CDTX(sc, firsttx)->et_txstatus |= ET_TXSTAT_OWNER;
+ EPIC_CDTXSYNC(sc, firsttx,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /* Start the transmitter. */
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_COMMAND,
+ COMMAND_TXQUEUED);
+
+ /* Set a watchdog timer in case the chip flakes out. */
+ ifp->if_timer = 5;
+ }
+}
+
+/*
+ * Watchdog timer handler.
+ * [ifnet interface function]
+ */
+void
+epic_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct epic_softc *sc = ifp->if_softc;
+
+ printf("%s: device timeout\n", sc->sc_dev.dv_xname);
+ ifp->if_oerrors++;
+
+ (void) epic_init(ifp);
+}
+
+/*
+ * Handle control requests from the operator.
+ * [ifnet interface function]
+ */
+int
+epic_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct epic_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error;
+
+ s = splnet();
+
+ if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
+ splx(s);
+ return (error);
+ }
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ epic_init(ifp);
+ arp_ifinit(&sc->sc_arpcom, ifa);
+ break;
+#endif
+ default:
+ epic_init(ifp);
+ break;
+ }
+ break;
+
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
+ error = EINVAL;
+ } else if (ifp->if_mtu != ifr->ifr_mtu) {
+ ifp->if_mtu = ifr->ifr_mtu;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * 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)
+ epic_init(ifp);
+ else if (ifp->if_flags & IFF_RUNNING)
+ epic_stop(ifp, 1);
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_arpcom) :
+ ether_delmulti(ifr, &sc->sc_arpcom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware
+ * filter accordingly.
+ */
+ if (ifp->if_flags & IFF_RUNNING)
+ mii_pollstat(&sc->sc_mii);
+ epic_set_mchash(sc);
+ error = 0;
+ }
+ break;
+
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return (error);
+}
+
+/*
+ * Interrupt handler.
+ */
+int
+epic_intr(arg)
+ void *arg;
+{
+ struct epic_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ struct epic_rxdesc *rxd;
+ struct epic_txdesc *txd;
+ struct epic_descsoft *ds;
+ struct mbuf *m;
+ u_int32_t intstat, rxstatus, txstatus;
+ int i, claimed = 0;
+ u_int len;
+
+ top:
+ /*
+ * Get the interrupt status from the EPIC.
+ */
+ intstat = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_INTSTAT);
+ if ((intstat & INTSTAT_INT_ACTV) == 0)
+ return (claimed);
+
+ claimed = 1;
+
+ /*
+ * Acknowledge the interrupt.
+ */
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_INTSTAT,
+ intstat & INTMASK);
+
+ /*
+ * Check for receive interrupts.
+ */
+ if (intstat & (INTSTAT_RCC | INTSTAT_RXE | INTSTAT_RQE)) {
+ for (i = sc->sc_rxptr;; i = EPIC_NEXTRX(i)) {
+ rxd = EPIC_CDRX(sc, i);
+ ds = EPIC_DSRX(sc, i);
+
+ EPIC_CDRXSYNC(sc, i,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+ rxstatus = rxd->er_rxstatus;
+ if (rxstatus & ER_RXSTAT_OWNER) {
+ /*
+ * We have processed all of the
+ * receive buffers.
+ */
+ break;
+ }
+
+ /*
+ * Make sure the packet arrived intact. If an error
+ * occurred, update stats and reset the descriptor.
+ * The buffer will be reused the next time the
+ * descriptor comes up in the ring.
+ */
+ if ((rxstatus & ER_RXSTAT_PKTINTACT) == 0) {
+ if (rxstatus & ER_RXSTAT_CRCERROR)
+ printf("%s: CRC error\n",
+ sc->sc_dev.dv_xname);
+ if (rxstatus & ER_RXSTAT_ALIGNERROR)
+ printf("%s: alignment error\n",
+ sc->sc_dev.dv_xname);
+ ifp->if_ierrors++;
+ EPIC_INIT_RXDESC(sc, i);
+ continue;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
+ ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
+
+ /*
+ * The EPIC includes the CRC with every packet;
+ * trim it.
+ */
+ len = RXSTAT_RXLENGTH(rxstatus) - ETHER_CRC_LEN;
+
+ if (len < sizeof(struct ether_header)) {
+ /*
+ * Runt packet; drop it now.
+ */
+ ifp->if_ierrors++;
+ EPIC_INIT_RXDESC(sc, i);
+ bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
+ ds->ds_dmamap->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+ continue;
+ }
+
+ /*
+ * If the packet is small enough to fit in a
+ * single header mbuf, allocate one and copy
+ * the data into it. This greatly reduces
+ * memory consumption when we receive lots
+ * of small packets.
+ *
+ * Otherwise, we add a new buffer to the receive
+ * chain. If this fails, we drop the packet and
+ * recycle the old buffer.
+ */
+ if (epic_copy_small != 0 && len <= MHLEN) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ goto dropit;
+ memcpy(mtod(m, caddr_t),
+ mtod(ds->ds_mbuf, caddr_t), len);
+ EPIC_INIT_RXDESC(sc, i);
+ bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
+ ds->ds_dmamap->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+ } else {
+ m = ds->ds_mbuf;
+ if (epic_add_rxbuf(sc, i) != 0) {
+ dropit:
+ ifp->if_ierrors++;
+ EPIC_INIT_RXDESC(sc, i);
+ bus_dmamap_sync(sc->sc_dmat,
+ ds->ds_dmamap, 0,
+ ds->ds_dmamap->dm_mapsize,
+ BUS_DMASYNC_PREREAD);
+ continue;
+ }
+ }
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = len;
+
+#if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass it up the stack if its for us.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+ /* Pass it on. */
+ ether_input_mbuf(ifp, m);
+ ifp->if_ipackets++;
+ }
+
+ /* Update the receive pointer. */
+ sc->sc_rxptr = i;
+
+ /*
+ * Check for receive queue underflow.
+ */
+ if (intstat & INTSTAT_RQE) {
+ printf("%s: receiver queue empty\n",
+ sc->sc_dev.dv_xname);
+ /*
+ * Ring is already built; just restart the
+ * receiver.
+ */
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_PRCDAR,
+ EPIC_CDRXADDR(sc, sc->sc_rxptr));
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_COMMAND,
+ COMMAND_RXQUEUED | COMMAND_START_RX);
+ }
+ }
+
+ /*
+ * Check for transmission complete interrupts.
+ */
+ if (intstat & (INTSTAT_TXC | INTSTAT_TXU)) {
+ ifp->if_flags &= ~IFF_OACTIVE;
+ for (i = sc->sc_txdirty; sc->sc_txpending != 0;
+ i = EPIC_NEXTTX(i), sc->sc_txpending--) {
+ txd = EPIC_CDTX(sc, i);
+ ds = EPIC_DSTX(sc, i);
+
+ EPIC_CDTXSYNC(sc, i,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+ txstatus = txd->et_txstatus;
+ if (txstatus & ET_TXSTAT_OWNER)
+ break;
+
+ EPIC_CDFLSYNC(sc, i, BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap,
+ 0, ds->ds_dmamap->dm_mapsize,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
+ m_freem(ds->ds_mbuf);
+ ds->ds_mbuf = NULL;
+
+ /*
+ * Check for errors and collisions.
+ */
+ if ((txstatus & ET_TXSTAT_PACKETTX) == 0)
+ ifp->if_oerrors++;
+ else
+ ifp->if_opackets++;
+ ifp->if_collisions +=
+ TXSTAT_COLLISIONS(txstatus);
+ if (txstatus & ET_TXSTAT_CARSENSELOST)
+ printf("%s: lost carrier\n",
+ sc->sc_dev.dv_xname);
+ }
+
+ /* Update the dirty transmit buffer pointer. */
+ sc->sc_txdirty = i;
+
+ /*
+ * Cancel the watchdog timer if there are no pending
+ * transmissions.
+ */
+ if (sc->sc_txpending == 0)
+ ifp->if_timer = 0;
+
+ /*
+ * Kick the transmitter after a DMA underrun.
+ */
+ if (intstat & INTSTAT_TXU) {
+ printf("%s: transmit underrun\n", sc->sc_dev.dv_xname);
+ bus_space_write_4(sc->sc_st, sc->sc_sh,
+ EPIC_COMMAND, COMMAND_TXUGO);
+ if (sc->sc_txpending)
+ bus_space_write_4(sc->sc_st, sc->sc_sh,
+ EPIC_COMMAND, COMMAND_TXQUEUED);
+ }
+
+ /*
+ * Try to get more packets going.
+ */
+ epic_start(ifp);
+ }
+
+ /*
+ * Check for fatal interrupts.
+ */
+ if (intstat & INTSTAT_FATAL_INT) {
+ if (intstat & INTSTAT_PTA)
+ printf("%s: PCI target abort error\n",
+ sc->sc_dev.dv_xname);
+ else if (intstat & INTSTAT_PMA)
+ printf("%s: PCI master abort error\n",
+ sc->sc_dev.dv_xname);
+ else if (intstat & INTSTAT_APE)
+ printf("%s: PCI address parity error\n",
+ sc->sc_dev.dv_xname);
+ else if (intstat & INTSTAT_DPE)
+ printf("%s: PCI data parity error\n",
+ sc->sc_dev.dv_xname);
+ else
+ printf("%s: unknown fatal error\n",
+ sc->sc_dev.dv_xname);
+ (void) epic_init(ifp);
+ }
+
+ /*
+ * Check for more interrupts.
+ */
+ goto top;
+}
+
+/*
+ * One second timer, used to tick the MII.
+ */
+void
+epic_tick(arg)
+ void *arg;
+{
+ struct epic_softc *sc = arg;
+ int s;
+
+ s = splnet();
+ mii_tick(&sc->sc_mii);
+ splx(s);
+
+ timeout_add(&sc->sc_mii_timeout, hz);
+}
+
+/*
+ * Fixup the clock source on the EPIC.
+ */
+void
+epic_fixup_clock_source(sc)
+ struct epic_softc *sc;
+{
+ int i;
+
+ /*
+ * According to SMC Application Note 7-15, the EPIC's clock
+ * source is incorrect following a reset. This manifests itself
+ * as failure to recognize when host software has written to
+ * a register on the EPIC. The appnote recommends issuing at
+ * least 16 consecutive writes to the CLOCK TEST bit to correctly
+ * configure the clock source.
+ */
+ for (i = 0; i < 16; i++)
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_TEST,
+ TEST_CLOCKTEST);
+}
+
+/*
+ * Perform a soft reset on the EPIC.
+ */
+void
+epic_reset(sc)
+ struct epic_softc *sc;
+{
+
+ epic_fixup_clock_source(sc);
+
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_GENCTL, 0);
+ delay(100);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_GENCTL, GENCTL_SOFTRESET);
+ delay(100);
+
+ epic_fixup_clock_source(sc);
+}
+
+/*
+ * Initialize the interface. Must be called at splnet().
+ */
+int
+epic_init(ifp)
+ struct ifnet *ifp;
+{
+ struct epic_softc *sc = ifp->if_softc;
+ bus_space_tag_t st = sc->sc_st;
+ bus_space_handle_t sh = sc->sc_sh;
+ struct epic_txdesc *txd;
+ struct epic_descsoft *ds;
+ u_int32_t genctl, reg0;
+ int i, error = 0;
+
+ /*
+ * Cancel any pending I/O.
+ */
+ epic_stop(ifp, 0);
+
+ /*
+ * Reset the EPIC to a known state.
+ */
+ epic_reset(sc);
+
+ /*
+ * Magical mystery initialization.
+ */
+ bus_space_write_4(st, sh, EPIC_TXTEST, 0);
+
+ /*
+ * Initialize the EPIC genctl register:
+ *
+ * - 64 byte receive FIFO threshold
+ * - automatic advance to next receive frame
+ */
+ genctl = GENCTL_RX_FIFO_THRESH0 | GENCTL_ONECOPY;
+#if BYTE_ORDER == BIG_ENDIAN
+ genctl |= GENCTL_BIG_ENDIAN;
+#endif
+ bus_space_write_4(st, sh, EPIC_GENCTL, genctl);
+
+ /*
+ * Reset the MII bus and PHY.
+ */
+ reg0 = bus_space_read_4(st, sh, EPIC_NVCTL);
+ bus_space_write_4(st, sh, EPIC_NVCTL, reg0 | NVCTL_GPIO1 | NVCTL_GPOE1);
+ bus_space_write_4(st, sh, EPIC_MIICFG, MIICFG_ENASER);
+ bus_space_write_4(st, sh, EPIC_GENCTL, genctl | GENCTL_RESET_PHY);
+ delay(100);
+ bus_space_write_4(st, sh, EPIC_GENCTL, genctl);
+ delay(1000);
+ bus_space_write_4(st, sh, EPIC_NVCTL, reg0);
+
+ /*
+ * Initialize Ethernet address.
+ */
+ reg0 = sc->sc_arpcom.ac_enaddr[1] << 8 | sc->sc_arpcom.ac_enaddr[0];
+ bus_space_write_4(st, sh, EPIC_LAN0, reg0);
+ reg0 = sc->sc_arpcom.ac_enaddr[3] << 8 | sc->sc_arpcom.ac_enaddr[2];
+ bus_space_write_4(st, sh, EPIC_LAN1, reg0);
+ reg0 = sc->sc_arpcom.ac_enaddr[5] << 8 | sc->sc_arpcom.ac_enaddr[4];
+ bus_space_write_4(st, sh, EPIC_LAN2, reg0);
+
+ /*
+ * Initialize receive control. Remember the external buffer
+ * size setting.
+ */
+ reg0 = bus_space_read_4(st, sh, EPIC_RXCON) &
+ (RXCON_EXTBUFSIZESEL1 | RXCON_EXTBUFSIZESEL0);
+ reg0 |= (RXCON_RXMULTICAST | RXCON_RXBROADCAST);
+ if (ifp->if_flags & IFF_PROMISC)
+ reg0 |= RXCON_PROMISCMODE;
+ bus_space_write_4(st, sh, EPIC_RXCON, reg0);
+
+ /* Set the current media. */
+ epic_mediachange(ifp);
+
+ /* Set up the multicast hash table. */
+ epic_set_mchash(sc);
+
+ /*
+ * Initialize the transmit descriptor ring. txlast is initialized
+ * to the end of the list so that it will wrap around to the first
+ * descriptor when the first packet is transmitted.
+ */
+ for (i = 0; i < EPIC_NTXDESC; i++) {
+ txd = EPIC_CDTX(sc, i);
+ memset(txd, 0, sizeof(struct epic_txdesc));
+ txd->et_bufaddr = EPIC_CDFLADDR(sc, i);
+ txd->et_nextdesc = EPIC_CDTXADDR(sc, EPIC_NEXTTX(i));
+ EPIC_CDTXSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ }
+ sc->sc_txpending = 0;
+ sc->sc_txdirty = 0;
+ sc->sc_txlast = EPIC_NTXDESC - 1;
+
+ /*
+ * Initialize the receive descriptor ring.
+ */
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ ds = EPIC_DSRX(sc, i);
+ if (ds->ds_mbuf == NULL) {
+ if ((error = epic_add_rxbuf(sc, i)) != 0) {
+ printf("%s: unable to allocate or map rx "
+ "buffer %d error = %d\n",
+ sc->sc_dev.dv_xname, i, error);
+ /*
+ * XXX Should attempt to run with fewer receive
+ * XXX buffers instead of just failing.
+ */
+ epic_rxdrain(sc);
+ goto out;
+ }
+ } else
+ EPIC_INIT_RXDESC(sc, i);
+ }
+ sc->sc_rxptr = 0;
+
+ /*
+ * Initialize the interrupt mask and enable interrupts.
+ */
+ bus_space_write_4(st, sh, EPIC_INTMASK, INTMASK);
+ bus_space_write_4(st, sh, EPIC_GENCTL, genctl | GENCTL_INTENA);
+
+ /*
+ * Give the transmit and receive rings to the EPIC.
+ */
+ bus_space_write_4(st, sh, EPIC_PTCDAR,
+ EPIC_CDTXADDR(sc, EPIC_NEXTTX(sc->sc_txlast)));
+ bus_space_write_4(st, sh, EPIC_PRCDAR,
+ EPIC_CDRXADDR(sc, sc->sc_rxptr));
+
+ /*
+ * Set the EPIC in motion.
+ */
+ bus_space_write_4(st, sh, EPIC_COMMAND,
+ COMMAND_RXQUEUED | COMMAND_START_RX);
+
+ /*
+ * ...all done!
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * Start the one second clock.
+ */
+ timeout_add(&sc->sc_mii_timeout, hz);
+
+ /*
+ * Attempt to start output on the interface.
+ */
+ epic_start(ifp);
+
+ out:
+ if (error)
+ printf("%s: interface not running\n", sc->sc_dev.dv_xname);
+ return (error);
+}
+
+/*
+ * Drain the receive queue.
+ */
+void
+epic_rxdrain(sc)
+ struct epic_softc *sc;
+{
+ struct epic_descsoft *ds;
+ int i;
+
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ ds = EPIC_DSRX(sc, i);
+ if (ds->ds_mbuf != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
+ m_freem(ds->ds_mbuf);
+ ds->ds_mbuf = NULL;
+ }
+ }
+}
+
+/*
+ * Stop transmission on the interface.
+ */
+void
+epic_stop(ifp, disable)
+ struct ifnet *ifp;
+ int disable;
+{
+ struct epic_softc *sc = ifp->if_softc;
+ bus_space_tag_t st = sc->sc_st;
+ bus_space_handle_t sh = sc->sc_sh;
+ struct epic_descsoft *ds;
+ u_int32_t reg;
+ int i;
+
+ /*
+ * Stop the one second clock.
+ */
+ timeout_del(&sc->sc_mii_timeout);
+
+ /* Down the MII. */
+ mii_down(&sc->sc_mii);
+
+ /* Paranoia... */
+ epic_fixup_clock_source(sc);
+
+ /*
+ * Disable interrupts.
+ */
+ reg = bus_space_read_4(st, sh, EPIC_GENCTL);
+ bus_space_write_4(st, sh, EPIC_GENCTL, reg & ~GENCTL_INTENA);
+ bus_space_write_4(st, sh, EPIC_INTMASK, 0);
+
+ /*
+ * Stop the DMA engine and take the receiver off-line.
+ */
+ bus_space_write_4(st, sh, EPIC_COMMAND, COMMAND_STOP_RDMA |
+ COMMAND_STOP_TDMA | COMMAND_STOP_RX);
+
+ /*
+ * Release any queued transmit buffers.
+ */
+ for (i = 0; i < EPIC_NTXDESC; i++) {
+ ds = EPIC_DSTX(sc, i);
+ if (ds->ds_mbuf != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
+ m_freem(ds->ds_mbuf);
+ ds->ds_mbuf = NULL;
+ }
+ }
+
+ if (disable)
+ epic_rxdrain(sc);
+
+ /*
+ * Mark the interface down and cancel the watchdog timer.
+ */
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ ifp->if_timer = 0;
+}
+
+/*
+ * Read the EPIC Serial EEPROM.
+ */
+void
+epic_read_eeprom(sc, word, wordcnt, data)
+ struct epic_softc *sc;
+ int word, wordcnt;
+ u_int16_t *data;
+{
+ bus_space_tag_t st = sc->sc_st;
+ bus_space_handle_t sh = sc->sc_sh;
+ u_int16_t reg;
+ int i, x;
+
+#define EEPROM_WAIT_READY(st, sh) \
+ while ((bus_space_read_4((st), (sh), EPIC_EECTL) & EECTL_EERDY) == 0) \
+ /* nothing */
+
+ /*
+ * Enable the EEPROM.
+ */
+ bus_space_write_4(st, sh, EPIC_EECTL, EECTL_ENABLE);
+ EEPROM_WAIT_READY(st, sh);
+
+ for (i = 0; i < wordcnt; i++) {
+ /* Send CHIP SELECT for one clock tick. */
+ bus_space_write_4(st, sh, EPIC_EECTL, EECTL_ENABLE|EECTL_EECS);
+ EEPROM_WAIT_READY(st, sh);
+
+ /* Shift in the READ opcode. */
+ for (x = 3; x > 0; x--) {
+ reg = EECTL_ENABLE|EECTL_EECS;
+ if (EPIC_EEPROM_OPC_READ & (1 << (x - 1)))
+ reg |= EECTL_EEDI;
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ bus_space_write_4(st, sh, EPIC_EECTL, reg|EECTL_EESK);
+ EEPROM_WAIT_READY(st, sh);
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ }
+
+ /* Shift in address. */
+ for (x = 6; x > 0; x--) {
+ reg = EECTL_ENABLE|EECTL_EECS;
+ if ((word + i) & (1 << (x - 1)))
+ reg |= EECTL_EEDI;
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ bus_space_write_4(st, sh, EPIC_EECTL, reg|EECTL_EESK);
+ EEPROM_WAIT_READY(st, sh);
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ }
+
+ /* Shift out data. */
+ reg = EECTL_ENABLE|EECTL_EECS;
+ data[i] = 0;
+ for (x = 16; x > 0; x--) {
+ bus_space_write_4(st, sh, EPIC_EECTL, reg|EECTL_EESK);
+ EEPROM_WAIT_READY(st, sh);
+ if (bus_space_read_4(st, sh, EPIC_EECTL) & EECTL_EEDO)
+ data[i] |= (1 << (x - 1));
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ }
+
+ /* Clear CHIP SELECT. */
+ bus_space_write_4(st, sh, EPIC_EECTL, EECTL_ENABLE);
+ EEPROM_WAIT_READY(st, sh);
+ }
+
+ /*
+ * Disable the EEPROM.
+ */
+ bus_space_write_4(st, sh, EPIC_EECTL, 0);
+
+#undef EEPROM_WAIT_READY
+}
+
+/*
+ * Add a receive buffer to the indicated descriptor.
+ */
+int
+epic_add_rxbuf(sc, idx)
+ struct epic_softc *sc;
+ int idx;
+{
+ struct epic_descsoft *ds = EPIC_DSRX(sc, idx);
+ struct mbuf *m;
+ int error;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (ENOBUFS);
+
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+
+ if (ds->ds_mbuf != NULL)
+ bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
+
+ ds->ds_mbuf = m;
+
+ error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap,
+ m->m_ext.ext_buf, m->m_ext.ext_size, NULL,
+ BUS_DMA_READ|BUS_DMA_NOWAIT);
+ if (error) {
+ printf("%s: can't load rx DMA map %d, error = %d\n",
+ sc->sc_dev.dv_xname, idx, error);
+ panic("epic_add_rxbuf"); /* XXX */
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
+ ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
+
+ EPIC_INIT_RXDESC(sc, idx);
+
+ return (0);
+}
+
+/*
+ * Set the EPIC multicast hash table.
+ *
+ * NOTE: We rely on a recently-updated mii_media_active here!
+ */
+void
+epic_set_mchash(sc)
+ struct epic_softc *sc;
+{
+ struct arpcom *ac = &sc->sc_arpcom;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ u_int32_t hash, mchash[4];
+
+ /*
+ * Set up the multicast address filter by passing all multicast
+ * addresses through a CRC generator, and then using the low-order
+ * 6 bits as an index into the 64 bit multicast hash table (only
+ * the lower 16 bits of each 32 bit multicast hash register are
+ * valid). The high order bits select the register, while the
+ * rest of the bits select the bit within the register.
+ */
+
+ if (ifp->if_flags & IFF_PROMISC)
+ goto allmulti;
+
+ if (IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_10_T) {
+ /* XXX hardware bug in 10Mbps mode. */
+ goto allmulti;
+ }
+
+ mchash[0] = mchash[1] = mchash[2] = mchash[3] = 0;
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN))
+ goto allmulti;
+
+ hash = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
+ hash >>= 26;
+
+ /* Set the corresponding bit in the hash table. */
+ mchash[hash >> 4] |= 1 << (hash & 0xf);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ goto sethash;
+
+ allmulti:
+ ifp->if_flags |= IFF_ALLMULTI;
+ mchash[0] = mchash[1] = mchash[2] = mchash[3] = 0xffff;
+
+ sethash:
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC0, mchash[0]);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC1, mchash[1]);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC2, mchash[2]);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC3, mchash[3]);
+}
+
+/*
+ * Wait for the MII to become ready.
+ */
+int
+epic_mii_wait(sc, rw)
+ struct epic_softc *sc;
+ u_int32_t rw;
+{
+ int i;
+
+ for (i = 0; i < 50; i++) {
+ if ((bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MMCTL) & rw)
+ == 0)
+ break;
+ delay(2);
+ }
+ if (i == 50) {
+ printf("%s: MII timed out\n", sc->sc_dev.dv_xname);
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Read from the MII.
+ */
+int
+epic_mii_read(self, phy, reg)
+ struct device *self;
+ int phy, reg;
+{
+ struct epic_softc *sc = (struct epic_softc *)self;
+
+ if (epic_mii_wait(sc, MMCTL_WRITE))
+ return (0);
+
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MMCTL,
+ MMCTL_ARG(phy, reg, MMCTL_READ));
+
+ if (epic_mii_wait(sc, MMCTL_READ))
+ return (0);
+
+ return (bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MMDATA) &
+ MMDATA_MASK);
+}
+
+/*
+ * Write to the MII.
+ */
+void
+epic_mii_write(self, phy, reg, val)
+ struct device *self;
+ int phy, reg, val;
+{
+ struct epic_softc *sc = (struct epic_softc *)self;
+
+ if (epic_mii_wait(sc, MMCTL_WRITE))
+ return;
+
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MMDATA, val);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MMCTL,
+ MMCTL_ARG(phy, reg, MMCTL_WRITE));
+}
+
+/*
+ * Callback from PHY when media changes.
+ */
+void
+epic_statchg(self)
+ struct device *self;
+{
+ struct epic_softc *sc = (struct epic_softc *)self;
+ u_int32_t txcon, miicfg;
+
+ /*
+ * Update loopback bits in TXCON to reflect duplex mode.
+ */
+ txcon = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_TXCON);
+ if (sc->sc_mii.mii_media_active & IFM_FDX)
+ txcon |= (TXCON_LOOPBACK_D1|TXCON_LOOPBACK_D2);
+ else
+ txcon &= ~(TXCON_LOOPBACK_D1|TXCON_LOOPBACK_D2);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_TXCON, txcon);
+
+ /* On some cards we need manualy set fullduplex led */
+ if (sc->sc_hwflags & EPIC_DUPLEXLED_ON_694) {
+ miicfg = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG);
+ if (IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX)
+ miicfg |= MIICFG_ENABLE;
+ else
+ miicfg &= ~MIICFG_ENABLE;
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG, miicfg);
+ }
+
+ /*
+ * There is a multicast filter bug in 10Mbps mode. Kick the
+ * multicast filter in case the speed changed.
+ */
+ epic_set_mchash(sc);
+}
+
+/*
+ * Callback from ifmedia to request current media status.
+ */
+void
+epic_mediastatus(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct epic_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;
+}
+
+/*
+ * Callback from ifmedia to request new media setting.
+ */
+int
+epic_mediachange(ifp)
+ struct ifnet *ifp;
+{
+ struct epic_softc *sc = ifp->if_softc;
+ struct mii_data *mii = &sc->sc_mii;
+ struct ifmedia *ifm = &mii->mii_media;
+ int media = ifm->ifm_cur->ifm_media;
+ u_int32_t miicfg;
+ struct mii_softc *miisc;
+ int cfg;
+
+ if (!(ifp->if_flags & IFF_UP))
+ return (0);
+
+ if (IFM_INST(media) != sc->sc_serinst) {
+ /* If we're not selecting serial interface, select MII mode */
+#ifdef EPICMEDIADEBUG
+ printf("%s: parallel mode\n", ifp->if_xname);
+#endif
+ miicfg = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG);
+ miicfg &= ~MIICFG_SERMODEENA;
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG, miicfg);
+ }
+
+ mii_mediachg(mii);
+
+ if (IFM_INST(media) == sc->sc_serinst) {
+ /* select serial interface */
+#ifdef EPICMEDIADEBUG
+ printf("%s: serial mode\n", ifp->if_xname);
+#endif
+ miicfg = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG);
+ miicfg |= (MIICFG_SERMODEENA | MIICFG_ENABLE);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG, miicfg);
+
+ /* There is no driver to fill this */
+ mii->mii_media_active = media;
+ mii->mii_media_status = 0;
+
+ epic_statchg(&sc->sc_dev);
+ return (0);
+ }
+
+ /* Lookup selected PHY */
+ for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
+ miisc = LIST_NEXT(miisc, mii_list)) {
+ if (IFM_INST(media) == miisc->mii_inst)
+ break;
+ }
+ if (!miisc) {
+ printf("epic_mediachange: can't happen\n"); /* ??? panic */
+ return (0);
+ }
+#ifdef EPICMEDIADEBUG
+ printf("%s: using phy %s\n", ifp->if_xname,
+ miisc->mii_dev.dv_xname);
+#endif
+
+ if (miisc->mii_flags & MIIF_HAVEFIBER) {
+ /* XXX XXX assume it's a Level1 - should check */
+
+ /* We have to powerup fiber transceivers */
+ cfg = PHY_READ(miisc, MII_LXTPHY_CONFIG);
+ if (IFM_SUBTYPE(media) == IFM_100_FX) {
+#ifdef EPICMEDIADEBUG
+ printf("%s: power up fiber\n", ifp->if_xname);
+#endif
+ cfg |= (CONFIG_LEDC1 | CONFIG_LEDC0);
+ } else {
+#ifdef EPICMEDIADEBUG
+ printf("%s: power down fiber\n", ifp->if_xname);
+#endif
+ cfg &= ~(CONFIG_LEDC1 | CONFIG_LEDC0);
+ }
+ PHY_WRITE(miisc, MII_LXTPHY_CONFIG, cfg);
+ }
+
+ return (0);
+}
diff --git a/sys/dev/ic/smc83c170reg.h b/sys/dev/ic/smc83c170reg.h
new file mode 100644
index 00000000000..5c9c98779fb
--- /dev/null
+++ b/sys/dev/ic/smc83c170reg.h
@@ -0,0 +1,487 @@
+/* $OpenBSD: smc83c170reg.h,v 1.1 2005/05/10 01:16:32 brad Exp $ */
+/* $NetBSD: smc83c170reg.h,v 1.9 2003/11/08 16:08:13 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _DEV_IC_SMC83C170REG_H_
+#define _DEV_IC_SMC83C170REG_H_
+
+/*
+ * Register description for the Standard Microsystems Corp. 83C170
+ * Ethernet PCI Integrated Controller (EPIC/100).
+ */
+
+/*
+ * EPIC transmit descriptor. Must be 4-byte aligned.
+ */
+struct epic_txdesc {
+ u_int32_t et_txstatus; /* transmit status; see below */
+ u_int32_t et_bufaddr; /* buffer address */
+ u_int32_t et_control; /* control word; see below */
+ u_int32_t et_nextdesc; /* next descriptor pointer */
+};
+
+/* et_txstatus */
+#define TXSTAT_TXLENGTH_SHIFT 16 /* TX length in higher 16bits */
+#define TXSTAT_TXLENGTH(x) ((x) << TXSTAT_TXLENGTH_SHIFT)
+
+#define ET_TXSTAT_OWNER 0x8000 /* NIC owns descriptor */
+#define ET_TXSTAT_COLLMASK 0x1f00 /* collisions */
+#define ET_TXSTAT_DEFERRING 0x0080 /* deferring due to jabber */
+#define ET_TXSTAT_OOWCOLL 0x0040 /* out of window collision */
+#define ET_TXSTAT_CDHB 0x0020 /* collision detect heartbeat */
+#define ET_TXSTAT_UNDERRUN 0x0010 /* DMA underrun */
+#define ET_TXSTAT_CARSENSELOST 0x0008 /* carrier lost */
+#define ET_TXSTAT_TXWITHCOLL 0x0004 /* encountered collisions during tx */
+#define ET_TXSTAT_NONDEFERRED 0x0002 /* transmitted without deferring */
+#define ET_TXSTAT_PACKETTX 0x0001 /* packet transmitted successfully */
+
+#define TXSTAT_COLLISIONS(x) (((x) & ET_TXSTAT_COLLMASK) >> 8)
+
+/* et_control */
+#define TXCTL_BUFLENGTH_MASK 0x0000ffff /* buf length in lower 16bits */
+#define TXCTL_BUFLENGTH(x) ((x) & TXCTL_BUFLENGTH_MASK)
+
+#define ET_TXCTL_LASTDESC 0x00100000 /* last descriptor in frame */
+#define ET_TXCTL_NOCRC 0x00080000 /* disable CRC generation */
+#define ET_TXCTL_IAF 0x00040000 /* interrupt after frame */
+#define ET_TXCTL_LFFORM 0x00020000 /* alternate fraglist format */
+#define ET_TXCTL_FRAGLIST 0x00010000 /* descriptor points to fraglist */
+
+/*
+ * EPIC receive descriptor. Must be 4-byte aligned.
+ */
+struct epic_rxdesc {
+ u_int32_t er_rxstatus; /* receive status; see below */
+ u_int32_t er_bufaddr; /* buffer address */
+ u_int32_t er_control; /* control word; see below */
+ u_int32_t er_nextdesc; /* next descriptor pointer */
+};
+
+/* er_rxstatus */
+#define RXSTAT_RXLENGTH_SHIFT 16 /* TX length in higher 16bits */
+#define RXSTAT_RXLENGTH(x) ((x) >> RXSTAT_RXLENGTH_SHIFT)
+
+#define ER_RXSTAT_OWNER 0x8000 /* NIC owns descriptor */
+#define ER_RXSTAT_HDRCOPIED 0x4000 /* rx status posted after hdr copy */
+#define ER_RXSTAT_FRAGLISTERR 0x2000 /* ran out of frags to copy frame */
+#define ER_RXSTAT_NETSTATVALID 0x1000 /* length and status are valid */
+#define ER_RXSTAT_RCVRDIS 0x0040 /* receiver disabled */
+#define ER_RXSTAT_BCAST 0x0020 /* broadcast address recognized */
+#define ER_RXSTAT_MCAST 0x0010 /* multicast address recognized */
+#define ER_RXSTAT_MISSEDPKT 0x0008 /* missed packet */
+#define ER_RXSTAT_CRCERROR 0x0004 /* EPIC or MII asserted CRC error */
+#define ER_RXSTAT_ALIGNERROR 0x0002 /* frame not byte-aligned */
+#define ER_RXSTAT_PKTINTACT 0x0001 /* packet received without error */
+
+/* er_control */
+#define RXCTL_BUFLENGTH_MASK 0x0000ffff /* buf length in lower 16bits */
+#define RXCTL_BUFLENGTH(x) ((x) & RXCTL_BUFLENGTH_MASK)
+
+#define ER_RXCTL_HEADER 0x00040000 /* descriptor is for hdr copy */
+#define ER_RXCTL_LFFORM 0x00020000 /* alternate fraglist format */
+#define ER_RXCTL_FRAGLIST 0x00010000 /* descriptor points to fraglist */
+
+/*
+ * This is not really part of the register description, but we need
+ * to define the number of transmit fragments *somewhere*.
+ */
+#define EPIC_NFRAGS 16 /* maximum number of frags in list */
+
+/*
+ * EPIC fraglist descriptor.
+ */
+struct epic_fraglist {
+ u_int32_t ef_nfrags; /* number of frags in list */
+ struct {
+ u_int32_t ef_addr; /* address of frag */
+ u_int32_t ef_length; /* length of frag */
+ } ef_frags[EPIC_NFRAGS];
+};
+
+/*
+ * EPIC control registers.
+ */
+
+#define EPIC_COMMAND 0x00 /* COMMAND */
+#define COMMAND_TXUGO 0x00000080 /* start tx after underrun */
+#define COMMAND_STOP_RDMA 0x00000040 /* stop rx dma */
+#define COMMAND_STOP_TDMA 0x00000020 /* stop tx dma */
+#define COMMAND_NEXTFRAME 0x00000010 /* move onto next rx frame */
+#define COMMAND_RXQUEUED 0x00000008 /* queue a rx descriptor */
+#define COMMAND_TXQUEUED 0x00000004 /* queue a tx descriptor */
+#define COMMAND_START_RX 0x00000002 /* start receiver */
+#define COMMAND_STOP_RX 0x00000001 /* stop receiver */
+
+#define EPIC_INTSTAT 0x04 /* INTERRUPT STATUS */
+#define INTSTAT_PTA 0x08000000 /* PCI target abort */
+#define INTSTAT_PMA 0x04000000 /* PCI master abort */
+#define INTSTAT_APE 0x02000000 /* PCI address parity error */
+#define INTSTAT_DPE 0x01000000 /* PCI data parity error */
+#define INTSTAT_RSV 0x00800000 /* rx status valid */
+#define INTSTAT_RCTS 0x00400000 /* rx copy threshold status */
+#define INTSTAT_RBE 0x00200000 /* rx buffers empty */
+#define INTSTAT_TCIP 0x00100000 /* tx copy in progress */
+#define INTSTAT_RCIP 0x00080000 /* rx copy in progress */
+#define INTSTAT_TXIDLE 0x00040000 /* transmit idle */
+#define INTSTAT_RXIDLE 0x00020000 /* receive idle */
+#define INTSTAT_INT_ACTV 0x00010000 /* interrupt active */
+#define INTSTAT_GP2_INT 0x00008000 /* gpio2 low (PHY event) */
+#define INTSTAT_FATAL_INT 0x00001000 /* fatal error occurred */
+#define INTSTAT_RCT 0x00000800 /* rx copy threshold crossed */
+#define INTSTAT_PREI 0x00000400 /* preemptive interrupt */
+#define INTSTAT_CNT 0x00000200 /* counter overflow */
+#define INTSTAT_TXU 0x00000100 /* transmit underrun */
+#define INTSTAT_TQE 0x00000080 /* transmit queue empty */
+#define INTSTAT_TCC 0x00000040 /* transmit chain complete */
+#define INTSTAT_TXC 0x00000020 /* transmit complete */
+#define INTSTAT_RXE 0x00000010 /* receive error */
+#define INTSTAT_OVW 0x00000008 /* rx buffer overflow */
+#define INTSTAT_RQE 0x00000004 /* receive queue empty */
+#define INTSTAT_HCC 0x00000002 /* header copy complete */
+#define INTSTAT_RCC 0x00000001 /* receive copy complete */
+
+#define EPIC_INTMASK 0x08 /* INTERRUPT MASK */
+ /* Bits 0-15 enable the corresponding interrupt in INTSTAT. */
+
+#define EPIC_GENCTL 0x0c /* GENERAL CONTROL */
+#define GENCTL_RESET_PHY 0x00004000 /* reset PHY */
+#define GENCTL_SOFT1 0x00002000 /* software use */
+#define GENCTL_SOFT0 0x00001000 /* software use */
+#define GENCTL_MEM_READ_CTL1 0x00000800 /* PCI memory control */
+#define GENCTL_MEM_READ_CTL0 0x00000400 /* (see below) */
+#define GENCTL_RX_FIFO_THRESH1 0x00000200 /* rx fifo thresh */
+#define GENCTL_RX_FIFO_THRESH0 0x00000100 /* (see below) */
+#define GENCTL_BIG_ENDIAN 0x00000020 /* big endian mode */
+#define GENCTL_ONECOPY 0x00000010 /* auto-NEXTFRAME */
+#define GENCTL_POWERDOWN 0x00000008 /* powersave sleep mode */
+#define GENCTL_SOFTINT 0x00000004 /* software-generated intr */
+#define GENCTL_INTENA 0x00000002 /* interrupt enable */
+#define GENCTL_SOFTRESET 0x00000001 /* initialize EPIC */
+
+/*
+ * Explanation of MEMORY READ CONTROL:
+ *
+ * These bits control which PCI command the transmit DMA will use when
+ * bursting data over the PCI bus. When CTL1 is set, the transmit DMA
+ * will use the PCI "memory read line" command. When CTL0 is set, the
+ * transmit DMA will use the PCI "memory read multiple" command. When
+ * neither bit is set, the transmit DMA will use the "memory read" command.
+ * Use of "memory read line" or "memory read multiple" may enhance
+ * performance on some systems.
+ */
+
+/*
+ * Explanation of RECEIVE FIFO THRESHOLD:
+ *
+ * Controls the level at which the PCI burst state machine begins to
+ * empty the receive FIFO. Default is "1/2 full" (0,1).
+ *
+ * 0,0 1/4 full 32 bytes
+ * 0,1 1/2 full 64 bytes
+ * 1,0 3/4 full 96 bytes
+ * 1,1 full 128 bytes
+ */
+
+#define EPIC_NVCTL 0x10 /* NON-VOLATILE CONTROL */
+#define NVCTL_IPG_DLY_MASK 0x00000780 /* interpacket delay gap */
+#define NVCTL_CB_MODE 0x00000040 /* CardBus mode */
+#define NVCTL_GPIO2 0x00000020 /* general purpose i/o */
+#define NVCTL_GPIO1 0x00000010 /* ... */
+#define NVCTL_GPOE2 0x00000008 /* general purpose output ena */
+#define NVCTL_GPOE1 0x00000004 /* ... */
+#define NVCTL_CLKRUNSUPP 0x00000002 /* clock run supported */
+#define NVCTL_ENAMEMMAP 0x00000001 /* enable memory map */
+
+#define NVCTL_IPG_DLY(x) (((x) & NVCTL_IPG_DLY_MASK) >> 7)
+
+#define EPIC_EECTL 0x14 /* EEPROM CONTROL */
+#define EECTL_EEPROMSIZE 0x00000040 /* eeprom size; see below */
+#define EECTL_EERDY 0x00000020 /* eeprom ready */
+#define EECTL_EEDO 0x00000010 /* eeprom data out (from) */
+#define EECTL_EEDI 0x00000008 /* eeprom data in (to) */
+#define EECTL_EESK 0x00000004 /* eeprom clock */
+#define EECTL_EECS 0x00000002 /* eeprom chip select */
+#define EECTL_ENABLE 0x00000001 /* eeprom enable */
+
+/*
+ * Explanation of EEPROM SIZE:
+ *
+ * Indicates the size of the serial EEPROM:
+ *
+ * 1 16x16 or 64x16
+ * 0 128x16 or 256x16
+ */
+
+/*
+ * Serial EEPROM opcodes, including start bit:
+ */
+#define EPIC_EEPROM_OPC_WRITE 0x05
+#define EPIC_EEPROM_OPC_READ 0x06
+
+#define EPIC_PBLCNT 0x18 /* PBLCNT */
+#define PBLCNT_MASK 0x0000003f /* programmable burst length */
+
+#define EPIC_TEST 0x1c /* TEST */
+#define TEST_CLOCKTEST 0x00000008
+
+#define EPIC_CRCCNT 0x20 /* CRC ERROR COUNTER */
+#define CRCCNT_MASK 0x0000000f /* crc errs since last read */
+
+#define EPIC_ALICNT 0x24 /* FRAME ALIGNMENT ERROR COUNTER */
+#define ALICNT_MASK 0x0000000f /* align errs since last read */
+
+#define EPIC_MPCNT 0x28 /* MISSED PACKET COUNTER */
+#define MPCNT_MASK 0x0000000f /* miss. pkts since last read */
+
+#define EPIC_RXFIFO 0x2c
+
+#define EPIC_MMCTL 0x30 /* MII MANAGEMENT INTERFACE CONTROL */
+#define MMCTL_PHY_ADDR_MASK 0x00003e00 /* phy address field */
+#define MMCTL_PHY_REG_ADDR_MASK 0x000001f0 /* phy register address field */
+#define MMCTL_RESPONDER 0x00000008 /* phy responder */
+#define MMCTL_WRITE 0x00000002 /* write to phy */
+#define MMCTL_READ 0x00000001 /* read from phy */
+
+#define MMCTL_ARG(phy, reg, cmd) (((phy) << 9) | ((reg) << 4) | (cmd))
+
+#define EPIC_MMDATA 0x34 /* MII MANAGEMENT INTERFACE DATA */
+#define MMDATA_MASK 0x0000ffff /* MII frame data */
+
+#define EPIC_MIICFG 0x38 /* MII CONFIGURATION */
+#define MIICFG_ALTDIR 0x00000080 /* alternate direction */
+#define MIICFG_ALTDATA 0x00000040 /* alternate data */
+#define MIICFG_ALTCLOCK 0x00000020 /* alternate clock source */
+#define MIICFG_ENASER 0x00000010 /* enable serial manag intf */
+#define MIICFG_PHYPRESENT 0x00000008 /* phy present on MII */
+#define MIICFG_LINKSTATUS 0x00000004 /* 694 link status */
+#define MIICFG_ENABLE 0x00000002 /* enable 694 */
+#define MIICFG_SERMODEENA 0x00000001 /* serial mode enable */
+
+#define EPIC_IPG 0x3c /* INTERPACKET GAP */
+#define IPG_INTERFRAME_MASK 0x00007f00 /* interframe gap time */
+#define IPG_INTERPKT_MASK 0x000000ff /* interpacket gap time */
+
+#define EPIC_LAN0 0x40 /* LAN ADDRESS */
+
+#define EPIC_LAN1 0x44
+
+#define EPIC_LAN2 0x48
+
+#define LANn_MASK 0x0000ffff
+
+/*
+ * Explanation of LAN ADDRESS registers:
+ *
+ * LAN address is described as:
+ *
+ * 0000 [n1][n0][n3][n2] | 0000 [n5][n4][n7][n6] | 0000 [n9][n8][n11][n10]
+ *
+ * n == one nibble, mapped as follows:
+ *
+ * LAN0 [15-12] n3
+ * LAN0 [11-8] n2
+ * LAN0 [7-4] n1
+ * LAN0 [3-0] n0
+ * LAN1 [15-12] n7
+ * LAN1 [11-8] n6
+ * LAN1 [7-4] n5
+ * LAN1 [3-0] n4
+ * LAN2 [15-12] n11
+ * LAN2 [11-8] n10
+ * LAN2 [7-4] n9
+ * LAN2 [3-0] n8
+ *
+ * The LAN address is automatically recalled from the EEPROM after a
+ * hard reseet.
+ */
+
+#define EPIC_IDCHK 0x4c /* BOARD ID/CHECKSUM */
+#define IDCHK_ID_MASK 0x0000ff00 /* board ID */
+#define IDCHK_CKSUM_MASK 0x000000ff /* checksum (should be 0xff) */
+
+#define EPIC_MC0 0x50 /* MULTICAST ADDRESS HASH TABLE */
+
+#define EPIC_MC1 0x54
+
+#define EPIC_MC2 0x58
+
+#define EPIC_MC3 0x5c
+
+/*
+ * Explanation of MULTICAST ADDRESS HASH TABLE registers:
+ *
+ * Bits in the hash table are encoded as follows:
+ *
+ * MC0 [15-0]
+ * MC1 [31-16]
+ * MC2 [47-32]
+ * MC3 [53-48]
+ */
+
+#define EPIC_RXCON 0x60 /* RECEIVE CONTROL */
+#define RXCON_EXTBUFSIZESEL1 0x00000200 /* ext buf size; see below */
+#define RXCON_EXTBUFSIZESEL0 0x00000100 /* ... */
+#define RXCON_EARLYRXENABLE 0x00000080 /* early receive enable */
+#define RXCON_MONITORMODE 0x00000040 /* monitor mode */
+#define RXCON_PROMISCMODE 0x00000020 /* promiscuous mode */
+#define RXCON_RXINVADDR 0x00000010 /* rx inv individual addr */
+#define RXCON_RXMULTICAST 0x00000008 /* receive multicast */
+#define RXCON_RXBROADCAST 0x00000004 /* receive broadcast */
+#define RXCON_RXRUNT 0x00000002 /* receive runt frames */
+#define RXCON_SAVEERRPKTS 0x00000001 /* save errored packets */
+
+/*
+ * Explanation of EXTERNAL BUFFER SIZE SELECT:
+ *
+ * 0,0 external buffer access is disabled
+ * 0,1 16k
+ * 1,0 32k
+ * 1,1 128k
+ */
+
+#define EPIC_RXSTAT 0x64 /* RECEIVE STATUS */
+
+#define EPIC_RXCNT 0x68
+
+#define EPIC_RXTEST 0x6c
+
+#define EPIC_TXCON 0x70 /* TRANSMIT CONTROL */
+#define TXCON_SLOTTIME_MASK 0x000000f8 /* slot time */
+#define TXCON_LOOPBACK_D2 0x00000004 /* loopback mode bit 2 */
+#define TXCON_LOOPBACK_D1 0x00000002 /* loopback mode bit 1 */
+#define TXCON_EARLYTX_ENABLE 0x00000001 /* early transmit enable */
+
+/*
+ * Explanation of LOOPBACK MODE BIT:
+ *
+ * 0,0 normal operation
+ * 0,1 internal loopback (before PHY)
+ * 1,0 external loopback (after PHY)
+ * 1,1 full duplex - decouples transmit and receive blocks
+ */
+
+#define EPIC_TXSTAT 0x74 /* TRANSMIT STATUS */
+
+#define EPIC_TDPAR 0x78
+
+#define EPIC_TXTEST 0x7c
+
+#define EPIC_PRFDAR 0x80
+
+#define EPIC_PRCDAR 0x84 /* PCI RECEIVE CURRENT DESCRIPTOR ADDR */
+
+#define EPIC_PRHDAR 0x88
+
+#define EPIC_PRFLAR 0x8c
+
+#define EPIC_PRDLGTH 0x90
+
+#define EPIC_PRFCNT 0x94
+
+#define EPIC_PRLCAR 0x98
+
+#define EPIC_PRLPAR 0x9c
+
+#define EPIC_PREFAR 0xa0
+
+#define EPIC_PRSTAT 0xa4 /* PCI RECEIVE DMA STATUS */
+
+#define EPIC_PRBUF 0xa8
+
+#define EPIC_RDNCAR 0xac
+
+#define EPIC_PRCPTHR 0xb0 /* PCI RECEIVE COPY THRESHOLD */
+
+#define EPIC_ROMDATA 0xb4
+
+#define EPIC_PREEMPR 0xbc
+
+#define EPIC_PTFDAR 0xc0
+
+#define EPIC_PTCDAR 0xc4 /* PCI TRANSMIT CURRENT DESCRIPTOR ADDR */
+
+#define EPIC_PTHDAR 0xc8
+
+#define EPIC_PTFLAR 0xcc
+
+#define EPIC_PTDLGTH 0xd0
+
+#define EPIC_PTFCNT 0xd4
+
+#define EPIC_PTLCAR 0xd8
+
+#define EPIC_ETXTHR 0xdc /* EARLY TRANSMIT THRESHOLD */
+
+#define EPIC_PTETXC 0xe0
+
+#define EPIC_PTSTAT 0xe4
+
+#define EPIC_PTBUF 0xe8
+
+#define EPIC_PTFDAR2 0xec
+
+#define EPIC_FEVTR 0xf0 /* FEVTR (CardBus) */
+
+#define EPIC_FEVTRMSKR 0xf4 /* FEVTRMSKR (CardBus) */
+
+#define EPIC_FPRSTSTR 0xf8 /* FPRSTR (CardBus) */
+
+#define EPIC_FFRCEVTR 0xfc /* PPRCEVTR (CardBus) */
+
+/*
+ * EEPROM format:
+ *
+ * Word Bits Description
+ * ---- ---- -----------
+ * 0 7-0 LAN Address Byte 0
+ * 0 15-8 LAN Address Byte 1
+ * 1 7-0 LAN Address Byte 2
+ * 1 15-8 LAN Address Byte 3
+ * 2 7-0 LAN Address Byte 4
+ * 2 15-8 LAN Address Byte 5
+ * 3 7-0 Board ID
+ * 3 15-8 Checksum
+ * 4 5-0 Non-Volatile Control Register Contents
+ * 5 7-0 PCI Minimum Grant Desired Setting
+ * 5 15-8 PCI Maximum Latency Desired Setting
+ * 6 15-0 Subsystem Vendor ID
+ * 7 14-0 Subsystem ID
+ */
+
+#endif /* _DEV_IC_SMC83C170REG_H_ */
diff --git a/sys/dev/ic/smc83c170var.h b/sys/dev/ic/smc83c170var.h
new file mode 100644
index 00000000000..33398da9bc5
--- /dev/null
+++ b/sys/dev/ic/smc83c170var.h
@@ -0,0 +1,191 @@
+/* $OpenBSD: smc83c170var.h,v 1.1 2005/05/10 01:16:32 brad Exp $ */
+/* $NetBSD: smc83c170var.h,v 1.9 2005/02/04 02:10:37 perry Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _DEV_IC_SMC83C170VAR_H_
+#define _DEV_IC_SMC83C170VAR_H_
+
+#include <sys/timeout.h>
+
+/*
+ * Misc. definitions for the Standard Microsystems Corp. 83C170
+ * Ethernet PCI Integrated Controller (EPIC/100) driver.
+ */
+
+/*
+ * Transmit descriptor list size.
+ */
+#define EPIC_NTXDESC 128
+#define EPIC_NTXDESC_MASK (EPIC_NTXDESC - 1)
+#define EPIC_NEXTTX(x) ((x + 1) & EPIC_NTXDESC_MASK)
+
+/*
+ * Receive descriptor list size.
+ */
+#define EPIC_NRXDESC 64
+#define EPIC_NRXDESC_MASK (EPIC_NRXDESC - 1)
+#define EPIC_NEXTRX(x) ((x + 1) & EPIC_NRXDESC_MASK)
+
+/*
+ * Control structures are DMA'd to the EPIC chip. We allocate them in
+ * a single clump that maps to a single DMA segment to make several things
+ * easier.
+ */
+struct epic_control_data {
+ /*
+ * The transmit descriptors.
+ */
+ struct epic_txdesc ecd_txdescs[EPIC_NTXDESC];
+
+ /*
+ * The receive descriptors.
+ */
+ struct epic_rxdesc ecd_rxdescs[EPIC_NRXDESC];
+
+ /*
+ * The transmit fraglists.
+ */
+ struct epic_fraglist ecd_txfrags[EPIC_NTXDESC];
+};
+
+#define EPIC_CDOFF(x) offsetof(struct epic_control_data, x)
+#define EPIC_CDTXOFF(x) EPIC_CDOFF(ecd_txdescs[(x)])
+#define EPIC_CDRXOFF(x) EPIC_CDOFF(ecd_rxdescs[(x)])
+#define EPIC_CDFLOFF(x) EPIC_CDOFF(ecd_txfrags[(x)])
+
+/*
+ * Software state for transmit and receive desciptors.
+ */
+struct epic_descsoft {
+ struct mbuf *ds_mbuf; /* head of mbuf chain */
+ bus_dmamap_t ds_dmamap; /* our DMA map */
+};
+
+/*
+ * Software state per device.
+ */
+struct epic_softc {
+ struct device sc_dev; /* generic device information */
+ bus_space_tag_t sc_st; /* bus space tag */
+ bus_space_handle_t sc_sh; /* bus space handle */
+ bus_dma_tag_t sc_dmat; /* bus DMA tag */
+ struct arpcom sc_arpcom; /* ethernet common data */
+ void *sc_sdhook; /* shutdown hook */
+
+ int sc_hwflags; /* info about board */
+#define EPIC_HAS_BNC 0x01 /* BNC on serial interface */
+#define EPIC_HAS_MII_FIBER 0x02 /* fiber on MII lxtphy */
+#define EPIC_DUPLEXLED_ON_694 0x04 /* duplex LED by software */
+
+ struct mii_data sc_mii; /* MII/media information */
+ struct timeout sc_mii_timeout; /* MII timeout */
+
+ bus_dmamap_t sc_cddmamap; /* control data DMA map */
+#define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
+ bus_dmamap_t sc_nulldmamap; /* DMA map for the pad buffer */
+#define sc_nulldma sc_nulldmamap->dm_segs[0].ds_addr
+
+ /*
+ * Software state for transmit and receive descriptors.
+ */
+ struct epic_descsoft sc_txsoft[EPIC_NTXDESC];
+ struct epic_descsoft sc_rxsoft[EPIC_NRXDESC];
+
+ /*
+ * Control data structures.
+ */
+ struct epic_control_data *sc_control_data;
+
+ int sc_txpending; /* number of TX requests pending */
+ int sc_txdirty; /* first dirty TX descriptor */
+ int sc_txlast; /* last used TX descriptor */
+
+ int sc_rxptr; /* next ready RX descriptor */
+
+ u_int sc_serinst; /* ifmedia instance for serial mode */
+};
+
+#define EPIC_CDTXADDR(sc, x) ((sc)->sc_cddma + EPIC_CDTXOFF((x)))
+#define EPIC_CDRXADDR(sc, x) ((sc)->sc_cddma + EPIC_CDRXOFF((x)))
+#define EPIC_CDFLADDR(sc, x) ((sc)->sc_cddma + EPIC_CDFLOFF((x)))
+
+#define EPIC_CDTX(sc, x) (&(sc)->sc_control_data->ecd_txdescs[(x)])
+#define EPIC_CDRX(sc, x) (&(sc)->sc_control_data->ecd_rxdescs[(x)])
+#define EPIC_CDFL(sc, x) (&(sc)->sc_control_data->ecd_txfrags[(x)])
+
+#define EPIC_DSTX(sc, x) (&(sc)->sc_txsoft[(x)])
+#define EPIC_DSRX(sc, x) (&(sc)->sc_rxsoft[(x)])
+
+#define EPIC_CDTXSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \
+ EPIC_CDTXOFF((x)), sizeof(struct epic_txdesc), (ops))
+
+#define EPIC_CDRXSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \
+ EPIC_CDRXOFF((x)), sizeof(struct epic_rxdesc), (ops))
+
+#define EPIC_CDFLSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \
+ EPIC_CDFLOFF((x)), sizeof(struct epic_fraglist), (ops))
+
+#define EPIC_INIT_RXDESC(sc, x) \
+do { \
+ struct epic_descsoft *__ds = EPIC_DSRX((sc), (x)); \
+ struct epic_rxdesc *__rxd = EPIC_CDRX((sc), (x)); \
+ struct mbuf *__m = __ds->ds_mbuf; \
+ \
+ /* \
+ * Note we scoot the packet forward 2 bytes in the buffer \
+ * so that the payload after the Ethernet header is aligned \
+ * to a 4 byte boundary. \
+ */ \
+ __m->m_data = __m->m_ext.ext_buf + 2; \
+ __rxd->er_bufaddr = __ds->ds_dmamap->dm_segs[0].ds_addr + 2; \
+ __rxd->er_control = RXCTL_BUFLENGTH(__m->m_ext.ext_size - 2); \
+ __rxd->er_rxstatus = ER_RXSTAT_OWNER; \
+ __rxd->er_nextdesc = EPIC_CDRXADDR((sc), EPIC_NEXTRX((x))); \
+ EPIC_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
+} while (/* CONSTCOND */ 0)
+
+#ifdef _KERNEL
+void epic_attach(struct epic_softc *, const char *);
+int epic_intr(void *);
+#endif /* _KERNEL */
+
+#endif /* _DEV_IC_SMC83C170VAR_H_ */
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 5f5fece1a16..13bbd56b393 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.175 2005/05/02 17:26:00 grange Exp $
+# $OpenBSD: files.pci,v 1.176 2005/05/10 01:16:32 brad 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.
@@ -303,10 +303,9 @@ file dev/pci/if_em_hw.c em
attach dc at pci with dc_pci
file dev/pci/if_dc_pci.c dc_pci
-# SMC EPIC, 83c170
-device tx: ether, ifnet, mii, ifmedia
-attach tx at pci
-file dev/pci/if_tx.c tx
+# SMC EPIC/100 Fast Ethernet on PCI
+attach epic at pci with epic_pci
+file dev/pci/if_epic_pci.c epic_pci
# Alteon Tigon I & II
device ti: ether, ifnet, ifmedia, firmload
diff --git a/sys/dev/pci/if_epic_pci.c b/sys/dev/pci/if_epic_pci.c
new file mode 100644
index 00000000000..1aad3554170
--- /dev/null
+++ b/sys/dev/pci/if_epic_pci.c
@@ -0,0 +1,277 @@
+/* $OpenBSD: if_epic_pci.c,v 1.1 2005/05/10 01:16:32 brad Exp $ */
+/* $NetBSD: if_epic_pci.c,v 1.28 2005/02/27 00:27:32 perry Exp $ */
+
+/*-
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * PCI bus front-end for the Standard Microsystems Corp. 83C170
+ * Ethernet PCI Integrated Controller (EPIC/100) driver.
+ */
+
+#if 0
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: if_epic_pci.c,v 1.28 2005/02/27 00:27:32 perry Exp $");
+#endif
+
+#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/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.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>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net/if_media.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/ic/smc83c170reg.h>
+#include <dev/ic/smc83c170var.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+/*
+ * PCI configuration space registers used by the EPIC.
+ */
+#define EPIC_PCI_IOBA 0x10 /* i/o mapped base */
+#define EPIC_PCI_MMBA 0x14 /* memory mapped base */
+
+struct epic_pci_softc {
+ struct epic_softc sc_epic; /* real EPIC softc */
+
+ /* PCI-specific goo. */
+ void *sc_ih; /* interrupt handle */
+};
+
+static int epic_pci_match(struct device *, void *, void *);
+static void epic_pci_attach(struct device *, struct device *, void *);
+
+struct cfattach epic_pci_ca = {
+ sizeof(struct epic_pci_softc), epic_pci_match, epic_pci_attach
+};
+
+static const struct epic_pci_product {
+ u_int32_t epp_prodid; /* PCI product ID */
+ const char *epp_name; /* device name */
+} epic_pci_products[] = {
+ { PCI_PRODUCT_SMC_83C170, "SMC 83c170 Fast Ethernet" },
+ { PCI_PRODUCT_SMC_83C175, "SMC 83c175 Fast Ethernet" },
+ { 0, NULL },
+};
+
+static const struct epic_pci_product *
+epic_pci_lookup(const struct pci_attach_args *pa)
+{
+ const struct epic_pci_product *epp;
+
+ if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SMC)
+ return (NULL);
+
+ for (epp = epic_pci_products; epp->epp_name != NULL; epp++)
+ if (PCI_PRODUCT(pa->pa_id) == epp->epp_prodid)
+ return (epp);
+
+ return (NULL);
+}
+
+static const struct epic_pci_subsys_info {
+ pcireg_t subsysid;
+ int flags;
+} epic_pci_subsys_info[] = {
+ { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa015), /* SMC9432BTX */
+ EPIC_HAS_BNC },
+ { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa024), /* SMC9432BTX1 */
+ EPIC_HAS_BNC },
+ { PCI_ID_CODE(PCI_VENDOR_SMC, 0xa016), /* SMC9432FTX */
+ EPIC_HAS_MII_FIBER | EPIC_DUPLEXLED_ON_694 },
+ { 0xffffffff,
+ 0 }
+};
+
+static const struct epic_pci_subsys_info *
+epic_pci_subsys_lookup(const struct pci_attach_args *pa)
+{
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pcireg_t reg;
+ const struct epic_pci_subsys_info *esp;
+
+ reg = pci_conf_read(pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+
+ for (esp = epic_pci_subsys_info; esp->subsysid != 0xffffffff; esp++)
+ if (esp->subsysid == reg)
+ return (esp);
+
+ return (NULL);
+}
+
+static int
+epic_pci_match(struct device *parent, void *match, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+
+ if (epic_pci_lookup(pa) != NULL)
+ return (1);
+
+ return (0);
+}
+
+static void
+epic_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct epic_pci_softc *psc = (struct epic_pci_softc *)self;
+ struct epic_softc *sc = &psc->sc_epic;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ const struct epic_pci_product *epp;
+ const struct epic_pci_subsys_info *esp;
+ bus_space_tag_t iot, memt;
+ bus_space_handle_t ioh, memh;
+ pcireg_t reg;
+ int pmreg, ioh_valid, memh_valid;
+
+ epp = epic_pci_lookup(pa);
+ if (epp == NULL) {
+ printf("\n");
+ panic(": epic_pci_attach: impossible");
+ }
+
+ if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
+ reg = pci_conf_read(pc, pa->pa_tag, pmreg + PCI_PMCSR);
+ switch (reg & PCI_PMCSR_STATE_MASK) {
+ case PCI_PMCSR_STATE_D1:
+ case PCI_PMCSR_STATE_D2:
+ printf(": waking up from power state D%d\n",
+ sc->sc_dev.dv_xname, reg & PCI_PMCSR_STATE_MASK);
+ pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR,
+ (reg & ~PCI_PMCSR_STATE_MASK) |
+ PCI_PMCSR_STATE_D0);
+ break;
+ case PCI_PMCSR_STATE_D3:
+ /*
+ * IO and MEM are disabled. We can't enable
+ * the card because the BARs might be invalid.
+ */
+ printf(
+ ": unable to wake up from power state D3, "
+ "reboot required.\n", sc->sc_dev.dv_xname);
+ pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR,
+ (reg & ~PCI_PMCSR_STATE_MASK) |
+ PCI_PMCSR_STATE_D0);
+ return;
+ }
+ }
+
+ /*
+ * Map the device.
+ */
+ ioh_valid = (pci_mapreg_map(pa, EPIC_PCI_IOBA,
+ PCI_MAPREG_TYPE_IO, 0,
+ &iot, &ioh, NULL, NULL, 0) == 0);
+ memh_valid = (pci_mapreg_map(pa, EPIC_PCI_MMBA,
+ PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
+ &memt, &memh, NULL, NULL, 0) == 0);
+
+ if (memh_valid) {
+ sc->sc_st = memt;
+ sc->sc_sh = memh;
+ } else if (ioh_valid) {
+ sc->sc_st = iot;
+ sc->sc_sh = ioh;
+ } else {
+ printf(": unable to map device registers\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+
+ sc->sc_dmat = pa->pa_dmat;
+
+ /* Make sure bus mastering is enabled. */
+ pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+ pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
+ PCI_COMMAND_MASTER_ENABLE);
+
+ /*
+ * Map and establish our interrupt.
+ */
+ if (pci_intr_map(pa, &ih)) {
+ printf(": unable to map interrupt\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+ psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, epic_intr, sc,
+ self->dv_xname);
+ if (psc->sc_ih == NULL) {
+ printf("%s: unable to establish interrupt",
+ sc->sc_dev.dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+
+ esp = epic_pci_subsys_lookup(pa);
+ if (esp)
+ sc->sc_hwflags = esp->flags;
+
+ /*
+ * Finish off the attach.
+ */
+ epic_attach(sc, intrstr);
+}