summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1999-12-04 17:41:31 +0000
committerwpaul <wpaul@FreeBSD.org>1999-12-04 17:41:31 +0000
commitcdd3a692fef117748428ae5f3c1c4991493348a0 (patch)
treec7c9beca143450e4c9418057e32fb311cb40b041 /sys
parent46e40e0c76b9170a8c1a4d7d1236f62a00b8fc19 (diff)
downloadFreeBSD-src-cdd3a692fef117748428ae5f3c1c4991493348a0.zip
FreeBSD-src-cdd3a692fef117748428ae5f3c1c4991493348a0.tar.gz
Add the if_dc driver and remove all of the al, ax, dm, pn and mx drivers
which it replaces. The new driver supports all of the chips supported by the ones it replaces, as well as many DEC/Intel 21143 10/100 cards. This also completes my quest to convert things to miibus and add Alpha support.
Diffstat (limited to 'sys')
-rw-r--r--sys/alpha/conf/GENERIC6
-rw-r--r--sys/alpha/conf/NOTES6
-rw-r--r--sys/amd64/conf/GENERIC6
-rw-r--r--sys/conf/NOTES31
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/dc/dcphy.c (renamed from sys/dev/mii/mxphy.c)236
-rw-r--r--sys/dev/dc/if_dc.c2689
-rw-r--r--sys/dev/dc/if_dcreg.h903
-rw-r--r--sys/dev/dc/pnphy.c311
-rw-r--r--sys/dev/mii/dcphy.c528
-rw-r--r--sys/dev/mii/pnphy.c311
-rw-r--r--sys/i386/conf/GENERIC6
-rw-r--r--sys/i386/conf/LINT31
-rw-r--r--sys/i386/conf/NEWCARD6
-rw-r--r--sys/i386/conf/NOTES31
-rw-r--r--sys/i386/conf/PCCARD6
-rw-r--r--sys/i386/i386/userconfig.c6
-rw-r--r--sys/modules/Makefile6
-rw-r--r--sys/modules/ax/Makefile8
-rw-r--r--sys/modules/dc/Makefile (renamed from sys/modules/al/Makefile)4
-rw-r--r--sys/modules/dm/Makefile10
-rw-r--r--sys/modules/mii/Makefile2
-rw-r--r--sys/modules/mx/Makefile8
-rw-r--r--sys/modules/pn/Makefile8
-rw-r--r--sys/pci/if_al.c1762
-rw-r--r--sys/pci/if_alreg.h553
-rw-r--r--sys/pci/if_ax.c2233
-rw-r--r--sys/pci/if_axreg.h575
-rw-r--r--sys/pci/if_dc.c2689
-rw-r--r--sys/pci/if_dcreg.h903
-rw-r--r--sys/pci/if_dm.c1709
-rw-r--r--sys/pci/if_dmreg.h419
-rw-r--r--sys/pci/if_mx.c1992
-rw-r--r--sys/pci/if_mxreg.h595
-rw-r--r--sys/pci/if_pn.c2326
-rw-r--r--sys/pci/if_pnreg.h714
36 files changed, 8505 insertions, 13130 deletions
diff --git a/sys/alpha/conf/GENERIC b/sys/alpha/conf/GENERIC
index 785ff00..fc9c4be 100644
--- a/sys/alpha/conf/GENERIC
+++ b/sys/alpha/conf/GENERIC
@@ -114,17 +114,13 @@ device sio0 at isa0 port IO_COM1 irq 4
device sio1 at isa0 port IO_COM2 irq 3 flags 0x50
# PCI Ethernet NICs.
-device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
device le0 # Lance
-device pn0 # Lite-On 82c168/82c169 (``PNIC'')
# PCI Ethernet NICs that use the common MII bus controller code.
controller miibus0 # MII bus support
-device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
-device dm0 # Davicom DM9100/DM9102
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
+device dc0 # DEC/Intel 21143 and workalikes
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/alpha/conf/NOTES b/sys/alpha/conf/NOTES
index 785ff00..fc9c4be 100644
--- a/sys/alpha/conf/NOTES
+++ b/sys/alpha/conf/NOTES
@@ -114,17 +114,13 @@ device sio0 at isa0 port IO_COM1 irq 4
device sio1 at isa0 port IO_COM2 irq 3 flags 0x50
# PCI Ethernet NICs.
-device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
device le0 # Lance
-device pn0 # Lite-On 82c168/82c169 (``PNIC'')
# PCI Ethernet NICs that use the common MII bus controller code.
controller miibus0 # MII bus support
-device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
-device dm0 # Davicom DM9100/DM9102
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
+device dc0 # DEC/Intel 21143 and workalikes
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index 9f6702e..dcdee22 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -175,18 +175,14 @@ device ppi0 # Parallel port interface device
# PCI Ethernet NICs.
-device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
-device pn0 # Lite-On 82c168/82c169 (``PNIC'')
device tx0 # SMC 9432TX (83c170 ``EPIC'')
device vx0 # 3Com 3c590, 3c595 (``Vortex'')
# PCI Ethernet NICs that use the common MII bus controller code.
controller miibus0 # MII bus support
-device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
-device dm0 # Davicom DM9100/DM9102
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
+device dc0 # DEC/Intel 21143 and various workalikes
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 70df1ae..c52b4c1 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -1646,31 +1646,20 @@ controller miibus0
# nd 1040B PCI SCSI host adapters, as well as the Qlogic ISP 2100
# FC/AL Host Adapter.
#
-# The `al' device provides support for PCI fast ethernet adapters
-# based on the ADMtek Inc. AL981 "Comet" and the AN985 "Centaur" chips.
-#
-# The `ax' device provides support for PCI fast ethernet adapters
-# based on the ASIX Electronics AX88140A chip, including the Alfa
-# Inc. GFC2204.
+# The `dc' device provides support for PCI fast ethernet adapters
+# based on the DEC/Intel 21143 and various workalikes including:
+# the ADMtek AL981 Comet and AN985 Centaur, the ASIX Electronics
+# AX88140A and AX88141, the Davicom DM9100 and DM9102, the Lite-On
+# 82c168 and 82c169 PNIC, the Lite-On/Macronix LC82C115 PNIC II
+# and the Macronix 98713/98713A/98715/98715A/98725 PMAC. This driver
+# replaces the old al, ax, dm, pn and mx drivers.
#
# The `de' device provides support for the Digital Equipment DC21040
# self-contained Ethernet adapter.
#
-# The `dm' device provides support for PCI fast ethernet adapters
-# based on the the Davicom DM9100 and DM9102 controller chips, including
-# the Jaton Corporation XPressNet.
-#
# The `fxp' device provides support for the Intel EtherExpress Pro/100B
# PCI Fast Ethernet adapters.
#
-# The `mx' device provides support for various fast ethernet adapters
-# based on the Macronix 98713, 987615 and 98725 series chips.
-#
-# The `pn' device provides support for various fast ethernet adapters
-# based on the Lite-On 82c168 and 82c169 PNIC chips, including the
-# LinkSys LNE100TX, the NetGear FA310TX rev. D1 and the Matrox
-# FastNIC 10/100.
-#
# The 'rl' device provides support for PCI fast ethernet adapters based
# on the RealTek 8129/8139 chipset. Note that the RealTek driver defaults
# to using programmed I/O to do register accesses because memory mapped
@@ -1852,13 +1841,9 @@ options SCSI_ISP_WWN="0x5000000099990000"
#options ISP_COMPILE_2100_FW=1
#options ISP_COMPILE_2200_FW=1
-device al0
-device ax0
+device dc0
device de0
-device dm0
device fxp0
-device mx0
-device pn0
device rl0
device sf0
device sis0
diff --git a/sys/conf/files b/sys/conf/files
index ef04f36..08ee5cd 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -715,18 +715,14 @@ dev/bktr/bktr_os.c optional bktr pci
pci/pccbb.c optional pccbb cardbus
pci/cy_pci.c optional cy pci
pci/ida_pci.c optional ida pci
-pci/if_al.c optional al
pci/if_ar_p.c optional ar pci
-pci/if_ax.c optional ax
+pci/if_dc.c optional dc
pci/if_de.c optional de
-pci/if_dm.c optional dm
pci/if_en_pci.c optional en pci
pci/if_fpa.c optional fpa pci
pci/if_fxp.c optional fxp
pci/if_lnc_p.c optional lnc pci
pci/if_mn.c optional mn
-pci/if_mx.c optional mx
-pci/if_pn.c optional pn
pci/if_rl.c optional rl
pci/if_sf.c optional sf
pci/if_sis.c optional sis
diff --git a/sys/dev/mii/mxphy.c b/sys/dev/dc/dcphy.c
index fbd5573..2543e87 100644
--- a/sys/dev/mii/mxphy.c
+++ b/sys/dev/dc/dcphy.c
@@ -33,13 +33,12 @@
*/
/*
- * Pseudo-driver for internal NWAY support on Macronix 98713/98715/98725
- * PMAC controller chips. The Macronix chips use the same internal
- * NWAY register layout as the DEC/Intel 21143. Technically we're
- * abusing the miibus code to handle the media selection and NWAY
- * support here since there is no MII interface. However the logical
- * operations are roughly the same, and the alternative is to create
- * a fake MII interface in the driver, which is harder to do.
+ * Pseudo-driver for internal NWAY support on DEC 21143 and workalike
+ * controllers. Technically we're abusing the miibus code to handle
+ * media selection and NWAY support here since there is no MII
+ * interface. However the logical operations are roughly the same,
+ * and the alternative is to create a fake MII interface in the driver,
+ * which is harder to do.
*/
#include <sys/param.h>
@@ -66,7 +65,9 @@
#include <machine/resource.h>
#include <sys/bus.h>
-#include <pci/if_mxreg.h>
+#include <pci/pcivar.h>
+
+#include <pci/if_dcreg.h>
#include "miibus_if.h"
@@ -75,45 +76,45 @@ static const char rcsid[] =
"$FreeBSD$";
#endif
-#define MX_SETBIT(sc, reg, x) \
+#define DC_SETBIT(sc, reg, x) \
CSR_WRITE_4(sc, reg, \
CSR_READ_4(sc, reg) | x)
-#define MX_CLRBIT(sc, reg, x) \
+#define DC_CLRBIT(sc, reg, x) \
CSR_WRITE_4(sc, reg, \
CSR_READ_4(sc, reg) & ~x)
#define MIIF_AUTOTIMEOUT 0x0004
-static int mxphy_probe __P((device_t));
-static int mxphy_attach __P((device_t));
-static int mxphy_detach __P((device_t));
+static int dcphy_probe __P((device_t));
+static int dcphy_attach __P((device_t));
+static int dcphy_detach __P((device_t));
-static device_method_t mxphy_methods[] = {
+static device_method_t dcphy_methods[] = {
/* device interface */
- DEVMETHOD(device_probe, mxphy_probe),
- DEVMETHOD(device_attach, mxphy_attach),
- DEVMETHOD(device_detach, mxphy_detach),
+ DEVMETHOD(device_probe, dcphy_probe),
+ DEVMETHOD(device_attach, dcphy_attach),
+ DEVMETHOD(device_detach, dcphy_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
{ 0, 0 }
};
-static devclass_t mxphy_devclass;
+static devclass_t dcphy_devclass;
-static driver_t mxphy_driver = {
- "mxphy",
- mxphy_methods,
+static driver_t dcphy_driver = {
+ "dcphy",
+ dcphy_methods,
sizeof(struct mii_softc)
};
-DRIVER_MODULE(mxphy, miibus, mxphy_driver, mxphy_devclass, 0, 0);
+DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0);
-int mxphy_service __P((struct mii_softc *, struct mii_data *, int));
-void mxphy_status __P((struct mii_softc *));
-static int mxphy_auto __P((struct mii_softc *, int));
-static void mxphy_reset __P((struct mii_softc *));
+int dcphy_service __P((struct mii_softc *, struct mii_data *, int));
+void dcphy_status __P((struct mii_softc *));
+static int dcphy_auto __P((struct mii_softc *, int));
+static void dcphy_reset __P((struct mii_softc *));
-static int mxphy_probe(dev)
+static int dcphy_probe(dev)
device_t dev;
{
struct mii_attach_args *ma;
@@ -121,25 +122,25 @@ static int mxphy_probe(dev)
ma = device_get_ivars(dev);
/*
- * The mx driver will report a Macronix vendor and device
+ * The dc driver will report the 21143 vendor and device
* ID to let us know that it wants us to attach.
*/
- if (ma->mii_id1 != MX_VENDORID ||
- ma->mii_id2 != MX_DEVICEID_987x5)
+ if (ma->mii_id1 != DC_VENDORID_DEC ||
+ ma->mii_id2 != DC_DEVICEID_21143)
return(ENXIO);
- device_set_desc(dev, "Macronix NWAY media interface");
+ device_set_desc(dev, "Intel 21143 NWAY media interface");
return (0);
}
-static int mxphy_attach(dev)
+static int dcphy_attach(dev)
device_t dev;
{
struct mii_softc *sc;
struct mii_attach_args *ma;
struct mii_data *mii;
- struct mx_softc *mx_sc;
+ struct dc_softc *dc_sc;
sc = device_get_softc(dev);
ma = device_get_ivars(dev);
@@ -149,7 +150,7 @@ static int mxphy_attach(dev)
sc->mii_inst = mii->mii_instance;
sc->mii_phy = ma->mii_phyno;
- sc->mii_service = mxphy_service;
+ sc->mii_service = dcphy_service;
sc->mii_pdata = mii;
sc->mii_flags |= MIIF_NOISOLATE;
@@ -163,13 +164,24 @@ static int mxphy_attach(dev)
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
BMCR_LOOP|BMCR_S100);
- /*mxphy_reset(sc);*/
- mx_sc = mii->mii_ifp->if_softc;
- CSR_WRITE_4(mx_sc, MX_10BTSTAT, 0);
- CSR_WRITE_4(mx_sc, MX_10BTCTRL, 0);
+ /*dcphy_reset(sc);*/
+ dc_sc = mii->mii_ifp->if_softc;
+ CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
+ CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
+
+ switch(pci_read_config(device_get_parent(sc->mii_dev),
+ DC_PCI_CSID, 4)) {
+ case 0x99999999:
+ /* Example of how to only allow 10Mbps modes. */
+ sc->mii_capabilities = BMSR_10TFDX|BMSR_10THDX;
+ break;
+ default:
+ sc->mii_capabilities =
+ BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|
+ BMSR_10TFDX|BMSR_10THDX;
+ break;
+ }
- sc->mii_capabilities =
- BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX|BMSR_10THDX;
sc->mii_capabilities &= ma->mii_capmask;
device_printf(dev, " ");
if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
@@ -183,7 +195,7 @@ static int mxphy_attach(dev)
return(0);
}
-static int mxphy_detach(dev)
+static int dcphy_detach(dev)
device_t dev;
{
struct mii_softc *sc;
@@ -198,17 +210,17 @@ static int mxphy_detach(dev)
}
int
-mxphy_service(sc, mii, cmd)
+dcphy_service(sc, mii, cmd)
struct mii_softc *sc;
struct mii_data *mii;
int cmd;
{
- struct mx_softc *mx_sc;
+ struct dc_softc *dc_sc;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int reg;
u_int32_t mode;
- mx_sc = mii->mii_ifp->if_softc;
+ dc_sc = mii->mii_ifp->if_softc;
switch (cmd) {
case MII_POLLSTAT:
@@ -237,14 +249,14 @@ mxphy_service(sc, mii, cmd)
sc->mii_flags = 0;
mii->mii_media_active = IFM_NONE;
- mode = CSR_READ_4(mx_sc, MX_NETCFG);
- mode &= ~(MX_NETCFG_FULLDUPLEX|MX_NETCFG_PORTSEL|
- MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER|MX_NETCFG_SPEEDSEL);
+ mode = CSR_READ_4(dc_sc, DC_NETCFG);
+ mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL|
+ DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL);
switch (IFM_SUBTYPE(ife->ifm_media)) {
case IFM_AUTO:
- mxphy_reset(sc);
- (void) mxphy_auto(sc, 0);
+ /*dcphy_reset(sc);*/
+ (void) dcphy_auto(sc, 0);
break;
case IFM_100_T4:
/*
@@ -252,26 +264,32 @@ mxphy_service(sc, mii, cmd)
*/
return (EINVAL);
case IFM_100_TX:
- mxphy_reset(sc);
- MX_CLRBIT(mx_sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
- mode |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|
- MX_NETCFG_SCRAMBLER;
+ dcphy_reset(sc);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS|
+ DC_NETCFG_SCRAMBLER;
if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
- mode |= MX_NETCFG_FULLDUPLEX;
+ mode |= DC_NETCFG_FULLDUPLEX;
else
- mode &= ~MX_NETCFG_FULLDUPLEX;
- CSR_WRITE_4(mx_sc, MX_NETCFG, mode);
+ mode &= ~DC_NETCFG_FULLDUPLEX;
+ CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
break;
case IFM_10_T:
- mxphy_reset(sc);
- MX_CLRBIT(mx_sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
- mode &= ~MX_NETCFG_PORTSEL;
- mode |= MX_NETCFG_SPEEDSEL;
+ DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
+ else
+ DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
+ DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ mode &= ~DC_NETCFG_PORTSEL;
+ mode |= DC_NETCFG_SPEEDSEL;
if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
- mode |= MX_NETCFG_FULLDUPLEX;
+ mode |= DC_NETCFG_FULLDUPLEX;
else
- mode &= ~MX_NETCFG_FULLDUPLEX;
- CSR_WRITE_4(mx_sc, MX_NETCFG, mode);
+ mode &= ~DC_NETCFG_FULLDUPLEX;
+ CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
break;
default:
return(EINVAL);
@@ -315,25 +333,31 @@ mxphy_service(sc, mii, cmd)
* need to restart the autonegotiation process. Read
* the BMSR twice in case it's latched.
*/
- reg = CSR_READ_4(mx_sc, MX_10BTSTAT) &
- (MX_TSTAT_LS10|MX_TSTAT_LS100);
+ reg = CSR_READ_4(dc_sc, DC_10BTSTAT) &
+ (DC_TSTAT_LS10|DC_TSTAT_LS100);
if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX &&
- !(reg & MX_TSTAT_LS100)) {
+ !(reg & DC_TSTAT_LS100)) {
if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
break;
} else
return(0);
} else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T &&
- !(reg & MX_TSTAT_LS10)) {
+ !(reg & DC_TSTAT_LS10)) {
if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
break;
} else
return(0);
} else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE &&
- (!(reg & MX_TSTAT_LS10) || !(reg & MX_TSTAT_LS100))) {
+ (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ } else if (CSR_READ_4(dc_sc, DC_ISR) & DC_ISR_LINKGOOD) {
if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
break;
@@ -342,14 +366,14 @@ mxphy_service(sc, mii, cmd)
}
sc->mii_ticks = 0;
- mxphy_reset(sc);
- mxphy_auto(sc, 0);
+ /*dcphy_reset(sc);*/
+ dcphy_auto(sc, 0);
break;
}
/* Update the media status. */
- mxphy_status(sc);
+ dcphy_status(sc);
/* Callback if something changed. */
if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
@@ -360,22 +384,22 @@ mxphy_service(sc, mii, cmd)
}
void
-mxphy_status(sc)
+dcphy_status(sc)
struct mii_softc *sc;
{
struct mii_data *mii = sc->mii_pdata;
int reg, anlpar;
- struct mx_softc *mx_sc;
+ struct dc_softc *dc_sc;
- mx_sc = mii->mii_ifp->if_softc;
+ dc_sc = mii->mii_ifp->if_softc;
mii->mii_media_status = IFM_AVALID;
mii->mii_media_active = IFM_ETHER;
- reg = CSR_READ_4(mx_sc, MX_10BTSTAT) &
- (MX_TSTAT_LS10|MX_TSTAT_LS100);
+ reg = CSR_READ_4(dc_sc, DC_10BTSTAT) &
+ (DC_TSTAT_LS10|DC_TSTAT_LS100);
- if (!(reg & MX_TSTAT_LS10) || !(reg & MX_TSTAT_LS100))
+ if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
mii->mii_media_status |= IFM_ACTIVE;
if (sc->mii_flags & MIIF_DOINGAUTO) {
@@ -383,17 +407,17 @@ mxphy_status(sc)
return;
}
- if (CSR_READ_4(mx_sc, MX_10BTCTRL) & MX_TCTL_AUTONEGENBL &&
- CSR_READ_4(mx_sc, MX_10BTSTAT) & MX_TSTAT_ANEGSTAT) {
+ if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL &&
+ CSR_READ_4(dc_sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT) {
/* Erg, still trying, I guess... */
- if ((CSR_READ_4(mx_sc, MX_10BTSTAT) &
- MX_ASTAT_AUTONEGCMP) != MX_ASTAT_AUTONEGCMP) {
+ if ((CSR_READ_4(dc_sc, DC_10BTSTAT) &
+ DC_ASTAT_AUTONEGCMP) != DC_ASTAT_AUTONEGCMP) {
mii->mii_media_active |= IFM_NONE;
return;
}
- if (CSR_READ_4(mx_sc, MX_10BTSTAT) & MX_TSTAT_LP_CAN_NWAY) {
- anlpar = CSR_READ_4(mx_sc, MX_10BTSTAT) >> 16;
+ if (CSR_READ_4(dc_sc, DC_10BTSTAT) & DC_TSTAT_LP_CAN_NWAY) {
+ anlpar = CSR_READ_4(dc_sc, DC_10BTSTAT) >> 16;
if (anlpar & ANLPAR_T4)
mii->mii_media_active |= IFM_100_T4;
else if (anlpar & ANLPAR_TX_FD)
@@ -406,59 +430,65 @@ mxphy_status(sc)
mii->mii_media_active |= IFM_10_T;
else
mii->mii_media_active |= IFM_NONE;
+ if (DC_IS_INTEL(dc_sc))
+ DC_CLRBIT(dc_sc, DC_10BTCTRL,
+ DC_TCTL_AUTONEGENBL);
return;
}
/*
- * If the other side doesn't support NWAY, then the
+ * If the other side doesn't support NWAY, then the
* best we can do is determine if we have a 10Mbps or
- * 100Mbps link. There's no way to know if the link
+ * 100Mbps link. There's no way to know if the link
* is full or half duplex, so we default to half duplex
* and hope that the user is clever enough to manually
* change the media settings if we're wrong.
*/
- if (!(reg & MX_TSTAT_LS100))
+ if (!(reg & DC_TSTAT_LS100))
mii->mii_media_active |= IFM_100_TX;
- else if (!(reg & MX_TSTAT_LS10))
+ else if (!(reg & DC_TSTAT_LS10))
mii->mii_media_active |= IFM_10_T;
else
mii->mii_media_active |= IFM_NONE;
+ if (DC_IS_INTEL(dc_sc))
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
return;
}
- if (CSR_READ_4(mx_sc, MX_NETCFG) & MX_NETCFG_SCRAMBLER)
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SCRAMBLER)
mii->mii_media_active |= IFM_100_TX;
else
mii->mii_media_active |= IFM_10_T;
- if (CSR_READ_4(mx_sc, MX_NETCFG) & MX_NETCFG_FULLDUPLEX)
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
mii->mii_media_active |= IFM_FDX;
-
return;
}
static int
-mxphy_auto(mii, waitfor)
+dcphy_auto(mii, waitfor)
struct mii_softc *mii;
int waitfor;
{
int i;
- struct mx_softc *sc;
+ struct dc_softc *sc;
sc = mii->mii_pdata->mii_ifp->if_softc;
if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
- CSR_WRITE_4(sc, MX_10BTCTRL, 0x3FFFF);
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX);
- MX_SETBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL);
- MX_SETBIT(sc, MX_10BTCTRL, MX_ASTAT_TXDISABLE);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
+ DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
}
if (waitfor) {
/* Wait 500ms for it to complete. */
for (i = 0; i < 500; i++) {
- if ((CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_ANEGSTAT)
- == MX_ASTAT_AUTONEGCMP)
+ if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT)
+ == DC_ASTAT_AUTONEGCMP)
return(0);
DELAY(1000);
}
@@ -482,16 +512,16 @@ mxphy_auto(mii, waitfor)
}
static void
-mxphy_reset(mii)
+dcphy_reset(mii)
struct mii_softc *mii;
{
- struct mx_softc *sc;
+ struct dc_softc *sc;
sc = mii->mii_pdata->mii_ifp->if_softc;
- MX_SETBIT(sc, MX_SIARESET, MX_SIA_RESET_NWAY);
+ DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
DELAY(1000);
- MX_CLRBIT(sc, MX_SIARESET, MX_SIA_RESET_NWAY);
+ DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
return;
}
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
new file mode 100644
index 0000000..25491e0
--- /dev/null
+++ b/sys/dev/dc/if_dc.c
@@ -0,0 +1,2689 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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$
+ */
+
+/*
+ * DEC "tulip" clone ethernet driver. Supports the DEC/Intel 21143
+ * series chips and several workalikes including the following:
+ *
+ * Macronix 98713/98715/98725 PMAC (www.macronix.com)
+ * Macronix/Lite-On 82c115 PNIC II (www.macronix.com)
+ * Lite-On 82c168/82c169 PNIC (www.litecom.com)
+ * ASIX Electronics AX88140A (www.asix.com.tw)
+ * ASIX Electronics AX88141 (www.asix.com.tw)
+ * ADMtek AL981 (www.admtek.com.tw)
+ * ADMtek AN985 (www.admtek.com.tw)
+ * Davicom DM9100, DM9102 (www.davicom8.com)
+ *
+ * Datasheets for the 21143 are available at developer.intel.com.
+ * Datasheets for the clone parts can be found at their respective sites.
+ * (Except for the PNIC; see www.freebsd.org/~wpaul/PNIC/pnic.ps.gz.)
+ * The PNIC II is essentially a Macronix 98715A chip; the only difference
+ * worth noting is that its multicast hash table is only 128 bits wide
+ * instead of 512.
+ *
+ * Written by Bill Paul <wpaul@ee.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The Intel 21143 is the successor to the DEC 21140. It is basically
+ * the same as the 21140 but with a few new features. The 21143 supports
+ * three kinds of media attachments:
+ *
+ * o MII port, for 10Mbps and 100Mbps support and NWAY
+ * autonegotiation provided by an external PHY.
+ * o SYM port, for symbol mode 100Mbps support.
+ * o 10baseT port.
+ * o AUI/BNC port.
+ *
+ * The 100Mbps SYM port and 10baseT port can be used together in
+ * combination with the internal NWAY support to create a 10/100
+ * autosensing configuration.
+ *
+ * Knowing which media is available on a given card is tough: you're
+ * supposed to go slogging through the EEPROM looking for media
+ * description structures. Unfortunately, some card vendors that use
+ * the 21143 don't obey the DEC SROM spec correctly, which means that
+ * what you find in the EEPROM may not agree with reality. Fortunately,
+ * the 21143 provides us a way to get around this issue: lurking in
+ * PCI configuration space is the Configuration Wake-Up Command Register.
+ * This register is loaded with a value from the EEPROM when wake on LAN
+ * mode is enabled; this value tells us quite clearly what kind of media
+ * is attached to the NIC. The main purpose of this register is to tell
+ * the NIC what media to scan when in wake on LAN mode, however by
+ * forcibly enabling wake on LAN mode, we can use to learn what kind of
+ * media a given NIC has available and adapt ourselves accordingly.
+ *
+ * Of course, if the media description blocks in the EEPROM are bogus.
+ * what are the odds that the CWUC aren't bogus as well, right? Well,
+ * the CWUC value is more likely to be correct since wake on LAN mode
+ * won't work correctly without it, and wake on LAN is a big selling
+ * point these days. It's also harder to screw up a single byte than
+ * a whole media descriptor block.
+ *
+ * Note that not all tulip workalikes are handled in this driver: we only
+ * deal with those which are relatively well behaved. The Winbond is
+ * handled separately due to its different register offsets and the
+ * special handling needed for its various bugs. The PNIC is handled
+ * here, but I'm not thrilled about it.
+ *
+ * All of the workalike chips use some form of MII transceiver support
+ * with the exception of the Macronix chips, which also have a SYM port.
+ * The ASIX AX88140A is also documented to have a SYM port, but all
+ * the cards I've seen use an MII transceiver, probably because the
+ * AX88140A doesn't support internal NWAY.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/clock.h> /* for DELAY */
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#define DC_USEIOSPACE
+
+#include <pci/if_dcreg.h>
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct dc_type dc_devs[] = {
+ { DC_VENDORID_DEC, DC_DEVICEID_21143,
+ "Intel 21143 10/100BaseTX" },
+ { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9100,
+ "Davicom DM9100 10/100BaseTX" },
+ { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102,
+ "Davicom DM9102 10/100BaseTX" },
+ { DC_VENDORID_ADMTEK, DC_DEVICEID_AL981,
+ "ADMtek AL981 10/100BaseTX" },
+ { DC_VENDORID_ADMTEK, DC_DEVICEID_AN985,
+ "ADMtek AN985 10/100BaseTX" },
+ { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A,
+ "ASIX AX88140A 10/100BaseTX" },
+ { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A,
+ "ASIX AX88141 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_98713,
+ "Macronix 98713 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_98713,
+ "Macronix 98713A 10/100BaseTX" },
+ { DC_VENDORID_CP, DC_DEVICEID_98713_CP,
+ "Compex RL100-TX 10/100BaseTX" },
+ { DC_VENDORID_CP, DC_DEVICEID_98713_CP,
+ "Compex RL100-TX 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_987x5,
+ "Macronix 98715/98715A 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_987x5,
+ "Macronix 98725 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C115,
+ "LC82C115 PNIC II 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C168,
+ "82c168 PNIC 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C168,
+ "82c169 PNIC 10/100BaseTX" },
+ { 0, 0, NULL }
+};
+
+static int dc_probe __P((device_t));
+static int dc_attach __P((device_t));
+static int dc_detach __P((device_t));
+static void dc_acpi __P((device_t));
+static struct dc_type *dc_devtype __P((device_t));
+static int dc_newbuf __P((struct dc_softc *, int, struct mbuf *));
+static int dc_encap __P((struct dc_softc *, struct mbuf *,
+ u_int32_t *));
+static void dc_pnic_rx_bug_war __P((struct dc_softc *, int));
+static void dc_rxeof __P((struct dc_softc *));
+static void dc_txeof __P((struct dc_softc *));
+static void dc_tick __P((void *));
+static void dc_intr __P((void *));
+static void dc_start __P((struct ifnet *));
+static int dc_ioctl __P((struct ifnet *, u_long, caddr_t));
+static void dc_init __P((void *));
+static void dc_stop __P((struct dc_softc *));
+static void dc_watchdog __P((struct ifnet *));
+static void dc_shutdown __P((device_t));
+static int dc_ifmedia_upd __P((struct ifnet *));
+static void dc_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
+
+static void dc_delay __P((struct dc_softc *));
+static void dc_eeprom_idle __P((struct dc_softc *));
+static void dc_eeprom_putbyte __P((struct dc_softc *, int));
+static void dc_eeprom_getword __P((struct dc_softc *, int, u_int16_t *));
+static void dc_eeprom_getword_pnic
+ __P((struct dc_softc *, int, u_int16_t *));
+static void dc_read_eeprom __P((struct dc_softc *, caddr_t, int,
+ int, int));
+
+static void dc_mii_writebit __P((struct dc_softc *, int));
+static int dc_mii_readbit __P((struct dc_softc *));
+static void dc_mii_sync __P((struct dc_softc *));
+static void dc_mii_send __P((struct dc_softc *, u_int32_t, int));
+static int dc_mii_readreg __P((struct dc_softc *, struct dc_mii_frame *));
+static int dc_mii_writereg __P((struct dc_softc *, struct dc_mii_frame *));
+static int dc_miibus_readreg __P((device_t, int, int));
+static int dc_miibus_writereg __P((device_t, int, int, int));
+static void dc_miibus_statchg __P((device_t));
+
+static void dc_setcfg __P((struct dc_softc *, int));
+static u_int32_t dc_crc_le __P((struct dc_softc *, caddr_t));
+static u_int32_t dc_crc_be __P((caddr_t));
+static void dc_setfilt_21143 __P((struct dc_softc *));
+static void dc_setfilt_asix __P((struct dc_softc *));
+static void dc_setfilt_admtek __P((struct dc_softc *));
+
+static void dc_setfilt __P((struct dc_softc *));
+
+static void dc_reset __P((struct dc_softc *));
+static int dc_list_rx_init __P((struct dc_softc *));
+static int dc_list_tx_init __P((struct dc_softc *));
+
+#ifdef DC_USEIOSPACE
+#define DC_RES SYS_RES_IOPORT
+#define DC_RID DC_PCI_CFBIO
+#else
+#define DC_RES SYS_RES_MEMORY
+#define DC_RID DC_PCI_CFBMA
+#endif
+
+static device_method_t dc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, dc_probe),
+ DEVMETHOD(device_attach, dc_attach),
+ DEVMETHOD(device_detach, dc_detach),
+ DEVMETHOD(device_shutdown, dc_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, dc_miibus_readreg),
+ DEVMETHOD(miibus_writereg, dc_miibus_writereg),
+ DEVMETHOD(miibus_statchg, dc_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t dc_driver = {
+ "dc",
+ dc_methods,
+ sizeof(struct dc_softc)
+};
+
+static devclass_t dc_devclass;
+
+DRIVER_MODULE(if_dc, pci, dc_driver, dc_devclass, 0, 0);
+DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0);
+
+#define DC_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x))
+
+#define DC_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x))
+
+#define SIO_SET(x) DC_SETBIT(sc, DC_SIO, (x))
+#define SIO_CLR(x) DC_CLRBIT(sc, DC_SIO, (x))
+
+static void dc_delay(sc)
+ struct dc_softc *sc;
+{
+ int idx;
+
+ for (idx = (300 / 33) + 1; idx > 0; idx--)
+ CSR_READ_4(sc, DC_BUSCTL);
+}
+
+static void dc_eeprom_idle(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+
+ for (i = 0; i < 25; i++) {
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+ CSR_WRITE_4(sc, DC_SIO, 0x00000000);
+
+ return;
+}
+
+/*
+ * Send a read command and address to the EEPROM, check for ACK.
+ */
+static void dc_eeprom_putbyte(sc, addr)
+ struct dc_softc *sc;
+ int addr;
+{
+ register int d, i;
+
+ /*
+ * The AN985 has a 93C66 EEPROM on it instead of
+ * a 93C46. It uses a different bit sequence for
+ * specifying the "read" opcode.
+ */
+ if (DC_IS_CENTAUR(sc))
+ d = addr | (DC_EECMD_READ << 2);
+ else
+ d = addr | DC_EECMD_READ;
+
+ /*
+ * Feed in each bit and strobe the clock.
+ */
+ for (i = 0x400; i; i >>= 1) {
+ if (d & i) {
+ SIO_SET(DC_SIO_EE_DATAIN);
+ } else {
+ SIO_CLR(DC_SIO_EE_DATAIN);
+ }
+ dc_delay(sc);
+ SIO_SET(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ SIO_CLR(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ * The PNIC 82c168/82c169 has its own non-standard way to read
+ * the EEPROM.
+ */
+static void dc_eeprom_getword_pnic(sc, addr, dest)
+ struct dc_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int32_t r;
+
+ CSR_WRITE_4(sc, DC_PN_SIOCTL, DC_PN_EEOPCODE_READ|addr);
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(1);
+ r = CSR_READ_4(sc, DC_SIO);
+ if (!(r & DC_PN_SIOCTL_BUSY)) {
+ *dest = (u_int16_t)(r & 0xFFFF);
+ return;
+ }
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ */
+static void dc_eeprom_getword(sc, addr, dest)
+ struct dc_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int16_t word = 0;
+
+ /* Force EEPROM to idle state. */
+ dc_eeprom_idle(sc);
+
+ /* Enter EEPROM access mode. */
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+
+ /*
+ * Send address of word we want to read.
+ */
+ dc_eeprom_putbyte(sc, addr);
+
+ /*
+ * Start reading bits from EEPROM.
+ */
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_SET(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ if (CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT)
+ word |= i;
+ dc_delay(sc);
+ SIO_CLR(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ /* Turn off EEPROM access mode. */
+ dc_eeprom_idle(sc);
+
+ *dest = word;
+
+ return;
+}
+
+/*
+ * Read a sequence of words from the EEPROM.
+ */
+static void dc_read_eeprom(sc, dest, off, cnt, swap)
+ struct dc_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int i;
+ u_int16_t word = 0, *ptr;
+
+ for (i = 0; i < cnt; i++) {
+ if (DC_IS_PNIC(sc))
+ dc_eeprom_getword_pnic(sc, off + i, &word);
+ else
+ dc_eeprom_getword(sc, off + i, &word);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return;
+}
+
+/*
+ * The following two routines are taken from the Macronix 98713
+ * Application Notes pp.19-21.
+ */
+/*
+ * Write a bit to the MII bus.
+ */
+static void dc_mii_writebit(sc, bit)
+ struct dc_softc *sc;
+ int bit;
+{
+ if (bit)
+ CSR_WRITE_4(sc, DC_SIO,
+ DC_SIO_ROMCTL_WRITE|DC_SIO_MII_DATAOUT);
+ else
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE);
+
+ DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+
+ return;
+}
+
+/*
+ * Read a bit from the MII bus.
+ */
+static int dc_mii_readbit(sc)
+ struct dc_softc *sc;
+{
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_READ|DC_SIO_MII_DIR);
+ CSR_READ_4(sc, DC_SIO);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ if (CSR_READ_4(sc, DC_SIO) & DC_SIO_MII_DATAIN)
+ return(1);
+
+ return(0);
+}
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void dc_mii_sync(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE);
+
+ for (i = 0; i < 32; i++)
+ dc_mii_writebit(sc, 1);
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void dc_mii_send(sc, bits, cnt)
+ struct dc_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1)
+ dc_mii_writebit(sc, bits & i);
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int dc_mii_readreg(sc, frame)
+ struct dc_softc *sc;
+ struct dc_mii_frame *frame;
+
+{
+ int i, ack, s;
+
+ s = splimp();
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = DC_MII_STARTDELIM;
+ frame->mii_opcode = DC_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ /*
+ * Sync the PHYs.
+ */
+ dc_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ dc_mii_send(sc, frame->mii_stdelim, 2);
+ dc_mii_send(sc, frame->mii_opcode, 2);
+ dc_mii_send(sc, frame->mii_phyaddr, 5);
+ dc_mii_send(sc, frame->mii_regaddr, 5);
+
+#ifdef notdef
+ /* Idle bit */
+ dc_mii_writebit(sc, 1);
+ dc_mii_writebit(sc, 0);
+#endif
+
+ /* Check for ack */
+ ack = dc_mii_readbit(sc);
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ dc_mii_readbit(sc);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ if (!ack) {
+ if (dc_mii_readbit(sc))
+ frame->mii_data |= i;
+ }
+ }
+
+fail:
+
+ dc_mii_writebit(sc, 0);
+ dc_mii_writebit(sc, 0);
+
+ splx(s);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int dc_mii_writereg(sc, frame)
+ struct dc_softc *sc;
+ struct dc_mii_frame *frame;
+
+{
+ int s;
+
+ s = splimp();
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = DC_MII_STARTDELIM;
+ frame->mii_opcode = DC_MII_WRITEOP;
+ frame->mii_turnaround = DC_MII_TURNAROUND;
+
+ /*
+ * Sync the PHYs.
+ */
+ dc_mii_sync(sc);
+
+ dc_mii_send(sc, frame->mii_stdelim, 2);
+ dc_mii_send(sc, frame->mii_opcode, 2);
+ dc_mii_send(sc, frame->mii_phyaddr, 5);
+ dc_mii_send(sc, frame->mii_regaddr, 5);
+ dc_mii_send(sc, frame->mii_turnaround, 2);
+ dc_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ dc_mii_writebit(sc, 0);
+ dc_mii_writebit(sc, 0);
+
+ splx(s);
+
+ return(0);
+}
+
+static int dc_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct dc_mii_frame frame;
+ struct dc_softc *sc;
+ int i, rval, phy_reg;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ /*
+ * Note: both the AL981 and AN985 have internal PHYs,
+ * however the AL981 provides direct access to the PHY
+ * registers while the AN985 uses a serial MII interface.
+ * The AN985's MII interface is also buggy in that you
+ * can read from any MII address (0 to 31), but only address 1
+ * behaves normally. To deal with both cases, we pretend
+ * that the PHY is at MII address 1.
+ */
+ if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR)
+ return(0);
+
+ if (sc->dc_pmode == DC_PMODE_SYM) {
+ if (phy == (MII_NPHY - 1)) {
+ switch(reg) {
+ case MII_BMSR:
+ /*
+ * Fake something to make the probe
+ * code think there's a PHY here.
+ */
+ return(BMSR_MEDIAMASK);
+ break;
+ case MII_PHYIDR1:
+ if (DC_IS_PNIC(sc))
+ return(DC_VENDORID_LO);
+ return(DC_VENDORID_DEC);
+ break;
+ case MII_PHYIDR2:
+ if (DC_IS_PNIC(sc))
+ return(DC_DEVICEID_82C168);
+ return(DC_DEVICEID_21143);
+ break;
+ default:
+ return(0);
+ break;
+ }
+ } else
+ return(0);
+ }
+
+ if (DC_IS_PNIC(sc)) {
+ CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_READ |
+ (phy << 23) | (reg << 18));
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(1);
+ rval = CSR_READ_4(sc, DC_PN_MII);
+ if (!(rval & DC_PN_MII_BUSY)) {
+ rval &= 0xFFFF;
+ return(rval == 0xFFFF ? 0 : rval);
+ }
+ }
+ return(0);
+ }
+
+ if (DC_IS_COMET(sc)) {
+ switch(reg) {
+ case MII_BMCR:
+ phy_reg = DC_AL_BMCR;
+ break;
+ case MII_BMSR:
+ phy_reg = DC_AL_BMSR;
+ break;
+ case MII_PHYIDR1:
+ phy_reg = DC_AL_VENID;
+ break;
+ case MII_PHYIDR2:
+ phy_reg = DC_AL_DEVID;
+ break;
+ case MII_ANAR:
+ phy_reg = DC_AL_ANAR;
+ break;
+ case MII_ANLPAR:
+ phy_reg = DC_AL_LPAR;
+ break;
+ case MII_ANER:
+ phy_reg = DC_AL_ANER;
+ break;
+ default:
+ printf("dc%d: phy_read: bad phy register %x\n",
+ sc->dc_unit, reg);
+ return(0);
+ break;
+ }
+
+ rval = CSR_READ_4(sc, phy_reg) & 0x0000FFFF;
+
+ if (rval == 0xFFFF)
+ return(0);
+ return(rval);
+ }
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ dc_mii_readreg(sc, &frame);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+
+ return(frame.mii_data);
+}
+
+static int dc_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct dc_softc *sc;
+ struct dc_mii_frame frame;
+ int i, phy_reg;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR)
+ return(0);
+
+ if (DC_IS_PNIC(sc)) {
+ CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_WRITE |
+ (phy << 23) | (reg << 10) | data);
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, DC_PN_MII) & DC_PN_MII_BUSY))
+ break;
+ }
+ return(0);
+ }
+
+ if (DC_IS_COMET(sc)) {
+ switch(reg) {
+ case MII_BMCR:
+ phy_reg = DC_AL_BMCR;
+ break;
+ case MII_BMSR:
+ phy_reg = DC_AL_BMSR;
+ break;
+ case MII_PHYIDR1:
+ phy_reg = DC_AL_VENID;
+ break;
+ case MII_PHYIDR2:
+ phy_reg = DC_AL_DEVID;
+ break;
+ case MII_ANAR:
+ phy_reg = DC_AL_ANAR;
+ break;
+ case MII_ANLPAR:
+ phy_reg = DC_AL_LPAR;
+ break;
+ case MII_ANER:
+ phy_reg = DC_AL_ANER;
+ break;
+ default:
+ printf("dc%d: phy_write: bad phy register %x\n",
+ sc->dc_unit, reg);
+ return(0);
+ break;
+ }
+
+ CSR_WRITE_4(sc, phy_reg, data);
+ return(0);
+ }
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ dc_mii_writereg(sc, &frame);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+
+ return(0);
+}
+
+static void dc_miibus_statchg(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ if (DC_IS_ADMTEK(sc))
+ return;
+ mii = device_get_softc(sc->dc_miibus);
+ dc_setcfg(sc, mii->mii_media_active);
+ sc->dc_if_media = mii->mii_media_active;
+
+ return;
+}
+
+#define DC_POLY 0xEDB88320
+#define DC_BITS 9
+#define DC_BITS_PNIC_II 7
+
+static u_int32_t dc_crc_le(sc, addr)
+ struct dc_softc *sc;
+ caddr_t addr;
+{
+ u_int32_t idx, bit, data, crc;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (idx = 0; idx < 6; idx++) {
+ for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DC_POLY : 0);
+ }
+
+ /* The hash table on the PNIC II is only 128 bits wide. */
+ if (DC_IS_PNICII(sc))
+ return (crc & ((1 << DC_BITS_PNIC_II) - 1));
+
+ return (crc & ((1 << DC_BITS) - 1));
+}
+
+/*
+ * Calculate CRC of a multicast group address, return the lower 6 bits.
+ */
+static u_int32_t dc_crc_be(addr)
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return((crc >> 26) & 0x0000003F);
+}
+
+/*
+ * 21143-style RX filter setup routine. Filter programming is done by
+ * downloading a special setup frame into the TX engine. 21143, Macronix,
+ * PNIC, PNIC II and Davicom chips are programmed this way.
+ *
+ * We always program the chip using 'hash perfect' mode, i.e. one perfect
+ * address (our node address) and a 512-bit hash filter for multicast
+ * frames. We also sneak the broadcast address into the hash filter since
+ * we need that too.
+ */
+void dc_setfilt_21143(sc)
+ struct dc_softc *sc;
+{
+ struct dc_desc *sframe;
+ u_int32_t h, *sp;
+ struct ifmultiaddr *ifma;
+ struct ifnet *ifp;
+ int i;
+
+ ifp = &sc->arpcom.ac_if;
+
+ i = sc->dc_cdata.dc_tx_prod;
+ DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
+ sc->dc_cdata.dc_tx_cnt++;
+ sframe = &sc->dc_ldata->dc_tx_list[i];
+ sp = (u_int32_t *)&sc->dc_cdata.dc_sbuf;
+ bzero((char *)sp, DC_SFRAME_LEN);
+
+ sframe->dc_data = vtophys(&sc->dc_cdata.dc_sbuf);
+ sframe->dc_ctl = DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK |
+ DC_FILTER_HASHPERF | DC_TXCTL_FINT;
+
+ sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)&sc->dc_cdata.dc_sbuf;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
+ ifma = ifma->ifma_link.le_next) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_le(sc,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ if (ifp->if_flags & IFF_BROADCAST) {
+ h = dc_crc_le(sc, (caddr_t)&etherbroadcastaddr);
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ /* Set our MAC address */
+ sp[39] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0];
+ sp[40] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1];
+ sp[41] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2];
+
+ sframe->dc_status = DC_TXSTAT_OWN;
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ /*
+ * The PNIC takes an exceedingly long time to process its
+ * setup frame; wait 10ms after posting the setup frame
+ * before proceeding, just so it has time to swallow its
+ * medicine.
+ */
+ DELAY(10000);
+
+ ifp->if_timer = 5;
+
+ return;
+}
+
+void dc_setfilt_admtek(sc)
+ struct dc_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Init our MAC address */
+ CSR_WRITE_4(sc, DC_AL_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
+ CSR_WRITE_4(sc, DC_AL_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, DC_AL_MAR0, 0);
+ CSR_WRITE_4(sc, DC_AL_MAR1, 0);
+
+ /*
+ * If we're already in promisc or allmulti mode, we
+ * don't have to bother programming the multicast filter.
+ */
+ if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
+ return;
+
+ /* now program new ones */
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
+ ifma = ifma->ifma_link.le_next) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+
+ CSR_WRITE_4(sc, DC_AL_MAR0, hashes[0]);
+ CSR_WRITE_4(sc, DC_AL_MAR1, hashes[1]);
+
+ return;
+}
+
+void dc_setfilt_asix(sc)
+ struct dc_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Init our MAC address */
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA,
+ *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA,
+ *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ /*
+ * The ASIX chip has a special bit to enable reception
+ * of broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST)
+ DC_SETBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD);
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, 0);
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, 0);
+
+ /*
+ * If we're already in promisc or allmulti mode, we
+ * don't have to bother programming the multicast filter.
+ */
+ if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
+ return;
+
+ /* now program new ones */
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
+ ifma = ifma->ifma_link.le_next) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[0]);
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[1]);
+
+ return;
+}
+
+static void dc_setfilt(sc)
+ struct dc_softc *sc;
+{
+ if (DC_IS_INTEL(sc) || DC_IS_MACRONIX(sc) || DC_IS_PNIC(sc) ||
+ DC_IS_PNICII(sc) || DC_IS_DAVICOM(sc))
+ dc_setfilt_21143(sc);
+
+ if (DC_IS_ASIX(sc))
+ dc_setfilt_asix(sc);
+
+ if (DC_IS_ADMTEK(sc))
+ dc_setfilt_admtek(sc);
+
+ return;
+}
+
+/*
+ * In order to fiddle with the
+ * 'full-duplex' and '100Mbps' bits in the netconfig register, we
+ * first have to put the transmit and/or receive logic in the idle state.
+ */
+static void dc_setcfg(sc, media)
+ struct dc_softc *sc;
+ int media;
+{
+ int i, restart = 0;
+ u_int32_t isr;
+
+ if (IFM_SUBTYPE(media) == IFM_NONE)
+ return;
+
+ if (CSR_READ_4(sc, DC_NETCFG) & (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON)) {
+ restart = 1;
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON));
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(10);
+ isr = CSR_READ_4(sc, DC_ISR);
+ if (isr & DC_ISR_TX_IDLE ||
+ (isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED)
+ break;
+ }
+
+ if (i == DC_TIMEOUT)
+ printf("dc%d: failed to force tx and "
+ "rx to idle state\n", sc->dc_unit);
+
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_100_TX) {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT);
+ if (sc->dc_pmode == DC_PMODE_MII) {
+ DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS);
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_PORTSEL|DC_NETCFG_SCRAMBLER));
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_SCRAMBLER));
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF);
+ } else {
+ if (DC_IS_PNIC(sc)) {
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_SPEEDSEL);
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP);
+ DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL);
+ }
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL|
+ DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER);
+ }
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_10_T) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT);
+ if (sc->dc_pmode == DC_PMODE_MII) {
+ DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS);
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_PORTSEL|DC_NETCFG_SCRAMBLER));
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF);
+ } else {
+ if (DC_IS_PNIC(sc)) {
+ DC_PN_GPIO_CLRBIT(sc, DC_PN_GPIO_SPEEDSEL);
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP);
+ DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL);
+ }
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS);
+ }
+ }
+
+ if ((media & IFM_GMASK) == IFM_FDX) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc))
+ DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX);
+ } else {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc))
+ DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX);
+ }
+
+ if (restart)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON|DC_NETCFG_RX_ON);
+
+ return;
+}
+
+static void dc_reset(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET);
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_4(sc, DC_BUSCTL) & DC_BUSCTL_RESET))
+ break;
+ }
+
+ if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc)) {
+ DELAY(10000);
+ DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET);
+ i = 0;
+ }
+
+ if (i == DC_TIMEOUT)
+ printf("dc%d: reset never completed!\n", sc->dc_unit);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ CSR_WRITE_4(sc, DC_BUSCTL, 0x00000000);
+ CSR_WRITE_4(sc, DC_NETCFG, 0x00000000);
+
+ return;
+}
+
+static struct dc_type *dc_devtype(dev)
+ device_t dev;
+{
+ struct dc_type *t;
+ u_int32_t rev;
+
+ t = dc_devs;
+
+ while(t->dc_name != NULL) {
+ if ((pci_get_vendor(dev) == t->dc_vid) &&
+ (pci_get_device(dev) == t->dc_did)) {
+ /* Check the PCI revision */
+ rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF;
+ if (t->dc_did == DC_DEVICEID_98713 &&
+ rev >= DC_REVISION_98713A)
+ t++;
+ if (t->dc_did == DC_DEVICEID_98713_CP &&
+ rev >= DC_REVISION_98713A)
+ t++;
+ if (t->dc_did == DC_DEVICEID_987x5 &&
+ rev >= DC_REVISION_98725)
+ t++;
+ if (t->dc_did == DC_DEVICEID_AX88140A &&
+ rev >= DC_REVISION_88141)
+ t++;
+ if (t->dc_did == DC_DEVICEID_82C168 &&
+ rev >= DC_REVISION_82C169)
+ t++;
+ return(t);
+ }
+ t++;
+ }
+
+ return(NULL);
+}
+
+/*
+ * Probe for a 21143 or clone chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ * We do a little bit of extra work to identify the exact type of
+ * chip. The MX98713 and MX98713A have the same PCI vendor/device ID,
+ * but different revision IDs. The same is true for 98715/98715A
+ * chips and the 98725, as well as the ASIX and ADMtek chips. In some
+ * cases, the exact chip revision affects driver behavior.
+ */
+static int dc_probe(dev)
+ device_t dev;
+{
+ struct dc_type *t;
+
+ t = dc_devtype(dev);
+
+ if (t != NULL) {
+ device_set_desc(dev, t->dc_name);
+ return(0);
+ }
+
+ return(ENXIO);
+}
+
+static void dc_acpi(dev)
+ device_t dev;
+{
+ u_int32_t r, cptr;
+ int unit;
+
+ unit = device_get_unit(dev);
+
+ /* Find the location of the capabilities block */
+ cptr = pci_read_config(dev, DC_PCI_CCAP, 4) & 0xFF;
+
+ r = pci_read_config(dev, cptr, 4) & 0xFF;
+ if (r == 0x01) {
+
+ r = pci_read_config(dev, cptr + 4, 4);
+ if (r & DC_PSTATE_D3) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, DC_PCI_CFBIO, 4);
+ membase = pci_read_config(dev, DC_PCI_CFBMA, 4);
+ irq = pci_read_config(dev, DC_PCI_CFIT, 4);
+
+ /* Reset the power state. */
+ printf("dc%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit, r & DC_PSTATE_D3);
+ r &= 0xFFFFFFFC;
+ pci_write_config(dev, cptr + 4, r, 4);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, DC_PCI_CFBIO, iobase, 4);
+ pci_write_config(dev, DC_PCI_CFBMA, membase, 4);
+ pci_write_config(dev, DC_PCI_CFIT, irq, 4);
+ }
+ }
+ return;
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int dc_attach(dev)
+ device_t dev;
+{
+ int s;
+ u_char eaddr[ETHER_ADDR_LEN];
+ u_int32_t command;
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t revision;
+ int unit, error = 0, rid, mac_offset;
+
+ s = splimp();
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct dc_softc));
+
+ /*
+ * Handle power management nonsense.
+ */
+ dc_acpi(dev);
+
+ /*
+ * Map control/status registers.
+ */
+ command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
+ command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
+ pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
+ command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
+
+#ifdef DC_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("dc%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("dc%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ rid = DC_RID;
+ sc->dc_res = bus_alloc_resource(dev, DC_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->dc_res == NULL) {
+ printf("dc%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->dc_btag = rman_get_bustag(sc->dc_res);
+ sc->dc_bhandle = rman_get_bushandle(sc->dc_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->dc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->dc_irq == NULL) {
+ printf("dc%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET,
+ dc_intr, sc, &sc->dc_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ printf("dc%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ /* Need this info to decide on a chip type. */
+ sc->dc_info = dc_devtype(dev);
+ revision = pci_read_config(dev, DC_PCI_CFRV, 4) & 0x000000FF;
+
+ switch(sc->dc_info->dc_did) {
+ case DC_DEVICEID_21143:
+ sc->dc_type = DC_TYPE_21143;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ break;
+ case DC_DEVICEID_DM9100:
+ case DC_DEVICEID_DM9102:
+ sc->dc_type = DC_TYPE_DM9102;
+ sc->dc_flags |= DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_AL981:
+ sc->dc_type = DC_TYPE_AL981;
+ sc->dc_flags |= DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_TX_ADMTEK_WAR;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_AN985:
+ sc->dc_type = DC_TYPE_AN985;
+ sc->dc_flags |= DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_TX_ADMTEK_WAR;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_98713:
+ case DC_DEVICEID_98713_CP:
+ if (revision < DC_REVISION_98713A) {
+ sc->dc_type = DC_TYPE_98713;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ }
+ if (revision >= DC_REVISION_98713A)
+ sc->dc_type = DC_TYPE_98713A;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ break;
+ case DC_DEVICEID_987x5:
+ sc->dc_type = DC_TYPE_987x5;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ break;
+ case DC_DEVICEID_82C115:
+ sc->dc_type = DC_TYPE_PNICII;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ break;
+ case DC_DEVICEID_82C168:
+ sc->dc_type = DC_TYPE_PNIC;
+ sc->dc_flags |= DC_TX_STORENFWD|DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_PNIC_RX_BUG_WAR;
+ sc->dc_pnic_rx_buf = malloc(DC_RXLEN * 5, M_DEVBUF, M_NOWAIT);
+ if (revision < DC_REVISION_82C169)
+ sc->dc_pmode = DC_PMODE_SYM;
+ break;
+ case DC_DEVICEID_AX88140A:
+ sc->dc_type = DC_TYPE_ASIX;
+ sc->dc_flags |= DC_TX_USE_TX_INTR|DC_TX_INTR_FIRSTFRAG;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ default:
+ printf("dc%d: unknown device: %x\n", sc->dc_unit,
+ sc->dc_info->dc_did);
+ break;
+ }
+
+ /* Save the cache line size. */
+ sc->dc_cachesize = pci_read_config(dev, DC_PCI_CFLT, 4) & 0xFF;
+
+ /* Reset the adapter. */
+ dc_reset(sc);
+
+ /* Take 21143 out of snooze mode */
+ if (DC_IS_INTEL(sc)) {
+ command = pci_read_config(dev, DC_PCI_CFDD, 4);
+ command &= ~(DC_CFDD_SNOOZE_MODE|DC_CFDD_SLEEP_MODE);
+ pci_write_config(dev, DC_PCI_CFDD, command, 4);
+ }
+
+ /*
+ * Try to learn something about the supported media.
+ * We know that ASIX and ADMtek and Davicom devices
+ * will *always* be using MII media, so that's a no-brainer.
+ * The tricky ones are the Macronix/PNIC II and the
+ * Intel 21143.
+ */
+ if (DC_IS_INTEL(sc)) {
+ u_int32_t media, cwuc;
+ cwuc = pci_read_config(dev, DC_PCI_CWUC, 4);
+ cwuc |= DC_CWUC_FORCE_WUL;
+ pci_write_config(dev, DC_PCI_CWUC, cwuc, 4);
+ DELAY(10000);
+ media = pci_read_config(dev, DC_PCI_CWUC, 4);
+ cwuc &= ~DC_CWUC_FORCE_WUL;
+ pci_write_config(dev, DC_PCI_CWUC, cwuc, 4);
+ DELAY(10000);
+ if (media & DC_CWUC_MII_ABILITY)
+ sc->dc_pmode = DC_PMODE_MII;
+ if (media & DC_CWUC_SYM_ABILITY)
+ sc->dc_pmode = DC_PMODE_SYM;
+ /*
+ * If none of the bits are set, then this NIC
+ * isn't meant to support 'wake up LAN' mode.
+ * This is usually only the case on multiport
+ * cards, and these cards almost always have
+ * MII transceivers.
+ */
+ if (media == 0)
+ sc->dc_pmode = DC_PMODE_MII;
+ } else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) {
+ if (sc->dc_type == DC_TYPE_98713)
+ sc->dc_pmode = DC_PMODE_MII;
+ else
+ sc->dc_pmode = DC_PMODE_SYM;
+ } else if (!sc->dc_pmode)
+ sc->dc_pmode = DC_PMODE_MII;
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ switch(sc->dc_type) {
+ case DC_TYPE_98713:
+ case DC_TYPE_98713A:
+ case DC_TYPE_987x5:
+ case DC_TYPE_PNICII:
+ dc_read_eeprom(sc, (caddr_t)&mac_offset,
+ (DC_EE_NODEADDR_OFFSET / 2), 1, 0);
+ dc_read_eeprom(sc, (caddr_t)&eaddr, (mac_offset / 2), 3, 0);
+ break;
+ case DC_TYPE_PNIC:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 1);
+ break;
+ case DC_TYPE_DM9102:
+ case DC_TYPE_21143:
+ case DC_TYPE_ASIX:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
+ break;
+ case DC_TYPE_AL981:
+ case DC_TYPE_AN985:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_AL_EE_NODEADDR, 3, 0);
+ break;
+ default:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
+ break;
+ }
+
+ /*
+ * A 21143 or clone chip was detected. Inform the world.
+ */
+ printf("dc%d: Ethernet address: %6D\n", unit, eaddr, ":");
+
+ sc->dc_unit = unit;
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ sc->dc_ldata = contigmalloc(sizeof(struct dc_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->dc_ldata == NULL) {
+ printf("dc%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->dc_ldata, sizeof(struct dc_list_data));
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "dc";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = dc_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = dc_start;
+ ifp->if_watchdog = dc_watchdog;
+ ifp->if_init = dc_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = DC_TX_LIST_CNT - 1;
+
+ /*
+ * Do MII setup.
+ */
+ error = mii_phy_probe(dev, &sc->dc_miibus,
+ dc_ifmedia_upd, dc_ifmedia_sts);
+
+ if (error && DC_IS_INTEL(sc)) {
+ sc->dc_pmode = DC_PMODE_SYM;
+ mii_phy_probe(dev, &sc->dc_miibus,
+ dc_ifmedia_upd, dc_ifmedia_sts);
+ error = 0;
+ }
+
+ if (error) {
+ printf("dc%d: MII without any PHY!\n", sc->dc_unit);
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * Call MI attach routines.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ callout_handle_init(&sc->dc_stat_ch);
+
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+
+fail:
+ splx(s);
+
+ return(error);
+}
+
+static int dc_detach(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ int s;
+
+ s = splimp();
+
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ dc_stop(sc);
+ if_detach(ifp);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->dc_miibus);
+
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+
+ contigfree(sc->dc_ldata, sizeof(struct dc_list_data), M_DEVBUF);
+ if (sc->dc_pnic_rx_buf != NULL)
+ free(sc->dc_pnic_rx_buf, M_DEVBUF);
+
+ splx(s);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int dc_list_tx_init(sc)
+ struct dc_softc *sc;
+{
+ struct dc_chain_data *cd;
+ struct dc_list_data *ld;
+ int i;
+
+ cd = &sc->dc_cdata;
+ ld = sc->dc_ldata;
+ for (i = 0; i < DC_TX_LIST_CNT; i++) {
+ if (i == (DC_TX_LIST_CNT - 1)) {
+ ld->dc_tx_list[i].dc_next =
+ vtophys(&ld->dc_tx_list[0]);
+ } else {
+ ld->dc_tx_list[i].dc_next =
+ vtophys(&ld->dc_tx_list[i + 1]);
+ }
+ cd->dc_tx_chain[i] = NULL;
+ ld->dc_tx_list[i].dc_data = 0;
+ ld->dc_tx_list[i].dc_ctl = 0;
+ }
+
+ cd->dc_tx_prod = cd->dc_tx_cons = cd->dc_tx_cnt = 0;
+
+ return(0);
+}
+
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int dc_list_rx_init(sc)
+ struct dc_softc *sc;
+{
+ struct dc_chain_data *cd;
+ struct dc_list_data *ld;
+ int i;
+
+ cd = &sc->dc_cdata;
+ ld = sc->dc_ldata;
+
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ if (dc_newbuf(sc, i, NULL) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (DC_RX_LIST_CNT - 1)) {
+ ld->dc_rx_list[i].dc_next =
+ vtophys(&ld->dc_rx_list[0]);
+ } else {
+ ld->dc_rx_list[i].dc_next =
+ vtophys(&ld->dc_rx_list[i + 1]);
+ }
+ }
+
+ cd->dc_rx_prod = 0;
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int dc_newbuf(sc, i, m)
+ struct dc_softc *sc;
+ int i;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+ struct dc_desc *c;
+
+ c = &sc->dc_ldata->dc_rx_list[i];
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ printf("dc%d: no memory for rx list "
+ "-- packet dropped!\n", sc->dc_unit);
+ return(ENOBUFS);
+ }
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ printf("dc%d: no memory for rx list "
+ "-- packet dropped!\n", sc->dc_unit);
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, sizeof(u_int64_t));
+
+ /*
+ * If this is a PNIC chip, zero the buffer. This is part
+ * of the workaround for the receive bug in the 82c168 and
+ * 82c169 chips.
+ */
+ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR)
+ bzero((char *)mtod(m_new, char *), m_new->m_len);
+
+ sc->dc_cdata.dc_rx_chain[i] = m_new;
+ c->dc_data = vtophys(mtod(m_new, caddr_t));
+ c->dc_ctl = DC_RXCTL_RLINK | DC_RXLEN;
+ c->dc_status = DC_RXSTAT_OWN;
+
+ return(0);
+}
+
+/*
+ * Grrrrr.
+ * The PNIC chip has a terrible bug in it that manifests itself during
+ * periods of heavy activity. The exact mode of failure if difficult to
+ * pinpoint: sometimes it only happens in promiscuous mode, sometimes it
+ * will happen on slow machines. The bug is that sometimes instead of
+ * uploading one complete frame during reception, it uploads what looks
+ * like the entire contents of its FIFO memory. The frame we want is at
+ * the end of the whole mess, but we never know exactly how much data has
+ * been uploaded, so salvaging the frame is hard.
+ *
+ * There is only one way to do it reliably, and it's disgusting.
+ * Here's what we know:
+ *
+ * - We know there will always be somewhere between one and three extra
+ * descriptors uploaded.
+ *
+ * - We know the desired received frame will always be at the end of the
+ * total data upload.
+ *
+ * - We know the size of the desired received frame because it will be
+ * provided in the length field of the status word in the last descriptor.
+ *
+ * Here's what we do:
+ *
+ * - When we allocate buffers for the receive ring, we bzero() them.
+ * This means that we know that the buffer contents should be all
+ * zeros, except for data uploaded by the chip.
+ *
+ * - We also force the PNIC chip to upload frames that include the
+ * ethernet CRC at the end.
+ *
+ * - We gather all of the bogus frame data into a single buffer.
+ *
+ * - We then position a pointer at the end of this buffer and scan
+ * backwards until we encounter the first non-zero byte of data.
+ * This is the end of the received frame. We know we will encounter
+ * some data at the end of the frame because the CRC will always be
+ * there, so even if the sender transmits a packet of all zeros,
+ * we won't be fooled.
+ *
+ * - We know the size of the actual received frame, so we subtract
+ * that value from the current pointer location. This brings us
+ * to the start of the actual received packet.
+ *
+ * - We copy this into an mbuf and pass it on, along with the actual
+ * frame length.
+ *
+ * The performance hit is tremendous, but it beats dropping frames all
+ * the time.
+ */
+
+#define DC_WHOLEFRAME (DC_RXSTAT_FIRSTFRAG|DC_RXSTAT_LASTFRAG)
+static void dc_pnic_rx_bug_war(sc, idx)
+ struct dc_softc *sc;
+ int idx;
+{
+ struct dc_desc *cur_rx;
+ struct dc_desc *c = NULL;
+ struct mbuf *m = NULL;
+ unsigned char *ptr;
+ int i, total_len;
+ u_int32_t rxstat = 0;
+
+ i = sc->dc_pnic_rx_bug_save;
+ cur_rx = &sc->dc_ldata->dc_rx_list[idx];
+ ptr = sc->dc_pnic_rx_buf;
+ bzero(ptr, sizeof(DC_RXLEN * 5));
+
+ /* Copy all the bytes from the bogus buffers. */
+ while (1) {
+ c = &sc->dc_ldata->dc_rx_list[i];
+ rxstat = c->dc_status;
+ m = sc->dc_cdata.dc_rx_chain[i];
+ bcopy(mtod(m, char *), ptr, DC_RXLEN);
+ ptr += DC_RXLEN;
+ /* If this is the last buffer, break out. */
+ if (i == idx || rxstat & DC_RXSTAT_LASTFRAG)
+ break;
+ dc_newbuf(sc, i, m);
+ DC_INC(i, DC_RX_LIST_CNT);
+ }
+
+ /* Find the length of the actual receive frame. */
+ total_len = DC_RXBYTES(rxstat);
+
+ /* Scan backwards until we hit a non-zero byte. */
+ while(*ptr == 0x00)
+ ptr--;
+
+ /* Round off. */
+ if ((uintptr_t)(ptr) & 0x3)
+ ptr -= 1;
+
+ /* Now find the start of the frame. */
+ ptr -= total_len;
+ if (ptr < sc->dc_pnic_rx_buf)
+ ptr = sc->dc_pnic_rx_buf;
+
+ /*
+ * Now copy the salvaged frame to the last mbuf and fake up
+ * the status word to make it look like a successful
+ * frame reception.
+ */
+ dc_newbuf(sc, i, m);
+ bcopy(ptr, mtod(m, char *), total_len);
+ cur_rx->dc_status = rxstat | DC_RXSTAT_FIRSTFRAG;
+
+ return;
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void dc_rxeof(sc)
+ struct dc_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct dc_desc *cur_rx;
+ int i, total_len = 0;
+ u_int32_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+ i = sc->dc_cdata.dc_rx_prod;
+
+ while(!(sc->dc_ldata->dc_rx_list[i].dc_status & DC_RXSTAT_OWN)) {
+ struct mbuf *m0 = NULL;
+
+ cur_rx = &sc->dc_ldata->dc_rx_list[i];
+ rxstat = cur_rx->dc_status;
+ m = sc->dc_cdata.dc_rx_chain[i];
+ total_len = DC_RXBYTES(rxstat);
+
+ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) {
+ if ((rxstat & DC_WHOLEFRAME) != DC_WHOLEFRAME) {
+ if (rxstat & DC_RXSTAT_FIRSTFRAG)
+ sc->dc_pnic_rx_bug_save = i;
+ if ((rxstat & DC_RXSTAT_LASTFRAG) == 0) {
+ DC_INC(i, DC_RX_LIST_CNT);
+ continue;
+ }
+ dc_pnic_rx_bug_war(sc, i);
+ rxstat = cur_rx->dc_status;
+ total_len = DC_RXBYTES(rxstat);
+ }
+ }
+
+ sc->dc_cdata.dc_rx_chain[i] = NULL;
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (rxstat & DC_RXSTAT_RXERR) {
+ ifp->if_ierrors++;
+ if (rxstat & DC_RXSTAT_COLLSEEN)
+ ifp->if_collisions++;
+ dc_newbuf(sc, i, m);
+ if (rxstat & DC_RXSTAT_CRCERR) {
+ DC_INC(i, DC_RX_LIST_CNT);
+ continue;
+ } else {
+ dc_init(sc);
+ return;
+ }
+ }
+
+ /* No errors; receive the packet. */
+ total_len -= ETHER_CRC_LEN;
+
+ m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
+ total_len + ETHER_ALIGN, 0, ifp, NULL);
+ dc_newbuf(sc, i, m);
+ DC_INC(i, DC_RX_LIST_CNT);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ continue;
+ }
+ m_adj(m0, ETHER_ALIGN);
+ m = m0;
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+
+ /*
+ * Handle BPF listeners. Let the BPF user see the packet, but
+ * don't pass it up to the ether_input() layer unless it's
+ * a broadcast packet, multicast packet, matches our ethernet
+ * address or the interface is in promiscuous mode.
+ */
+ if (ifp->if_bpf) {
+ bpf_mtap(ifp, m);
+ if (ifp->if_flags & IFF_PROMISC &&
+ (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ ETHER_ADDR_LEN) &&
+ (eh->ether_dhost[0] & 1) == 0)) {
+ m_freem(m);
+ continue;
+ }
+ }
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ sc->dc_cdata.dc_rx_prod = i;
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+static void dc_txeof(sc)
+ struct dc_softc *sc;
+{
+ struct dc_desc *cur_tx = NULL;
+ struct ifnet *ifp;
+ int idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ idx = sc->dc_cdata.dc_tx_cons;
+ while(idx != sc->dc_cdata.dc_tx_prod) {
+ u_int32_t txstat;
+
+ cur_tx = &sc->dc_ldata->dc_tx_list[idx];
+ txstat = cur_tx->dc_status;
+
+ if (txstat & DC_TXSTAT_OWN)
+ break;
+
+ if (!(cur_tx->dc_ctl & DC_TXCTL_LASTFRAG) ||
+ cur_tx->dc_ctl & DC_TXCTL_SETUP) {
+ sc->dc_cdata.dc_tx_cnt--;
+ if (cur_tx->dc_ctl & DC_TXCTL_SETUP) {
+ /*
+ * Yes, the PNIC is so brain damaged
+ * that it will sometimes generate a TX
+ * underrun error while DMAing the RX
+ * filter setup frame. If we detect this,
+ * we have to send the setup frame again,
+ * or else the filter won't be programmed
+ * correctly.
+ */
+ if (DC_IS_PNIC(sc)) {
+ if (txstat & DC_TXSTAT_ERRSUM)
+ dc_setfilt(sc);
+ }
+ sc->dc_cdata.dc_tx_chain[idx] = NULL;
+ }
+ DC_INC(idx, DC_TX_LIST_CNT);
+ continue;
+ }
+
+ if (/*sc->dc_type == DC_TYPE_21143 &&*/
+ sc->dc_pmode == DC_PMODE_MII &&
+ ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
+ DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST)))
+ txstat &= ~DC_TXSTAT_ERRSUM;
+
+ if (txstat & DC_TXSTAT_ERRSUM) {
+ ifp->if_oerrors++;
+ if (txstat & DC_TXSTAT_EXCESSCOLL)
+ ifp->if_collisions++;
+ if (txstat & DC_TXSTAT_LATECOLL)
+ ifp->if_collisions++;
+ if (!(txstat & DC_TXSTAT_UNDERRUN)) {
+ dc_init(sc);
+ return;
+ }
+ }
+
+ ifp->if_collisions += (txstat & DC_TXSTAT_COLLCNT) >> 3;
+
+ ifp->if_opackets++;
+ if (sc->dc_cdata.dc_tx_chain[idx] != NULL) {
+ m_freem(sc->dc_cdata.dc_tx_chain[idx]);
+ sc->dc_cdata.dc_tx_chain[idx] = NULL;
+ }
+
+ sc->dc_cdata.dc_tx_cnt--;
+ DC_INC(idx, DC_TX_LIST_CNT);
+ }
+
+ sc->dc_cdata.dc_tx_cons = idx;
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+static void dc_tick(xsc)
+ void *xsc;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ int s;
+ u_int32_t r;
+
+ s = splimp();
+
+ sc = xsc;
+ ifp = &sc->arpcom.ac_if;
+ mii = device_get_softc(sc->dc_miibus);
+
+ if (sc->dc_flags & DC_REDUCED_MII_POLL) {
+ r = CSR_READ_4(sc, DC_ISR);
+ if (DC_IS_INTEL(sc)) {
+ if (r & DC_ISR_LINKFAIL) {
+ sc->dc_link = 0;
+ mii_tick(mii);
+ }
+ } else {
+ if ((r & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT &&
+ sc->dc_cdata.dc_tx_prod == 0)
+ mii_tick(mii);
+ }
+ } else
+ mii_tick(mii);
+
+ /*
+ * When the init routine completes, we expect to be able to send
+ * packets right away, and in fact the network code will send a
+ * gratuitous ARP the moment the init routine marks the interface
+ * as running. However, even though the MAC may have been initialized,
+ * there may be a delay of a few seconds before the PHY completes
+ * autonegotiation and the link is brought up. Any transmissions
+ * made during that delay will be lost. Dealing with this is tricky:
+ * we can't just pause in the init routine while waiting for the
+ * PHY to come ready since that would bring the whole system to
+ * a screeching halt for several seconds.
+ *
+ * What we do here is prevent the TX start routine from sending
+ * any packets until a link has been established. After the
+ * interface has been initialized, the tick routine will poll
+ * the state of the PHY until the IFM_ACTIVE flag is set. Until
+ * that time, packets will stay in the send queue, and once the
+ * link comes up, they will be flushed out to the wire.
+ */
+ if (!sc->dc_link) {
+ mii_pollstat(mii);
+ if (mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->dc_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+ }
+ }
+
+ sc->dc_stat_ch = timeout(dc_tick, sc, hz);
+
+ splx(s);
+
+ return;
+}
+
+static void dc_intr(arg)
+ void *arg;
+{
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t status;
+
+ sc = arg;
+ ifp = &sc->arpcom.ac_if;
+
+ /* Supress unwanted interrupts */
+ if (!(ifp->if_flags & IFF_UP)) {
+ if (CSR_READ_4(sc, DC_ISR) & DC_INTRS)
+ dc_stop(sc);
+ return;
+ }
+
+ /* Disable interrupts. */
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+
+ while((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) {
+
+ CSR_WRITE_4(sc, DC_ISR, status);
+
+ if (status & DC_ISR_RX_OK)
+ dc_rxeof(sc);
+
+ if (status & (DC_ISR_TX_OK|DC_ISR_TX_NOBUF))
+ dc_txeof(sc);
+
+ if (status & DC_ISR_TX_IDLE) {
+ dc_txeof(sc);
+ if (sc->dc_cdata.dc_tx_cnt) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+ }
+ }
+
+ if (status & DC_ISR_TX_UNDERRUN) {
+ u_int32_t cfg;
+
+ printf("dc%d: TX underrun -- ", sc->dc_unit);
+ if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc))
+ dc_init(sc);
+ cfg = CSR_READ_4(sc, DC_NETCFG);
+ cfg &= ~DC_NETCFG_TX_THRESH;
+ if (sc->dc_txthresh == DC_TXTHRESH_160BYTES) {
+ printf("using store and forward mode\n");
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ } else {
+ sc->dc_txthresh += 0x4000;
+ printf("increasing TX threshold\n");
+ CSR_WRITE_4(sc, DC_NETCFG, cfg);
+ DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ }
+ }
+
+ if ((status & DC_ISR_RX_WATDOGTIMEO)
+ || (status & DC_ISR_RX_NOBUF))
+ dc_rxeof(sc);
+
+ if (status & DC_ISR_BUS_ERR) {
+ dc_reset(sc);
+ dc_init(sc);
+ }
+ }
+
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int dc_encap(sc, m_head, txidx)
+ struct dc_softc *sc;
+ struct mbuf *m_head;
+ u_int32_t *txidx;
+{
+ struct dc_desc *f = NULL;
+ struct mbuf *m;
+ int frag, cur, cnt = 0;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ cur = frag = *txidx;
+
+ for (m = m_head; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (sc->dc_flags & DC_TX_ADMTEK_WAR) {
+ if (*txidx != sc->dc_cdata.dc_tx_prod &&
+ frag == (DC_TX_LIST_CNT - 1))
+ return(ENOBUFS);
+ }
+ if ((DC_TX_LIST_CNT -
+ (sc->dc_cdata.dc_tx_cnt + cnt)) < 5)
+ return(ENOBUFS);
+
+ f = &sc->dc_ldata->dc_tx_list[frag];
+ f->dc_ctl = DC_TXCTL_TLINK | m->m_len;
+ if (cnt == 0) {
+ f->dc_status = 0;
+ f->dc_ctl |= DC_TXCTL_FIRSTFRAG;
+ } else
+ f->dc_status = DC_TXSTAT_OWN;
+ f->dc_data = vtophys(mtod(m, vm_offset_t));
+ cur = frag;
+ DC_INC(frag, DC_TX_LIST_CNT);
+ cnt++;
+ }
+ }
+
+ if (m != NULL)
+ return(ENOBUFS);
+
+ sc->dc_cdata.dc_tx_cnt += cnt;
+ sc->dc_cdata.dc_tx_chain[cur] = m_head;
+ sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_LASTFRAG;
+ if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG)
+ sc->dc_ldata->dc_tx_list[*txidx].dc_ctl |= DC_TXCTL_FINT;
+ if (sc->dc_flags & DC_TX_USE_TX_INTR && sc->dc_cdata.dc_tx_cnt > 64)
+ sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_FINT;
+ sc->dc_ldata->dc_tx_list[*txidx].dc_status = DC_TXSTAT_OWN;
+ *txidx = frag;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+
+static void dc_start(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+ struct mbuf *m_head = NULL;
+ int idx;
+
+ sc = ifp->if_softc;
+
+ if (!sc->dc_link)
+ return;
+
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ idx = sc->dc_cdata.dc_tx_prod;
+
+ while(sc->dc_cdata.dc_tx_chain[idx] == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ if (dc_encap(sc, m_head, &idx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+ }
+
+ /* Transmit */
+ sc->dc_cdata.dc_tx_prod = idx;
+ if (!(sc->dc_flags & DC_TX_POLL))
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ return;
+}
+
+static void dc_init(xsc)
+ void *xsc;
+{
+ struct dc_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mii_data *mii;
+ int s;
+
+ s = splimp();
+
+ mii = device_get_softc(sc->dc_miibus);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ dc_stop(sc);
+ dc_reset(sc);
+
+ /*
+ * Set cache alignment and burst length.
+ */
+ if (DC_IS_ASIX(sc))
+ CSR_WRITE_4(sc, DC_BUSCTL, 0);
+ else
+ CSR_WRITE_4(sc, DC_BUSCTL, DC_BUSCTL_MRME|DC_BUSCTL_MRLE);
+ if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc)) {
+ DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_USECA);
+ } else {
+ DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_16LONG);
+ }
+ if (sc->dc_flags & DC_TX_POLL)
+ DC_SETBIT(sc, DC_BUSCTL, DC_TXPOLL_1);
+ switch(sc->dc_cachesize) {
+ case 32:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_32LONG);
+ break;
+ case 16:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_16LONG);
+ break;
+ case 8:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_8LONG);
+ break;
+ case 0:
+ default:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_NONE);
+ break;
+ }
+
+ if (sc->dc_flags & DC_TX_STORENFWD)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ else {
+ if (sc->dc_txthresh == DC_TXTHRESH_160BYTES) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ } else {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh);
+ }
+ }
+
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_NO_RXCRC);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_BACKOFF);
+
+ if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) {
+ /*
+ * The app notes for the 98713 and 98715A say that
+ * in order to have the chips operate properly, a magic
+ * number must be written to CSR16. Macronix does not
+ * document the meaning of these bits so there's no way
+ * to know exactly what they do. The 98713 has a magic
+ * number all its own; the rest all use a different one.
+ */
+ DC_CLRBIT(sc, DC_MX_MAGICPACKET, 0xFFFF0000);
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98713);
+ else
+ DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98715);
+ }
+
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH);
+ DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_72BYTES);
+
+ /* Init circular RX list. */
+ if (dc_list_rx_init(sc) == ENOBUFS) {
+ printf("dc%d: initialization failed: no "
+ "memory for rx buffers\n", sc->dc_unit);
+ dc_stop(sc);
+ (void)splx(s);
+ return;
+ }
+
+ /*
+ * Init tx descriptors.
+ */
+ dc_list_tx_init(sc);
+
+ /*
+ * Load the address of the RX list.
+ */
+ CSR_WRITE_4(sc, DC_RXADDR, vtophys(&sc->dc_ldata->dc_rx_list[0]));
+ CSR_WRITE_4(sc, DC_TXADDR, vtophys(&sc->dc_ldata->dc_tx_list[0]));
+
+ /*
+ * Enable interrupts.
+ */
+ CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+ CSR_WRITE_4(sc, DC_ISR, 0xFFFFFFFF);
+
+ /* Enable transmitter. */
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+
+ /*
+ * Load the RX/multicast filter. We do this sort of late
+ * because the filter programming scheme on the 21143 and
+ * some clones requires DMAing a setup frame via the TX
+ * engine, and we need the transmitter enabled for that.
+ */
+ dc_setfilt(sc);
+
+ /* Enable receiver. */
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON);
+ CSR_WRITE_4(sc, DC_RXSTART, 0xFFFFFFFF);
+
+ mii_mediachg(mii);
+ dc_setcfg(sc, sc->dc_if_media);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ (void)splx(s);
+
+ sc->dc_stat_ch = timeout(dc_tick, sc, hz);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int dc_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->dc_miibus);
+ mii_mediachg(mii);
+ sc->dc_link = 0;
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void dc_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->dc_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int dc_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct dc_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->dc_if_flags & IFF_PROMISC)) {
+ dc_setfilt(sc);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->dc_if_flags & IFF_PROMISC) {
+ dc_setfilt(sc);
+ } else if (!(ifp->if_flags & IFF_RUNNING)) {
+ sc->dc_txthresh = 0;
+ dc_init(sc);
+ }
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ dc_stop(sc);
+ }
+ sc->dc_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ dc_setfilt(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->dc_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ (void)splx(s);
+
+ return(error);
+}
+
+static void dc_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+
+ sc = ifp->if_softc;
+
+ ifp->if_oerrors++;
+ printf("dc%d: watchdog timeout\n", sc->dc_unit);
+
+ dc_stop(sc);
+ dc_reset(sc);
+ dc_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void dc_stop(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ untimeout(dc_tick, sc, sc->dc_stat_ch);
+
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON|DC_NETCFG_TX_ON));
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ CSR_WRITE_4(sc, DC_TXADDR, 0x00000000);
+ CSR_WRITE_4(sc, DC_RXADDR, 0x00000000);
+ sc->dc_link = 0;
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ if (sc->dc_cdata.dc_rx_chain[i] != NULL) {
+ m_freem(sc->dc_cdata.dc_rx_chain[i]);
+ sc->dc_cdata.dc_rx_chain[i] = NULL;
+ }
+ }
+ bzero((char *)&sc->dc_ldata->dc_rx_list,
+ sizeof(sc->dc_ldata->dc_rx_list));
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < DC_TX_LIST_CNT; i++) {
+ if (sc->dc_cdata.dc_tx_chain[i] != NULL) {
+ if (sc->dc_ldata->dc_tx_list[i].dc_ctl &
+ DC_TXCTL_SETUP) {
+ sc->dc_cdata.dc_tx_chain[i] = NULL;
+ continue;
+ }
+ m_freem(sc->dc_cdata.dc_tx_chain[i]);
+ sc->dc_cdata.dc_tx_chain[i] = NULL;
+ }
+ }
+
+ bzero((char *)&sc->dc_ldata->dc_tx_list,
+ sizeof(sc->dc_ldata->dc_tx_list));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void dc_shutdown(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ dc_stop(sc);
+
+ return;
+}
diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h
new file mode 100644
index 0000000..7994e94
--- /dev/null
+++ b/sys/dev/dc/if_dcreg.h
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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$
+ */
+
+/*
+ * 21143 and clone common register definitions.
+ */
+
+#define DC_BUSCTL 0x00 /* bus control */
+#define DC_TXSTART 0x08 /* tx start demand */
+#define DC_RXSTART 0x10 /* rx start demand */
+#define DC_RXADDR 0x18 /* rx descriptor list start addr */
+#define DC_TXADDR 0x20 /* tx descriptor list start addr */
+#define DC_ISR 0x28 /* interrupt status register */
+#define DC_NETCFG 0x30 /* network config register */
+#define DC_IMR 0x38 /* interrupt mask */
+#define DC_FRAMESDISCARDED 0x40 /* # of discarded frames */
+#define DC_SIO 0x48 /* MII and ROM/EEPROM access */
+#define DC_ROM 0x50 /* ROM programming address */
+#define DC_TIMER 0x58 /* general timer */
+#define DC_10BTSTAT 0x60 /* SIA status */
+#define DC_SIARESET 0x68 /* SIA connectivity */
+#define DC_10BTCTRL 0x70 /* SIA transmit and receive */
+#define DC_WATCHDOG 0x78 /* SIA and general purpose port */
+
+/*
+ * There are two general 'types' of MX chips that we need to be
+ * concerned with. One is the original 98713, which has its internal
+ * NWAY support controlled via the MDIO bits in the serial I/O
+ * register. The other is everything else (from the 98713A on up),
+ * which has its internal NWAY controlled via CSR13, CSR14 and CSR15,
+ * just like the 21143. This type setting also governs which of the
+ * 'magic' numbers we write to CSR16. The PNIC II falls into the
+ * 98713A/98715/98715A/98725 category.
+ */
+#define DC_TYPE_98713 0x1
+#define DC_TYPE_98713A 0x2
+#define DC_TYPE_987x5 0x3
+
+/* Other type of supported chips. */
+#define DC_TYPE_21143 0x4 /* Intel 21143 */
+#define DC_TYPE_ASIX 0x5 /* ASIX AX88140A/AX88141 */
+#define DC_TYPE_AL981 0x6 /* ADMtek AL981 Comet */
+#define DC_TYPE_AN985 0x7 /* ADMtek AN985 Centaur */
+#define DC_TYPE_DM9102 0x8 /* Davicom DM9102 */
+#define DC_TYPE_PNICII 0x9 /* 82c115 PNIC II */
+#define DC_TYPE_PNIC 0xA /* 82c168/82c169 PNIC I */
+
+#define DC_IS_MACRONIX(x) \
+ (x->dc_type == DC_TYPE_98713 || \
+ x->dc_type == DC_TYPE_98713A || \
+ x->dc_type == DC_TYPE_987x5)
+
+#define DC_IS_ADMTEK(x) \
+ (x->dc_type == DC_TYPE_AL981 || \
+ x->dc_type == DC_TYPE_AN985)
+
+#define DC_IS_INTEL(x) (x->dc_type == DC_TYPE_21143)
+#define DC_IS_ASIX(x) (x->dc_type == DC_TYPE_ASIX)
+#define DC_IS_COMET(x) (x->dc_type == DC_TYPE_AL981)
+#define DC_IS_CENTAUR(x) (x->dc_type == DC_TYPE_AN985)
+#define DC_IS_DAVICOM(x) (x->dc_type == DC_TYPE_DM9102)
+#define DC_IS_PNICII(x) (x->dc_type == DC_TYPE_PNICII)
+#define DC_IS_PNIC(x) (x->dc_type == DC_TYPE_PNIC)
+
+/* MII/symbol mode port types */
+#define DC_PMODE_MII 0x1
+#define DC_PMODE_SYM 0x2
+
+/*
+ * Bus control bits.
+ */
+#define DC_BUSCTL_RESET 0x00000001
+#define DC_BUSCTL_ARBITRATION 0x00000002
+#define DC_BUSCTL_SKIPLEN 0x0000007C
+#define DC_BUSCTL_BUF_BIGENDIAN 0x00000080
+#define DC_BUSCTL_BURSTLEN 0x00003F00
+#define DC_BUSCTL_CACHEALIGN 0x0000C000
+#define DC_BUSCTL_TXPOLL 0x000E0000
+#define DC_BUSCTL_DBO 0x00100000
+#define DC_BUSCTL_MRME 0x00200000
+#define DC_BUSCTL_MRLE 0x00800000
+#define DC_BUSCTL_MWIE 0x01000000
+#define DC_BUSCTL_ONNOW_ENB 0x04000000
+
+#define DC_SKIPLEN_1LONG 0x00000004
+#define DC_SKIPLEN_2LONG 0x00000008
+#define DC_SKIPLEN_3LONG 0x00000010
+#define DC_SKIPLEN_4LONG 0x00000020
+#define DC_SKIPLEN_5LONG 0x00000040
+
+#define DC_CACHEALIGN_NONE 0x00000000
+#define DC_CACHEALIGN_8LONG 0x00004000
+#define DC_CACHEALIGN_16LONG 0x00008000
+#define DC_CACHEALIGN_32LONG 0x0000C000
+
+#define DC_BURSTLEN_USECA 0x00000000
+#define DC_BURSTLEN_1LONG 0x00000100
+#define DC_BURSTLEN_2LONG 0x00000200
+#define DC_BURSTLEN_4LONG 0x00000400
+#define DC_BURSTLEN_8LONG 0x00000800
+#define DC_BURSTLEN_16LONG 0x00001000
+#define DC_BURSTLEN_32LONG 0x00002000
+
+#define DC_TXPOLL_OFF 0x00000000
+#define DC_TXPOLL_1 0x00020000
+#define DC_TXPOLL_2 0x00040000
+#define DC_TXPOLL_3 0x00060000
+#define DC_TXPOLL_4 0x00080000
+#define DC_TXPOLL_5 0x000A0000
+#define DC_TXPOLL_6 0x000C0000
+#define DC_TXPOLL_7 0x000E0000
+
+/*
+ * Interrupt status bits.
+ */
+#define DC_ISR_TX_OK 0x00000001
+#define DC_ISR_TX_IDLE 0x00000002
+#define DC_ISR_TX_NOBUF 0x00000004
+#define DC_ISR_TX_JABBERTIMEO 0x00000008
+#define DC_ISR_LINKGOOD 0x00000010
+#define DC_ISR_TX_UNDERRUN 0x00000020
+#define DC_ISR_RX_OK 0x00000040
+#define DC_ISR_RX_NOBUF 0x00000080
+#define DC_ISR_RX_READ 0x00000100
+#define DC_ISR_RX_WATDOGTIMEO 0x00000200
+#define DC_ISR_TX_EARLY 0x00000400
+#define DC_ISR_TIMER_EXPIRED 0x00000800
+#define DC_ISR_LINKFAIL 0x00001000
+#define DC_ISR_BUS_ERR 0x00002000
+#define DC_ISR_RX_EARLY 0x00004000
+#define DC_ISR_ABNORMAL 0x00008000
+#define DC_ISR_NORMAL 0x00010000
+#define DC_ISR_RX_STATE 0x000E0000
+#define DC_ISR_TX_STATE 0x00700000
+#define DC_ISR_BUSERRTYPE 0x03800000
+#define DC_ISR_100MBPSLINK 0x08000000
+#define DC_ISR_MAGICKPACK 0x10000000
+
+#define DC_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
+#define DC_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
+#define DC_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
+#define DC_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
+#define DC_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
+#define DC_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */
+#define DC_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
+#define DC_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
+
+#define DC_TXSTATE_RESET 0x00000000 /* 000 - reset */
+#define DC_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
+#define DC_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
+#define DC_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
+#define DC_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
+#define DC_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
+#define DC_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
+#define DC_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
+
+/*
+ * Network config bits.
+ */
+#define DC_NETCFG_RX_HASHPERF 0x00000001
+#define DC_NETCFG_RX_ON 0x00000002
+#define DC_NETCFG_RX_HASHONLY 0x00000004
+#define DC_NETCFG_RX_BADFRAMES 0x00000008
+#define DC_NETCFG_RX_INVFILT 0x00000010
+#define DC_NETCFG_BACKOFFCNT 0x00000020
+#define DC_NETCFG_RX_PROMISC 0x00000040
+#define DC_NETCFG_RX_ALLMULTI 0x00000080
+#define DC_NETCFG_FULLDUPLEX 0x00000200
+#define DC_NETCFG_LOOPBACK 0x00000C00
+#define DC_NETCFG_FORCECOLL 0x00001000
+#define DC_NETCFG_TX_ON 0x00002000
+#define DC_NETCFG_TX_THRESH 0x0000C000
+#define DC_NETCFG_TX_BACKOFF 0x00020000
+#define DC_NETCFG_PORTSEL 0x00040000 /* 0 == 10, 1 == 100 */
+#define DC_NETCFG_HEARTBEAT 0x00080000
+#define DC_NETCFG_STORENFWD 0x00200000
+#define DC_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */
+#define DC_NETCFG_PCS 0x00800000
+#define DC_NETCFG_SCRAMBLER 0x01000000
+#define DC_NETCFG_NO_RXCRC 0x02000000
+#define DC_NETCFG_RX_ALL 0x40000000
+#define DC_NETCFG_CAPEFFECT 0x80000000
+
+#define DC_OPMODE_NORM 0x00000000
+#define DC_OPMODE_INTLOOP 0x00000400
+#define DC_OPMODE_EXTLOOP 0x00000800
+
+#define DC_TXTHRESH_72BYTES 0x00000000
+#define DC_TXTHRESH_96BYTES 0x00004000
+#define DC_TXTHRESH_128BYTES 0x00008000
+#define DC_TXTHRESH_160BYTES 0x0000C000
+
+
+/*
+ * Interrupt mask bits.
+ */
+#define DC_IMR_TX_OK 0x00000001
+#define DC_IMR_TX_IDLE 0x00000002
+#define DC_IMR_TX_NOBUF 0x00000004
+#define DC_IMR_TX_JABBERTIMEO 0x00000008
+#define DC_IMR_LINKGOOD 0x00000010
+#define DC_IMR_TX_UNDERRUN 0x00000020
+#define DC_IMR_RX_OK 0x00000040
+#define DC_IMR_RX_NOBUF 0x00000080
+#define DC_IMR_RX_READ 0x00000100
+#define DC_IMR_RX_WATDOGTIMEO 0x00000200
+#define DC_IMR_TX_EARLY 0x00000400
+#define DC_IMR_TIMER_EXPIRED 0x00000800
+#define DC_IMR_LINKFAIL 0x00001000
+#define DC_IMR_BUS_ERR 0x00002000
+#define DC_IMR_RX_EARLY 0x00004000
+#define DC_IMR_ABNORMAL 0x00008000
+#define DC_IMR_NORMAL 0x00010000
+#define DC_IMR_100MBPSLINK 0x08000000
+#define DC_IMR_MAGICKPACK 0x10000000
+
+#define DC_INTRS \
+ (DC_IMR_RX_OK|DC_IMR_TX_OK|DC_IMR_RX_NOBUF|DC_IMR_RX_WATDOGTIMEO|\
+ DC_IMR_TX_NOBUF|DC_IMR_TX_UNDERRUN|DC_IMR_BUS_ERR| \
+ DC_IMR_ABNORMAL|DC_IMR_NORMAL/*|DC_IMR_TX_EARLY*/)
+/*
+ * Serial I/O (EEPROM/ROM) bits.
+ */
+#define DC_SIO_EE_CS 0x00000001 /* EEPROM chip select */
+#define DC_SIO_EE_CLK 0x00000002 /* EEPROM clock */
+#define DC_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */
+#define DC_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */
+#define DC_SIO_ROMDATA4 0x00000010
+#define DC_SIO_ROMDATA5 0x00000020
+#define DC_SIO_ROMDATA6 0x00000040
+#define DC_SIO_ROMDATA7 0x00000080
+#define DC_SIO_EESEL 0x00000800
+#define DC_SIO_ROMSEL 0x00001000
+#define DC_SIO_ROMCTL_WRITE 0x00002000
+#define DC_SIO_ROMCTL_READ 0x00004000
+#define DC_SIO_MII_CLK 0x00010000 /* MDIO clock */
+#define DC_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */
+#define DC_SIO_MII_DIR 0x00040000 /* MDIO dir */
+#define DC_SIO_MII_DATAIN 0x00080000 /* MDIO data in */
+
+#define DC_EECMD_WRITE 0x140
+#define DC_EECMD_READ 0x180
+#define DC_EECMD_ERASE 0x1c0
+
+#define DC_EE_NODEADDR_OFFSET 0x70
+#define DC_EE_NODEADDR 10
+
+/*
+ * General purpose timer register
+ */
+#define DC_TIMER_VALUE 0x0000FFFF
+#define DC_TIMER_CONTINUOUS 0x00010000
+
+/*
+ * 10baseT status register
+ */
+#define DC_TSTAT_MIIACT 0x00000001 /* MII port activity */
+#define DC_TSTAT_LS100 0x00000002 /* link status of 100baseTX */
+#define DC_TSTAT_LS10 0x00000004 /* link status of 10baseT */
+#define DC_TSTAT_AUTOPOLARITY 0x00000008
+#define DC_TSTAT_AUIACT 0x00000100 /* AUI activity */
+#define DC_TSTAT_10BTACT 0x00000200 /* 10baseT activity */
+#define DC_TSTAT_NSN 0x00000400 /* non-stable FLPs detected */
+#define DC_TSTAT_REMFAULT 0x00000800
+#define DC_TSTAT_ANEGSTAT 0x00007000
+#define DC_TSTAT_LP_CAN_NWAY 0x00008000 /* link partner supports NWAY */
+#define DC_TSTAT_LPCODEWORD 0xFFFF0000 /* link partner's code word */
+
+#define DC_ASTAT_DISABLE 0x00000000
+#define DC_ASTAT_TXDISABLE 0x00001000
+#define DC_ASTAT_ABDETECT 0x00002000
+#define DC_ASTAT_ACKDETECT 0x00003000
+#define DC_ASTAT_CMPACKDETECT 0x00004000
+#define DC_ASTAT_AUTONEGCMP 0x00005000
+#define DC_ASTAT_LINKCHECK 0x00006000
+
+/*
+ * PHY reset register
+ */
+#define DC_SIA_RESET 0x00000001
+#define DC_SIA_AUI 0x00000008 /* AUI or 10baseT */
+
+/*
+ * 10baseT control register
+ */
+#define DC_TCTL_ENCODER_ENB 0x00000001
+#define DC_TCTL_LOOPBACK 0x00000002
+#define DC_TCTL_DRIVER_ENB 0x00000004
+#define DC_TCTL_LNKPULSE_ENB 0x00000008
+#define DC_TCTL_HALFDUPLEX 0x00000040
+#define DC_TCTL_AUTONEGENBL 0x00000080
+#define DC_TCTL_RX_SQUELCH 0x00000100
+#define DC_TCTL_COLL_SQUELCH 0x00000200
+#define DC_TCTL_COLL_DETECT 0x00000400
+#define DC_TCTL_SQE_ENB 0x00000800
+#define DC_TCTL_LINKTEST 0x00001000
+#define DC_TCTL_AUTOPOLARITY 0x00002000
+#define DC_TCTL_SET_POL_PLUS 0x00004000
+#define DC_TCTL_AUTOSENSE 0x00008000 /* 10bt/AUI autosense */
+#define DC_TCTL_100BTXHALF 0x00010000
+#define DC_TCTL_100BTXFULL 0x00020000
+#define DC_TCTL_100BT4 0x00040000
+
+/*
+ * Watchdog timer register
+ */
+#define DC_WDOG_JABBERDIS 0x00000001
+#define DC_WDOG_HOSTUNJAB 0x00000002
+#define DC_WDOG_JABBERCLK 0x00000004
+#define DC_WDOG_RXWDOGDIS 0x00000010
+#define DC_WDOG_RXWDOGCLK 0x00000020
+#define DC_WDOG_MUSTBEZERO 0x00000100
+
+/*
+ * Size of a setup frame.
+ */
+#define DC_SFRAME_LEN 192
+
+/*
+ * 21x4x TX/RX list structure.
+ */
+
+struct dc_desc {
+ u_int32_t dc_status;
+ u_int32_t dc_ctl;
+ u_int32_t dc_ptr1;
+ u_int32_t dc_ptr2;
+};
+
+#define dc_data dc_ptr1
+#define dc_next dc_ptr2
+
+#define DC_RXSTAT_FIFOOFLOW 0x00000001
+#define DC_RXSTAT_CRCERR 0x00000002
+#define DC_RXSTAT_DRIBBLE 0x00000004
+#define DC_RXSTAT_WATCHDOG 0x00000010
+#define DC_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */
+#define DC_RXSTAT_COLLSEEN 0x00000040
+#define DC_RXSTAT_GIANT 0x00000080
+#define DC_RXSTAT_LASTFRAG 0x00000100
+#define DC_RXSTAT_FIRSTFRAG 0x00000200
+#define DC_RXSTAT_MULTICAST 0x00000400
+#define DC_RXSTAT_RUNT 0x00000800
+#define DC_RXSTAT_RXTYPE 0x00003000
+#define DC_RXSTAT_RXERR 0x00008000
+#define DC_RXSTAT_RXLEN 0x3FFF0000
+#define DC_RXSTAT_OWN 0x80000000
+
+#define DC_RXBYTES(x) ((x & DC_RXSTAT_RXLEN) >> 16)
+#define DC_RXSTAT (DC_RXSTAT_FIRSTFRAG|DC_RXSTAT_LASTFRAG|DC_RXSTAT_OWN)
+
+#define DC_RXCTL_BUFLEN1 0x00000FFF
+#define DC_RXCTL_BUFLEN2 0x00FFF000
+#define DC_RXCTL_RLINK 0x01000000
+#define DC_RXCTL_RLAST 0x02000000
+
+#define DC_TXSTAT_DEFER 0x00000001
+#define DC_TXSTAT_UNDERRUN 0x00000002
+#define DC_TXSTAT_LINKFAIL 0x00000003
+#define DC_TXSTAT_COLLCNT 0x00000078
+#define DC_TXSTAT_SQE 0x00000080
+#define DC_TXSTAT_EXCESSCOLL 0x00000100
+#define DC_TXSTAT_LATECOLL 0x00000200
+#define DC_TXSTAT_NOCARRIER 0x00000400
+#define DC_TXSTAT_CARRLOST 0x00000800
+#define DC_TXSTAT_JABTIMEO 0x00004000
+#define DC_TXSTAT_ERRSUM 0x00008000
+#define DC_TXSTAT_OWN 0x80000000
+
+#define DC_TXCTL_BUFLEN1 0x000007FF
+#define DC_TXCTL_BUFLEN2 0x003FF800
+#define DC_TXCTL_FILTTYPE0 0x00400000
+#define DC_TXCTL_PAD 0x00800000
+#define DC_TXCTL_TLINK 0x01000000
+#define DC_TXCTL_TLAST 0x02000000
+#define DC_TXCTL_NOCRC 0x04000000
+#define DC_TXCTL_SETUP 0x08000000
+#define DC_TXCTL_FILTTYPE1 0x10000000
+#define DC_TXCTL_FIRSTFRAG 0x20000000
+#define DC_TXCTL_LASTFRAG 0x40000000
+#define DC_TXCTL_FINT 0x80000000
+
+#define DC_FILTER_PERFECT 0x00000000
+#define DC_FILTER_HASHPERF 0x00400000
+#define DC_FILTER_INVERSE 0x10000000
+#define DC_FILTER_HASHONLY 0x10400000
+
+#define DC_MAXFRAGS 16
+#define DC_RX_LIST_CNT 64
+#define DC_TX_LIST_CNT 256
+#define DC_MIN_FRAMELEN 60
+#define DC_RXLEN 1536
+
+#define DC_INC(x, y) (x) = (x + 1) % y
+
+struct dc_list_data {
+ struct dc_desc dc_rx_list[DC_RX_LIST_CNT];
+ struct dc_desc dc_tx_list[DC_TX_LIST_CNT];
+};
+
+struct dc_chain_data {
+ struct mbuf *dc_rx_chain[DC_RX_LIST_CNT];
+ struct mbuf *dc_tx_chain[DC_TX_LIST_CNT];
+ u_int32_t dc_sbuf[DC_SFRAME_LEN/sizeof(u_int32_t)];
+ u_int8_t dc_pad[DC_MIN_FRAMELEN];
+ int dc_tx_prod;
+ int dc_tx_cons;
+ int dc_tx_cnt;
+ int dc_rx_prod;
+};
+
+struct dc_type {
+ u_int16_t dc_vid;
+ u_int16_t dc_did;
+ char *dc_name;
+};
+
+struct dc_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define DC_MII_STARTDELIM 0x01
+#define DC_MII_READOP 0x02
+#define DC_MII_WRITEOP 0x01
+#define DC_MII_TURNAROUND 0x02
+
+
+/*
+ * Registers specific to clone devices.
+ * This mainly relates to RX filter programming: not all 21x4x clones
+ * use the standard DEC filter programming mechanism.
+ */
+
+/*
+ * ADMtek specific registers and constants for the AL981 and AN985.
+ * The AN985 doesn't use the magic PHY registers.
+ */
+#define DC_AL_PAR0 0xA4 /* station address */
+#define DC_AL_PAR1 0xA8 /* station address */
+#define DC_AL_MAR0 0xAC /* multicast hash filter */
+#define DC_AL_MAR1 0xB0 /* multicast hash filter */
+#define DC_AL_BMCR 0xB4 /* built in PHY control */
+#define DC_AL_BMSR 0xB8 /* built in PHY status */
+#define DC_AL_VENID 0xBC /* built in PHY ID0 */
+#define DC_AL_DEVID 0xC0 /* built in PHY ID1 */
+#define DC_AL_ANAR 0xC4 /* built in PHY autoneg advert */
+#define DC_AL_LPAR 0xC8 /* bnilt in PHY link part. ability */
+#define DC_AL_ANER 0xCC /* built in PHY autoneg expansion */
+
+#define DC_ADMTEK_PHYADDR 0x1
+#define DC_AL_EE_NODEADDR 4
+/* End of ADMtek specific registers */
+
+/*
+ * ASIX specific registers.
+ */
+#define DC_AX_FILTIDX 0x68 /* RX filter index */
+#define DC_AX_FILTDATA 0x70 /* RX filter data */
+
+/*
+ * Special ASIX-specific bits in the ASIX NETCFG register (CSR6).
+ */
+#define DC_AX_NETCFG_RX_BROAD 0x00000100
+
+/*
+ * RX Filter Index Register values
+ */
+#define DC_AX_FILTIDX_PAR0 0x00000000
+#define DC_AX_FILTIDX_PAR1 0x00000001
+#define DC_AX_FILTIDX_MAR0 0x00000002
+#define DC_AX_FILTIDX_MAR1 0x00000003
+/* End of ASIX specific registers */
+
+/*
+ * Macronix specific registers. The Macronix chips have a special
+ * register for reading the NWAY status, which we don't use, plus
+ * a magic packet register, which we need to tweak a bit per the
+ * Macronix application notes.
+ */
+#define DC_MX_MAGICPACKET 0x80
+#define DC_MX_NWAYSTAT 0xA0
+
+/*
+ * Magic packet register
+ */
+#define DC_MX_MPACK_DISABLE 0x00400000
+
+/*
+ * NWAY status register.
+ */
+#define DC_MX_NWAY_10BTHALF 0x08000000
+#define DC_MX_NWAY_10BTFULL 0x10000000
+#define DC_MX_NWAY_100BTHALF 0x20000000
+#define DC_MX_NWAY_100BTFULL 0x40000000
+#define DC_MX_NWAY_100BT4 0x80000000
+
+/*
+ * These are magic values that must be written into CSR16
+ * (DC_MX_MAGICPACKET) in order to put the chip into proper
+ * operating mode. The magic numbers are documented in the
+ * Macronix 98715 application notes.
+ */
+#define DC_MX_MAGIC_98713 0x0F370000
+#define DC_MX_MAGIC_98713A 0x0B3C0000
+#define DC_MX_MAGIC_98715 0x0B3C0000
+#define DC_MX_MAGIC_98725 0x0B3C0000
+/* End of Macronix specific registers */
+
+/*
+ * PNIC 82c168/82c169 specific registers.
+ * The PNIC has its own special NWAY support, which doesn't work,
+ * and shortcut ways of reading the EEPROM and MII bus.
+ */
+#define DC_PN_GPIO 0x60 /* general purpose pins control */
+#define DC_PN_PWRUP_CFG 0x90 /* config register, set by EEPROM */
+#define DC_PN_SIOCTL 0x98 /* serial EEPROM control register */
+#define DC_PN_MII 0xA0 /* MII access register */
+#define DC_PN_NWAY 0xB8 /* Internal NWAY register */
+
+/* Serial I/O EEPROM register */
+#define DC_PN_SIOCTL_DATA 0x0000003F
+#define DC_PN_SIOCTL_OPCODE 0x00000300
+#define DC_PN_SIOCTL_BUSY 0x80000000
+
+#define DC_PN_EEOPCODE_ERASE 0x00000300
+#define DC_PN_EEOPCODE_READ 0x00000600
+#define DC_PN_EEOPCODE_WRITE 0x00000100
+
+/*
+ * The first two general purpose pins control speed selection and
+ * 100Mbps loopback on the 82c168 chip. The control bits should always
+ * be set (to make the data pins outputs) and the speed selction and
+ * loopback bits set accordingly when changing media. Physically, this
+ * will set the state of a relay mounted on the card.
+ */
+#define DC_PN_GPIO_DATA0 0x000000001
+#define DC_PN_GPIO_DATA1 0x000000002
+#define DC_PN_GPIO_DATA2 0x000000004
+#define DC_PN_GPIO_DATA3 0x000000008
+#define DC_PN_GPIO_CTL0 0x000000010
+#define DC_PN_GPIO_CTL1 0x000000020
+#define DC_PN_GPIO_CTL2 0x000000040
+#define DC_PN_GPIO_CTL3 0x000000080
+#define DC_PN_GPIO_SPEEDSEL DC_PN_GPIO_DATA0/* 1 == 100Mbps, 0 == 10Mbps */
+#define DC_PN_GPIO_100TX_LOOP DC_PN_GPIO_DATA1/* 1 == normal, 0 == loop */
+#define DC_PN_GPIO_BNC_ENB DC_PN_GPIO_DATA2
+#define DC_PN_GPIO_100TX_LNK DC_PN_GPIO_DATA3
+#define DC_PN_GPIO_SETBIT(sc, r) \
+ DC_SETBIT(sc, DC_PN_GPIO, ((r) | (r << 4)))
+#define DC_PN_GPIO_CLRBIT(sc, r) \
+ { \
+ DC_SETBIT(sc, DC_PN_GPIO, ((r) << 4)); \
+ DC_CLRBIT(sc, DC_PN_GPIO, (r)); \
+ }
+
+/* shortcut MII access register */
+#define DC_PN_MII_DATA 0x0000FFFF
+#define DC_PN_MII_RESERVER 0x00020000
+#define DC_PN_MII_REGADDR 0x007C0000
+#define DC_PN_MII_PHYADDR 0x0F800000
+#define DC_PN_MII_OPCODE 0x30000000
+#define DC_PN_MII_BUSY 0x80000000
+
+#define DC_PN_MIIOPCODE_READ 0x60020000
+#define DC_PN_MIIOPCODE_WRITE 0x50020000
+
+/* Internal NWAY bits */
+#define DC_PN_NWAY_RESET 0x00000001 /* reset */
+#define DC_PN_NWAY_PDOWN 0x00000002 /* power down */
+#define DC_PN_NWAY_BYPASS 0x00000004 /* bypass */
+#define DC_PN_NWAY_AUILOWCUR 0x00000008 /* AUI low current */
+#define DC_PN_NWAY_TPEXTEND 0x00000010 /* low squelch voltage */
+#define DC_PN_NWAY_POLARITY 0x00000020 /* 0 == on, 1 == off */
+#define DC_PN_NWAY_TP 0x00000040 /* 1 == tp, 0 == AUI */
+#define DC_PN_NWAY_AUIVOLT 0x00000080 /* 1 == full, 0 == half */
+#define DC_PN_NWAY_DUPLEX 0x00000100 /* LED, 1 == full, 0 == half */
+#define DC_PN_NWAY_LINKTEST 0x00000200 /* 0 == on, 1 == off */
+#define DC_PN_NWAY_AUTODETECT 0x00000400 /* 1 == off, 0 == on */
+#define DC_PN_NWAY_SPEEDSEL 0x00000800 /* LED, 0 = 10, 1 == 100 */
+#define DC_PN_NWAY_NWAY_ENB 0x00001000 /* 0 == off, 1 == on */
+#define DC_PN_NWAY_CAP10HDX 0x00002000
+#define DC_PN_NWAY_CAP10FDX 0x00004000
+#define DC_PN_NWAY_CAP100FDX 0x00008000
+#define DC_PN_NWAY_CAP100HDX 0x00010000
+#define DC_PN_NWAY_CAP100T4 0x00020000
+#define DC_PN_NWAY_ANEGRESTART 0x02000000 /* resets when aneg done */
+#define DC_PN_NWAY_REMFAULT 0x04000000
+#define DC_PN_NWAY_LPAR10HDX 0x08000000
+#define DC_PN_NWAY_LPAR10FDX 0x10000000
+#define DC_PN_NWAY_LPAR100FDX 0x20000000
+#define DC_PN_NWAY_LPAR100HDX 0x40000000
+#define DC_PN_NWAY_LPAR100T4 0x80000000
+
+/* End of PNIC specific registers */
+
+struct dc_softc {
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t dc_bhandle; /* bus space handle */
+ bus_space_tag_t dc_btag; /* bus space tag */
+ void *dc_intrhand;
+ struct resource *dc_irq;
+ struct resource *dc_res;
+ struct dc_type *dc_info; /* adapter info */
+ device_t dc_miibus;
+ u_int8_t dc_unit; /* interface number */
+ u_int8_t dc_type;
+ u_int8_t dc_pmode;
+ u_int8_t dc_link;
+ u_int8_t dc_cachesize;
+ int dc_pnic_rx_bug_save;
+ unsigned char *dc_pnic_rx_buf;
+ int dc_if_flags;
+ int dc_if_media;
+ u_int32_t dc_flags;
+ u_int32_t dc_txthresh;
+ struct dc_list_data *dc_ldata;
+ struct dc_chain_data dc_cdata;
+ struct callout_handle dc_stat_ch;
+};
+
+#define DC_TX_POLL 0x00000001
+#define DC_TX_COALESCE 0x00000002
+#define DC_TX_ADMTEK_WAR 0x00000004
+#define DC_TX_USE_TX_INTR 0x00000008
+#define DC_RX_FILTER_TULIP 0x00000010
+#define DC_TX_INTR_FIRSTFRAG 0x00000020
+#define DC_PNIC_RX_BUG_WAR 0x00000040
+#define DC_TX_FIXED_RING 0x00000080
+#define DC_TX_STORENFWD 0x00000100
+#define DC_REDUCED_MII_POLL 0x00000200
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->dc_btag, sc->dc_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->dc_btag, sc->dc_bhandle, reg)
+
+#define DC_TIMEOUT 1000
+#define ETHER_ALIGN 2
+
+/*
+ * General constants that are fun to know.
+ */
+
+/*
+ * DEC PCI vendor ID
+ */
+#define DC_VENDORID_DEC 0x1011
+
+/*
+ * DEC/Intel 21143 PCI device ID
+ */
+#define DC_DEVICEID_21143 0x0019
+
+/*
+ * Macronix PCI vendor ID
+ */
+#define DC_VENDORID_MX 0x10D9
+
+/*
+ * Macronix PMAC device IDs.
+ */
+#define DC_DEVICEID_98713 0x0512
+#define DC_DEVICEID_987x5 0x0531
+
+/* Macronix PCI revision codes. */
+#define DC_REVISION_98713 0x00
+#define DC_REVISION_98713A 0x10
+#define DC_REVISION_98715 0x20
+#define DC_REVISION_98725 0x30
+
+/*
+ * Compex PCI vendor ID.
+ */
+#define DC_VENDORID_CP 0x11F6
+
+/*
+ * Compex PMAC PCI device IDs.
+ */
+#define DC_DEVICEID_98713_CP 0x9881
+
+/*
+ * Lite-On PNIC PCI vendor ID
+ */
+#define DC_VENDORID_LO 0x11AD
+
+/*
+ * 82c168/82c169 PNIC device IDs. Both chips have the same device
+ * ID but different revisions. Revision 0x10 is the 82c168, and
+ * 0x20 is the 82c169.
+ */
+#define DC_DEVICEID_82C168 0x0002
+
+#define DC_REVISION_82C168 0x10
+#define DC_REVISION_82C169 0x20
+
+/*
+ * Lite-On PNIC II device ID. Note: this is actually a Macronix 98715A
+ * with wake on lan/magic packet support.
+ */
+#define DC_DEVICEID_82C115 0xc115
+
+/*
+ * Davicom vendor ID.
+ */
+#define DC_VENDORID_DAVICOM 0x1282
+
+/*
+ * Davicom device IDs.
+ */
+#define DC_DEVICEID_DM9100 0x9100
+#define DC_DEVICEID_DM9102 0x9102
+
+/*
+ * ADMtek vendor ID.
+ */
+#define DC_VENDORID_ADMTEK 0x1317
+
+/*
+ * ADMtek device IDs.
+ */
+#define DC_DEVICEID_AL981 0x0981
+#define DC_DEVICEID_AN985 0x0985
+
+/*
+ * ASIX vendor ID.
+ */
+#define DC_VENDORID_ASIX 0x125B
+
+/*
+ * ASIX device IDs.
+ */
+#define DC_DEVICEID_AX88140A 0x1400
+
+/*
+ * The ASIX AX88140 and ASIX AX88141 have the same vendor and
+ * device IDs but different revision values.
+ */
+#define DC_REVISION_88140 0x00
+#define DC_REVISION_88141 0x10
+
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers.
+ */
+
+#define DC_PCI_CFID 0x00 /* Id */
+#define DC_PCI_CFCS 0x04 /* Command and status */
+#define DC_PCI_CFRV 0x08 /* Revision */
+#define DC_PCI_CFLT 0x0C /* Latency timer */
+#define DC_PCI_CFBIO 0x10 /* Base I/O address */
+#define DC_PCI_CFBMA 0x14 /* Base memory address */
+#define DC_PCI_CCIS 0x28 /* Card info struct */
+#define DC_PCI_CSID 0x2C /* Subsystem ID */
+#define DC_PCI_CBER 0x30 /* Expansion ROM base address */
+#define DC_PCI_CCAP 0x34 /* Caps pointer - PD/TD chip only */
+#define DC_PCI_CFIT 0x3C /* Interrupt */
+#define DC_PCI_CFDD 0x40 /* Device and driver area */
+#define DC_PCI_CWUA0 0x44 /* Wake-Up LAN addr 0 */
+#define DC_PCI_CWUA1 0x48 /* Wake-Up LAN addr 1 */
+#define DC_PCI_SOP0 0x4C /* SecureON passwd 0 */
+#define DC_PCI_SOP1 0x50 /* SecureON passwd 1 */
+#define DC_PCI_CWUC 0x54 /* Configuration Wake-Up cmd */
+#define DC_PCI_CCID 0xDC /* Capability ID - PD/TD only */
+#define DC_PCI_CPMC 0xE0 /* Pwrmgmt ctl & sts - PD/TD only */
+
+/* PCI ID register */
+#define DC_CFID_VENDOR 0x0000FFFF
+#define DC_CFID_DEVICE 0xFFFF0000
+
+/* PCI command/status register */
+#define DC_CFCS_IOSPACE 0x00000001 /* I/O space enable */
+#define DC_CFCS_MEMSPACE 0x00000002 /* memory space enable */
+#define DC_CFCS_BUSMASTER 0x00000004 /* bus master enable */
+#define DC_CFCS_MWI_ENB 0x00000008 /* mem write and inval enable */
+#define DC_CFCS_PARITYERR_ENB 0x00000020 /* parity error enable */
+#define DC_CFCS_SYSERR_ENB 0x00000080 /* system error enable */
+#define DC_CFCS_NEWCAPS 0x00100000 /* new capabilities */
+#define DC_CFCS_FAST_B2B 0x00800000 /* fast back-to-back capable */
+#define DC_CFCS_DATAPARITY 0x01000000 /* Parity error report */
+#define DC_CFCS_DEVSELTIM 0x06000000 /* devsel timing */
+#define DC_CFCS_TGTABRT 0x10000000 /* received target abort */
+#define DC_CFCS_MASTERABRT 0x20000000 /* received master abort */
+#define DC_CFCS_SYSERR 0x40000000 /* asserted system error */
+#define DC_CFCS_PARITYERR 0x80000000 /* asserted parity error */
+
+/* PCI revision register */
+#define DC_CFRV_STEPPING 0x0000000F
+#define DC_CFRV_REVISION 0x000000F0
+#define DC_CFRV_SUBCLASS 0x00FF0000
+#define DC_CFRV_BASECLASS 0xFF000000
+
+#define DC_21143_PB_REV 0x00000030
+#define DC_21143_TB_REV 0x00000030
+#define DC_21143_PC_REV 0x00000030
+#define DC_21143_TC_REV 0x00000030
+#define DC_21143_PD_REV 0x00000041
+#define DC_21143_TD_REV 0x00000041
+
+/* PCI latency timer register */
+#define DC_CFLT_CACHELINESIZE 0x000000FF
+#define DC_CFLT_LATENCYTIMER 0x0000FF00
+
+/* PCI subsystem ID register */
+#define DC_CSID_VENDOR 0x0000FFFF
+#define DC_CSID_DEVICE 0xFFFF0000
+
+/* PCI cababilities pointer */
+#define DC_CCAP_OFFSET 0x000000FF
+
+/* PCI interrupt config register */
+#define DC_CFIT_INTLINE 0x000000FF
+#define DC_CFIT_INTPIN 0x0000FF00
+#define DC_CFIT_MIN_GNT 0x00FF0000
+#define DC_CFIT_MAX_LAT 0xFF000000
+
+/* PCI capability register */
+#define DC_CCID_CAPID 0x000000FF
+#define DC_CCID_NEXTPTR 0x0000FF00
+#define DC_CCID_PM_VERS 0x00070000
+#define DC_CCID_PME_CLK 0x00080000
+#define DC_CCID_DVSPEC_INT 0x00200000
+#define DC_CCID_STATE_D1 0x02000000
+#define DC_CCID_STATE_D2 0x04000000
+#define DC_CCID_PME_D0 0x08000000
+#define DC_CCID_PME_D1 0x10000000
+#define DC_CCID_PME_D2 0x20000000
+#define DC_CCID_PME_D3HOT 0x40000000
+#define DC_CCID_PME_D3COLD 0x80000000
+
+/* PCI power management control/status register */
+#define DC_CPMC_STATE 0x00000003
+#define DC_CPMC_PME_ENB 0x00000100
+#define DC_CPMC_PME_STS 0x00008000
+
+#define DC_PSTATE_D0 0x0
+#define DC_PSTATE_D1 0x1
+#define DC_PSTATE_D2 0x2
+#define DC_PSTATE_D3 0x3
+
+/* Device specific region */
+/* Configuration and driver area */
+#define DC_CFDD_DRVUSE 0x0000FFFF
+#define DC_CFDD_SNOOZE_MODE 0x40000000
+#define DC_CFDD_SLEEP_MODE 0x80000000
+
+/* Configuration wake-up command register */
+#define DC_CWUC_MUST_BE_ZERO 0x00000001
+#define DC_CWUC_SECUREON_ENB 0x00000002
+#define DC_CWUC_FORCE_WUL 0x00000004
+#define DC_CWUC_BNC_ABILITY 0x00000008
+#define DC_CWUC_AUI_ABILITY 0x00000010
+#define DC_CWUC_TP10_ABILITY 0x00000020
+#define DC_CWUC_MII_ABILITY 0x00000040
+#define DC_CWUC_SYM_ABILITY 0x00000080
+#define DC_CWUC_LOCK 0x00000100
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/dev/dc/pnphy.c b/sys/dev/dc/pnphy.c
new file mode 100644
index 0000000..0f8498e
--- /dev/null
+++ b/sys/dev/dc/pnphy.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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$
+ */
+
+/*
+ * Pseudo-driver for media selection on the Lite-On PNIC 82c168
+ * chip. The NWAY support on this chip is horribly broken, so we
+ * only support manual mode selection. This is lame, but getting
+ * NWAY to work right is amazingly difficult.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+
+#include <machine/clock.h>
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <pci/if_dcreg.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+#define DC_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | x)
+
+#define DC_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~x)
+
+static int pnphy_probe __P((device_t));
+static int pnphy_attach __P((device_t));
+static int pnphy_detach __P((device_t));
+
+static device_method_t pnphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, pnphy_probe),
+ DEVMETHOD(device_attach, pnphy_attach),
+ DEVMETHOD(device_detach, pnphy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t pnphy_devclass;
+
+static driver_t pnphy_driver = {
+ "pnphy",
+ pnphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0);
+
+int pnphy_service __P((struct mii_softc *, struct mii_data *, int));
+void pnphy_status __P((struct mii_softc *));
+
+static int pnphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ /*
+ * The dc driver will report the 82c168 vendor and device
+ * ID to let us know that it wants us to attach.
+ */
+ if (ma->mii_id1 != DC_VENDORID_LO ||
+ ma->mii_id2 != DC_DEVICEID_82C168)
+ return(ENXIO);
+
+ device_set_desc(dev, "PNIC 82c168 media interface");
+
+ return (0);
+}
+
+static int pnphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = pnphy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ sc->mii_capabilities =
+ BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX|BMSR_10THDX;
+ sc->mii_capabilities &= ma->mii_capmask;
+ device_printf(dev, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities, sc->mii_inst);
+ printf("\n");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int pnphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+int
+pnphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct dc_softc *dc_sc;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ return (0);
+ }
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ sc->mii_flags = 0;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /* NWAY is busted on this chip */
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ case IFM_100_TX:
+ mii->mii_media_active = IFM_ETHER|IFM_100_TX;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ MIIBUS_STATCHG(sc->mii_dev);
+ return(0);
+ break;
+ case IFM_10_T:
+ mii->mii_media_active = IFM_ETHER|IFM_10_T;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ MIIBUS_STATCHG(sc->mii_dev);
+ return(0);
+ break;
+ default:
+ return(EINVAL);
+ break;
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ return(0);
+ }
+
+ /* Update the media status. */
+ pnphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+void
+pnphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int reg;
+ struct dc_softc *dc_sc;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ reg = CSR_READ_4(dc_sc, DC_ISR);
+
+ if (!(reg & DC_ISR_LINKFAIL))
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_100_TX;
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+
+ return;
+}
diff --git a/sys/dev/mii/dcphy.c b/sys/dev/mii/dcphy.c
new file mode 100644
index 0000000..2543e87
--- /dev/null
+++ b/sys/dev/mii/dcphy.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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$
+ */
+
+/*
+ * Pseudo-driver for internal NWAY support on DEC 21143 and workalike
+ * controllers. Technically we're abusing the miibus code to handle
+ * media selection and NWAY support here since there is no MII
+ * interface. However the logical operations are roughly the same,
+ * and the alternative is to create a fake MII interface in the driver,
+ * which is harder to do.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+
+#include <machine/clock.h>
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <pci/pcivar.h>
+
+#include <pci/if_dcreg.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+#define DC_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | x)
+
+#define DC_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~x)
+
+#define MIIF_AUTOTIMEOUT 0x0004
+
+static int dcphy_probe __P((device_t));
+static int dcphy_attach __P((device_t));
+static int dcphy_detach __P((device_t));
+
+static device_method_t dcphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, dcphy_probe),
+ DEVMETHOD(device_attach, dcphy_attach),
+ DEVMETHOD(device_detach, dcphy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t dcphy_devclass;
+
+static driver_t dcphy_driver = {
+ "dcphy",
+ dcphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0);
+
+int dcphy_service __P((struct mii_softc *, struct mii_data *, int));
+void dcphy_status __P((struct mii_softc *));
+static int dcphy_auto __P((struct mii_softc *, int));
+static void dcphy_reset __P((struct mii_softc *));
+
+static int dcphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ /*
+ * The dc driver will report the 21143 vendor and device
+ * ID to let us know that it wants us to attach.
+ */
+ if (ma->mii_id1 != DC_VENDORID_DEC ||
+ ma->mii_id2 != DC_DEVICEID_21143)
+ return(ENXIO);
+
+ device_set_desc(dev, "Intel 21143 NWAY media interface");
+
+ return (0);
+}
+
+static int dcphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+ struct dc_softc *dc_sc;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = dcphy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+ /*dcphy_reset(sc);*/
+ dc_sc = mii->mii_ifp->if_softc;
+ CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
+ CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
+
+ switch(pci_read_config(device_get_parent(sc->mii_dev),
+ DC_PCI_CSID, 4)) {
+ case 0x99999999:
+ /* Example of how to only allow 10Mbps modes. */
+ sc->mii_capabilities = BMSR_10TFDX|BMSR_10THDX;
+ break;
+ default:
+ sc->mii_capabilities =
+ BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|
+ BMSR_10TFDX|BMSR_10THDX;
+ break;
+ }
+
+ sc->mii_capabilities &= ma->mii_capmask;
+ device_printf(dev, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities, sc->mii_inst);
+ printf("\n");
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int dcphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+int
+dcphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct dc_softc *dc_sc;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+ u_int32_t mode;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ return (0);
+ }
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ return (0);
+ }
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ sc->mii_flags = 0;
+ mii->mii_media_active = IFM_NONE;
+ mode = CSR_READ_4(dc_sc, DC_NETCFG);
+ mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL|
+ DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL);
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /*dcphy_reset(sc);*/
+ (void) dcphy_auto(sc, 0);
+ break;
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ case IFM_100_TX:
+ dcphy_reset(sc);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS|
+ DC_NETCFG_SCRAMBLER;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mode |= DC_NETCFG_FULLDUPLEX;
+ else
+ mode &= ~DC_NETCFG_FULLDUPLEX;
+ CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
+ break;
+ case IFM_10_T:
+ DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
+ else
+ DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
+ DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ mode &= ~DC_NETCFG_PORTSEL;
+ mode |= DC_NETCFG_SPEEDSEL;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mode |= DC_NETCFG_FULLDUPLEX;
+ else
+ mode &= ~DC_NETCFG_FULLDUPLEX;
+ CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
+ break;
+ default:
+ return(EINVAL);
+ break;
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ if (sc->mii_flags & MIIF_DOINGAUTO) {
+ if (++sc->mii_ticks != 5)
+ return(0);
+ else {
+ sc->mii_ticks = 0;
+ sc->mii_flags &= ~MIIF_DOINGAUTO;
+ sc->mii_flags |= MIIF_AUTOTIMEOUT;
+ }
+ }
+
+ sc->mii_flags &= ~MIIF_DOINGAUTO;
+
+ /*
+ * Check to see if we have link. If we do, we don't
+ * need to restart the autonegotiation process. Read
+ * the BMSR twice in case it's latched.
+ */
+ reg = CSR_READ_4(dc_sc, DC_10BTSTAT) &
+ (DC_TSTAT_LS10|DC_TSTAT_LS100);
+
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX &&
+ !(reg & DC_TSTAT_LS100)) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T &&
+ !(reg & DC_TSTAT_LS10)) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE &&
+ (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ } else if (CSR_READ_4(dc_sc, DC_ISR) & DC_ISR_LINKGOOD) {
+ if (sc->mii_flags & MIIF_AUTOTIMEOUT) {
+ sc->mii_flags &= ~MIIF_AUTOTIMEOUT;
+ break;
+ } else
+ return(0);
+ }
+
+ sc->mii_ticks = 0;
+ /*dcphy_reset(sc);*/
+ dcphy_auto(sc, 0);
+
+ break;
+ }
+
+ /* Update the media status. */
+ dcphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+void
+dcphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int reg, anlpar;
+ struct dc_softc *dc_sc;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ reg = CSR_READ_4(dc_sc, DC_10BTSTAT) &
+ (DC_TSTAT_LS10|DC_TSTAT_LS100);
+
+ if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ if (sc->mii_flags & MIIF_DOINGAUTO) {
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL &&
+ CSR_READ_4(dc_sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT) {
+ /* Erg, still trying, I guess... */
+ if ((CSR_READ_4(dc_sc, DC_10BTSTAT) &
+ DC_ASTAT_AUTONEGCMP) != DC_ASTAT_AUTONEGCMP) {
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (CSR_READ_4(dc_sc, DC_10BTSTAT) & DC_TSTAT_LP_CAN_NWAY) {
+ anlpar = CSR_READ_4(dc_sc, DC_10BTSTAT) >> 16;
+ if (anlpar & ANLPAR_T4)
+ mii->mii_media_active |= IFM_100_T4;
+ else if (anlpar & ANLPAR_TX_FD)
+ mii->mii_media_active |= IFM_100_TX|IFM_FDX;
+ else if (anlpar & ANLPAR_TX)
+ mii->mii_media_active |= IFM_100_TX;
+ else if (anlpar & ANLPAR_10_FD)
+ mii->mii_media_active |= IFM_10_T|IFM_FDX;
+ else if (anlpar & ANLPAR_10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ if (DC_IS_INTEL(dc_sc))
+ DC_CLRBIT(dc_sc, DC_10BTCTRL,
+ DC_TCTL_AUTONEGENBL);
+ return;
+ }
+ /*
+ * If the other side doesn't support NWAY, then the
+ * best we can do is determine if we have a 10Mbps or
+ * 100Mbps link. There's no way to know if the link
+ * is full or half duplex, so we default to half duplex
+ * and hope that the user is clever enough to manually
+ * change the media settings if we're wrong.
+ */
+ if (!(reg & DC_TSTAT_LS100))
+ mii->mii_media_active |= IFM_100_TX;
+ else if (!(reg & DC_TSTAT_LS10))
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ if (DC_IS_INTEL(dc_sc))
+ DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ return;
+ }
+
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SCRAMBLER)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+
+ return;
+}
+
+static int
+dcphy_auto(mii, waitfor)
+ struct mii_softc *mii;
+ int waitfor;
+{
+ int i;
+ struct dc_softc *sc;
+
+ sc = mii->mii_pdata->mii_ifp->if_softc;
+
+ if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
+ DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
+ DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
+ }
+
+ if (waitfor) {
+ /* Wait 500ms for it to complete. */
+ for (i = 0; i < 500; i++) {
+ if ((CSR_READ_4(sc, DC_10BTSTAT) & DC_TSTAT_ANEGSTAT)
+ == DC_ASTAT_AUTONEGCMP)
+ return(0);
+ DELAY(1000);
+ }
+ /*
+ * Don't need to worry about clearing MIIF_DOINGAUTO.
+ * If that's set, a timeout is pending, and it will
+ * clear the flag.
+ */
+ return(EIO);
+ }
+
+ /*
+ * Just let it finish asynchronously. This is for the benefit of
+ * the tick handler driving autonegotiation. Don't want 500ms
+ * delays all the time while the system is running!
+ */
+ if ((mii->mii_flags & MIIF_DOINGAUTO) == 0)
+ mii->mii_flags |= MIIF_DOINGAUTO;
+
+ return(EJUSTRETURN);
+}
+
+static void
+dcphy_reset(mii)
+ struct mii_softc *mii;
+{
+ struct dc_softc *sc;
+
+ sc = mii->mii_pdata->mii_ifp->if_softc;
+
+ DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
+ DELAY(1000);
+ DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
+
+ return;
+}
+
diff --git a/sys/dev/mii/pnphy.c b/sys/dev/mii/pnphy.c
new file mode 100644
index 0000000..0f8498e
--- /dev/null
+++ b/sys/dev/mii/pnphy.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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$
+ */
+
+/*
+ * Pseudo-driver for media selection on the Lite-On PNIC 82c168
+ * chip. The NWAY support on this chip is horribly broken, so we
+ * only support manual mode selection. This is lame, but getting
+ * NWAY to work right is amazingly difficult.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+
+#include <machine/clock.h>
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <pci/if_dcreg.h>
+
+#include "miibus_if.h"
+
+#if !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+#define DC_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) | x)
+
+#define DC_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, \
+ CSR_READ_4(sc, reg) & ~x)
+
+static int pnphy_probe __P((device_t));
+static int pnphy_attach __P((device_t));
+static int pnphy_detach __P((device_t));
+
+static device_method_t pnphy_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, pnphy_probe),
+ DEVMETHOD(device_attach, pnphy_attach),
+ DEVMETHOD(device_detach, pnphy_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ { 0, 0 }
+};
+
+static devclass_t pnphy_devclass;
+
+static driver_t pnphy_driver = {
+ "pnphy",
+ pnphy_methods,
+ sizeof(struct mii_softc)
+};
+
+DRIVER_MODULE(pnphy, miibus, pnphy_driver, pnphy_devclass, 0, 0);
+
+int pnphy_service __P((struct mii_softc *, struct mii_data *, int));
+void pnphy_status __P((struct mii_softc *));
+
+static int pnphy_probe(dev)
+ device_t dev;
+{
+ struct mii_attach_args *ma;
+
+ ma = device_get_ivars(dev);
+
+ /*
+ * The dc driver will report the 82c168 vendor and device
+ * ID to let us know that it wants us to attach.
+ */
+ if (ma->mii_id1 != DC_VENDORID_LO ||
+ ma->mii_id2 != DC_DEVICEID_82C168)
+ return(ENXIO);
+
+ device_set_desc(dev, "PNIC 82c168 media interface");
+
+ return (0);
+}
+
+static int pnphy_attach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_attach_args *ma;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ ma = device_get_ivars(dev);
+ sc->mii_dev = device_get_parent(dev);
+ mii = device_get_softc(sc->mii_dev);
+ LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_service = pnphy_service;
+ sc->mii_pdata = mii;
+
+ sc->mii_flags |= MIIF_NOISOLATE;
+ mii->mii_instance++;
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+
+ sc->mii_capabilities =
+ BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX|BMSR_10THDX;
+ sc->mii_capabilities &= ma->mii_capmask;
+ device_printf(dev, " ");
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0)
+ printf("no media present");
+ else
+ mii_add_media(mii, sc->mii_capabilities, sc->mii_inst);
+ printf("\n");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ BMCR_ISO);
+
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
+ BMCR_LOOP|BMCR_S100);
+
+#undef ADD
+
+ MIIBUS_MEDIAINIT(sc->mii_dev);
+ return(0);
+}
+
+static int pnphy_detach(dev)
+ device_t dev;
+{
+ struct mii_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(device_get_parent(dev));
+ sc->mii_dev = NULL;
+ LIST_REMOVE(sc, mii_list);
+
+ return(0);
+}
+
+int
+pnphy_service(sc, mii, cmd)
+ struct mii_softc *sc;
+ struct mii_data *mii;
+ int cmd;
+{
+ struct dc_softc *dc_sc;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ switch (cmd) {
+ case MII_POLLSTAT:
+ /*
+ * If we're not polling our PHY instance, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
+ return (0);
+ }
+ break;
+
+ case MII_MEDIACHG:
+ /*
+ * If the media indicates a different PHY instance,
+ * isolate ourselves.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * If the interface is not up, don't do anything.
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ break;
+
+ sc->mii_flags = 0;
+
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ /* NWAY is busted on this chip */
+ case IFM_100_T4:
+ /*
+ * XXX Not supported as a manual setting right now.
+ */
+ return (EINVAL);
+ case IFM_100_TX:
+ mii->mii_media_active = IFM_ETHER|IFM_100_TX;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ MIIBUS_STATCHG(sc->mii_dev);
+ return(0);
+ break;
+ case IFM_10_T:
+ mii->mii_media_active = IFM_ETHER|IFM_10_T;
+ if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ MIIBUS_STATCHG(sc->mii_dev);
+ return(0);
+ break;
+ default:
+ return(EINVAL);
+ break;
+ }
+ break;
+
+ case MII_TICK:
+ /*
+ * If we're not currently selected, just return.
+ */
+ if (IFM_INST(ife->ifm_media) != sc->mii_inst)
+ return (0);
+
+ /*
+ * Only used for autonegotiation.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /*
+ * Is the interface even up?
+ */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (0);
+
+ return(0);
+ }
+
+ /* Update the media status. */
+ pnphy_status(sc);
+
+ /* Callback if something changed. */
+ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
+ MIIBUS_STATCHG(sc->mii_dev);
+ sc->mii_active = mii->mii_media_active;
+ }
+ return (0);
+}
+
+void
+pnphy_status(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int reg;
+ struct dc_softc *dc_sc;
+
+ dc_sc = mii->mii_ifp->if_softc;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ reg = CSR_READ_4(dc_sc, DC_ISR);
+
+ if (!(reg & DC_ISR_LINKFAIL))
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_100_TX;
+ if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+
+ return;
+}
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index 9f6702e..dcdee22 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -175,18 +175,14 @@ device ppi0 # Parallel port interface device
# PCI Ethernet NICs.
-device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
-device pn0 # Lite-On 82c168/82c169 (``PNIC'')
device tx0 # SMC 9432TX (83c170 ``EPIC'')
device vx0 # 3Com 3c590, 3c595 (``Vortex'')
# PCI Ethernet NICs that use the common MII bus controller code.
controller miibus0 # MII bus support
-device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
-device dm0 # Davicom DM9100/DM9102
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
+device dc0 # DEC/Intel 21143 and various workalikes
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 70df1ae..c52b4c1 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -1646,31 +1646,20 @@ controller miibus0
# nd 1040B PCI SCSI host adapters, as well as the Qlogic ISP 2100
# FC/AL Host Adapter.
#
-# The `al' device provides support for PCI fast ethernet adapters
-# based on the ADMtek Inc. AL981 "Comet" and the AN985 "Centaur" chips.
-#
-# The `ax' device provides support for PCI fast ethernet adapters
-# based on the ASIX Electronics AX88140A chip, including the Alfa
-# Inc. GFC2204.
+# The `dc' device provides support for PCI fast ethernet adapters
+# based on the DEC/Intel 21143 and various workalikes including:
+# the ADMtek AL981 Comet and AN985 Centaur, the ASIX Electronics
+# AX88140A and AX88141, the Davicom DM9100 and DM9102, the Lite-On
+# 82c168 and 82c169 PNIC, the Lite-On/Macronix LC82C115 PNIC II
+# and the Macronix 98713/98713A/98715/98715A/98725 PMAC. This driver
+# replaces the old al, ax, dm, pn and mx drivers.
#
# The `de' device provides support for the Digital Equipment DC21040
# self-contained Ethernet adapter.
#
-# The `dm' device provides support for PCI fast ethernet adapters
-# based on the the Davicom DM9100 and DM9102 controller chips, including
-# the Jaton Corporation XPressNet.
-#
# The `fxp' device provides support for the Intel EtherExpress Pro/100B
# PCI Fast Ethernet adapters.
#
-# The `mx' device provides support for various fast ethernet adapters
-# based on the Macronix 98713, 987615 and 98725 series chips.
-#
-# The `pn' device provides support for various fast ethernet adapters
-# based on the Lite-On 82c168 and 82c169 PNIC chips, including the
-# LinkSys LNE100TX, the NetGear FA310TX rev. D1 and the Matrox
-# FastNIC 10/100.
-#
# The 'rl' device provides support for PCI fast ethernet adapters based
# on the RealTek 8129/8139 chipset. Note that the RealTek driver defaults
# to using programmed I/O to do register accesses because memory mapped
@@ -1852,13 +1841,9 @@ options SCSI_ISP_WWN="0x5000000099990000"
#options ISP_COMPILE_2100_FW=1
#options ISP_COMPILE_2200_FW=1
-device al0
-device ax0
+device dc0
device de0
-device dm0
device fxp0
-device mx0
-device pn0
device rl0
device sf0
device sis0
diff --git a/sys/i386/conf/NEWCARD b/sys/i386/conf/NEWCARD
index 9f90731..bae4f12 100644
--- a/sys/i386/conf/NEWCARD
+++ b/sys/i386/conf/NEWCARD
@@ -169,13 +169,9 @@ device ppi0 # Parallel port interface device
controller miibus0
# PCI Ethernet NICs.
-device al0 # ADMtek AL981 (``Comet'')
-device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
-device dm0 # Davicom DM9100/DM9102
+device dc0 # DEC/Intel 21143 and various workalikes
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
-device pn0 # Lite-On 82c168/82c169 (``PNIC'')
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 70df1ae..c52b4c1 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -1646,31 +1646,20 @@ controller miibus0
# nd 1040B PCI SCSI host adapters, as well as the Qlogic ISP 2100
# FC/AL Host Adapter.
#
-# The `al' device provides support for PCI fast ethernet adapters
-# based on the ADMtek Inc. AL981 "Comet" and the AN985 "Centaur" chips.
-#
-# The `ax' device provides support for PCI fast ethernet adapters
-# based on the ASIX Electronics AX88140A chip, including the Alfa
-# Inc. GFC2204.
+# The `dc' device provides support for PCI fast ethernet adapters
+# based on the DEC/Intel 21143 and various workalikes including:
+# the ADMtek AL981 Comet and AN985 Centaur, the ASIX Electronics
+# AX88140A and AX88141, the Davicom DM9100 and DM9102, the Lite-On
+# 82c168 and 82c169 PNIC, the Lite-On/Macronix LC82C115 PNIC II
+# and the Macronix 98713/98713A/98715/98715A/98725 PMAC. This driver
+# replaces the old al, ax, dm, pn and mx drivers.
#
# The `de' device provides support for the Digital Equipment DC21040
# self-contained Ethernet adapter.
#
-# The `dm' device provides support for PCI fast ethernet adapters
-# based on the the Davicom DM9100 and DM9102 controller chips, including
-# the Jaton Corporation XPressNet.
-#
# The `fxp' device provides support for the Intel EtherExpress Pro/100B
# PCI Fast Ethernet adapters.
#
-# The `mx' device provides support for various fast ethernet adapters
-# based on the Macronix 98713, 987615 and 98725 series chips.
-#
-# The `pn' device provides support for various fast ethernet adapters
-# based on the Lite-On 82c168 and 82c169 PNIC chips, including the
-# LinkSys LNE100TX, the NetGear FA310TX rev. D1 and the Matrox
-# FastNIC 10/100.
-#
# The 'rl' device provides support for PCI fast ethernet adapters based
# on the RealTek 8129/8139 chipset. Note that the RealTek driver defaults
# to using programmed I/O to do register accesses because memory mapped
@@ -1852,13 +1841,9 @@ options SCSI_ISP_WWN="0x5000000099990000"
#options ISP_COMPILE_2100_FW=1
#options ISP_COMPILE_2200_FW=1
-device al0
-device ax0
+device dc0
device de0
-device dm0
device fxp0
-device mx0
-device pn0
device rl0
device sf0
device sis0
diff --git a/sys/i386/conf/PCCARD b/sys/i386/conf/PCCARD
index e783794..b8bb803 100644
--- a/sys/i386/conf/PCCARD
+++ b/sys/i386/conf/PCCARD
@@ -159,18 +159,14 @@ device ppi0 # Parallel port interface device
# PCI Ethernet NICs.
-device ax0 # ASIX AX88140A
device de0 # DEC/Intel DC21x4x (``Tulip'')
device fxp0 # Intel EtherExpress PRO/100B (82557, 82558)
-device pn0 # Lite-On 82c168/82c169 (``PNIC'')
device tx0 # SMC 9432TX (83c170 ``EPIC'')
device vx0 # 3Com 3c590, 3c595 (``Vortex'')
# PCI Ethernet NICs that use the common MII bus controller code.
controller miibus0 # MII bus support
-device al0 # ADMtek AL981/AN985 (``Comet''/``Centaur'')
-device dm0 # Davicom DM9100/DM9102
-device mx0 # Macronix 98713/98715/98725 (``PMAC'')
+device dc0 # DEC/Intrl 21143 and various workalikes
device rl0 # RealTek 8129/8139
device sf0 # Adaptec AIC-6915 (``Starfire'')
device sis0 # Silicon Integrated Systems SiS 900/SiS 7016
diff --git a/sys/i386/i386/userconfig.c b/sys/i386/i386/userconfig.c
index 909303d..7ac1d89 100644
--- a/sys/i386/i386/userconfig.c
+++ b/sys/i386/i386/userconfig.c
@@ -401,14 +401,10 @@ static DEV_INFO device_info[] = {
{"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK},
{"ze", "IBM/National Semiconductor PCMCIA Ethernet adapter",0, CLS_NETWORK},
{"zp", "3COM PCMCIA Etherlink III Ethernet adapter", 0, CLS_NETWORK},
-{"al", "ADMtek AL981/AN985 ethernet adapter", FLG_FIXED, CLS_NETWORK},
-{"ax", "ASIX AX88140A ethernet adapter", FLG_FIXED, CLS_NETWORK},
+{"dc", "DEC/Intel 21143 or clone Ethernet adapter", FLG_FIXED, CLS_NETWORK},
{"de", "DEC DC21040 Ethernet adapter", FLG_FIXED, CLS_NETWORK},
-{"dm", "Davicom DM910x Ethernet adapter", FLG_FIXED, CLS_NETWORK},
{"fpa", "DEC DEFPA PCI FDDI adapter", FLG_FIXED, CLS_NETWORK},
{"rl", "RealTek 8129/8139 ethernet adapter", FLG_FIXED, CLS_NETWORK},
-{"mx", "Macronix PMAC ethernet adapter", FLG_FIXED, CLS_NETWORK},
-{"pn", "Lite-On 82c168/82c169 PNIC adapter", FLG_FIXED, CLS_NETWORK},
{"tl", "Texas Instruments ThunderLAN ethernet adapter", FLG_FIXED, CLS_NETWORK},
{"vr", "VIA Rhine/Rhine II ethernet adapter", FLG_FIXED, CLS_NETWORK},
{"wb", "Winbond W89C840F ethernet adapter", FLG_FIXED, CLS_NETWORK},
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index bc97db6..e6cd0cf 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -2,9 +2,9 @@
# XXX present but broken: atapi ip_mroute_mod joy pcic
-SUBDIR= aha al ax ccd cd9660 coda dm fdesc fxp if_disc if_ppp if_sl if_tun \
- ipfilter ipfw kernfs md mfs mii msdos mx netgraph nfs ntfs nullfs \
- pn portal procfs rl sf sis sk ste ti tl umapfs union vn vr wb xl
+SUBDIR= aha ccd dc cd9660 coda fdesc fxp if_disc if_ppp if_sl if_tun \
+ ipfilter ipfw kernfs md mfs mii msdos netgraph nfs ntfs nullfs \
+ portal procfs rl sf sis sk ste ti tl umapfs union vn vr wb xl
SUBDIR+=usb ugen uhid ukbd ulpt ums umodem umass
diff --git a/sys/modules/ax/Makefile b/sys/modules/ax/Makefile
deleted file mode 100644
index 3368a7f..0000000
--- a/sys/modules/ax/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR}/../../pci
-KMOD = if_ax
-SRCS = if_ax.c opt_bdg.h device_if.h bus_if.h pci_if.h
-CFLAGS += ${DEBUG_FLAGS}
-
-.include <bsd.kmod.mk>
diff --git a/sys/modules/al/Makefile b/sys/modules/dc/Makefile
index 58170cf..2f87272 100644
--- a/sys/modules/al/Makefile
+++ b/sys/modules/dc/Makefile
@@ -1,8 +1,8 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../pci
-KMOD = al
-SRCS = if_al.c opt_bdg.h device_if.h bus_if.h pci_if.h
+KMOD = if_dc
+SRCS = if_dc.c opt_bdg.h device_if.h bus_if.h pci_if.h
SRCS += miibus_if.h
CFLAGS += ${DEBUG_FLAGS}
KMODDEPS = miibus
diff --git a/sys/modules/dm/Makefile b/sys/modules/dm/Makefile
deleted file mode 100644
index e0e19ba..0000000
--- a/sys/modules/dm/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR}/../../pci
-KMOD = if_dm
-SRCS = if_dm.c opt_bdg.h device_if.h bus_if.h pci_if.h
-SRCS += miibus_if.h
-CFLAGS += ${DEBUG_FLAGS}
-KMODDEPS = miibus
-
-.include <bsd.kmod.mk>
diff --git a/sys/modules/mii/Makefile b/sys/modules/mii/Makefile
index 72eb718..407f3c3 100644
--- a/sys/modules/mii/Makefile
+++ b/sys/modules/mii/Makefile
@@ -4,7 +4,7 @@
KMOD = miibus
SRCS = mii.c mii_physubr.c ukphy.c ukphy_subr.c bus_if.h
SRCS += miibus_if.h device_if.h miibus_if.c exphy.c nsphy.c
-SRCS += mlphy.c tlphy.c rlphy.c amphy.c mxphy.c
+SRCS += mlphy.c tlphy.c rlphy.c amphy.c dcphy.c pnphy.c
CFLAGS += ${DEBUG_FLAGS}
.include <bsd.kmod.mk>
diff --git a/sys/modules/mx/Makefile b/sys/modules/mx/Makefile
deleted file mode 100644
index bbb49c0..0000000
--- a/sys/modules/mx/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR}/../../pci
-KMOD = if_mx
-SRCS = if_mx.c opt_bdg.h device_if.h bus_if.h pci_if.h miibus_if.h
-CFLAGS += ${DEBUG_FLAGS}
-
-.include <bsd.kmod.mk>
diff --git a/sys/modules/pn/Makefile b/sys/modules/pn/Makefile
deleted file mode 100644
index 51909c0..0000000
--- a/sys/modules/pn/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR}/../../pci
-KMOD = if_pn
-SRCS = if_pn.c opt_bdg.h device_if.h bus_if.h pci_if.h
-CFLAGS += ${DEBUG_FLAGS}
-
-.include <bsd.kmod.mk>
diff --git a/sys/pci/if_al.c b/sys/pci/if_al.c
deleted file mode 100644
index 246a58e..0000000
--- a/sys/pci/if_al.c
+++ /dev/null
@@ -1,1762 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * ADMtek AL981 Comet and AN985 Centaur fast ethernet PCI NIC driver.
- * Datasheets for the AL981 are available from http://www.admtek.com.tw.
- *
- * Written by Bill Paul <wpaul@ee.columbia.edu>
- * Electrical Engineering Department
- * Columbia University, New York City
- */
-
-/*
- * The ADMtek AL981 Comet is still another DEC 21x4x clone. It's
- * a reasonably close copy of the tulip, except for the receiver filter
- * programming. Where the DEC chip has a special setup frame that
- * needs to be downloaded into the transmit DMA engine, the ADMtek chip
- * has physical address and multicast address registers.
- *
- * The AN985 is an update to the AL981 which is mostly the same, except
- * for the following things:
- * - The AN985 uses a 99C66 EEPROM which requires a slightly different
- * bit sequence to initiate a read.
- * - The AN985 uses a serial MII interface instead of providing direct
- * access to the PHY registers (it uses an internal PHY though).
- * Although the datasheet for the AN985 is not yet available, you can
- * use an AL981 datasheet as a reference for most of the chip functions,
- * except for the MII interface which matches the DEC 21x4x specification
- * (bits 16, 17, 18 and 19 in the serial I/O register control the MII).
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sockio.h>
-#include <sys/mbuf.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ethernet.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
-
-#include <net/bpf.h>
-
-#include <vm/vm.h> /* for vtophys */
-#include <vm/pmap.h> /* for vtophys */
-#include <machine/clock.h> /* for DELAY */
-#include <machine/bus_pio.h>
-#include <machine/bus_memio.h>
-#include <machine/bus.h>
-#include <machine/resource.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
-
-#include <dev/mii/mii.h>
-#include <dev/mii/miivar.h>
-
-#include <pci/pcireg.h>
-#include <pci/pcivar.h>
-
-/* Enable workaround for small transmitter bug. */
-#define AL_TX_STALL_WAR
-
-#define AL_USEIOSPACE
-
-#include <pci/if_alreg.h>
-
-#include "miibus_if.h"
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-/*
- * Various supported device vendors/types and their names.
- */
-static struct al_type al_devs[] = {
- { AL_VENDORID, AL_DEVICEID_AL981, "ADMtek AL981 10/100BaseTX" },
- { AL_VENDORID, AL_DEVICEID_AN985, "ADMtek AN985 10/100BaseTX" },
- { 0, 0, NULL }
-};
-
-static int al_probe __P((device_t));
-static int al_attach __P((device_t));
-static int al_detach __P((device_t));
-
-static int al_newbuf __P((struct al_softc *,
- struct al_desc *,
- struct mbuf *));
-static int al_encap __P((struct al_softc *,
- struct mbuf *, u_int32_t *));
-
-static void al_rxeof __P((struct al_softc *));
-static void al_txeof __P((struct al_softc *));
-static void al_tick __P((void *));
-static void al_intr __P((void *));
-static void al_start __P((struct ifnet *));
-static int al_ioctl __P((struct ifnet *, u_long, caddr_t));
-static void al_init __P((void *));
-static void al_stop __P((struct al_softc *));
-static void al_watchdog __P((struct ifnet *));
-static void al_shutdown __P((device_t));
-static int al_ifmedia_upd __P((struct ifnet *));
-static void al_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
-
-static void al_delay __P((struct al_softc *));
-static void al_eeprom_idle __P((struct al_softc *));
-static void al_eeprom_putbyte __P((struct al_softc *, int));
-static void al_eeprom_getword __P((struct al_softc *, int, u_int16_t *));
-static void al_read_eeprom __P((struct al_softc *, caddr_t, int,
- int, int));
-
-static void al_mii_writebit __P((struct al_softc *, int));
-static int al_mii_readbit __P((struct al_softc *));
-static void al_mii_sync __P((struct al_softc *));
-static void al_mii_send __P((struct al_softc *, u_int32_t, int));
-static int al_mii_readreg __P((struct al_softc *, struct al_mii_frame *));
-static int al_mii_writereg __P((struct al_softc *, struct al_mii_frame *));
-
-static int al_miibus_readreg __P((device_t, int, int));
-static int al_miibus_writereg __P((device_t, int, int, int));
-static void al_miibus_statchg __P((device_t));
-
-static u_int32_t al_calchash __P((caddr_t));
-static void al_setmulti __P((struct al_softc *));
-static void al_reset __P((struct al_softc *));
-static int al_list_rx_init __P((struct al_softc *));
-static int al_list_tx_init __P((struct al_softc *));
-
-#ifdef AL_USEIOSPACE
-#define AL_RES SYS_RES_IOPORT
-#define AL_RID AL_PCI_LOIO
-#else
-#define AL_RES SYS_RES_MEMORY
-#define AL_RID AL_PCI_LOMEM
-#endif
-
-static device_method_t al_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, al_probe),
- DEVMETHOD(device_attach, al_attach),
- DEVMETHOD(device_detach, al_detach),
- DEVMETHOD(device_shutdown, al_shutdown),
-
- /* bus interface */
- DEVMETHOD(bus_print_child, bus_generic_print_child),
- DEVMETHOD(bus_driver_added, bus_generic_driver_added),
-
- /* MII interface */
- DEVMETHOD(miibus_readreg, al_miibus_readreg),
- DEVMETHOD(miibus_writereg, al_miibus_writereg),
- DEVMETHOD(miibus_statchg, al_miibus_statchg),
-
- { 0, 0 }
-};
-
-static driver_t al_driver = {
- "al",
- al_methods,
- sizeof(struct al_softc),
-};
-
-static devclass_t al_devclass;
-
-DRIVER_MODULE(if_al, pci, al_driver, al_devclass, 0, 0);
-DRIVER_MODULE(miibus, al, miibus_driver, miibus_devclass, 0, 0);
-
-#define AL_SETBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) | x)
-
-#define AL_CLRBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) & ~x)
-
-#define SIO_SET(x) \
- CSR_WRITE_4(sc, AL_SIO, \
- CSR_READ_4(sc, AL_SIO) | x)
-
-#define SIO_CLR(x) \
- CSR_WRITE_4(sc, AL_SIO, \
- CSR_READ_4(sc, AL_SIO) & ~x)
-
-static void al_delay(sc)
- struct al_softc *sc;
-{
- int idx;
-
- for (idx = (300 / 33) + 1; idx > 0; idx--)
- CSR_READ_4(sc, AL_BUSCTL);
-}
-
-static void al_eeprom_idle(sc)
- struct al_softc *sc;
-{
- register int i;
-
- CSR_WRITE_4(sc, AL_SIO, AL_SIO_EESEL);
- al_delay(sc);
- AL_SETBIT(sc, AL_SIO, AL_SIO_ROMCTL_READ);
- al_delay(sc);
- AL_SETBIT(sc, AL_SIO, AL_SIO_EE_CS);
- al_delay(sc);
- AL_SETBIT(sc, AL_SIO, AL_SIO_EE_CLK);
- al_delay(sc);
-
- for (i = 0; i < 25; i++) {
- AL_CLRBIT(sc, AL_SIO, AL_SIO_EE_CLK);
- al_delay(sc);
- AL_SETBIT(sc, AL_SIO, AL_SIO_EE_CLK);
- al_delay(sc);
- }
-
- AL_CLRBIT(sc, AL_SIO, AL_SIO_EE_CLK);
- al_delay(sc);
- AL_CLRBIT(sc, AL_SIO, AL_SIO_EE_CS);
- al_delay(sc);
- CSR_WRITE_4(sc, AL_SIO, 0x00000000);
-
- return;
-}
-
-/*
- * Send a read command and address to the EEPROM, check for ACK.
- */
-static void al_eeprom_putbyte(sc, addr)
- struct al_softc *sc;
- int addr;
-{
- register int d, i;
-
- /*
- * The AN985 has a 99C66 EEPROM on it instead of
- * a 99C64. It uses a different bit sequence for
- * specifying the "read" opcode.
- */
- if (sc->al_did == AL_DEVICEID_AN985)
- d = addr | (AL_EECMD_READ << 2);
- else
- d = addr | AL_EECMD_READ;
-
- /*
- * Feed in each bit and stobe the clock.
- */
- for (i = 0x400; i; i >>= 1) {
- if (d & i) {
- SIO_SET(AL_SIO_EE_DATAIN);
- } else {
- SIO_CLR(AL_SIO_EE_DATAIN);
- }
- al_delay(sc);
- SIO_SET(AL_SIO_EE_CLK);
- al_delay(sc);
- SIO_CLR(AL_SIO_EE_CLK);
- al_delay(sc);
- }
-
- return;
-}
-
-/*
- * Read a word of data stored in the EEPROM at address 'addr.'
- */
-static void al_eeprom_getword(sc, addr, dest)
- struct al_softc *sc;
- int addr;
- u_int16_t *dest;
-{
- register int i;
- u_int16_t word = 0;
-
- /* Force EEPROM to idle state. */
- al_eeprom_idle(sc);
-
- /* Enter EEPROM access mode. */
- CSR_WRITE_4(sc, AL_SIO, AL_SIO_EESEL);
- al_delay(sc);
- AL_SETBIT(sc, AL_SIO, AL_SIO_ROMCTL_READ);
- al_delay(sc);
- AL_SETBIT(sc, AL_SIO, AL_SIO_EE_CS);
- al_delay(sc);
- AL_CLRBIT(sc, AL_SIO, AL_SIO_EE_CLK);
- al_delay(sc);
-
- /*
- * Send address of word we want to read.
- */
- al_eeprom_putbyte(sc, addr);
-
- /*
- * Start reading bits from EEPROM.
- */
- for (i = 0x8000; i; i >>= 1) {
- SIO_SET(AL_SIO_EE_CLK);
- al_delay(sc);
- if (CSR_READ_4(sc, AL_SIO) & AL_SIO_EE_DATAOUT)
- word |= i;
- al_delay(sc);
- SIO_CLR(AL_SIO_EE_CLK);
- al_delay(sc);
- }
-
- /* Turn off EEPROM access mode. */
- al_eeprom_idle(sc);
-
- *dest = word;
-
- return;
-}
-
-/*
- * Read a sequence of words from the EEPROM.
- */
-static void al_read_eeprom(sc, dest, off, cnt, swap)
- struct al_softc *sc;
- caddr_t dest;
- int off;
- int cnt;
- int swap;
-{
- int i;
- u_int16_t word = 0, *ptr;
-
- for (i = 0; i < cnt; i++) {
- al_eeprom_getword(sc, off + i, &word);
- ptr = (u_int16_t *)(dest + (i * 2));
- if (swap)
- *ptr = ntohs(word);
- else
- *ptr = word;
- }
-
- return;
-}
-
-/*
- * Write a bit to the MII bus.
- */
-static void al_mii_writebit(sc, bit)
- struct al_softc *sc;
- int bit;
-{
- if (bit)
- CSR_WRITE_4(sc, AL_SIO, AL_SIO_ROMCTL_WRITE|AL_SIO_MII_DATAOUT);
- else
- CSR_WRITE_4(sc, AL_SIO, AL_SIO_ROMCTL_WRITE);
-
- AL_SETBIT(sc, AL_SIO, AL_SIO_MII_CLK);
- AL_CLRBIT(sc, AL_SIO, AL_SIO_MII_CLK);
-
- return;
-}
-
-/*
- * Read a bit from the MII bus.
- */
-static int al_mii_readbit(sc)
- struct al_softc *sc;
-{
- CSR_WRITE_4(sc, AL_SIO, AL_SIO_ROMCTL_READ|AL_SIO_MII_DIR);
- CSR_READ_4(sc, AL_SIO);
- AL_SETBIT(sc, AL_SIO, AL_SIO_MII_CLK);
- AL_CLRBIT(sc, AL_SIO, AL_SIO_MII_CLK);
- if (CSR_READ_4(sc, AL_SIO) & AL_SIO_MII_DATAIN)
- return(1);
-
- return(0);
-}
-
-/*
- * Sync the PHYs by setting data bit and strobing the clock 32 times.
- */
-static void al_mii_sync(sc)
- struct al_softc *sc;
-{
- register int i;
-
- CSR_WRITE_4(sc, AL_SIO, AL_SIO_ROMCTL_WRITE);
-
- for (i = 0; i < 32; i++)
- al_mii_writebit(sc, 1);
-
- return;
-}
-
-/*
- * Clock a series of bits through the MII.
- */
-static void al_mii_send(sc, bits, cnt)
- struct al_softc *sc;
- u_int32_t bits;
- int cnt;
-{
- int i;
-
- for (i = (0x1 << (cnt - 1)); i; i >>= 1)
- al_mii_writebit(sc, bits & i);
-}
-
-/*
- * Read an PHY register through the MII.
- */
-static int al_mii_readreg(sc, frame)
- struct al_softc *sc;
- struct al_mii_frame *frame;
-
-{
- int i, ack, s;
-
- s = splimp();
-
- /*
- * Set up frame for RX.
- */
- frame->mii_stdelim = AL_MII_STARTDELIM;
- frame->mii_opcode = AL_MII_READOP;
- frame->mii_turnaround = 0;
- frame->mii_data = 0;
-
- /*
- * Sync the PHYs.
- */
- al_mii_sync(sc);
-
- /*
- * Send command/address info.
- */
- al_mii_send(sc, frame->mii_stdelim, 2);
- al_mii_send(sc, frame->mii_opcode, 2);
- al_mii_send(sc, frame->mii_phyaddr, 5);
- al_mii_send(sc, frame->mii_regaddr, 5);
-
-#ifdef notdef
- /* Idle bit */
- al_mii_writebit(sc, 1);
- al_mii_writebit(sc, 0);
-#endif
-
- /* Check for ack */
- ack = al_mii_readbit(sc);
-
- /*
- * Now try reading data bits. If the ack failed, we still
- * need to clock through 16 cycles to keep the PHY(s) in sync.
- */
- if (ack) {
- for(i = 0; i < 16; i++) {
- al_mii_readbit(sc);
- }
- goto fail;
- }
-
- for (i = 0x8000; i; i >>= 1) {
- if (!ack) {
- if (al_mii_readbit(sc))
- frame->mii_data |= i;
- }
- }
-
-fail:
-
- al_mii_writebit(sc, 0);
- al_mii_writebit(sc, 0);
-
- splx(s);
-
- if (ack)
- return(1);
- return(0);
-}
-
-/*
- * Write to a PHY register through the MII.
- */
-static int al_mii_writereg(sc, frame)
- struct al_softc *sc;
- struct al_mii_frame *frame;
-
-{
- int s;
-
- s = splimp();
- /*
- * Set up frame for TX.
- */
-
- frame->mii_stdelim = AL_MII_STARTDELIM;
- frame->mii_opcode = AL_MII_WRITEOP;
- frame->mii_turnaround = AL_MII_TURNAROUND;
-
- /*
- * Sync the PHYs.
- */
- al_mii_sync(sc);
-
- al_mii_send(sc, frame->mii_stdelim, 2);
- al_mii_send(sc, frame->mii_opcode, 2);
- al_mii_send(sc, frame->mii_phyaddr, 5);
- al_mii_send(sc, frame->mii_regaddr, 5);
- al_mii_send(sc, frame->mii_turnaround, 2);
- al_mii_send(sc, frame->mii_data, 16);
-
- /* Idle bit. */
- al_mii_writebit(sc, 0);
- al_mii_writebit(sc, 0);
-
- splx(s);
-
- return(0);
-}
-
-static int al_miibus_readreg(dev, phy, reg)
- device_t dev;
- int phy, reg;
-{
- struct al_mii_frame frame;
- u_int16_t rval = 0;
- u_int16_t phy_reg = 0;
- struct al_softc *sc;
-
- sc = device_get_softc(dev);
-
- /*
- * Note: both the AL981 and AN985 have internal PHYs,
- * however the AL981 provides direct access to the PHY
- * registers while the AN985 uses a serial MII interface.
- * The AN985's MII interface is also buggy in that you
- * can read from any MII address (0 to 31), but only address 1
- * behaves normally. To deal with both cases, we pretend
- * that the PHY is at MII address 1.
- */
- if (phy != 1)
- return(0);
-
- if (sc->al_did == AL_DEVICEID_AN985) {
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- al_mii_readreg(sc, &frame);
-
- return(frame.mii_data);
- }
-
- switch(reg) {
- case MII_BMCR:
- phy_reg = AL_BMCR;
- break;
- case MII_BMSR:
- phy_reg = AL_BMSR;
- break;
- case MII_PHYIDR1:
- phy_reg = AL_VENID;
- break;
- case MII_PHYIDR2:
- phy_reg = AL_DEVID;
- break;
- case MII_ANAR:
- phy_reg = AL_ANAR;
- break;
- case MII_ANLPAR:
- phy_reg = AL_LPAR;
- break;
- case MII_ANER:
- phy_reg = AL_ANER;
- break;
- default:
- printf("al%d: read: bad phy register %x\n",
- sc->al_unit, reg);
- return(0);
- break;
- }
-
- rval = CSR_READ_4(sc, phy_reg) & 0x0000FFFF;
-
- if (rval == 0xFFFF)
- return(0);
-
- return(rval);
-}
-
-static int al_miibus_writereg(dev, phy, reg, data)
- device_t dev;
- int phy, reg, data;
-{
- struct al_mii_frame frame;
- struct al_softc *sc;
- u_int16_t phy_reg = 0;
-
- sc = device_get_softc(dev);
-
- if (phy != 1)
- return(0);
-
- if (sc->al_did == AL_DEVICEID_AN985) {
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- frame.mii_data = data;
-
- al_mii_writereg(sc, &frame);
- return(0);
- }
-
- switch(reg) {
- case MII_BMCR:
- phy_reg = AL_BMCR;
- break;
- case MII_BMSR:
- phy_reg = AL_BMSR;
- break;
- case MII_PHYIDR1:
- phy_reg = AL_VENID;
- break;
- case MII_PHYIDR2:
- phy_reg = AL_DEVID;
- break;
- case MII_ANAR:
- phy_reg = AL_ANAR;
- break;
- case MII_ANLPAR:
- phy_reg = AL_LPAR;
- break;
- case MII_ANER:
- phy_reg = AL_ANER;
- break;
- default:
- printf("al%d: phy_write: bad phy register %x\n",
- sc->al_unit, reg);
- return(0);
- break;
- }
-
- CSR_WRITE_4(sc, phy_reg, data);
-
- return(0);
-}
-
-static void al_miibus_statchg(dev)
- device_t dev;
-{
- return;
-}
-
-/*
- * Calculate CRC of a multicast group address, return the lower 6 bits.
- */
-static u_int32_t al_calchash(addr)
- caddr_t addr;
-{
- u_int32_t crc, carry;
- int i, j;
- u_int8_t c;
-
- /* Compute CRC for the address value. */
- crc = 0xFFFFFFFF; /* initial value */
-
- for (i = 0; i < 6; i++) {
- c = *(addr + i);
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
- crc <<= 1;
- c >>= 1;
- if (carry)
- crc = (crc ^ 0x04c11db6) | carry;
- }
- }
-
- /* return the filter bit position */
- return((crc >> 26) & 0x0000003F);
-}
-
-static void al_setmulti(sc)
- struct al_softc *sc;
-{
- struct ifnet *ifp;
- int h = 0;
- u_int32_t hashes[2] = { 0, 0 };
- struct ifmultiaddr *ifma;
- u_int32_t rxfilt;
-
- ifp = &sc->arpcom.ac_if;
-
- rxfilt = CSR_READ_4(sc, AL_NETCFG);
-
- if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
- rxfilt |= AL_NETCFG_RX_ALLMULTI;
- CSR_WRITE_4(sc, AL_NETCFG, rxfilt);
- return;
- } else
- rxfilt &= ~AL_NETCFG_RX_ALLMULTI;
-
- /* first, zot all the existing hash bits */
- CSR_WRITE_4(sc, AL_MAR0, 0);
- CSR_WRITE_4(sc, AL_MAR1, 0);
-
- /* now program new ones */
- for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
- ifma = ifma->ifma_link.le_next) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- h = al_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
- if (h < 32)
- hashes[0] |= (1 << h);
- else
- hashes[1] |= (1 << (h - 32));
- }
-
- CSR_WRITE_4(sc, AL_MAR0, hashes[0]);
- CSR_WRITE_4(sc, AL_MAR1, hashes[1]);
- CSR_WRITE_4(sc, AL_NETCFG, rxfilt);
-
- return;
-}
-
-static void al_reset(sc)
- struct al_softc *sc;
-{
- register int i;
-
- AL_SETBIT(sc, AL_BUSCTL, AL_BUSCTL_RESET);
-
- for (i = 0; i < AL_TIMEOUT; i++) {
- DELAY(10);
- if (!(CSR_READ_4(sc, AL_BUSCTL) & AL_BUSCTL_RESET))
- break;
- }
-#ifdef notdef
- if (i == AL_TIMEOUT)
- printf("al%d: reset never completed!\n", sc->al_unit);
-#endif
- CSR_WRITE_4(sc, AL_BUSCTL, AL_BUSCTL_ARBITRATION);
-
- /* Wait a little while for the chip to get its brains in order. */
- DELAY(1000);
- return;
-}
-
-/*
- * Probe for an ADMtek chip. Check the PCI vendor and device
- * IDs against our list and return a device name if we find a match.
- */
-static int al_probe(dev)
- device_t dev;
-{
- struct al_type *t;
-
- t = al_devs;
-
- while(t->al_name != NULL) {
- if ((pci_get_vendor(dev) == t->al_vid) &&
- (pci_get_device(dev) == t->al_did)) {
- device_set_desc(dev, t->al_name);
- return(0);
- }
- t++;
- }
-
- return(ENXIO);
-}
-
-/*
- * Attach the interface. Allocate softc structures, do ifmedia
- * setup and ethernet/BPF attach.
- */
-static int al_attach(dev)
- device_t dev;
-{
- int s;
- u_char eaddr[ETHER_ADDR_LEN];
- u_int32_t command;
- struct al_softc *sc;
- struct ifnet *ifp;
- int unit, error = 0, rid;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- unit = device_get_unit(dev);
- bzero(sc, sizeof(struct al_softc));
- sc->al_did = pci_get_device(dev);
-
- /*
- * Handle power management nonsense.
- */
-
- command = pci_read_config(dev, AL_PCI_CAPID, 4) & 0x000000FF;
- if (command == 0x01) {
-
- command = pci_read_config(dev, AL_PCI_PWRMGMTCTRL, 4);
- if (command & AL_PSTATE_MASK) {
- u_int32_t iobase, membase, irq;
-
- /* Save important PCI config data. */
- iobase = pci_read_config(dev, AL_PCI_LOIO, 4);
- membase = pci_read_config(dev, AL_PCI_LOMEM, 4);
- irq = pci_read_config(dev, AL_PCI_INTLINE, 4);
-
- /* Reset the power state. */
- printf("al%d: chip is in D%d power mode "
- "-- setting to D0\n", unit, command & AL_PSTATE_MASK);
- command &= 0xFFFFFFFC;
- pci_write_config(dev, AL_PCI_PWRMGMTCTRL, command, 4);
-
- /* Restore PCI config data. */
- pci_write_config(dev, AL_PCI_LOIO, iobase, 4);
- pci_write_config(dev, AL_PCI_LOMEM, membase, 4);
- pci_write_config(dev, AL_PCI_INTLINE, irq, 4);
- }
- }
-
- /*
- * Map control/status registers.
- */
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
- command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
- pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
-
-#ifdef AL_USEIOSPACE
- if (!(command & PCIM_CMD_PORTEN)) {
- printf("al%d: failed to enable I/O ports!\n", unit);
- error = ENXIO;;
- goto fail;
- }
-#else
- if (!(command & PCIM_CMD_MEMEN)) {
- printf("al%d: failed to enable memory mapping!\n", unit);
- error = ENXIO;;
- goto fail;
- }
-#endif
-
- rid = AL_RID;
- sc->al_res = bus_alloc_resource(dev, AL_RES, &rid,
- 0, ~0, 1, RF_ACTIVE);
-
- if (sc->al_res == NULL) {
- printf("al%d: couldn't map ports/memory\n", unit);
- error = ENXIO;
- goto fail;
- }
-
- sc->al_btag = rman_get_bustag(sc->al_res);
- sc->al_bhandle = rman_get_bushandle(sc->al_res);
-
- /* Allocate interrupt */
- rid = 0;
- sc->al_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
- RF_SHAREABLE | RF_ACTIVE);
-
- if (sc->al_irq == NULL) {
- printf("al%d: couldn't map interrupt\n", unit);
- bus_release_resource(dev, AL_RES, AL_RID, sc->al_res);
- error = ENXIO;
- goto fail;
- }
-
- error = bus_setup_intr(dev, sc->al_irq, INTR_TYPE_NET,
- al_intr, sc, &sc->al_intrhand);
-
- if (error) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->al_res);
- bus_release_resource(dev, AL_RES, AL_RID, sc->al_res);
- printf("al%d: couldn't set up irq\n", unit);
- goto fail;
- }
-
- /* Save the cache line size. */
- sc->al_cachesize = pci_read_config(dev, AL_PCI_CACHELEN, 4) & 0xFF;
-
- /* Reset the adapter. */
- al_reset(sc);
-
- /*
- * Get station address from the EEPROM.
- */
- al_read_eeprom(sc, (caddr_t)&eaddr, AL_EE_NODEADDR, 3, 0);
-
- /*
- * An ADMtek chip was detected. Inform the world.
- */
- printf("al%d: Ethernet address: %6D\n", unit, eaddr, ":");
-
- sc->al_unit = unit;
- callout_handle_init(&sc->al_stat_ch);
- bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
-
- sc->al_ldata = contigmalloc(sizeof(struct al_list_data), M_DEVBUF,
- M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
-
- if (sc->al_ldata == NULL) {
- printf("al%d: no memory for list buffers!\n", unit);
- bus_teardown_intr(dev, sc->al_irq, sc->al_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->al_irq);
- bus_release_resource(dev, AL_RES, AL_RID, sc->al_res);
- error = ENXIO;
- goto fail;
- }
- bzero(sc->al_ldata, sizeof(struct al_list_data));
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_softc = sc;
- ifp->if_unit = unit;
- ifp->if_name = "al";
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = al_ioctl;
- ifp->if_output = ether_output;
- ifp->if_start = al_start;
- ifp->if_watchdog = al_watchdog;
- ifp->if_init = al_init;
- ifp->if_baudrate = 10000000;
- ifp->if_snd.ifq_maxlen = AL_TX_LIST_CNT - 1;
-
- /*
- * Do MII setup.
- */
- if (mii_phy_probe(dev, &sc->al_miibus,
- al_ifmedia_upd, al_ifmedia_sts)) {
- printf("al%d: MII without any PHY!\n", sc->al_unit);
- bus_teardown_intr(dev, sc->al_irq, sc->al_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->al_irq);
- bus_release_resource(dev, AL_RES, AL_RID, sc->al_res);
- error = ENXIO;
- goto fail;
- }
-
- /*
- * Call MI attach routines.
- */
- if_attach(ifp);
- ether_ifattach(ifp);
-
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-
-fail:
- splx(s);
- return(error);
-}
-
-static int al_detach(dev)
- device_t dev;
-{
- struct al_softc *sc;
- struct ifnet *ifp;
- int s;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- ifp = &sc->arpcom.ac_if;
-
- al_reset(sc);
- al_stop(sc);
- if_detach(ifp);
-
- bus_generic_detach(dev);
- device_delete_child(dev, sc->al_miibus);
-
- bus_teardown_intr(dev, sc->al_irq, sc->al_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->al_irq);
- bus_release_resource(dev, AL_RES, AL_RID, sc->al_res);
-
- contigfree(sc->al_ldata, sizeof(struct al_list_data), M_DEVBUF);
-
- splx(s);
-
- return(0);
-}
-
-/*
- * Initialize the transmit descriptors.
- */
-static int al_list_tx_init(sc)
- struct al_softc *sc;
-{
- struct al_chain_data *cd;
- struct al_list_data *ld;
- int i;
-
- cd = &sc->al_cdata;
- ld = sc->al_ldata;
- for (i = 0; i < AL_TX_LIST_CNT; i++) {
- if (i == (AL_TX_LIST_CNT - 1)) {
- ld->al_tx_list[i].al_nextdesc =
- &ld->al_tx_list[0];
- ld->al_tx_list[i].al_next =
- vtophys(&ld->al_tx_list[0]);
- } else {
- ld->al_tx_list[i].al_nextdesc =
- &ld->al_tx_list[i + 1];
- ld->al_tx_list[i].al_next =
- vtophys(&ld->al_tx_list[i + 1]);
- }
- ld->al_tx_list[i].al_mbuf = NULL;
- ld->al_tx_list[i].al_data = 0;
- ld->al_tx_list[i].al_ctl = 0;
- }
-
- cd->al_tx_prod = cd->al_tx_cons = cd->al_tx_cnt = 0;
-
- return(0);
-}
-
-
-/*
- * Initialize the RX descriptors and allocate mbufs for them. Note that
- * we arrange the descriptors in a closed ring, so that the last descriptor
- * points back to the first.
- */
-static int al_list_rx_init(sc)
- struct al_softc *sc;
-{
- struct al_chain_data *cd;
- struct al_list_data *ld;
- int i;
-
- cd = &sc->al_cdata;
- ld = sc->al_ldata;
-
- for (i = 0; i < AL_RX_LIST_CNT; i++) {
- if (al_newbuf(sc, &ld->al_rx_list[i], NULL) == ENOBUFS)
- return(ENOBUFS);
- if (i == (AL_RX_LIST_CNT - 1)) {
- ld->al_rx_list[i].al_nextdesc =
- &ld->al_rx_list[0];
- ld->al_rx_list[i].al_next =
- vtophys(&ld->al_rx_list[0]);
- } else {
- ld->al_rx_list[i].al_nextdesc =
- &ld->al_rx_list[i + 1];
- ld->al_rx_list[i].al_next =
- vtophys(&ld->al_rx_list[i + 1]);
- }
- }
-
- cd->al_rx_prod = 0;
-
- return(0);
-}
-
-/*
- * Initialize an RX descriptor and attach an MBUF cluster.
- */
-static int al_newbuf(sc, c, m)
- struct al_softc *sc;
- struct al_desc *c;
- struct mbuf *m;
-{
- struct mbuf *m_new = NULL;
-
- if (m == NULL) {
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("al%d: no memory for rx list "
- "-- packet dropped!\n", sc->al_unit);
- return(ENOBUFS);
- }
-
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- printf("al%d: no memory for rx list "
- "-- packet dropped!\n", sc->al_unit);
- m_freem(m_new);
- return(ENOBUFS);
- }
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- } else {
- m_new = m;
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- m_new->m_data = m_new->m_ext.ext_buf;
- }
-
- m_adj(m_new, sizeof(u_int64_t));
-
- c->al_mbuf = m_new;
- c->al_data = vtophys(mtod(m_new, caddr_t));
- c->al_ctl = AL_RXCTL_RLINK | AL_RXLEN;
- c->al_status = AL_RXSTAT_OWN;
-
- return(0);
-}
-
-/*
- * A frame has been uploaded: pass the resulting mbuf chain up to
- * the higher level protocols.
- */
-static void al_rxeof(sc)
- struct al_softc *sc;
-{
- struct ether_header *eh;
- struct mbuf *m;
- struct ifnet *ifp;
- struct al_desc *cur_rx;
- int i, total_len = 0;
- u_int32_t rxstat;
-
- ifp = &sc->arpcom.ac_if;
-
- i = sc->al_cdata.al_rx_prod;
-
- while(!(sc->al_ldata->al_rx_list[i].al_status & AL_RXSTAT_OWN)) {
- struct mbuf *m0 = NULL;
-
- cur_rx = &sc->al_ldata->al_rx_list[i];
- rxstat = cur_rx->al_status;
- m = cur_rx->al_mbuf;
- cur_rx->al_mbuf = NULL;
- total_len = AL_RXBYTES(rxstat);
- AL_INC(i, AL_RX_LIST_CNT);
-
- /*
- * If an error occurs, update stats, clear the
- * status word and leave the mbuf cluster in place:
- * it should simply get re-used next time this descriptor
- * comes up in the ring.
- */
- if (rxstat & AL_RXSTAT_RXERR) {
- ifp->if_ierrors++;
- if (rxstat & AL_RXSTAT_COLLSEEN)
- ifp->if_collisions++;
- al_newbuf(sc, cur_rx, m);
- al_init(sc);
- return;
- }
-
- /* No errors; receive the packet. */
- total_len -= ETHER_CRC_LEN;
-
- m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
- total_len + ETHER_ALIGN, 0, ifp, NULL);
- al_newbuf(sc, cur_rx, m);
- if (m0 == NULL) {
- ifp->if_ierrors++;
- continue;
- }
- m_adj(m0, ETHER_ALIGN);
- m = m0;
-
- ifp->if_ipackets++;
- eh = mtod(m, struct ether_header *);
-
- /*
- * Handle BPF listeners. Let the BPF user see the packet, but
- * don't pass it up to the ether_input() layer unless it's
- * a broadcast packet, multicast packet, matches our ethernet
- * address or the interface is in promiscuous mode.
- */
- if (ifp->if_bpf) {
- bpf_mtap(ifp, m);
- if (ifp->if_flags & IFF_PROMISC &&
- (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
- ETHER_ADDR_LEN) &&
- (eh->ether_dhost[0] & 1) == 0)) {
- m_freem(m);
- continue;
- }
- }
-
- /* Remove header from mbuf and pass it on. */
- m_adj(m, sizeof(struct ether_header));
- ether_input(ifp, eh, m);
- }
-
- sc->al_cdata.al_rx_prod = i;
-
- return;
-}
-
-/*
- * A frame was downloaded to the chip. It's safe for us to clean up
- * the list buffers.
- */
-
-static void al_txeof(sc)
- struct al_softc *sc;
-{
- struct al_desc *cur_tx = NULL;
- struct ifnet *ifp;
- u_int32_t idx;
-
- ifp = &sc->arpcom.ac_if;
-
- /* Clear the timeout timer. */
- ifp->if_timer = 0;
-
- /*
- * Go through our tx list and free mbufs for those
- * frames that have been transmitted.
- */
- idx = sc->al_cdata.al_tx_cons;
- while(idx != sc->al_cdata.al_tx_prod) {
- u_int32_t txstat;
-
- cur_tx = &sc->al_ldata->al_tx_list[idx];
- txstat = cur_tx->al_status;
-
- if (txstat & AL_TXSTAT_OWN)
- break;
-
- if (!(cur_tx->al_ctl & AL_TXCTL_LASTFRAG)) {
- sc->al_cdata.al_tx_cnt--;
- AL_INC(idx, AL_TX_LIST_CNT);
- continue;
- }
-
- if (txstat & AL_TXSTAT_ERRSUM) {
- ifp->if_oerrors++;
- if (txstat & AL_TXSTAT_EXCESSCOLL)
- ifp->if_collisions++;
- if (txstat & AL_TXSTAT_LATECOLL)
- ifp->if_collisions++;
- al_init(sc);
- return;
- }
-
- ifp->if_collisions += (txstat & AL_TXSTAT_COLLCNT) >> 3;
-
- ifp->if_opackets++;
- if (cur_tx->al_mbuf != NULL) {
- m_freem(cur_tx->al_mbuf);
- cur_tx->al_mbuf = NULL;
- }
-
- sc->al_cdata.al_tx_cnt--;
- AL_INC(idx, AL_TX_LIST_CNT);
- ifp->if_timer = 0;
- }
-
- sc->al_cdata.al_tx_cons = idx;
-
- if (cur_tx != NULL)
- ifp->if_flags &= ~IFF_OACTIVE;
-
- return;
-}
-
-static void al_tick(xsc)
- void *xsc;
-{
- struct al_softc *sc;
- struct mii_data *mii;
- int s;
-
- s = splimp();
-
- sc = xsc;
- mii = device_get_softc(sc->al_miibus);
- mii_tick(mii);
-
- sc->al_stat_ch = timeout(al_tick, sc, hz);
-
- splx(s);
-
- return;
-};
-
-static void al_intr(arg)
- void *arg;
-{
- struct al_softc *sc;
- struct ifnet *ifp;
- u_int32_t status;
-
-
- sc = arg;
- ifp = &sc->arpcom.ac_if;
-
- /* Supress unwanted interrupts */
- if (!(ifp->if_flags & IFF_UP)) {
- al_stop(sc);
- return;
- }
-
- /* Disable interrupts. */
- CSR_WRITE_4(sc, AL_IMR, 0x00000000);
-
- for (;;) {
- status = CSR_READ_4(sc, AL_ISR);
- if (status)
- CSR_WRITE_4(sc, AL_ISR, status);
-
- if ((status & AL_INTRS) == 0)
- break;
-
- if ((status & AL_ISR_TX_OK) ||
- (status & AL_ISR_TX_NOBUF))
- al_txeof(sc);
-
- if (status & AL_ISR_TX_IDLE) {
- al_txeof(sc);
- if (sc->al_cdata.al_tx_cnt) {
- AL_SETBIT(sc, AL_NETCFG, AL_NETCFG_TX_ON);
- CSR_WRITE_4(sc, AL_TXSTART, 0xFFFFFFFF);
- }
- }
-
- if (status & AL_ISR_TX_UNDERRUN) {
- u_int32_t cfg;
- cfg = CSR_READ_4(sc, AL_NETCFG);
- if ((cfg & AL_NETCFG_TX_THRESH) == AL_TXTHRESH_160BYTES)
- AL_SETBIT(sc, AL_NETCFG, AL_NETCFG_STORENFWD);
- else
- CSR_WRITE_4(sc, AL_NETCFG, cfg + 0x4000);
- }
-
- if (status & AL_ISR_RX_OK)
- al_rxeof(sc);
-
- if ((status & AL_ISR_RX_WATDOGTIMEO) ||
- (status & AL_ISR_RX_IDLE) ||
- (status & AL_ISR_RX_NOBUF)) {
- al_rxeof(sc);
- al_init(sc);
- }
-
- if (status & AL_ISR_BUS_ERR) {
- al_reset(sc);
- al_init(sc);
- }
- }
-
- /* Re-enable interrupts. */
- CSR_WRITE_4(sc, AL_IMR, AL_INTRS);
-
- if (ifp->if_snd.ifq_head != NULL) {
- al_start(ifp);
- }
-
- return;
-}
-
-/*
- * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
- * pointers to the fragment pointers.
- */
-static int al_encap(sc, m_head, txidx)
- struct al_softc *sc;
- struct mbuf *m_head;
- u_int32_t *txidx;
-{
- struct al_desc *f = NULL;
- struct mbuf *m;
- int frag, cur, cnt = 0;
-
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- m = m_head;
- cur = frag = *txidx;
-
- for (m = m_head; m != NULL; m = m->m_next) {
- if (m->m_len != 0) {
-#ifdef AL_TX_STALL_WAR
- /*
- * Work around some strange behavior in the Comet. For
- * some reason, the transmitter will sometimes wedge if
- * we queue up a descriptor chain that wraps from the end
- * of the transmit list back to the beginning. If we reach
- * the end of the list and still have more packets to queue,
- * don't queue them now: end the transmit session here and
- * then wait until it finishes before sending the other
- * packets.
- */
- if (*txidx != sc->al_cdata.al_tx_prod &&
- frag == (AL_TX_LIST_CNT - 1))
- return(ENOBUFS);
-#endif
- if ((AL_TX_LIST_CNT -
- (sc->al_cdata.al_tx_cnt + cnt)) < 2)
- return(ENOBUFS);
- f = &sc->al_ldata->al_tx_list[frag];
- f->al_ctl = AL_TXCTL_TLINK | m->m_len;
- if (cnt == 0) {
- f->al_status = 0;
- f->al_ctl |= AL_TXCTL_FIRSTFRAG;
- } else
- f->al_status = AL_TXSTAT_OWN;
- f->al_data = vtophys(mtod(m, vm_offset_t));
- cur = frag;
- AL_INC(frag, AL_TX_LIST_CNT);
- cnt++;
- }
- }
-
- if (m != NULL)
- return(ENOBUFS);
-
- sc->al_ldata->al_tx_list[cur].al_mbuf = m_head;
- sc->al_ldata->al_tx_list[cur].al_ctl |=
- AL_TXCTL_LASTFRAG|AL_TXCTL_FINT;
- sc->al_ldata->al_tx_list[*txidx].al_status |= AL_TXSTAT_OWN;
- sc->al_cdata.al_tx_cnt += cnt;
- *txidx = frag;
-
- return(0);
-}
-
-/*
- * Main transmit routine. To avoid having to do mbuf copies, we put pointers
- * to the mbuf data regions directly in the transmit lists. We also save a
- * copy of the pointers since the transmit list fragment pointers are
- * physical addresses.
- */
-
-static void al_start(ifp)
- struct ifnet *ifp;
-{
- struct al_softc *sc;
- struct mbuf *m_head = NULL;
- u_int32_t idx;
-
- sc = ifp->if_softc;
-
- if (ifp->if_flags & IFF_OACTIVE)
- return;
-
- idx = sc->al_cdata.al_tx_prod;
-
- while(sc->al_ldata->al_tx_list[idx].al_mbuf == NULL) {
- IF_DEQUEUE(&ifp->if_snd, m_head);
- if (m_head == NULL)
- break;
-
- if (al_encap(sc, m_head, &idx)) {
- IF_PREPEND(&ifp->if_snd, m_head);
- ifp->if_flags |= IFF_OACTIVE;
- break;
- }
-
- /*
- * If there's a BPF listener, bounce a copy of this frame
- * to him.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp, m_head);
- }
-
- /* Transmit */
- sc->al_cdata.al_tx_prod = idx;
- CSR_WRITE_4(sc, AL_TXSTART, 0xFFFFFFFF);
-
- /*
- * Set a timeout in case the chip goes out to lunch.
- */
- ifp->if_timer = 5;
-
- return;
-}
-
-static void al_init(xsc)
- void *xsc;
-{
- struct al_softc *sc = xsc;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- struct mii_data *mii;
- int s;
-
- s = splimp();
-
- mii = device_get_softc(sc->al_miibus);
-
- /*
- * Cancel pending I/O and free all RX/TX buffers.
- */
- al_stop(sc);
- al_reset(sc);
-
- /*
- * Set cache alignment and burst length.
- */
- CSR_WRITE_4(sc, AL_BUSCTL, AL_BUSCTL_ARBITRATION);
- AL_SETBIT(sc, AL_BUSCTL, AL_BURSTLEN_16LONG);
- switch(sc->al_cachesize) {
- case 32:
- AL_SETBIT(sc, AL_BUSCTL, AL_CACHEALIGN_32LONG);
- break;
- case 16:
- AL_SETBIT(sc, AL_BUSCTL, AL_CACHEALIGN_16LONG);
- break;
- case 8:
- AL_SETBIT(sc, AL_BUSCTL, AL_CACHEALIGN_8LONG);
- break;
- case 0:
- default:
- AL_SETBIT(sc, AL_BUSCTL, AL_CACHEALIGN_NONE);
- break;
- }
-
- AL_CLRBIT(sc, AL_NETCFG, AL_NETCFG_HEARTBEAT);
- AL_CLRBIT(sc, AL_NETCFG, AL_NETCFG_STORENFWD);
-
- AL_CLRBIT(sc, AL_NETCFG, AL_NETCFG_TX_THRESH);
-
- if (IFM_SUBTYPE(sc->ifmedia.ifm_media) == IFM_10_T)
- AL_SETBIT(sc, AL_NETCFG, AL_TXTHRESH_160BYTES);
- else
- AL_SETBIT(sc, AL_NETCFG, AL_TXTHRESH_72BYTES);
-
- /* Init our MAC address */
- CSR_WRITE_4(sc, AL_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
- CSR_WRITE_4(sc, AL_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
-
- /* Init circular RX list. */
- if (al_list_rx_init(sc) == ENOBUFS) {
- printf("al%d: initialization failed: no "
- "memory for rx buffers\n", sc->al_unit);
- al_stop(sc);
- (void)splx(s);
- return;
- }
-
- /*
- * Init tx descriptors.
- */
- al_list_tx_init(sc);
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC) {
- AL_SETBIT(sc, AL_NETCFG, AL_NETCFG_RX_PROMISC);
- } else {
- AL_CLRBIT(sc, AL_NETCFG, AL_NETCFG_RX_PROMISC);
- }
-
- /*
- * Load the multicast filter.
- */
- al_setmulti(sc);
-
- /*
- * Load the address of the RX list.
- */
- CSR_WRITE_4(sc, AL_RXADDR, vtophys(&sc->al_ldata->al_rx_list[0]));
- CSR_WRITE_4(sc, AL_TXADDR, vtophys(&sc->al_ldata->al_tx_list[0]));
-
- /*
- * Enable interrupts.
- */
- CSR_WRITE_4(sc, AL_IMR, AL_INTRS);
- CSR_WRITE_4(sc, AL_ISR, 0xFFFFFFFF);
-
- /* Enable receiver and transmitter. */
- AL_SETBIT(sc, AL_NETCFG, AL_NETCFG_TX_ON|AL_NETCFG_RX_ON);
- CSR_WRITE_4(sc, AL_RXSTART, 0xFFFFFFFF);
-
- mii_mediachg(mii);
-
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
-
- (void)splx(s);
-
- sc->al_stat_ch = timeout(al_tick, sc, hz);
-
- return;
-}
-
-/*
- * Set media options.
- */
-static int al_ifmedia_upd(ifp)
- struct ifnet *ifp;
-{
- struct al_softc *sc;
-
- sc = ifp->if_softc;
-
- if (ifp->if_flags & IFF_UP)
- al_init(sc);
-
- return(0);
-}
-
-/*
- * Report current media status.
- */
-static void al_ifmedia_sts(ifp, ifmr)
- struct ifnet *ifp;
- struct ifmediareq *ifmr;
-{
- struct al_softc *sc;
- struct mii_data *mii;
-
- sc = ifp->if_softc;
-
- mii = device_get_softc(sc->al_miibus);
- mii_pollstat(mii);
- ifmr->ifm_active = mii->mii_media_active;
- ifmr->ifm_status = mii->mii_media_status;
-
- return;
-}
-
-static int al_ioctl(ifp, command, data)
- struct ifnet *ifp;
- u_long command;
- caddr_t data;
-{
- struct al_softc *sc = ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *) data;
- struct mii_data *mii;
- int s, error = 0;
-
- s = splimp();
-
- switch(command) {
- case SIOCSIFADDR:
- case SIOCGIFADDR:
- case SIOCSIFMTU:
- error = ether_ioctl(ifp, command, data);
- break;
- case SIOCSIFFLAGS:
- if (ifp->if_flags & IFF_UP) {
- al_init(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- al_stop(sc);
- }
- error = 0;
- break;
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- al_setmulti(sc);
- error = 0;
- break;
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- mii = device_get_softc(sc->al_miibus);
- error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
- break;
- default:
- error = EINVAL;
- break;
- }
-
- (void)splx(s);
-
- return(error);
-}
-
-static void al_watchdog(ifp)
- struct ifnet *ifp;
-{
- struct al_softc *sc;
-
- sc = ifp->if_softc;
-
- ifp->if_oerrors++;
- printf("al%d: watchdog timeout\n", sc->al_unit);
-
- al_stop(sc);
- al_reset(sc);
- al_init(sc);
-
- if (ifp->if_snd.ifq_head != NULL)
- al_start(ifp);
-
- return;
-}
-
-/*
- * Stop the adapter and free any mbufs allocated to the
- * RX and TX lists.
- */
-static void al_stop(sc)
- struct al_softc *sc;
-{
- register int i;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_timer = 0;
-
- untimeout(al_tick, sc, sc->al_stat_ch);
- AL_CLRBIT(sc, AL_NETCFG, (AL_NETCFG_RX_ON|AL_NETCFG_TX_ON));
- CSR_WRITE_4(sc, AL_IMR, 0x00000000);
- CSR_WRITE_4(sc, AL_TXADDR, 0x00000000);
- CSR_WRITE_4(sc, AL_RXADDR, 0x00000000);
-
- /*
- * Free data in the RX lists.
- */
- for (i = 0; i < AL_RX_LIST_CNT; i++) {
- if (sc->al_ldata->al_rx_list[i].al_mbuf != NULL) {
- m_freem(sc->al_ldata->al_rx_list[i].al_mbuf);
- sc->al_ldata->al_rx_list[i].al_mbuf = NULL;
- }
- }
- bzero((char *)&sc->al_ldata->al_rx_list,
- sizeof(sc->al_ldata->al_rx_list));
-
- /*
- * Free the TX list buffers.
- */
- for (i = 0; i < AL_TX_LIST_CNT; i++) {
- if (sc->al_ldata->al_tx_list[i].al_mbuf != NULL) {
- m_freem(sc->al_ldata->al_tx_list[i].al_mbuf);
- sc->al_ldata->al_tx_list[i].al_mbuf = NULL;
- }
- }
-
- bzero((char *)&sc->al_ldata->al_tx_list,
- sizeof(sc->al_ldata->al_tx_list));
-
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-
- return;
-}
-
-/*
- * Stop all chip I/O so that the kernel's probe routines don't
- * get confused by errant DMAs when rebooting.
- */
-static void al_shutdown(dev)
- device_t dev;
-{
- struct al_softc *sc;
-
- sc = device_get_softc(dev);
- /*al_stop(sc); */
-
- return;
-}
diff --git a/sys/pci/if_alreg.h b/sys/pci/if_alreg.h
deleted file mode 100644
index 243903e..0000000
--- a/sys/pci/if_alreg.h
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * COMET register definitions.
- */
-
-#define AL_BUSCTL 0x00 /* bus control */
-#define AL_TXSTART 0x08 /* tx start demand */
-#define AL_RXSTART 0x10 /* rx start demand */
-#define AL_RXADDR 0x18 /* rx descriptor list start addr */
-#define AL_TXADDR 0x20 /* tx descriptor list start addr */
-#define AL_ISR 0x28 /* interrupt status register */
-#define AL_NETCFG 0x30 /* network config register */
-#define AL_IMR 0x38 /* interrupt mask */
-#define AL_FRAMESDISCARDED 0x40 /* # of discarded frames */
-#define AL_SIO 0x48 /* MII and ROM/EEPROM access */
-#define AL_RESERVED 0x50
-#define AL_GENTIMER 0x58 /* general timer */
-#define AL_GENPORT 0x60 /* general purpose port */
-#define AL_WAKEUP_CTL 0x68 /* wake-up control/status register */
-#define AL_WAKEUP_PAT 0x70 /* wake-up pattern data register */
-#define AL_WATCHDOG 0x78 /* watchdog timer */
-#define AL_ISR2 0x80 /* ISR assist register */
-#define AL_IMR2 0x84 /* IRM assist register */
-#define AL_COMMAND 0x88 /* command register */
-#define AL_PCIPERF 0x8C /* pci perf counter */
-#define AL_PWRMGMT 0x90 /* pwr management command/status */
-#define AL_TXBURST 0x9C /* tx burst counter/timeout */
-#define AL_FLASHPROM 0xA0 /* flash(boot) PROM port */
-#define AL_PAR0 0xA4 /* station address */
-#define AL_PAR1 0xA8 /* station address */
-#define AL_MAR0 0xAC /* multicast hash filter */
-#define AL_MAR1 0xB0 /* multicast hash filter */
-#define AL_BMCR 0xB4 /* built in PHY control */
-#define AL_BMSR 0xB8 /* built in PHY status */
-#define AL_VENID 0xBC /* built in PHY ID0 */
-#define AL_DEVID 0xC0 /* built in PHY ID1 */
-#define AL_ANAR 0xC4 /* built in PHY autoneg advert */
-#define AL_LPAR 0xC8 /* bnilt in PHY link part. ability */
-#define AL_ANER 0xCC /* built in PHY autoneg expansion */
-#define AL_PHY_MODECTL 0xD0 /* mode control */
-#define AL_PHY_CONFIG 0xD4 /* config info and inter status */
-#define AL_PHY_INTEN 0xD8 /* interrupto enable */
-#define AL_PHY_MODECTL_100TX 0xDC /* 100baseTX control/status */
-
-/*
- * Bus control bits.
- */
-#define AL_BUSCTL_RESET 0x00000001
-#define AL_BUSCTL_ARBITRATION 0x00000002
-#define AL_BUSCTL_SKIPLEN 0x0000007C
-#define AL_BUSCTL_BIGENDIAN 0x00000080
-#define AL_BUSCTL_BURSTLEN 0x00003F00
-#define AL_BUSCTL_CACHEALIGN 0x0000C000
-#define AL_BUSCTL_XMITPOLL 0x00060000
-#define AL_BUSCTL_BUF_BIGENDIAN 0x00100000
-#define AL_BUSCTL_READMULTI 0x00200000
-#define AL_BUSCTL_READLINE 0x00800000
-#define AL_BUSCTL_WRITEINVAL 0x01000000
-
-#define AL_SKIPLEN_1LONG 0x00000004
-#define AL_SKIPLEN_2LONG 0x00000008
-#define AL_SKIPLEN_3LONG 0x00000010
-#define AL_SKIPLEN_4LONG 0x00000020
-#define AL_SKIPLEN_5LONG 0x00000040
-
-#define AL_BURSTLEN_UNLIMIT 0x00000000
-#define AL_BURSTLEN_1LONG 0x00000100
-#define AL_BURSTLEN_2LONG 0x00000200
-#define AL_BURSTLEN_4LONG 0x00000400
-#define AL_BURSTLEN_8LONG 0x00000800
-#define AL_BURSTLEN_16LONG 0x00001000
-#define AL_BURSTLEN_32LONG 0x00002000
-
-#define AL_CACHEALIGN_NONE 0x00000000
-#define AL_CACHEALIGN_8LONG 0x00004000
-#define AL_CACHEALIGN_16LONG 0x00008000
-#define AL_CACHEALIGN_32LONG 0x0000C000
-
-#define AL_TXPOLL_OFF 0x00000000
-#define AL_TXPOLL_200U 0x00020000
-#define AX_TXPOLL_800U 0x00040000
-#define AL_TXPOLL_1600U 0x00060000
-
-/*
- * Interrupt status bits.
- */
-#define AL_ISR_TX_OK 0x00000001
-#define AL_ISR_TX_IDLE 0x00000002
-#define AL_ISR_TX_NOBUF 0x00000004
-#define AL_ISR_TX_JABBERTIMEO 0x00000008
-#define AL_ISR_TX_UNDERRUN 0x00000020
-#define AL_ISR_RX_OK 0x00000040
-#define AL_ISR_RX_NOBUF 0x00000080
-#define AL_ISR_RX_IDLE 0x00000100
-#define AL_ISR_RX_WATDOGTIMEO 0x00000200
-#define AL_ISR_TIMER_EXPIRED 0x00000800
-#define AL_ISR_BUS_ERR 0x00002000
-#define AL_ISR_ABNORMAL 0x00008000
-#define AL_ISR_NORMAL 0x00010000
-#define AL_ISR_RX_STATE 0x000E0000
-#define AL_ISR_TX_STATE 0x00700000
-#define AL_ISR_BUSERRTYPE 0x03800000
-
-#define AL_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
-#define AL_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
-#define AL_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
-#define AL_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
-#define AL_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
-#define AL_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */
-#define AL_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
-#define AL_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
-
-#define AL_TXSTATE_RESET 0x00000000 /* 000 - reset */
-#define AL_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
-#define AL_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
-#define AL_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
-#define AL_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
-#define AL_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
-#define AL_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
-#define AL_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
-
-/*
- * Network config bits.
- */
-#define AL_NETCFG_RX_ON 0x00000002
-#define AL_NETCFG_RX_BADFRAMES 0x00000008
-#define AL_NETCFG_RX_BACKOFF 0x00000020
-#define AL_NETCFG_RX_PROMISC 0x00000040
-#define AL_NETCFG_RX_ALLMULTI 0x00000080
-#define AL_NETCFG_OPMODE 0x00000C00
-#define AL_NETCFG_FORCECOLL 0x00001000
-#define AL_NETCFG_TX_ON 0x00002000
-#define AL_NETCFG_TX_THRESH 0x0000C000
-#define AL_NETCFG_HEARTBEAT 0x00080000 /* 0 == ON, 1 == OFF */
-#define AL_NETCFG_STORENFWD 0x00200000
-
-#define AL_OPMODE_NORM 0x00000000
-#define AL_OPMODE_INTLOOP 0x00000400
-#define AL_OPMODE_EXTLOOP 0x00000800
-
-#define AL_TXTHRESH_72BYTES 0x00000000
-#define AL_TXTHRESH_96BYTES 0x00004000
-#define AL_TXTHRESH_128BYTES 0x00008000
-#define AL_TXTHRESH_160BYTES 0x0000C000
-
-/*
- * Interrupt mask bits.
- */
-#define AL_IMR_TX_OK 0x00000001
-#define AL_IMR_TX_IDLE 0x00000002
-#define AL_IMR_TX_NOBUF 0x00000004
-#define AL_IMR_TX_JABBERTIMEO 0x00000008
-#define AL_IMR_TX_UNDERRUN 0x00000020
-#define AL_IMR_RX_OK 0x00000040
-#define AL_IMR_RX_NOBUF 0x00000080
-#define AL_IMR_RX_IDLE 0x00000100
-#define AL_IMR_RX_WATDOGTIMEO 0x00000200
-#define AL_IMR_TIMER_EXPIRED 0x00000800
-#define AL_IMR_BUS_ERR 0x00002000
-#define AL_IMR_ABNORMAL 0x00008000
-#define AL_IMR_NORMAL 0x00010000
-
-#define AL_INTRS \
- (AL_IMR_RX_OK|AL_IMR_TX_OK|AL_IMR_RX_NOBUF|AL_IMR_RX_WATDOGTIMEO|\
- AL_IMR_TX_NOBUF|AL_IMR_TX_UNDERRUN|AL_IMR_BUS_ERR| \
- AL_IMR_ABNORMAL|AL_IMR_NORMAL|AL_IMR_TX_IDLE|AL_IMR_RX_IDLE)
-
-/*
- * Missed packer register.
- */
-#define AL_MISSEDPKT_CNT 0x0000FFFF
-#define AL_MISSEDPKT_OFLOW 0x00010000
-
-/*
- * Serial I/O (EEPROM/ROM) bits.
- */
-#define AL_SIO_EE_CS 0x00000001 /* EEPROM chip select */
-#define AL_SIO_EE_CLK 0x00000002 /* EEPROM clock */
-#define AL_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */
-#define AL_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */
-#define AL_SIO_EESEL 0x00000800
-#define AL_SIO_ROMCTL_WRITE 0x00002000
-#define AL_SIO_ROMCTL_READ 0x00004000
-#define AL_SIO_MII_CLK 0x00010000 /* MDIO clock */
-#define AL_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */
-#define AL_SIO_MII_DIR 0x00040000 /* MDIO dir */
-#define AL_SIO_MII_DATAIN 0x00080000 /* MDIO data in */
-
-#define AL_EECMD_WRITE 0x140
-#define AL_EECMD_READ 0x180
-#define AL_EECMD_ERASE 0x1c0
-
-#define AL_EE_NODEADDR_OFFSET 0x70
-#define AL_EE_NODEADDR 4
-
-/*
- * General purpose timer register
- */
-#define AL_TIMER_VALUE 0x0000FFFF
-#define AL_TIMER_CONTINUOUS 0x00010000
-
-/*
- * Wakeup control/status register.
- */
-#define AL_WU_LINKSTS 0x00000001 /* link status changed */
-#define AL_WU_MAGICPKT 0x00000002 /* magic packet received */
-#define AL_WU_WUPKT 0x00000004 /* wake up pkt received */
-#define AL_WU_LINKSTS_ENB 0x00000100 /* enable linksts event */
-#define AL_WU_MAGICPKT_ENB 0x00000200 /* enable magicpkt event */
-#define AL_WU_WUPKT_ENB 0x00000400 /* enable wakeup pkt event */
-#define AL_WU_LINKON_ENB 0x00010000 /* enable link on detect */
-#define AL_WU_LINKOFF_ENB 0x00020000 /* enable link off detect */
-#define AL_WU_WKUPMATCH_PAT5 0x02000000 /* enable wkup pat 5 match */
-#define AL_WU_WKUPMATCH_PAT4 0x04000000 /* enable wkup pat 4 match */
-#define AL_WU_WKUPMATCH_PAT3 0x08000000 /* enable wkup pat 3 match */
-#define AL_WU_WKUPMATCH_PAT2 0x10000000 /* enable wkup pat 2 match */
-#define AL_WU_WKUPMATCH_PAT1 0x20000000 /* enable wkup pat 1 match */
-#define AL_WU_CRCTYPE 0x40000000 /* crc: 0=0000, 1=ffff */
-
-/*
- * Wakeup pattern structure.
- */
-struct al_wu_pattern {
- u_int32_t al_wu_bits[4];
-};
-
-struct al_wakeup {
- struct al_wu_pattern al_wu_pat;
- u_int16_t al_wu_crc1;
- u_int16_t al_wu_offset1;
-};
-
-struct al_wakup_record {
- struct al_wakeup al_wakeup[5];
-};
-
-/*
- * Watchdog timer register.
- */
-#define AL_WDOG_JABDISABLE 0x00000001
-#define AL_WDOG_NONJABBER 0x00000002
-#define AL_WDOG_JABCLK 0x00000004
-#define AL_WDOG_RXWDOG_DIS 0x00000010
-#define AL_WDOG_RXWDOG_REL 0x00000020
-
-/*
- * Assistant status register.
- */
-#define AL_ISR2_ABNORMAL 0x00008000
-#define AL_ISR2_NORMAL 0x00010000
-#define AL_ISR2_RX_STATE 0x000E0000
-#define AL_ISR2_TX_STATE 0x00700000
-#define AL_ISR2_BUSERRTYPE 0x03800000
-#define AL_ISR2_PAUSE 0x04000000 /* PAUSE frame received */
-#define AL_ISR2_TX_DEFER 0x10000000
-#define AL_ISR2_XCVR_INT 0x20000000
-#define AL_ISR2_RX_EARLY 0x40000000
-#define AL_ISR2_TX_EARLY 0x80000000
-
-/*
- * Assistant mask register.
- */
-#define AL_IMR2_ABNORMAL 0x00008000
-#define AL_IMR2_NORMAL 0x00010000
-#define AL_IMR2_PAUSE 0x04000000 /* PAUSE frame received */
-#define AL_IMR2_TX_DEFER 0x10000000
-#define AL_IMR2_XCVR_INT 0x20000000
-#define AL_IMR2_RX_EARLY 0x40000000
-#define AL_IMR2_TX_EARLY 0x80000000
-
-/*
- * Command register, some bits loaded from EEPROM.
- */
-#define AL_CMD_TXURUN_REC 0x00000001 /* enable TX underflow recovery */
-#define AL_CMD_SOFTWARE_INT 0x00000002 /* software interrupt */
-#define AL_CMD_DRT 0x0000000C /* drain receive threshold */
-#define AL_CMD_RXTHRESH_ENB 0x00000010 /* rx threshold enable */
-#define AL_CMD_PAUSE 0x00000020
-#define AL_CMD_RST_WU_PTR 0x00000040 /* reset wakeup pattern reg. */
-/* Values below loaded from EEPROM. */
-#define AL_CMD_WOL_ENB 0x00040000 /* WOL enable */
-#define AL_CMD_PM_ENB 0x00080000 /* pwr mgmt enable */
-#define AL_CMD_RX_FIFO 0x00300000
-#define AL_CMD_LED_MODE 0x00400000
-#define AL_CMD_CURRENT_MODE 0x70000000
-#define AL_CMD_D3COLD 0x80000000
-
-/*
- * PCI performance counter.
- */
-#define AL_PCI_DW_CNT 0x000000FF
-#define AL_PCI_CLK 0xFFFF0000
-
-/*
- * Power management command and status.
- */
-#define AL_PWRM_PWR_STATE 0x00000003
-#define AL_PWRM_PME_EN 0x00000100
-#define AL_PWRM_DSEL 0x00001E00
-#define AL_PWRM_DSCALE 0x00006000
-#define AL_PWRM_PME_STAT 0x00008000
-
-/*
- * TX burst count / timeout register.
- */
-#define AL_TXB_TIMEO 0x00000FFF
-#define AL_TXB_BURSTCNT 0x0000F000
-
-/*
- * Flash PROM register.
- */
-#define AL_PROM_DATA 0x0000000F
-#define AL_PROM_ADDR 0x01FFFFF0
-#define AL_PROM_WR_ENB 0x04000000
-#define AL_PROM_BRA16_ON 0x80000000
-
-/*
- * COMET TX/RX list structure.
- */
-
-struct al_desc {
- u_int32_t al_status;
- u_int32_t al_ctl;
- u_int32_t al_ptr1;
- u_int32_t al_ptr2;
- /* Driver specific stuff. */
-#ifdef __i386__
- u_int32_t al_pad;
-#endif
- struct mbuf *al_mbuf;
- struct al_desc *al_nextdesc;
-};
-
-#define al_data al_ptr1
-#define al_next al_ptr2
-
-#define AL_RXSTAT_FIFOOFLOW 0x00000001
-#define AL_RXSTAT_CRCERR 0x00000002
-#define AL_RXSTAT_DRIBBLE 0x00000004
-#define AL_RXSTAT_WATCHDOG 0x00000010
-#define AL_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */
-#define AL_RXSTAT_COLLSEEN 0x00000040
-#define AL_RXSTAT_GIANT 0x00000080
-#define AL_RXSTAT_LASTFRAG 0x00000100
-#define AL_RXSTAT_FIRSTFRAG 0x00000200
-#define AL_RXSTAT_MULTICAST 0x00000400
-#define AL_RXSTAT_RUNT 0x00000800
-#define AL_RXSTAT_RXTYPE 0x00003000
-#define AL_RXSTAT_RXERR 0x00008000
-#define AL_RXSTAT_RXLEN 0x3FFF0000
-#define AL_RXSTAT_OWN 0x80000000
-
-#define AL_RXBYTES(x) ((x & AL_RXSTAT_RXLEN) >> 16)
-#define AL_RXSTAT (AL_RXSTAT_FIRSTFRAG|AL_RXSTAT_LASTFRAG|AL_RXSTAT_OWN)
-
-#define AL_RXCTL_BUFLEN1 0x00000FFF
-#define AL_RXCTL_BUFLEN2 0x00FFF000
-#define AL_RXCTL_RLINK 0x01000000
-#define AL_RXCTL_RLAST 0x02000000
-
-#define AL_TXSTAT_DEFER 0x00000001
-#define AL_TXSTAT_UNDERRUN 0x00000002
-#define AL_TXSTAT_LINKFAIL 0x00000003
-#define AL_TXSTAT_COLLCNT 0x00000078
-#define AL_TXSTAT_SQE 0x00000080
-#define AL_TXSTAT_EXCESSCOLL 0x00000100
-#define AL_TXSTAT_LATECOLL 0x00000200
-#define AL_TXSTAT_NOCARRIER 0x00000400
-#define AL_TXSTAT_CARRLOST 0x00000800
-#define AL_TXSTAT_JABTIMEO 0x00004000
-#define AL_TXSTAT_ERRSUM 0x00008000
-#define AL_TXSTAT_OWN 0x80000000
-
-#define AL_TXCTL_BUFLEN1 0x000007FF
-#define AL_TXCTL_BUFLEN2 0x003FF800
-#define AL_TXCTL_PAD 0x00800000
-#define AL_TXCTL_TLINK 0x01000000
-#define AL_TXCTL_TLAST 0x02000000
-#define AL_TXCTL_NOCRC 0x04000000
-#define AL_TXCTL_FIRSTFRAG 0x20000000
-#define AL_TXCTL_LASTFRAG 0x40000000
-#define AL_TXCTL_FINT 0x80000000
-
-#define AL_MAXFRAGS 16
-#define AL_RX_LIST_CNT 64
-#define AL_TX_LIST_CNT 128
-#define AL_MIN_FRAMELEN 60
-#define AL_RXLEN 1536
-
-#define AL_INC(x, y) (x) = (x + 1) % y
-
-struct al_list_data {
- struct al_desc al_rx_list[AL_RX_LIST_CNT];
- struct al_desc al_tx_list[AL_TX_LIST_CNT];
-};
-
-struct al_chain_data {
- int al_tx_prod;
- int al_tx_cons;
- int al_tx_cnt;
- int al_rx_prod;
-};
-
-struct al_type {
- u_int16_t al_vid;
- u_int16_t al_did;
- char *al_name;
-};
-
-struct al_mii_frame {
- u_int8_t mii_stdelim;
- u_int8_t mii_opcode;
- u_int8_t mii_phyaddr;
- u_int8_t mii_regaddr;
- u_int8_t mii_turnaround;
- u_int16_t mii_data;
-};
-
-#define AL_MII_STARTDELIM 0x01
-#define AL_MII_READOP 0x02
-#define AL_MII_WRITEOP 0x01
-#define AL_MII_TURNAROUND 0x02
-
-struct al_softc {
- struct arpcom arpcom; /* interface info */
- struct ifmedia ifmedia; /* media info */
- bus_space_handle_t al_bhandle; /* bus space handle */
- bus_space_tag_t al_btag; /* bus space tag */
- struct resource *al_res;
- struct resource *al_irq;
- void *al_intrhand;
- device_t al_miibus;
- struct al_type *al_info; /* COMET adapter info */
- int al_did;
- u_int8_t al_unit; /* interface number */
- struct al_list_data *al_ldata;
- struct al_chain_data al_cdata;
- u_int8_t al_cachesize;
- struct callout_handle al_stat_ch;
-};
-
-/*
- * register space access macros
- */
-#define CSR_WRITE_4(sc, reg, val) \
- bus_space_write_4(sc->al_btag, sc->al_bhandle, reg, val)
-#define CSR_WRITE_2(sc, reg, val) \
- bus_space_write_2(sc->al_btag, sc->al_bbhandle, reg, val)
-#define CSR_WRITE_1(sc, reg, val) \
- bus_space_write_1(sc->al_btag, sc->al_bhandle, reg, val)
-
-#define CSR_READ_4(sc, reg) \
- bus_space_read_4(sc->al_btag, sc->al_bhandle, reg)
-#define CSR_READ_2(sc, reg) \
- bus_space_read_2(sc->al_btag, sc->al_bhandle, reg)
-#define CSR_READ_1(sc, reg) \
- bus_space_read_1(sc->al_btag, sc->al_bhandle, reg)
-
-#define AL_TIMEOUT 1000
-#define ETHER_ALIGN 2
-
-/*
- * General constants that are fun to know.
- *
- * ADMtek PCI vendor ID
- */
-#define AL_VENDORID 0x1317
-
-/*
- * AL981 device IDs.
- */
-#define AL_DEVICEID_AL981 0x0981
-
-/*
- * AN985 device IDs.
- */
-#define AL_DEVICEID_AN985 0x0985
-
-/*
- * PCI low memory base and low I/O base register, and
- * other PCI registers.
- */
-
-#define AL_PCI_VENDOR_ID 0x00
-#define AL_PCI_DEVICE_ID 0x02
-#define AL_PCI_COMMAND 0x04
-#define AL_PCI_STATUS 0x06
-#define AL_PCI_REVID 0x08
-#define AL_PCI_CLASSCODE 0x09
-#define AL_PCI_CACHELEN 0x0C
-#define AL_PCI_LATENCY_TIMER 0x0D
-#define AL_PCI_HEADER_TYPE 0x0E
-#define AL_PCI_LOIO 0x10
-#define AL_PCI_LOMEM 0x14
-#define AL_PCI_BIOSROM 0x30
-#define AL_PCI_INTLINE 0x3C
-#define AL_PCI_INTPIN 0x3D
-#define AL_PCI_MINGNT 0x3E
-#define AL_PCI_MINLAT 0x0F
-#define AL_PCI_RESETOPT 0x48
-#define AL_PCI_EEPROM_DATA 0x4C
-
-/* power management registers */
-#define AL_PCI_CAPID 0x44 /* 8 bits */
-#define AL_PCI_NEXTPTR 0x45 /* 8 bits */
-#define AL_PCI_PWRMGMTCAP 0x46 /* 16 bits */
-#define AL_PCI_PWRMGMTCTRL 0x48 /* 16 bits */
-
-#define AL_PSTATE_MASK 0x0003
-#define AL_PSTATE_D0 0x0000
-#define AL_PSTATE_D1 0x0001
-#define AL_PSTATE_D2 0x0002
-#define AL_PSTATE_D3 0x0003
-#define AL_PME_EN 0x0010
-#define AL_PME_STATUS 0x8000
-
-#ifdef __alpha__
-#undef vtophys
-#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
-#endif
diff --git a/sys/pci/if_ax.c b/sys/pci/if_ax.c
deleted file mode 100644
index e380a2b..0000000
--- a/sys/pci/if_ax.c
+++ /dev/null
@@ -1,2233 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * ASIX AX88140A and AX88141 fast ethernet PCI NIC driver.
- *
- * Written by Bill Paul <wpaul@ctr.columbia.edu>
- * Electrical Engineering Department
- * Columbia University, New York City
- */
-
-/*
- * The ASIX Electronics AX88140A is still another DEC 21x4x clone. It's
- * a reasonably close copy of the tulip, except for the receiver filter
- * programming. Where the DEC chip has a special setup frame that
- * needs to be downloaded into the transmit DMA engine, the ASIX chip
- * has a less complicated setup frame which is written into one of
- * the registers.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sockio.h>
-#include <sys/mbuf.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ethernet.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
-
-#include <net/bpf.h>
-
-#include <vm/vm.h> /* for vtophys */
-#include <vm/pmap.h> /* for vtophys */
-#include <machine/clock.h> /* for DELAY */
-#include <machine/bus_pio.h>
-#include <machine/bus_memio.h>
-#include <machine/bus.h>
-#include <machine/resource.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
-
-#include <pci/pcireg.h>
-#include <pci/pcivar.h>
-
-#define AX_USEIOSPACE
-
-/* #define AX_BACKGROUND_AUTONEG */
-
-#include <pci/if_axreg.h>
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-/*
- * Various supported device vendors/types and their names.
- */
-static struct ax_type ax_devs[] = {
- { AX_VENDORID, AX_DEVICEID_AX88140A,
- "ASIX AX88140A 10/100BaseTX" },
- { AX_VENDORID, AX_DEVICEID_AX88140A,
- "ASIX AX88141 10/100BaseTX" },
- { 0, 0, NULL }
-};
-
-/*
- * Various supported PHY vendors/types and their names. Note that
- * this driver will work with pretty much any MII-compliant PHY,
- * so failure to positively identify the chip is not a fatal error.
- */
-
-static struct ax_type ax_phys[] = {
- { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" },
- { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" },
- { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"},
- { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" },
- { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" },
- { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" },
- { 0, 0, "<MII-compliant physical interface>" }
-};
-
-static int ax_probe __P((device_t));
-static int ax_attach __P((device_t));
-static int ax_detach __P((device_t));
-
-static int ax_newbuf __P((struct ax_softc *,
- struct ax_chain_onefrag *,
- struct mbuf *));
-static int ax_encap __P((struct ax_softc *, struct ax_chain *,
- struct mbuf *));
-
-static void ax_rxeof __P((struct ax_softc *));
-static void ax_rxeoc __P((struct ax_softc *));
-static void ax_txeof __P((struct ax_softc *));
-static void ax_txeoc __P((struct ax_softc *));
-static void ax_intr __P((void *));
-static void ax_start __P((struct ifnet *));
-static int ax_ioctl __P((struct ifnet *, u_long, caddr_t));
-static void ax_init __P((void *));
-static void ax_stop __P((struct ax_softc *));
-static void ax_watchdog __P((struct ifnet *));
-static void ax_shutdown __P((device_t));
-static int ax_ifmedia_upd __P((struct ifnet *));
-static void ax_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
-
-static void ax_delay __P((struct ax_softc *));
-static void ax_eeprom_idle __P((struct ax_softc *));
-static void ax_eeprom_putbyte __P((struct ax_softc *, int));
-static void ax_eeprom_getword __P((struct ax_softc *, int, u_int16_t *));
-static void ax_read_eeprom __P((struct ax_softc *, caddr_t, int,
- int, int));
-
-static void ax_mii_writebit __P((struct ax_softc *, int));
-static int ax_mii_readbit __P((struct ax_softc *));
-static void ax_mii_sync __P((struct ax_softc *));
-static void ax_mii_send __P((struct ax_softc *, u_int32_t, int));
-static int ax_mii_readreg __P((struct ax_softc *, struct ax_mii_frame *));
-static int ax_mii_writereg __P((struct ax_softc *, struct ax_mii_frame *));
-static u_int16_t ax_phy_readreg __P((struct ax_softc *, int));
-static void ax_phy_writereg __P((struct ax_softc *, int, int));
-
-static void ax_autoneg_xmit __P((struct ax_softc *));
-static void ax_autoneg_mii __P((struct ax_softc *, int, int));
-static void ax_setmode_mii __P((struct ax_softc *, int));
-static void ax_setmode __P((struct ax_softc *, int, int));
-static void ax_getmode_mii __P((struct ax_softc *));
-static void ax_setcfg __P((struct ax_softc *, int));
-static u_int32_t ax_calchash __P((caddr_t));
-static void ax_setmulti __P((struct ax_softc *));
-static void ax_reset __P((struct ax_softc *));
-static int ax_list_rx_init __P((struct ax_softc *));
-static int ax_list_tx_init __P((struct ax_softc *));
-
-#ifdef AX_USEIOSPACE
-#define AX_RES SYS_RES_IOPORT
-#define AX_RID AX_PCI_LOIO
-#else
-#define AX_RES SYS_RES_IOPORT
-#define AX_RID AX_PCI_LOIO
-#endif
-
-static device_method_t ax_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, ax_probe),
- DEVMETHOD(device_attach, ax_attach),
- DEVMETHOD(device_detach, ax_detach),
- DEVMETHOD(device_shutdown, ax_shutdown),
- { 0, 0 }
-};
-
-static driver_t ax_driver = {
- "ax",
- ax_methods,
- sizeof(struct ax_softc)
-};
-
-static devclass_t ax_devclass;
-
-DRIVER_MODULE(if_ax, pci, ax_driver, ax_devclass, 0, 0);
-
-#define AX_SETBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) | x)
-
-#define AX_CLRBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) & ~x)
-
-#define SIO_SET(x) \
- CSR_WRITE_4(sc, AX_SIO, \
- CSR_READ_4(sc, AX_SIO) | x)
-
-#define SIO_CLR(x) \
- CSR_WRITE_4(sc, AX_SIO, \
- CSR_READ_4(sc, AX_SIO) & ~x)
-
-static void ax_delay(sc)
- struct ax_softc *sc;
-{
- int idx;
-
- for (idx = (300 / 33) + 1; idx > 0; idx--)
- CSR_READ_4(sc, AX_BUSCTL);
-}
-
-static void ax_eeprom_idle(sc)
- struct ax_softc *sc;
-{
- register int i;
-
- CSR_WRITE_4(sc, AX_SIO, AX_SIO_EESEL);
- ax_delay(sc);
- AX_SETBIT(sc, AX_SIO, AX_SIO_ROMCTL_READ);
- ax_delay(sc);
- AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CS);
- ax_delay(sc);
- AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CLK);
- ax_delay(sc);
-
- for (i = 0; i < 25; i++) {
- AX_CLRBIT(sc, AX_SIO, AX_SIO_EE_CLK);
- ax_delay(sc);
- AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CLK);
- ax_delay(sc);
- }
-
- AX_CLRBIT(sc, AX_SIO, AX_SIO_EE_CLK);
- ax_delay(sc);
- AX_CLRBIT(sc, AX_SIO, AX_SIO_EE_CS);
- ax_delay(sc);
- CSR_WRITE_4(sc, AX_SIO, 0x00000000);
-
- return;
-}
-
-/*
- * Send a read command and address to the EEPROM, check for ACK.
- */
-static void ax_eeprom_putbyte(sc, addr)
- struct ax_softc *sc;
- int addr;
-{
- register int d, i;
-
- d = addr | AX_EECMD_READ;
-
- /*
- * Feed in each bit and stobe the clock.
- */
- for (i = 0x400; i; i >>= 1) {
- if (d & i) {
- SIO_SET(AX_SIO_EE_DATAIN);
- } else {
- SIO_CLR(AX_SIO_EE_DATAIN);
- }
- ax_delay(sc);
- SIO_SET(AX_SIO_EE_CLK);
- ax_delay(sc);
- SIO_CLR(AX_SIO_EE_CLK);
- ax_delay(sc);
- }
-
- return;
-}
-
-/*
- * Read a word of data stored in the EEPROM at address 'addr.'
- */
-static void ax_eeprom_getword(sc, addr, dest)
- struct ax_softc *sc;
- int addr;
- u_int16_t *dest;
-{
- register int i;
- u_int16_t word = 0;
-
- /* Force EEPROM to idle state. */
- ax_eeprom_idle(sc);
-
- /* Enter EEPROM access mode. */
- CSR_WRITE_4(sc, AX_SIO, AX_SIO_EESEL);
- ax_delay(sc);
- AX_SETBIT(sc, AX_SIO, AX_SIO_ROMCTL_READ);
- ax_delay(sc);
- AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CS);
- ax_delay(sc);
- AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CLK);
- ax_delay(sc);
-
- /*
- * Send address of word we want to read.
- */
- ax_eeprom_putbyte(sc, addr);
-
- /*
- * Start reading bits from EEPROM.
- */
- for (i = 0x8000; i; i >>= 1) {
- SIO_SET(AX_SIO_EE_CLK);
- ax_delay(sc);
- if (CSR_READ_4(sc, AX_SIO) & AX_SIO_EE_DATAOUT)
- word |= i;
- ax_delay(sc);
- SIO_CLR(AX_SIO_EE_CLK);
- ax_delay(sc);
- }
-
- /* Turn off EEPROM access mode. */
- ax_eeprom_idle(sc);
-
- *dest = word;
-
- return;
-}
-
-/*
- * Read a sequence of words from the EEPROM.
- */
-static void ax_read_eeprom(sc, dest, off, cnt, swap)
- struct ax_softc *sc;
- caddr_t dest;
- int off;
- int cnt;
- int swap;
-{
- int i;
- u_int16_t word = 0, *ptr;
-
- for (i = 0; i < cnt; i++) {
- ax_eeprom_getword(sc, off + i, &word);
- ptr = (u_int16_t *)(dest + (i * 2));
- if (swap)
- *ptr = ntohs(word);
- else
- *ptr = word;
- }
-
- return;
-}
-
-/*
- * Write a bit to the MII bus.
- */
-static void ax_mii_writebit(sc, bit)
- struct ax_softc *sc;
- int bit;
-{
- if (bit)
- CSR_WRITE_4(sc, AX_SIO, AX_SIO_ROMCTL_WRITE|AX_SIO_MII_DATAOUT);
- else
- CSR_WRITE_4(sc, AX_SIO, AX_SIO_ROMCTL_WRITE);
-
- AX_SETBIT(sc, AX_SIO, AX_SIO_MII_CLK);
- AX_CLRBIT(sc, AX_SIO, AX_SIO_MII_CLK);
-
- return;
-}
-
-/*
- * Read a bit from the MII bus.
- */
-static int ax_mii_readbit(sc)
- struct ax_softc *sc;
-{
- CSR_WRITE_4(sc, AX_SIO, AX_SIO_ROMCTL_READ|AX_SIO_MII_DIR);
- CSR_READ_4(sc, AX_SIO);
- AX_SETBIT(sc, AX_SIO, AX_SIO_MII_CLK);
- AX_CLRBIT(sc, AX_SIO, AX_SIO_MII_CLK);
- if (CSR_READ_4(sc, AX_SIO) & AX_SIO_MII_DATAIN)
- return(1);
-
- return(0);
-}
-
-/*
- * Sync the PHYs by setting data bit and strobing the clock 32 times.
- */
-static void ax_mii_sync(sc)
- struct ax_softc *sc;
-{
- register int i;
-
- CSR_WRITE_4(sc, AX_SIO, AX_SIO_ROMCTL_WRITE);
-
- for (i = 0; i < 32; i++)
- ax_mii_writebit(sc, 1);
-
- return;
-}
-
-/*
- * Clock a series of bits through the MII.
- */
-static void ax_mii_send(sc, bits, cnt)
- struct ax_softc *sc;
- u_int32_t bits;
- int cnt;
-{
- int i;
-
- for (i = (0x1 << (cnt - 1)); i; i >>= 1)
- ax_mii_writebit(sc, bits & i);
-}
-
-/*
- * Read an PHY register through the MII.
- */
-static int ax_mii_readreg(sc, frame)
- struct ax_softc *sc;
- struct ax_mii_frame *frame;
-
-{
- int i, ack, s;
-
- s = splimp();
-
- /*
- * Set up frame for RX.
- */
- frame->mii_stdelim = AX_MII_STARTDELIM;
- frame->mii_opcode = AX_MII_READOP;
- frame->mii_turnaround = 0;
- frame->mii_data = 0;
-
- /*
- * Sync the PHYs.
- */
- ax_mii_sync(sc);
-
- /*
- * Send command/address info.
- */
- ax_mii_send(sc, frame->mii_stdelim, 2);
- ax_mii_send(sc, frame->mii_opcode, 2);
- ax_mii_send(sc, frame->mii_phyaddr, 5);
- ax_mii_send(sc, frame->mii_regaddr, 5);
-
-#ifdef notdef
- /* Idle bit */
- ax_mii_writebit(sc, 1);
- ax_mii_writebit(sc, 0);
-#endif
-
- /* Check for ack */
- ack = ax_mii_readbit(sc);
-
- /*
- * Now try reading data bits. If the ack failed, we still
- * need to clock through 16 cycles to keep the PHY(s) in sync.
- */
- if (ack) {
- for(i = 0; i < 16; i++) {
- ax_mii_readbit(sc);
- }
- goto fail;
- }
-
- for (i = 0x8000; i; i >>= 1) {
- if (!ack) {
- if (ax_mii_readbit(sc))
- frame->mii_data |= i;
- }
- }
-
-fail:
-
- ax_mii_writebit(sc, 0);
- ax_mii_writebit(sc, 0);
-
- splx(s);
-
- if (ack)
- return(1);
- return(0);
-}
-
-/*
- * Write to a PHY register through the MII.
- */
-static int ax_mii_writereg(sc, frame)
- struct ax_softc *sc;
- struct ax_mii_frame *frame;
-
-{
- int s;
-
- s = splimp();
- /*
- * Set up frame for TX.
- */
-
- frame->mii_stdelim = AX_MII_STARTDELIM;
- frame->mii_opcode = AX_MII_WRITEOP;
- frame->mii_turnaround = AX_MII_TURNAROUND;
-
- /*
- * Sync the PHYs.
- */
- ax_mii_sync(sc);
-
- ax_mii_send(sc, frame->mii_stdelim, 2);
- ax_mii_send(sc, frame->mii_opcode, 2);
- ax_mii_send(sc, frame->mii_phyaddr, 5);
- ax_mii_send(sc, frame->mii_regaddr, 5);
- ax_mii_send(sc, frame->mii_turnaround, 2);
- ax_mii_send(sc, frame->mii_data, 16);
-
- /* Idle bit. */
- ax_mii_writebit(sc, 0);
- ax_mii_writebit(sc, 0);
-
- splx(s);
-
- return(0);
-}
-
-static u_int16_t ax_phy_readreg(sc, reg)
- struct ax_softc *sc;
- int reg;
-{
- struct ax_mii_frame frame;
-
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = sc->ax_phy_addr;
- frame.mii_regaddr = reg;
- ax_mii_readreg(sc, &frame);
-
- return(frame.mii_data);
-}
-
-static void ax_phy_writereg(sc, reg, data)
- struct ax_softc *sc;
- int reg;
- int data;
-{
- struct ax_mii_frame frame;
-
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = sc->ax_phy_addr;
- frame.mii_regaddr = reg;
- frame.mii_data = data;
-
- ax_mii_writereg(sc, &frame);
-
- return;
-}
-
-/*
- * Calculate CRC of a multicast group address, return the lower 6 bits.
- */
-static u_int32_t ax_calchash(addr)
- caddr_t addr;
-{
- u_int32_t crc, carry;
- int i, j;
- u_int8_t c;
-
- /* Compute CRC for the address value. */
- crc = 0xFFFFFFFF; /* initial value */
-
- for (i = 0; i < 6; i++) {
- c = *(addr + i);
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
- crc <<= 1;
- c >>= 1;
- if (carry)
- crc = (crc ^ 0x04c11db6) | carry;
- }
- }
-
- /* return the filter bit position */
- return((crc >> 26) & 0x0000003F);
-}
-
-static void ax_setmulti(sc)
- struct ax_softc *sc;
-{
- struct ifnet *ifp;
- int h = 0;
- u_int32_t hashes[2] = { 0, 0 };
- struct ifmultiaddr *ifma;
- u_int32_t rxfilt;
-
- ifp = &sc->arpcom.ac_if;
-
- rxfilt = CSR_READ_4(sc, AX_NETCFG);
-
- if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
- rxfilt |= AX_NETCFG_RX_ALLMULTI;
- CSR_WRITE_4(sc, AX_NETCFG, rxfilt);
- return;
- } else
- rxfilt &= ~AX_NETCFG_RX_ALLMULTI;
-
- /* first, zot all the existing hash bits */
- CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR0);
- CSR_WRITE_4(sc, AX_FILTDATA, 0);
- CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR1);
- CSR_WRITE_4(sc, AX_FILTDATA, 0);
-
- /* now program new ones */
- for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
- ifma = ifma->ifma_link.le_next) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- h = ax_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
- if (h < 32)
- hashes[0] |= (1 << h);
- else
- hashes[1] |= (1 << (h - 32));
- }
-
- CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR0);
- CSR_WRITE_4(sc, AX_FILTDATA, hashes[0]);
- CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR1);
- CSR_WRITE_4(sc, AX_FILTDATA, hashes[1]);
- CSR_WRITE_4(sc, AX_NETCFG, rxfilt);
-
- return;
-}
-
-/*
- * Initiate an autonegotiation session.
- */
-static void ax_autoneg_xmit(sc)
- struct ax_softc *sc;
-{
- u_int16_t phy_sts;
-
- ax_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(ax_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
-
- phy_sts = ax_phy_readreg(sc, PHY_BMCR);
- phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR;
- ax_phy_writereg(sc, PHY_BMCR, phy_sts);
-
- return;
-}
-
-/*
- * Invoke autonegotiation on a PHY.
- */
-static void ax_autoneg_mii(sc, flag, verbose)
- struct ax_softc *sc;
- int flag;
- int verbose;
-{
- u_int16_t phy_sts = 0, media, advert, ability;
- struct ifnet *ifp;
- struct ifmedia *ifm;
-
- ifm = &sc->ifmedia;
- ifp = &sc->arpcom.ac_if;
-
- ifm->ifm_media = IFM_ETHER | IFM_AUTO;
-
- /*
- * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported'
- * bit cleared in the status register, but has the 'autoneg enabled'
- * bit set in the control register. This is a contradiction, and
- * I'm not sure how to handle it. If you want to force an attempt
- * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR
- * and see what happens.
- */
-#ifndef FORCE_AUTONEG_TFOUR
- /*
- * First, see if autoneg is supported. If not, there's
- * no point in continuing.
- */
- phy_sts = ax_phy_readreg(sc, PHY_BMSR);
- if (!(phy_sts & PHY_BMSR_CANAUTONEG)) {
- if (verbose)
- printf("ax%d: autonegotiation not supported\n",
- sc->ax_unit);
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- return;
- }
-#endif
-
- switch (flag) {
- case AX_FLAG_FORCEDELAY:
- /*
- * XXX Never use this option anywhere but in the probe
- * routine: making the kernel stop dead in its tracks
- * for three whole seconds after we've gone multi-user
- * is really bad manners.
- */
- ax_autoneg_xmit(sc);
- DELAY(5000000);
- break;
- case AX_FLAG_SCHEDDELAY:
- /*
- * Wait for the transmitter to go idle before starting
- * an autoneg session, otherwise ax_start() may clobber
- * our timeout, and we don't want to allow transmission
- * during an autoneg session since that can screw it up.
- */
- if (sc->ax_cdata.ax_tx_head != NULL) {
- sc->ax_want_auto = 1;
- return;
- }
- ax_autoneg_xmit(sc);
- ifp->if_timer = 5;
- sc->ax_autoneg = 1;
- sc->ax_want_auto = 0;
- return;
- break;
- case AX_FLAG_DELAYTIMEO:
- ifp->if_timer = 0;
- sc->ax_autoneg = 0;
- break;
- default:
- printf("ax%d: invalid autoneg flag: %d\n", sc->ax_unit, flag);
- return;
- }
-
- if (ax_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) {
- if (verbose)
- printf("ax%d: autoneg complete, ", sc->ax_unit);
- phy_sts = ax_phy_readreg(sc, PHY_BMSR);
- } else {
- if (verbose)
- printf("ax%d: autoneg not complete, ", sc->ax_unit);
- }
-
- media = ax_phy_readreg(sc, PHY_BMCR);
-
- /* Link is good. Report modes and set duplex mode. */
- if (ax_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) {
- if (verbose)
- printf("link status good ");
- advert = ax_phy_readreg(sc, PHY_ANAR);
- ability = ax_phy_readreg(sc, PHY_LPAR);
-
- if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) {
- ifm->ifm_media = IFM_ETHER|IFM_100_T4;
- media |= PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(100baseT4)\n");
- } else if (advert & PHY_ANAR_100BTXFULL &&
- ability & PHY_ANAR_100BTXFULL) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- media |= PHY_BMCR_SPEEDSEL;
- media |= PHY_BMCR_DUPLEX;
- printf("(full-duplex, 100Mbps)\n");
- } else if (advert & PHY_ANAR_100BTXHALF &&
- ability & PHY_ANAR_100BTXHALF) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
- media |= PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(half-duplex, 100Mbps)\n");
- } else if (advert & PHY_ANAR_10BTFULL &&
- ability & PHY_ANAR_10BTFULL) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
- media &= ~PHY_BMCR_SPEEDSEL;
- media |= PHY_BMCR_DUPLEX;
- printf("(full-duplex, 10Mbps)\n");
- } else if (advert & PHY_ANAR_10BTHALF &&
- ability & PHY_ANAR_10BTHALF) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- media &= ~PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(half-duplex, 10Mbps)\n");
- }
-
- media &= ~PHY_BMCR_AUTONEGENBL;
-
- /* Set ASIC's duplex mode to match the PHY. */
- ax_setcfg(sc, media);
- ax_phy_writereg(sc, PHY_BMCR, media);
- } else {
- if (verbose)
- printf("no carrier\n");
- }
-
- ax_init(sc);
-
- if (sc->ax_tx_pend) {
- sc->ax_autoneg = 0;
- sc->ax_tx_pend = 0;
- ax_start(ifp);
- }
-
- return;
-}
-
-static void ax_getmode_mii(sc)
- struct ax_softc *sc;
-{
- u_int16_t bmsr;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- bmsr = ax_phy_readreg(sc, PHY_BMSR);
- if (bootverbose)
- printf("ax%d: PHY status word: %x\n", sc->ax_unit, bmsr);
-
- /* fallback */
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
-
- if (bmsr & PHY_BMSR_10BTHALF) {
- if (bootverbose)
- printf("ax%d: 10Mbps half-duplex mode supported\n",
- sc->ax_unit);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
- }
-
- if (bmsr & PHY_BMSR_10BTFULL) {
- if (bootverbose)
- printf("ax%d: 10Mbps full-duplex mode supported\n",
- sc->ax_unit);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
- }
-
- if (bmsr & PHY_BMSR_100BTXHALF) {
- if (bootverbose)
- printf("ax%d: 100Mbps half-duplex mode supported\n",
- sc->ax_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
- }
-
- if (bmsr & PHY_BMSR_100BTXFULL) {
- if (bootverbose)
- printf("ax%d: 100Mbps full-duplex mode supported\n",
- sc->ax_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- }
-
- /* Some also support 100BaseT4. */
- if (bmsr & PHY_BMSR_100BT4) {
- if (bootverbose)
- printf("ax%d: 100baseT4 mode supported\n", sc->ax_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4;
-#ifdef FORCE_AUTONEG_TFOUR
- if (bootverbose)
- printf("ax%d: forcing on autoneg support for BT4\n",
- sc->ax_unit);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL):
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;
-#endif
- }
-
- if (bmsr & PHY_BMSR_CANAUTONEG) {
- if (bootverbose)
- printf("ax%d: autoneg supported\n", sc->ax_unit);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;
- }
-
- return;
-}
-
-/*
- * Set speed and duplex mode.
- */
-static void ax_setmode_mii(sc, media)
- struct ax_softc *sc;
- int media;
-{
- u_int16_t bmcr;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- /*
- * If an autoneg session is in progress, stop it.
- */
- if (sc->ax_autoneg) {
- printf("ax%d: canceling autoneg session\n", sc->ax_unit);
- ifp->if_timer = sc->ax_autoneg = sc->ax_want_auto = 0;
- bmcr = ax_phy_readreg(sc, PHY_BMCR);
- bmcr &= ~PHY_BMCR_AUTONEGENBL;
- ax_phy_writereg(sc, PHY_BMCR, bmcr);
- }
-
- printf("ax%d: selecting MII, ", sc->ax_unit);
-
- bmcr = ax_phy_readreg(sc, PHY_BMCR);
-
- bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL|
- PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK);
-
- if (IFM_SUBTYPE(media) == IFM_100_T4) {
- printf("100Mbps/T4, half-duplex\n");
- bmcr |= PHY_BMCR_SPEEDSEL;
- bmcr &= ~PHY_BMCR_DUPLEX;
- }
-
- if (IFM_SUBTYPE(media) == IFM_100_TX) {
- printf("100Mbps, ");
- bmcr |= PHY_BMCR_SPEEDSEL;
- }
-
- if (IFM_SUBTYPE(media) == IFM_10_T) {
- printf("10Mbps, ");
- bmcr &= ~PHY_BMCR_SPEEDSEL;
- }
-
- if ((media & IFM_GMASK) == IFM_FDX) {
- printf("full duplex\n");
- bmcr |= PHY_BMCR_DUPLEX;
- } else {
- printf("half duplex\n");
- bmcr &= ~PHY_BMCR_DUPLEX;
- }
-
- ax_setcfg(sc, bmcr);
- ax_phy_writereg(sc, PHY_BMCR, bmcr);
-
- return;
-}
-
-/*
- * Set speed and duplex mode on internal transceiver.
- */
-static void ax_setmode(sc, media, verbose)
- struct ax_softc *sc;
- int media;
- int verbose;
-{
- struct ifnet *ifp;
- u_int32_t mode;
-
- ifp = &sc->arpcom.ac_if;
-
- if (verbose)
- printf("ax%d: selecting internal xcvr, ", sc->ax_unit);
-
- mode = CSR_READ_4(sc, AX_NETCFG);
-
- mode &= ~(AX_NETCFG_FULLDUPLEX|AX_NETCFG_PORTSEL|
- AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER|AX_NETCFG_SPEEDSEL);
-
- if (IFM_SUBTYPE(media) == IFM_100_T4) {
- if (verbose)
- printf("100Mbps/T4, half-duplex\n");
- mode |= AX_NETCFG_PORTSEL|AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER;
- }
-
- if (IFM_SUBTYPE(media) == IFM_100_TX) {
- if (verbose)
- printf("100Mbps, ");
- mode |= AX_NETCFG_PORTSEL|AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER;
- }
-
- if (IFM_SUBTYPE(media) == IFM_10_T) {
- if (verbose)
- printf("10Mbps, ");
- mode &= ~AX_NETCFG_PORTSEL;
- mode |= AX_NETCFG_SPEEDSEL;
- }
-
- if ((media & IFM_GMASK) == IFM_FDX) {
- if (verbose)
- printf("full duplex\n");
- mode |= AX_NETCFG_FULLDUPLEX;
- } else {
- if (verbose)
- printf("half duplex\n");
- mode &= ~AX_NETCFG_FULLDUPLEX;
- }
-
- CSR_WRITE_4(sc, AX_NETCFG, mode);
-
- return;
-}
-
-/*
- * In order to fiddle with the
- * 'full-duplex' and '100Mbps' bits in the netconfig register, we
- * first have to put the transmit and/or receive logic in the idle state.
- */
-static void ax_setcfg(sc, bmcr)
- struct ax_softc *sc;
- int bmcr;
-{
- int i, restart = 0;
-
- if (CSR_READ_4(sc, AX_NETCFG) & (AX_NETCFG_TX_ON|AX_NETCFG_RX_ON)) {
- restart = 1;
- AX_CLRBIT(sc, AX_NETCFG, (AX_NETCFG_TX_ON|AX_NETCFG_RX_ON));
-
- for (i = 0; i < AX_TIMEOUT; i++) {
- DELAY(10);
- if (CSR_READ_4(sc, AX_ISR) & AX_ISR_TX_IDLE)
- break;
- }
-
- if (i == AX_TIMEOUT)
- printf("ax%d: failed to force tx and "
- "rx to idle state\n", sc->ax_unit);
-
- }
-
- if (bmcr & PHY_BMCR_SPEEDSEL)
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_SPEEDSEL);
- else
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_SPEEDSEL);
-
- if (bmcr & PHY_BMCR_DUPLEX)
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_FULLDUPLEX);
- else
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_FULLDUPLEX);
-
- if (restart)
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_TX_ON|AX_NETCFG_RX_ON);
-
- return;
-}
-
-static void ax_reset(sc)
- struct ax_softc *sc;
-{
- register int i;
-
- AX_SETBIT(sc, AX_BUSCTL, AX_BUSCTL_RESET);
-
- for (i = 0; i < AX_TIMEOUT; i++) {
- DELAY(10);
- if (!(CSR_READ_4(sc, AX_BUSCTL) & AX_BUSCTL_RESET))
- break;
- }
-#ifdef notdef
- if (i == AX_TIMEOUT)
- printf("ax%d: reset never completed!\n", sc->ax_unit);
-#endif
- CSR_WRITE_4(sc, AX_BUSCTL, AX_BUSCTL_CONFIG);
-
- /* Wait a little while for the chip to get its brains in order. */
- DELAY(1000);
- return;
-}
-
-/*
- * Probe for an ASIX chip. Check the PCI vendor and device
- * IDs against our list and return a device name if we find a match.
- */
-int ax_probe(dev)
- device_t dev;
-{
- struct ax_type *t;
- u_int32_t rev;
-
- t = ax_devs;
-
- while(t->ax_name != NULL) {
- if ((pci_get_vendor(dev) == t->ax_vid) &&
- (pci_get_device(dev) == t->ax_did)) {
- /* Check the PCI revision */
- rev = pci_read_config(dev, AX_PCI_REVID, 4) & 0xFF;
- if (rev >= AX_REVISION_88141)
- t++;
- device_set_desc(dev, t->ax_name);
- return(0);
- }
- t++;
- }
-
- return(ENXIO);
-}
-
-/*
- * Attach the interface. Allocate softc structures, do ifmedia
- * setup and ethernet/BPF attach.
- */
-static int ax_attach(dev)
- device_t dev;
-{
- int s, i;
- u_char eaddr[ETHER_ADDR_LEN];
- u_int32_t command;
- struct ax_softc *sc;
- struct ifnet *ifp;
- int media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- unsigned int round;
- caddr_t roundptr;
- struct ax_type *p;
- u_int16_t phy_vid, phy_did, phy_sts;
- int unit, error = 0, rid;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- unit = device_get_unit(dev);
- bzero(sc, sizeof(struct ax_softc));
-
- /*
- * Handle power management nonsense.
- */
-
- command = pci_read_config(dev, AX_PCI_CAPID, 4) & 0x000000FF;
- if (command == 0x01) {
-
- command = pci_read_config(dev, AX_PCI_PWRMGMTCTRL, 4);
- if (command & AX_PSTATE_MASK) {
- u_int32_t iobase, membase, irq;
-
- /* Save important PCI config data. */
- iobase = pci_read_config(dev, AX_PCI_LOIO, 4);
- membase = pci_read_config(dev, AX_PCI_LOMEM, 4);
- irq = pci_read_config(dev, AX_PCI_INTLINE, 4);
-
- /* Reset the power state. */
- printf("ax%d: chip is in D%d power mode "
- "-- setting to D0\n", unit, command & AX_PSTATE_MASK);
- command &= 0xFFFFFFFC;
- pci_write_config(dev, AX_PCI_PWRMGMTCTRL, command, 4);
-
- /* Restore PCI config data. */
- pci_write_config(dev, AX_PCI_LOIO, iobase, 4);
- pci_write_config(dev, AX_PCI_LOMEM, membase, 4);
- pci_write_config(dev, AX_PCI_INTLINE, irq, 4);
- }
- }
-
- /*
- * Map control/status registers.
- */
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
- command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
- pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
-
-#ifdef AX_USEIOSPACE
- if (!(command & PCIM_CMD_PORTEN)) {
- printf("ax%d: failed to enable I/O ports!\n", unit);
- error = ENXIO;;
- goto fail;
- }
-#else
- if (!(command & PCIM_CMD_MEMEN)) {
- printf("ax%d: failed to enable memory mapping!\n", unit);
- error = ENXIO;;
- goto fail;
- }
-#endif
-
- rid = AX_RID;
- sc->ax_res = bus_alloc_resource(dev, AX_RES, &rid,
- 0, ~0, 1, RF_ACTIVE);
-
- if (sc->ax_res == NULL) {
- printf("ax%d: couldn't map ports/memory\n", unit);
- error = ENXIO;
- goto fail;
- }
-
- sc->ax_btag = rman_get_bustag(sc->ax_res);
- sc->ax_bhandle = rman_get_bushandle(sc->ax_res);
-
- /* Allocate interrupt */
- rid = 0;
- sc->ax_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
- RF_SHAREABLE | RF_ACTIVE);
-
- if (sc->ax_irq == NULL) {
- printf("ax%d: couldn't map interrupt\n", unit);
- bus_release_resource(dev, AX_RES, AX_RID, sc->ax_res);
- error = ENXIO;
- goto fail;
- }
-
- error = bus_setup_intr(dev, sc->ax_irq, INTR_TYPE_NET,
- ax_intr, sc, &sc->ax_intrhand);
-
- if (error) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ax_res);
- bus_release_resource(dev, AX_RES, AX_RID, sc->ax_res);
- printf("ax%d: couldn't set up irq\n", unit);
- goto fail;
- }
-
- /* Reset the adapter. */
- ax_reset(sc);
-
- /*
- * Get station address from the EEPROM.
- */
- ax_read_eeprom(sc, (caddr_t)&eaddr, AX_EE_NODEADDR, 3, 0);
-
- /*
- * An ASIX chip was detected. Inform the world.
- */
- printf("ax%d: Ethernet address: %6D\n", unit, eaddr, ":");
-
- sc->ax_unit = unit;
- bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
-
- sc->ax_ldata_ptr = malloc(sizeof(struct ax_list_data) + 8,
- M_DEVBUF, M_NOWAIT);
- if (sc->ax_ldata_ptr == NULL) {
- printf("ax%d: no memory for list buffers!\n", unit);
- bus_teardown_intr(dev, sc->ax_irq, sc->ax_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ax_res);
- bus_release_resource(dev, AX_RES, AX_RID, sc->ax_res);
- error = ENXIO;
- goto fail;
- }
-
- sc->ax_ldata = (struct ax_list_data *)sc->ax_ldata_ptr;
- round = (uintptr_t)sc->ax_ldata_ptr & 0xF;
- roundptr = sc->ax_ldata_ptr;
- for (i = 0; i < 8; i++) {
- if (round % 8) {
- round++;
- roundptr++;
- } else
- break;
- }
- sc->ax_ldata = (struct ax_list_data *)roundptr;
- bzero(sc->ax_ldata, sizeof(struct ax_list_data));
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_softc = sc;
- ifp->if_unit = unit;
- ifp->if_name = "ax";
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = ax_ioctl;
- ifp->if_output = ether_output;
- ifp->if_start = ax_start;
- ifp->if_watchdog = ax_watchdog;
- ifp->if_init = ax_init;
- ifp->if_baudrate = 10000000;
- ifp->if_snd.ifq_maxlen = AX_TX_LIST_CNT - 1;
-
- if (bootverbose)
- printf("ax%d: probing for a PHY\n", sc->ax_unit);
- for (i = AX_PHYADDR_MIN; i < AX_PHYADDR_MAX + 1; i++) {
- if (bootverbose)
- printf("ax%d: checking address: %d\n",
- sc->ax_unit, i);
- sc->ax_phy_addr = i;
- ax_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(ax_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
- if ((phy_sts = ax_phy_readreg(sc, PHY_BMSR)))
- break;
- }
- if (phy_sts) {
- phy_vid = ax_phy_readreg(sc, PHY_VENID);
- phy_did = ax_phy_readreg(sc, PHY_DEVID);
- if (bootverbose)
- printf("ax%d: found PHY at address %d, ",
- sc->ax_unit, sc->ax_phy_addr);
- if (bootverbose)
- printf("vendor id: %x device id: %x\n",
- phy_vid, phy_did);
- p = ax_phys;
- while(p->ax_vid) {
- if (phy_vid == p->ax_vid &&
- (phy_did | 0x000F) == p->ax_did) {
- sc->ax_pinfo = p;
- break;
- }
- p++;
- }
- if (sc->ax_pinfo == NULL)
- sc->ax_pinfo = &ax_phys[PHY_UNKNOWN];
- if (bootverbose)
- printf("ax%d: PHY type: %s\n",
- sc->ax_unit, sc->ax_pinfo->ax_name);
- } else {
-#ifdef DIAGNOSTIC
- printf("ax%d: MII without any phy!\n", sc->ax_unit);
-#endif
- }
-
- /*
- * Do ifmedia setup.
- */
- ifmedia_init(&sc->ifmedia, 0, ax_ifmedia_upd, ax_ifmedia_sts);
-
- if (sc->ax_pinfo != NULL) {
- ax_getmode_mii(sc);
- if (cold) {
- ax_autoneg_mii(sc, AX_FLAG_FORCEDELAY, 1);
- ax_stop(sc);
- } else {
- ax_init(sc);
- ax_autoneg_mii(sc, AX_FLAG_SCHEDDELAY, 1);
- }
- } else {
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
- }
-
- media = sc->ifmedia.ifm_media;
- ifmedia_set(&sc->ifmedia, media);
-
- /*
- * Call MI attach routines.
- */
- if_attach(ifp);
- ether_ifattach(ifp);
-
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-
-fail:
- splx(s);
- return(error);
-}
-
-static int ax_detach(dev)
- device_t dev;
-{
- struct ax_softc *sc;
- struct ifnet *ifp;
- int s;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- ifp = &sc->arpcom.ac_if;
-
- ax_stop(sc);
- if_detach(ifp);
-
- bus_teardown_intr(dev, sc->ax_irq, sc->ax_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ax_res);
- bus_release_resource(dev, AX_RES, AX_RID, sc->ax_res);
-
- free(sc->ax_ldata_ptr, M_DEVBUF);
- ifmedia_removeall(&sc->ifmedia);
-
- splx(s);
-
- return(0);
-}
-
-/*
- * Initialize the transmit descriptors.
- */
-static int ax_list_tx_init(sc)
- struct ax_softc *sc;
-{
- struct ax_chain_data *cd;
- struct ax_list_data *ld;
- int i;
-
- cd = &sc->ax_cdata;
- ld = sc->ax_ldata;
- for (i = 0; i < AX_TX_LIST_CNT; i++) {
- cd->ax_tx_chain[i].ax_ptr = &ld->ax_tx_list[i];
- if (i == (AX_TX_LIST_CNT - 1))
- cd->ax_tx_chain[i].ax_nextdesc =
- &cd->ax_tx_chain[0];
- else
- cd->ax_tx_chain[i].ax_nextdesc =
- &cd->ax_tx_chain[i + 1];
- }
-
- cd->ax_tx_free = &cd->ax_tx_chain[0];
- cd->ax_tx_tail = cd->ax_tx_head = NULL;
-
- return(0);
-}
-
-
-/*
- * Initialize the RX descriptors and allocate mbufs for them. Note that
- * we arrange the descriptors in a closed ring, so that the last descriptor
- * points back to the first.
- */
-static int ax_list_rx_init(sc)
- struct ax_softc *sc;
-{
- struct ax_chain_data *cd;
- struct ax_list_data *ld;
- int i;
-
- cd = &sc->ax_cdata;
- ld = sc->ax_ldata;
-
- for (i = 0; i < AX_RX_LIST_CNT; i++) {
- cd->ax_rx_chain[i].ax_ptr =
- (volatile struct ax_desc *)&ld->ax_rx_list[i];
- if (ax_newbuf(sc, &cd->ax_rx_chain[i], NULL) == ENOBUFS)
- return(ENOBUFS);
- if (i == (AX_RX_LIST_CNT - 1)) {
- cd->ax_rx_chain[i].ax_nextdesc =
- &cd->ax_rx_chain[0];
- ld->ax_rx_list[i].ax_next =
- vtophys(&ld->ax_rx_list[0]);
- } else {
- cd->ax_rx_chain[i].ax_nextdesc =
- &cd->ax_rx_chain[i + 1];
- ld->ax_rx_list[i].ax_next =
- vtophys(&ld->ax_rx_list[i + 1]);
- }
- }
-
- cd->ax_rx_head = &cd->ax_rx_chain[0];
-
- return(0);
-}
-
-/*
- * Initialize an RX descriptor and attach an MBUF cluster.
- * Note: the length fields are only 11 bits wide, which means the
- * largest size we can specify is 2047. This is important because
- * MCLBYTES is 2048, so we have to subtract one otherwise we'll
- * overflow the field and make a mess.
- */
-static int ax_newbuf(sc, c, m)
- struct ax_softc *sc;
- struct ax_chain_onefrag *c;
- struct mbuf *m;
-{
- struct mbuf *m_new = NULL;
-
- if (m == NULL) {
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("ax%d: no memory for rx list "
- "-- packet dropped!\n", sc->ax_unit);
- return(ENOBUFS);
- }
-
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- printf("ax%d: no memory for rx list "
- "-- packet dropped!\n", sc->ax_unit);
- m_freem(m_new);
- return(ENOBUFS);
- }
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- } else {
- m_new = m;
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- m_new->m_data = m_new->m_ext.ext_buf;
- }
-
- m_adj(m_new, sizeof(u_int64_t));
- c->ax_mbuf = m_new;
- c->ax_ptr->ax_status = AX_RXSTAT;
- c->ax_ptr->ax_data = vtophys(mtod(m_new, caddr_t));
- c->ax_ptr->ax_ctl = MCLBYTES - 1;
-
- return(0);
-}
-
-/*
- * A frame has been uploaded: pass the resulting mbuf chain up to
- * the higher level protocols.
- */
-static void ax_rxeof(sc)
- struct ax_softc *sc;
-{
- struct ether_header *eh;
- struct mbuf *m;
- struct ifnet *ifp;
- struct ax_chain_onefrag *cur_rx;
- int total_len = 0;
- u_int32_t rxstat;
-
- ifp = &sc->arpcom.ac_if;
-
- while(!((rxstat = sc->ax_cdata.ax_rx_head->ax_ptr->ax_status) &
- AX_RXSTAT_OWN)) {
- struct mbuf *m0 = NULL;
-
- cur_rx = sc->ax_cdata.ax_rx_head;
- sc->ax_cdata.ax_rx_head = cur_rx->ax_nextdesc;
- m = cur_rx->ax_mbuf;
-
- /*
- * If an error occurs, update stats, clear the
- * status word and leave the mbuf cluster in place:
- * it should simply get re-used next time this descriptor
- * comes up in the ring.
- */
- if (rxstat & AX_RXSTAT_RXERR) {
- ifp->if_ierrors++;
- if (rxstat & AX_RXSTAT_COLLSEEN)
- ifp->if_collisions++;
- ax_newbuf(sc, cur_rx, m);
- continue;
- }
-
- /* No errors; receive the packet. */
- total_len = AX_RXBYTES(cur_rx->ax_ptr->ax_status);
-
- total_len -= ETHER_CRC_LEN;
-
- m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
- total_len + ETHER_ALIGN, 0, ifp, NULL);
- ax_newbuf(sc, cur_rx, m);
- if (m0 == NULL) {
- ifp->if_ierrors++;
- continue;
- }
- m_adj(m0, ETHER_ALIGN);
- m = m0;
-
- ifp->if_ipackets++;
- eh = mtod(m, struct ether_header *);
-
- /*
- * Handle BPF listeners. Let the BPF user see the packet, but
- * don't pass it up to the ether_input() layer unless it's
- * a broadcast packet, multicast packet, matches our ethernet
- * address or the interface is in promiscuous mode.
- */
- if (ifp->if_bpf) {
- bpf_mtap(ifp, m);
- if (ifp->if_flags & IFF_PROMISC &&
- (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
- ETHER_ADDR_LEN) &&
- (eh->ether_dhost[0] & 1) == 0)) {
- m_freem(m);
- continue;
- }
- }
-
- /* Remove header from mbuf and pass it on. */
- m_adj(m, sizeof(struct ether_header));
- ether_input(ifp, eh, m);
- }
-
- return;
-}
-
-void ax_rxeoc(sc)
- struct ax_softc *sc;
-{
-
- ax_rxeof(sc);
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_RX_ON);
- CSR_WRITE_4(sc, AX_RXADDR, vtophys(sc->ax_cdata.ax_rx_head->ax_ptr));
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_RX_ON);
- CSR_WRITE_4(sc, AX_RXSTART, 0xFFFFFFFF);
-
- return;
-}
-
-/*
- * A frame was downloaded to the chip. It's safe for us to clean up
- * the list buffers.
- */
-
-static void ax_txeof(sc)
- struct ax_softc *sc;
-{
- struct ax_chain *cur_tx;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- /* Clear the timeout timer. */
- ifp->if_timer = 0;
-
- if (sc->ax_cdata.ax_tx_head == NULL)
- return;
-
- /*
- * Go through our tx list and free mbufs for those
- * frames that have been transmitted.
- */
- while(sc->ax_cdata.ax_tx_head->ax_mbuf != NULL) {
- u_int32_t txstat;
-
- cur_tx = sc->ax_cdata.ax_tx_head;
- txstat = AX_TXSTATUS(cur_tx);
-
- if (txstat & AX_TXSTAT_OWN)
- break;
-
- if (txstat & AX_TXSTAT_ERRSUM) {
- ifp->if_oerrors++;
- if (txstat & AX_TXSTAT_EXCESSCOLL)
- ifp->if_collisions++;
- if (txstat & AX_TXSTAT_LATECOLL)
- ifp->if_collisions++;
- }
-
- ifp->if_collisions += (txstat & AX_TXSTAT_COLLCNT) >> 3;
-
- ifp->if_opackets++;
- m_freem(cur_tx->ax_mbuf);
- cur_tx->ax_mbuf = NULL;
-
- if (sc->ax_cdata.ax_tx_head == sc->ax_cdata.ax_tx_tail) {
- sc->ax_cdata.ax_tx_head = NULL;
- sc->ax_cdata.ax_tx_tail = NULL;
- break;
- }
-
- sc->ax_cdata.ax_tx_head = cur_tx->ax_nextdesc;
- }
-
- return;
-}
-
-/*
- * TX 'end of channel' interrupt handler.
- */
-static void ax_txeoc(sc)
- struct ax_softc *sc;
-{
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- ifp->if_timer = 0;
-
- if (sc->ax_cdata.ax_tx_head == NULL) {
- ifp->if_flags &= ~IFF_OACTIVE;
- sc->ax_cdata.ax_tx_tail = NULL;
- if (sc->ax_want_auto)
- ax_autoneg_mii(sc, AX_FLAG_DELAYTIMEO, 1);
- }
-
- return;
-}
-
-static void ax_intr(arg)
- void *arg;
-{
- struct ax_softc *sc;
- struct ifnet *ifp;
- u_int32_t status;
-
- sc = arg;
- ifp = &sc->arpcom.ac_if;
-
- /* Supress unwanted interrupts */
- if (!(ifp->if_flags & IFF_UP)) {
- ax_stop(sc);
- return;
- }
-
- /* Disable interrupts. */
- CSR_WRITE_4(sc, AX_IMR, 0x00000000);
-
- for (;;) {
- status = CSR_READ_4(sc, AX_ISR);
- if (status)
- CSR_WRITE_4(sc, AX_ISR, status);
-
- if ((status & AX_INTRS) == 0)
- break;
-
- if ((status & AX_ISR_TX_OK) || (status & AX_ISR_TX_EARLY))
- ax_txeof(sc);
-
- if (status & AX_ISR_TX_NOBUF)
- ax_txeoc(sc);
-
- if (status & AX_ISR_TX_IDLE) {
- ax_txeof(sc);
- if (sc->ax_cdata.ax_tx_head != NULL) {
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_TX_ON);
- CSR_WRITE_4(sc, AX_TXSTART, 0xFFFFFFFF);
- }
- }
-
- if (status & AX_ISR_TX_UNDERRUN) {
- u_int32_t cfg;
- cfg = CSR_READ_4(sc, AX_NETCFG);
- if ((cfg & AX_NETCFG_TX_THRESH) == AX_TXTHRESH_160BYTES)
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_STORENFWD);
- else
- CSR_WRITE_4(sc, AX_NETCFG, cfg + 0x4000);
- }
-
- if (status & AX_ISR_RX_OK)
- ax_rxeof(sc);
-
- if ((status & AX_ISR_RX_WATDOGTIMEO)
- || (status & AX_ISR_RX_NOBUF))
- ax_rxeoc(sc);
-
- if (status & AX_ISR_BUS_ERR) {
- ax_reset(sc);
- ax_init(sc);
- }
- }
-
- /* Re-enable interrupts. */
- CSR_WRITE_4(sc, AX_IMR, AX_INTRS);
-
- if (ifp->if_snd.ifq_head != NULL) {
- ax_start(ifp);
- }
-
- return;
-}
-
-/*
- * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
- * pointers to the fragment pointers.
- */
-static int ax_encap(sc, c, m_head)
- struct ax_softc *sc;
- struct ax_chain *c;
- struct mbuf *m_head;
-{
- int frag = 0;
- volatile struct ax_desc *f = NULL;
- int total_len;
- struct mbuf *m;
-
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- m = m_head;
- total_len = 0;
-
- for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
- if (m->m_len != 0) {
- if (frag == AX_MAXFRAGS)
- break;
- total_len += m->m_len;
- f = &c->ax_ptr->ax_frag[frag];
- f->ax_ctl = m->m_len;
- if (frag == 0) {
- f->ax_status = 0;
- f->ax_ctl |= AX_TXCTL_FIRSTFRAG;
- } else
- f->ax_status = AX_TXSTAT_OWN;
- f->ax_next = vtophys(&c->ax_ptr->ax_frag[frag + 1]);
- f->ax_data = vtophys(mtod(m, vm_offset_t));
- frag++;
- }
- }
-
- /*
- * Handle special case: we ran out of fragments,
- * but we have more mbufs left in the chain. Copy the
- * data into an mbuf cluster. Note that we don't
- * bother clearing the values in the other fragment
- * pointers/counters; it wouldn't gain us anything,
- * and would waste cycles.
- */
- if (m != NULL) {
- struct mbuf *m_new = NULL;
-
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("ax%d: no memory for tx list", sc->ax_unit);
- return(1);
- }
- if (m_head->m_pkthdr.len > MHLEN) {
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- printf("ax%d: no memory for tx list",
- sc->ax_unit);
- return(1);
- }
- }
- m_copydata(m_head, 0, m_head->m_pkthdr.len,
- mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
- m_freem(m_head);
- m_head = m_new;
- f = &c->ax_ptr->ax_frag[0];
- f->ax_status = 0;
- f->ax_data = vtophys(mtod(m_new, caddr_t));
- f->ax_ctl = total_len = m_new->m_len;
- f->ax_ctl |= AX_TXCTL_FIRSTFRAG;
- frag = 1;
- }
-
- c->ax_mbuf = m_head;
- c->ax_lastdesc = frag - 1;
- AX_TXCTL(c) |= AX_TXCTL_LASTFRAG|AX_TXCTL_FINT;
- c->ax_ptr->ax_frag[0].ax_ctl |= AX_TXCTL_FINT;
- AX_TXNEXT(c) = vtophys(&c->ax_nextdesc->ax_ptr->ax_frag[0]);
- return(0);
-}
-
-/*
- * Main transmit routine. To avoid having to do mbuf copies, we put pointers
- * to the mbuf data regions directly in the transmit lists. We also save a
- * copy of the pointers since the transmit list fragment pointers are
- * physical addresses.
- */
-
-static void ax_start(ifp)
- struct ifnet *ifp;
-{
- struct ax_softc *sc;
- struct mbuf *m_head = NULL;
- struct ax_chain *cur_tx = NULL, *start_tx;
-
- sc = ifp->if_softc;
-
- if (sc->ax_autoneg) {
- sc->ax_tx_pend = 1;
- return;
- }
-
- /*
- * Check for an available queue slot. If there are none,
- * punt.
- */
- if (sc->ax_cdata.ax_tx_free->ax_mbuf != NULL) {
- ifp->if_flags |= IFF_OACTIVE;
- return;
- }
-
- start_tx = sc->ax_cdata.ax_tx_free;
-
- while(sc->ax_cdata.ax_tx_free->ax_mbuf == NULL) {
- IF_DEQUEUE(&ifp->if_snd, m_head);
- if (m_head == NULL)
- break;
-
- /* Pick a descriptor off the free list. */
- cur_tx = sc->ax_cdata.ax_tx_free;
- sc->ax_cdata.ax_tx_free = cur_tx->ax_nextdesc;
-
- /* Pack the data into the descriptor. */
- ax_encap(sc, cur_tx, m_head);
- if (cur_tx != start_tx)
- AX_TXOWN(cur_tx) = AX_TXSTAT_OWN;
-
- /*
- * If there's a BPF listener, bounce a copy of this frame
- * to him.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp, cur_tx->ax_mbuf);
-
- AX_TXOWN(cur_tx) = AX_TXSTAT_OWN;
- CSR_WRITE_4(sc, AX_TXSTART, 0xFFFFFFFF);
- }
-
- sc->ax_cdata.ax_tx_tail = cur_tx;
- if (sc->ax_cdata.ax_tx_head == NULL)
- sc->ax_cdata.ax_tx_head = start_tx;
-
- /*
- * Set a timeout in case the chip goes out to lunch.
- */
- ifp->if_timer = 5;
-
- return;
-}
-
-static void ax_init(xsc)
- void *xsc;
-{
- struct ax_softc *sc = xsc;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- u_int16_t phy_bmcr = 0;
- int s;
-
- if (sc->ax_autoneg)
- return;
-
- s = splimp();
-
- if (sc->ax_pinfo != NULL)
- phy_bmcr = ax_phy_readreg(sc, PHY_BMCR);
-
- /*
- * Cancel pending I/O and free all RX/TX buffers.
- */
- ax_stop(sc);
- ax_reset(sc);
-
- /*
- * Set cache alignment and burst length.
- */
- CSR_WRITE_4(sc, AX_BUSCTL, AX_BUSCTL_CONFIG);
-
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_HEARTBEAT);
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_STORENFWD);
-
- if (sc->ax_pinfo != NULL) {
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_PORTSEL);
- ax_setcfg(sc, ax_phy_readreg(sc, PHY_BMCR));
- } else
- ax_setmode(sc, sc->ifmedia.ifm_media, 0);
-
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_TX_THRESH);
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_SPEEDSEL);
-
- if (IFM_SUBTYPE(sc->ifmedia.ifm_media) == IFM_10_T)
- AX_SETBIT(sc, AX_NETCFG, AX_TXTHRESH_160BYTES);
- else
- AX_SETBIT(sc, AX_NETCFG, AX_TXTHRESH_72BYTES);
-
- /* Init our MAC address */
- CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_PAR0);
- CSR_WRITE_4(sc, AX_FILTDATA, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
- CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_PAR1);
- CSR_WRITE_4(sc, AX_FILTDATA, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
-
- /* Init circular RX list. */
- if (ax_list_rx_init(sc) == ENOBUFS) {
- printf("ax%d: initialization failed: no "
- "memory for rx buffers\n", sc->ax_unit);
- ax_stop(sc);
- (void)splx(s);
- return;
- }
-
- /*
- * Init tx descriptors.
- */
- ax_list_tx_init(sc);
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC) {
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_RX_PROMISC);
- } else {
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_RX_PROMISC);
- }
-
- /*
- * Set the capture broadcast bit to capture broadcast frames.
- */
- if (ifp->if_flags & IFF_BROADCAST) {
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_RX_BROAD);
- } else {
- AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_RX_BROAD);
- }
-
- /*
- * Load the multicast filter.
- */
- ax_setmulti(sc);
-
- /*
- * Load the address of the RX list.
- */
- CSR_WRITE_4(sc, AX_RXADDR, vtophys(sc->ax_cdata.ax_rx_head->ax_ptr));
- CSR_WRITE_4(sc, AX_TXADDR, vtophys(&sc->ax_ldata->ax_tx_list[0]));
-
- /*
- * Enable interrupts.
- */
- CSR_WRITE_4(sc, AX_IMR, AX_INTRS);
- CSR_WRITE_4(sc, AX_ISR, 0xFFFFFFFF);
-
- /* Enable receiver and transmitter. */
- AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_TX_ON|AX_NETCFG_RX_ON);
- CSR_WRITE_4(sc, AX_RXSTART, 0xFFFFFFFF);
-
- /* Restore state of BMCR */
- if (sc->ax_pinfo != NULL)
- ax_phy_writereg(sc, PHY_BMCR, phy_bmcr);
-
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
-
- (void)splx(s);
-
- return;
-}
-
-/*
- * Set media options.
- */
-static int ax_ifmedia_upd(ifp)
- struct ifnet *ifp;
-{
- struct ax_softc *sc;
- struct ifmedia *ifm;
-
- sc = ifp->if_softc;
- ifm = &sc->ifmedia;
-
- if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
- return(EINVAL);
-
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO)
- ax_autoneg_mii(sc, AX_FLAG_SCHEDDELAY, 1);
- else {
- if (sc->ax_pinfo == NULL)
- ax_setmode(sc, ifm->ifm_media, 1);
- else
- ax_setmode_mii(sc, ifm->ifm_media);
- }
-
- return(0);
-}
-
-/*
- * Report current media status.
- */
-static void ax_ifmedia_sts(ifp, ifmr)
- struct ifnet *ifp;
- struct ifmediareq *ifmr;
-{
- struct ax_softc *sc;
- u_int16_t advert = 0, ability = 0;
- u_int32_t media = 0;
-
- sc = ifp->if_softc;
-
- ifmr->ifm_active = IFM_ETHER;
-
- if (sc->ax_pinfo == NULL) {
- media = CSR_READ_4(sc, AX_NETCFG);
- if (media & AX_NETCFG_PORTSEL)
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX;
- else
- ifmr->ifm_active = IFM_ETHER|IFM_10_T;
- if (media & AX_NETCFG_FULLDUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- return;
- }
-
- if (!(ax_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) {
- if (ax_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL)
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX;
- else
- ifmr->ifm_active = IFM_ETHER|IFM_10_T;
- if (ax_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- return;
- }
-
- ability = ax_phy_readreg(sc, PHY_LPAR);
- advert = ax_phy_readreg(sc, PHY_ANAR);
- if (advert & PHY_ANAR_100BT4 &&
- ability & PHY_ANAR_100BT4) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_T4;
- } else if (advert & PHY_ANAR_100BTXFULL &&
- ability & PHY_ANAR_100BTXFULL) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX;
- } else if (advert & PHY_ANAR_100BTXHALF &&
- ability & PHY_ANAR_100BTXHALF) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX;
- } else if (advert & PHY_ANAR_10BTFULL &&
- ability & PHY_ANAR_10BTFULL) {
- ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX;
- } else if (advert & PHY_ANAR_10BTHALF &&
- ability & PHY_ANAR_10BTHALF) {
- ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX;
- }
-
- return;
-}
-
-static int ax_ioctl(ifp, command, data)
- struct ifnet *ifp;
- u_long command;
- caddr_t data;
-{
- struct ax_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:
- if (ifp->if_flags & IFF_UP) {
- ax_init(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- ax_stop(sc);
- }
- error = 0;
- break;
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- ax_setmulti(sc);
- error = 0;
- break;
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
- break;
- default:
- error = EINVAL;
- break;
- }
-
- (void)splx(s);
-
- return(error);
-}
-
-static void ax_watchdog(ifp)
- struct ifnet *ifp;
-{
- struct ax_softc *sc;
-
- sc = ifp->if_softc;
-
- if (sc->ax_autoneg) {
- ax_autoneg_mii(sc, AX_FLAG_DELAYTIMEO, 1);
- if (!(ifp->if_flags & IFF_UP))
- ax_stop(sc);
- return;
- }
-
- ifp->if_oerrors++;
- printf("ax%d: watchdog timeout\n", sc->ax_unit);
-
- if (sc->ax_pinfo != NULL) {
- if (!(ax_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
- printf("ax%d: no carrier - transceiver "
- "cable problem?\n", sc->ax_unit);
- }
-
- ax_stop(sc);
- ax_reset(sc);
- ax_init(sc);
-
- if (ifp->if_snd.ifq_head != NULL)
- ax_start(ifp);
-
- return;
-}
-
-/*
- * Stop the adapter and free any mbufs allocated to the
- * RX and TX lists.
- */
-static void ax_stop(sc)
- struct ax_softc *sc;
-{
- register int i;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_timer = 0;
-
- AX_CLRBIT(sc, AX_NETCFG, (AX_NETCFG_RX_ON|AX_NETCFG_TX_ON));
- CSR_WRITE_4(sc, AX_IMR, 0x00000000);
- CSR_WRITE_4(sc, AX_TXADDR, 0x00000000);
- CSR_WRITE_4(sc, AX_RXADDR, 0x00000000);
-
- /*
- * Free data in the RX lists.
- */
- for (i = 0; i < AX_RX_LIST_CNT; i++) {
- if (sc->ax_cdata.ax_rx_chain[i].ax_mbuf != NULL) {
- m_freem(sc->ax_cdata.ax_rx_chain[i].ax_mbuf);
- sc->ax_cdata.ax_rx_chain[i].ax_mbuf = NULL;
- }
- }
- bzero((char *)&sc->ax_ldata->ax_rx_list,
- sizeof(sc->ax_ldata->ax_rx_list));
-
- /*
- * Free the TX list buffers.
- */
- for (i = 0; i < AX_TX_LIST_CNT; i++) {
- if (sc->ax_cdata.ax_tx_chain[i].ax_mbuf != NULL) {
- m_freem(sc->ax_cdata.ax_tx_chain[i].ax_mbuf);
- sc->ax_cdata.ax_tx_chain[i].ax_mbuf = NULL;
- }
- }
-
- bzero((char *)&sc->ax_ldata->ax_tx_list,
- sizeof(sc->ax_ldata->ax_tx_list));
-
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-
- return;
-}
-
-/*
- * Stop all chip I/O so that the kernel's probe routines don't
- * get confused by errant DMAs when rebooting.
- */
-static void ax_shutdown(dev)
- device_t dev;
-{
- struct ax_softc *sc;
-
- sc = device_get_softc(dev);
-
- ax_stop(sc);
-
- return;
-}
diff --git a/sys/pci/if_axreg.h b/sys/pci/if_axreg.h
deleted file mode 100644
index 1d3c3a6..0000000
--- a/sys/pci/if_axreg.h
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * ASIX register definitions.
- */
-
-#define AX_BUSCTL 0x00 /* bus control */
-#define AX_TXSTART 0x08 /* tx start demand */
-#define AX_RXSTART 0x10 /* rx start demand */
-#define AX_RXADDR 0x18 /* rx descriptor list start addr */
-#define AX_TXADDR 0x20 /* tx descriptor list start addr */
-#define AX_ISR 0x28 /* interrupt status register */
-#define AX_NETCFG 0x30 /* network config register */
-#define AX_IMR 0x38 /* interrupt mask */
-#define AX_FRAMESDISCARDED 0x40 /* # of discarded frames */
-#define AX_SIO 0x48 /* MII and ROM/EEPROM access */
-#define AX_RESERVED 0x50
-#define AX_GENTIMER 0x58 /* general timer */
-#define AX_GENPORT 0x60 /* general purpose port */
-#define AX_FILTIDX 0x68 /* RX filter index */
-#define AX_FILTDATA 0x70 /* RX filter data */
-
-/*
- * Bus control bits.
- */
-#define AX_BUSCTL_RESET 0x00000001
-#define AX_BUSCTL_ARBITRATION 0x00000002
-#define AX_BUSCTL_BIGENDIAN 0x00000080
-#define AX_BUSCTL_BURSTLEN 0x00003F00
-#define AX_BUSCTL_BUF_BIGENDIAN 0x00100000
-#define AX_BISCTL_READMULTI 0x00200000
-
-#define AX_BURSTLEN_UNLIMIT 0x00000000
-#define AX_BURSTLEN_1LONG 0x00000100
-#define AX_BURSTLEN_2LONG 0x00000200
-#define AX_BURSTLEN_4LONG 0x00000400
-#define AX_BURSTLEN_8LONG 0x00000800
-#define AX_BURSTLEN_16LONG 0x00001000
-#define AX_BURSTLEN_32LONG 0x00002000
-
-#define AX_BUSCTL_CONFIG (AX_BUSCTL_ARBITRATION|AX_BURSTLEN_8LONG|AX_BURSTLEN_8LONG)
-
-/*
- * Interrupt status bits.
- */
-#define AX_ISR_TX_OK 0x00000001
-#define AX_ISR_TX_IDLE 0x00000002
-#define AX_ISR_TX_NOBUF 0x00000004
-#define AX_ISR_TX_JABBERTIMEO 0x00000008
-#define AX_ISR_TX_UNDERRUN 0x00000020
-#define AX_ISR_RX_OK 0x00000040
-#define AX_ISR_RX_NOBUF 0x00000080
-#define AX_ISR_RX_IDLE 0x00000100
-#define AX_ISR_RX_WATDOGTIMEO 0x00000200
-#define AX_ISR_TX_EARLY 0x00000400
-#define AX_ISR_TIMER_EXPIRED 0x00000800
-#define AX_ISR_BUS_ERR 0x00002000
-#define AX_ISR_ABNORMAL 0x00008000
-#define AX_ISR_NORMAL 0x00010000
-#define AX_ISR_RX_STATE 0x000E0000
-#define AX_ISR_TX_STATE 0x00700000
-#define AX_ISR_BUSERRTYPE 0x03800000
-
-#define AX_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
-#define AX_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
-#define AX_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
-#define AX_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
-#define AX_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
-#define AX_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */
-#define AX_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
-#define AX_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
-
-#define AX_TXSTATE_RESET 0x00000000 /* 000 - reset */
-#define AX_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
-#define AX_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
-#define AX_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
-#define AX_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
-#define AX_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
-#define AX_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
-#define AX_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
-
-/*
- * Network config bits.
- */
-#define AX_NETCFG_LINKSTAT_PCS 0x00000001
-#define AX_NETCFG_RX_ON 0x00000002
-#define AX_NETCFG_RX_BADFRAMES 0x00000008
-#define AX_NETCFG_RX_PROMISC 0x00000040
-#define AX_NETCFG_RX_ALLMULTI 0x00000080
-#define AX_NETCFG_RX_BROAD 0x00000100
-#define AX_NETCFG_FULLDUPLEX 0x00000200
-#define AX_NETCFG_LOOPBACK 0x00000C00
-#define AX_NETCFG_FORCECOLL 0x00001000
-#define AX_NETCFG_TX_ON 0x00002000
-#define AX_NETCFG_TX_THRESH 0x0000C000
-#define AX_NETCFG_PORTSEL 0x00040000 /* 0 == SRL, 1 == MII/SYM */
-#define AX_NETCFG_HEARTBEAT 0x00080000 /* 0 == ON, 1 == OFF */
-#define AX_NETCFG_STORENFWD 0x00200000
-#define AX_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */
-#define AX_NETCFG_PCS 0x00800000
-#define AX_NETCFG_SCRAMBLER 0x01000000
-#define AX_NETCFG_RX_ALL 0x40000000
-
-#define AX_OPMODE_NORM 0x00000000
-#define AX_OPMODE_INTLOOP 0x00000400
-#define AX_OPMODE_EXTLOOP 0x00000800
-
-#define AX_TXTHRESH_72BYTES 0x00000000
-#define AX_TXTHRESH_96BYTES 0x00004000
-#define AX_TXTHRESH_128BYTES 0x00008000
-#define AX_TXTHRESH_160BYTES 0x0000C000
-
-/*
- * Interrupt mask bits.
- */
-#define AX_IMR_TX_OK 0x00000001
-#define AX_IMR_TX_IDLE 0x00000002
-#define AX_IMR_TX_NOBUF 0x00000004
-#define AX_IMR_TX_JABBERTIMEO 0x00000008
-#define AX_IMR_TX_UNDERRUN 0x00000020
-#define AX_IMR_RX_OK 0x00000040
-#define AX_IMR_RX_NOBUF 0x00000080
-#define AX_IMR_RX_IDLE 0x00000100
-#define AX_IMR_RX_WATDOGTIMEO 0x00000200
-#define AX_IMR_TX_EARLY 0x00000400
-#define AX_IMR_TIMER_EXPIRED 0x00000800
-#define AX_IMR_BUS_ERR 0x00002000
-#define AX_IMR_RX_EARLY 0x00004000
-#define AX_IMR_ABNORMAL 0x00008000
-#define AX_IMR_NORMAL 0x00010000
-
-#define AX_INTRS \
- (AX_IMR_RX_OK|AX_IMR_TX_OK|AX_IMR_RX_NOBUF|AX_IMR_RX_WATDOGTIMEO|\
- AX_IMR_TX_NOBUF|AX_IMR_TX_UNDERRUN|AX_IMR_BUS_ERR| \
- AX_IMR_ABNORMAL|AX_IMR_NORMAL|/*AX_IMR_TX_EARLY*/ \
- AX_IMR_TX_IDLE|AX_IMR_RX_IDLE)
-
-/*
- * Serial I/O (EEPROM/ROM) bits.
- */
-#define AX_SIO_EE_CS 0x00000001 /* EEPROM chip select */
-#define AX_SIO_EE_CLK 0x00000002 /* EEPROM clock */
-#define AX_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */
-#define AX_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */
-#define AX_SIO_EESEL 0x00000800
-#define AX_SIO_ROMSEL 0x00001000
-#define AX_SIO_ROMCTL_WRITE 0x00002000
-#define AX_SIO_ROMCTL_READ 0x00004000
-#define AX_SIO_MII_CLK 0x00010000 /* MDIO clock */
-#define AX_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */
-#define AX_SIO_MII_DIR 0x00040000 /* MDIO dir */
-#define AX_SIO_MII_DATAIN 0x00080000 /* MDIO data in */
-
-#define AX_EECMD_WRITE 0x140
-#define AX_EECMD_READ 0x180
-#define AX_EECMD_ERASE 0x1c0
-
-#define AX_EE_NODEADDR_OFFSET 0x70
-#define AX_EE_NODEADDR 10
-
-/*
- * General purpose timer register
- */
-#define AX_TIMER_VALUE 0x0000FFFF
-#define AX_TIMER_CONTINUOUS 0x00010000
-
-/*
- * RX Filter Index Register values
- */
-#define AX_FILTIDX_PAR0 0x00000000
-#define AX_FILTIDX_PAR1 0x00000001
-#define AX_FILTIDX_MAR0 0x00000002
-#define AX_FILTIDX_MAR1 0x00000003
-
-/*
- * ASIX TX/RX list structure.
- */
-
-struct ax_desc {
- volatile u_int32_t ax_status;
- volatile u_int32_t ax_ctl;
- volatile u_int32_t ax_ptr1;
- volatile u_int32_t ax_ptr2;
-};
-
-#define ax_data ax_ptr1
-#define ax_next ax_ptr2
-
-#define AX_RXSTAT_FIFOOFLOW 0x00000001
-#define AX_RXSTAT_CRCERR 0x00000002
-#define AX_RXSTAT_DRIBBLE 0x00000004
-#define AX_RXSTAT_WATCHDOG 0x00000010
-#define AX_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */
-#define AX_RXSTAT_COLLSEEN 0x00000040
-#define AX_RXSTAT_GIANT 0x00000080
-#define AX_RXSTAT_LASTFRAG 0x00000100
-#define AX_RXSTAT_FIRSTFRAG 0x00000200
-#define AX_RXSTAT_MULTICAST 0x00000400
-#define AX_RXSTAT_RUNT 0x00000800
-#define AX_RXSTAT_RXTYPE 0x00003000
-#define AX_RXSTAT_RXERR 0x00008000
-#define AX_RXSTAT_RXLEN 0x3FFF0000
-#define AX_RXSTAT_OWN 0x80000000
-
-#define AX_RXBYTES(x) ((x & AX_RXSTAT_RXLEN) >> 16)
-#define AX_RXSTAT (AX_RXSTAT_FIRSTFRAG|AX_RXSTAT_LASTFRAG|AX_RXSTAT_OWN)
-
-#define AX_RXCTL_BUFLEN1 0x00000FFF
-#define AX_RXCTL_BUFLEN2 0x00FFF000
-#define AX_RXCTL_RLAST 0x02000000
-
-#define AX_TXSTAT_DEFER 0x00000001
-#define AX_TXSTAT_UNDERRUN 0x00000002
-#define AX_TXSTAT_LINKFAIL 0x00000003
-#define AX_TXSTAT_COLLCNT 0x00000078
-#define AX_TXSTAT_SQE 0x00000080
-#define AX_TXSTAT_EXCESSCOLL 0x00000100
-#define AX_TXSTAT_LATECOLL 0x00000200
-#define AX_TXSTAT_NOCARRIER 0x00000400
-#define AX_TXSTAT_CARRLOST 0x00000800
-#define AX_TXSTAT_JABTIMEO 0x00004000
-#define AX_TXSTAT_ERRSUM 0x00008000
-#define AX_TXSTAT_OWN 0x80000000
-
-#define AX_TXCTL_BUFLEN1 0x000007FF
-#define AX_TXCTL_BUFLEN2 0x003FF800
-#define AX_TXCTL_PAD 0x00800000
-#define AX_TXCTL_TLAST 0x02000000
-#define AX_TXCTL_NOCRC 0x04000000
-#define AX_TXCTL_FIRSTFRAG 0x20000000
-#define AX_TXCTL_LASTFRAG 0x40000000
-#define AX_TXCTL_FINT 0x80000000
-
-#define AX_MAXFRAGS 16
-#define AX_RX_LIST_CNT 64
-#define AX_TX_LIST_CNT 128
-#define AX_MIN_FRAMELEN 60
-
-/*
- * A tx 'super descriptor' is actually 16 regular descriptors
- * back to back.
- */
-struct ax_txdesc {
- volatile struct ax_desc ax_frag[AX_MAXFRAGS];
-};
-
-#define AX_TXNEXT(x) x->ax_ptr->ax_frag[x->ax_lastdesc].ax_next
-#define AX_TXSTATUS(x) x->ax_ptr->ax_frag[x->ax_lastdesc].ax_status
-#define AX_TXCTL(x) x->ax_ptr->ax_frag[x->ax_lastdesc].ax_ctl
-#define AX_TXDATA(x) x->ax_ptr->ax_frag[x->ax_lastdesc].ax_data
-
-#define AX_TXOWN(x) x->ax_ptr->ax_frag[0].ax_status
-
-#define AX_UNSENT 0x12341234
-
-struct ax_list_data {
- volatile struct ax_desc ax_rx_list[AX_RX_LIST_CNT];
- volatile struct ax_txdesc ax_tx_list[AX_TX_LIST_CNT];
-};
-
-struct ax_chain {
- volatile struct ax_txdesc *ax_ptr;
- struct mbuf *ax_mbuf;
- struct ax_chain *ax_nextdesc;
- u_int8_t ax_lastdesc;
-};
-
-struct ax_chain_onefrag {
- volatile struct ax_desc *ax_ptr;
- struct mbuf *ax_mbuf;
- struct ax_chain_onefrag *ax_nextdesc;
-};
-
-struct ax_chain_data {
- struct ax_chain_onefrag ax_rx_chain[AX_RX_LIST_CNT];
- struct ax_chain ax_tx_chain[AX_TX_LIST_CNT];
-
- struct ax_chain_onefrag *ax_rx_head;
-
- struct ax_chain *ax_tx_head;
- struct ax_chain *ax_tx_tail;
- struct ax_chain *ax_tx_free;
-};
-
-struct ax_type {
- u_int16_t ax_vid;
- u_int16_t ax_did;
- char *ax_name;
-};
-
-struct ax_mii_frame {
- u_int8_t mii_stdelim;
- u_int8_t mii_opcode;
- u_int8_t mii_phyaddr;
- u_int8_t mii_regaddr;
- u_int8_t mii_turnaround;
- u_int16_t mii_data;
-};
-
-/*
- * MII constants
- */
-#define AX_MII_STARTDELIM 0x01
-#define AX_MII_READOP 0x02
-#define AX_MII_WRITEOP 0x01
-#define AX_MII_TURNAROUND 0x02
-
-#define AX_FLAG_FORCEDELAY 1
-#define AX_FLAG_SCHEDDELAY 2
-#define AX_FLAG_DELAYTIMEO 3
-
-struct ax_softc {
- struct arpcom arpcom; /* interface info */
- struct ifmedia ifmedia; /* media info */
- bus_space_handle_t ax_bhandle; /* bus space handle */
- bus_space_tag_t ax_btag; /* bus space tag */
- void *ax_intrhand;
- struct resource *ax_irq;
- struct resource *ax_res;
- struct ax_type *ax_info; /* ASIX adapter info */
- struct ax_type *ax_pinfo; /* phy info */
- u_int8_t ax_unit; /* interface number */
- u_int8_t ax_type;
- u_int8_t ax_phy_addr; /* PHY address */
- u_int8_t ax_tx_pend; /* TX pending */
- u_int8_t ax_want_auto;
- u_int8_t ax_autoneg;
- caddr_t ax_ldata_ptr;
- struct ax_list_data *ax_ldata;
- struct ax_chain_data ax_cdata;
-};
-
-/*
- * register space access macros
- */
-#define CSR_WRITE_4(sc, reg, val) \
- bus_space_write_4(sc->ax_btag, sc->ax_bhandle, reg, val)
-#define CSR_WRITE_2(sc, reg, val) \
- bus_space_write_2(sc->ax_btag, sc->ax_bbhandle, reg, val)
-#define CSR_WRITE_1(sc, reg, val) \
- bus_space_write_1(sc->ax_btag, sc->ax_bhandle, reg, val)
-
-#define CSR_READ_4(sc, reg) \
- bus_space_read_4(sc->ax_btag, sc->ax_bhandle, reg)
-#define CSR_READ_2(sc, reg) \
- bus_space_read_2(sc->ax_btag, sc->ax_bhandle, reg)
-#define CSR_READ_1(sc, reg) \
- bus_space_read_1(sc->ax_btag, sc->ax_bhandle, reg)
-
-#define AX_TIMEOUT 1000
-#define ETHER_ALIGN 2
-
-/*
- * General constants that are fun to know.
- *
- * ASIX PCI vendor ID
- */
-#define AX_VENDORID 0x125B
-
-/*
- * ASIX device IDs.
- */
-#define AX_DEVICEID_AX88140A 0x1400
-
-/*
- * The ASIX AX88140 and ASIX AX88141 have the same vendor and
- * device IDs but different revision values.
- */
-#define AX_REVISION_88140 0x00
-#define AX_REVISION_88141 0x10
-
-/*
- * Texas Instruments PHY identifiers
- */
-#define TI_PHY_VENDORID 0x4000
-#define TI_PHY_10BT 0x501F
-#define TI_PHY_100VGPMI 0x502F
-
-/*
- * These ID values are for the NS DP83840A 10/100 PHY
- */
-#define NS_PHY_VENDORID 0x2000
-#define NS_PHY_83840A 0x5C0F
-
-/*
- * Level 1 10/100 PHY
- */
-#define LEVEL1_PHY_VENDORID 0x7810
-#define LEVEL1_PHY_LXT970 0x000F
-
-/*
- * Intel 82555 10/100 PHY
- */
-#define INTEL_PHY_VENDORID 0x0A28
-#define INTEL_PHY_82555 0x015F
-
-/*
- * SEEQ 80220 10/100 PHY
- */
-#define SEEQ_PHY_VENDORID 0x0016
-#define SEEQ_PHY_80220 0xF83F
-
-
-/*
- * PCI low memory base and low I/O base register, and
- * other PCI registers.
- */
-
-#define AX_PCI_VENDOR_ID 0x00
-#define AX_PCI_DEVICE_ID 0x02
-#define AX_PCI_COMMAND 0x04
-#define AX_PCI_STATUS 0x06
-#define AX_PCI_REVID 0x08
-#define AX_PCI_CLASSCODE 0x09
-#define AX_PCI_LATENCY_TIMER 0x0D
-#define AX_PCI_HEADER_TYPE 0x0E
-#define AX_PCI_LOIO 0x10
-#define AX_PCI_LOMEM 0x14
-#define AX_PCI_BIOSROM 0x30
-#define AX_PCI_INTLINE 0x3C
-#define AX_PCI_INTPIN 0x3D
-#define AX_PCI_MINGNT 0x3E
-#define AX_PCI_MINLAT 0x0F
-#define AX_PCI_RESETOPT 0x48
-#define AX_PCI_EEPROM_DATA 0x4C
-
-/* power management registers */
-#define AX_PCI_CAPID 0x44 /* 8 bits */
-#define AX_PCI_NEXTPTR 0x45 /* 8 bits */
-#define AX_PCI_PWRMGMTCAP 0x46 /* 16 bits */
-#define AX_PCI_PWRMGMTCTRL 0x48 /* 16 bits */
-
-#define AX_PSTATE_MASK 0x0003
-#define AX_PSTATE_D0 0x0000
-#define AX_PSTATE_D1 0x0001
-#define AX_PSTATE_D2 0x0002
-#define AX_PSTATE_D3 0x0003
-#define AX_PME_EN 0x0010
-#define AX_PME_STATUS 0x8000
-
-#define PHY_UNKNOWN 6
-
-#define AX_PHYADDR_MIN 0x00
-#define AX_PHYADDR_MAX 0x1F
-
-#define PHY_BMCR 0x00
-#define PHY_BMSR 0x01
-#define PHY_VENID 0x02
-#define PHY_DEVID 0x03
-#define PHY_ANAR 0x04
-#define PHY_LPAR 0x05
-#define PHY_ANEXP 0x06
-
-#define PHY_ANAR_NEXTPAGE 0x8000
-#define PHY_ANAR_RSVD0 0x4000
-#define PHY_ANAR_TLRFLT 0x2000
-#define PHY_ANAR_RSVD1 0x1000
-#define PHY_ANAR_RSVD2 0x0800
-#define PHY_ANAR_RSVD3 0x0400
-#define PHY_ANAR_100BT4 0x0200
-#define PHY_ANAR_100BTXFULL 0x0100
-#define PHY_ANAR_100BTXHALF 0x0080
-#define PHY_ANAR_10BTFULL 0x0040
-#define PHY_ANAR_10BTHALF 0x0020
-#define PHY_ANAR_PROTO4 0x0010
-#define PHY_ANAR_PROTO3 0x0008
-#define PHY_ANAR_PROTO2 0x0004
-#define PHY_ANAR_PROTO1 0x0002
-#define PHY_ANAR_PROTO0 0x0001
-
-/*
- * These are the register definitions for the PHY (physical layer
- * interface chip).
- */
-/*
- * PHY BMCR Basic Mode Control Register
- */
-#define PHY_BMCR_RESET 0x8000
-#define PHY_BMCR_LOOPBK 0x4000
-#define PHY_BMCR_SPEEDSEL 0x2000
-#define PHY_BMCR_AUTONEGENBL 0x1000
-#define PHY_BMCR_RSVD0 0x0800 /* write as zero */
-#define PHY_BMCR_ISOLATE 0x0400
-#define PHY_BMCR_AUTONEGRSTR 0x0200
-#define PHY_BMCR_DUPLEX 0x0100
-#define PHY_BMCR_COLLTEST 0x0080
-#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */
-#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */
-#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */
-#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */
-#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */
-#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */
-#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */
-/*
- * RESET: 1 == software reset, 0 == normal operation
- * Resets status and control registers to default values.
- * Relatches all hardware config values.
- *
- * LOOPBK: 1 == loopback operation enabled, 0 == normal operation
- *
- * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s
- * Link speed is selected byt his bit or if auto-negotiation if bit
- * 12 (AUTONEGENBL) is set (in which case the value of this register
- * is ignored).
- *
- * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled
- * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13
- * determine speed and mode. Should be cleared and then set if PHY configured
- * for no autoneg on startup.
- *
- * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation
- *
- * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation
- *
- * DUPLEX: 1 == full duplex mode, 0 == half duplex mode
- *
- * COLLTEST: 1 == collision test enabled, 0 == normal operation
- */
-
-/*
- * PHY, BMSR Basic Mode Status Register
- */
-#define PHY_BMSR_100BT4 0x8000
-#define PHY_BMSR_100BTXFULL 0x4000
-#define PHY_BMSR_100BTXHALF 0x2000
-#define PHY_BMSR_10BTFULL 0x1000
-#define PHY_BMSR_10BTHALF 0x0800
-#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */
-#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */
-#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */
-#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */
-#define PHY_BMSR_MFPRESUP 0x0040
-#define PHY_BMSR_AUTONEGCOMP 0x0020
-#define PHY_BMSR_REMFAULT 0x0010
-#define PHY_BMSR_CANAUTONEG 0x0008
-#define PHY_BMSR_LINKSTAT 0x0004
-#define PHY_BMSR_JABBER 0x0002
-#define PHY_BMSR_EXTENDED 0x0001
-
-#ifdef __alpha__
-#undef vtophys
-#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
-#endif
diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c
new file mode 100644
index 0000000..25491e0
--- /dev/null
+++ b/sys/pci/if_dc.c
@@ -0,0 +1,2689 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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$
+ */
+
+/*
+ * DEC "tulip" clone ethernet driver. Supports the DEC/Intel 21143
+ * series chips and several workalikes including the following:
+ *
+ * Macronix 98713/98715/98725 PMAC (www.macronix.com)
+ * Macronix/Lite-On 82c115 PNIC II (www.macronix.com)
+ * Lite-On 82c168/82c169 PNIC (www.litecom.com)
+ * ASIX Electronics AX88140A (www.asix.com.tw)
+ * ASIX Electronics AX88141 (www.asix.com.tw)
+ * ADMtek AL981 (www.admtek.com.tw)
+ * ADMtek AN985 (www.admtek.com.tw)
+ * Davicom DM9100, DM9102 (www.davicom8.com)
+ *
+ * Datasheets for the 21143 are available at developer.intel.com.
+ * Datasheets for the clone parts can be found at their respective sites.
+ * (Except for the PNIC; see www.freebsd.org/~wpaul/PNIC/pnic.ps.gz.)
+ * The PNIC II is essentially a Macronix 98715A chip; the only difference
+ * worth noting is that its multicast hash table is only 128 bits wide
+ * instead of 512.
+ *
+ * Written by Bill Paul <wpaul@ee.columbia.edu>
+ * Electrical Engineering Department
+ * Columbia University, New York City
+ */
+
+/*
+ * The Intel 21143 is the successor to the DEC 21140. It is basically
+ * the same as the 21140 but with a few new features. The 21143 supports
+ * three kinds of media attachments:
+ *
+ * o MII port, for 10Mbps and 100Mbps support and NWAY
+ * autonegotiation provided by an external PHY.
+ * o SYM port, for symbol mode 100Mbps support.
+ * o 10baseT port.
+ * o AUI/BNC port.
+ *
+ * The 100Mbps SYM port and 10baseT port can be used together in
+ * combination with the internal NWAY support to create a 10/100
+ * autosensing configuration.
+ *
+ * Knowing which media is available on a given card is tough: you're
+ * supposed to go slogging through the EEPROM looking for media
+ * description structures. Unfortunately, some card vendors that use
+ * the 21143 don't obey the DEC SROM spec correctly, which means that
+ * what you find in the EEPROM may not agree with reality. Fortunately,
+ * the 21143 provides us a way to get around this issue: lurking in
+ * PCI configuration space is the Configuration Wake-Up Command Register.
+ * This register is loaded with a value from the EEPROM when wake on LAN
+ * mode is enabled; this value tells us quite clearly what kind of media
+ * is attached to the NIC. The main purpose of this register is to tell
+ * the NIC what media to scan when in wake on LAN mode, however by
+ * forcibly enabling wake on LAN mode, we can use to learn what kind of
+ * media a given NIC has available and adapt ourselves accordingly.
+ *
+ * Of course, if the media description blocks in the EEPROM are bogus.
+ * what are the odds that the CWUC aren't bogus as well, right? Well,
+ * the CWUC value is more likely to be correct since wake on LAN mode
+ * won't work correctly without it, and wake on LAN is a big selling
+ * point these days. It's also harder to screw up a single byte than
+ * a whole media descriptor block.
+ *
+ * Note that not all tulip workalikes are handled in this driver: we only
+ * deal with those which are relatively well behaved. The Winbond is
+ * handled separately due to its different register offsets and the
+ * special handling needed for its various bugs. The PNIC is handled
+ * here, but I'm not thrilled about it.
+ *
+ * All of the workalike chips use some form of MII transceiver support
+ * with the exception of the Macronix chips, which also have a SYM port.
+ * The ASIX AX88140A is also documented to have a SYM port, but all
+ * the cards I've seen use an MII transceiver, probably because the
+ * AX88140A doesn't support internal NWAY.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <vm/vm.h> /* for vtophys */
+#include <vm/pmap.h> /* for vtophys */
+#include <machine/clock.h> /* for DELAY */
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#define DC_USEIOSPACE
+
+#include <pci/if_dcreg.h>
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/types and their names.
+ */
+static struct dc_type dc_devs[] = {
+ { DC_VENDORID_DEC, DC_DEVICEID_21143,
+ "Intel 21143 10/100BaseTX" },
+ { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9100,
+ "Davicom DM9100 10/100BaseTX" },
+ { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102,
+ "Davicom DM9102 10/100BaseTX" },
+ { DC_VENDORID_ADMTEK, DC_DEVICEID_AL981,
+ "ADMtek AL981 10/100BaseTX" },
+ { DC_VENDORID_ADMTEK, DC_DEVICEID_AN985,
+ "ADMtek AN985 10/100BaseTX" },
+ { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A,
+ "ASIX AX88140A 10/100BaseTX" },
+ { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A,
+ "ASIX AX88141 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_98713,
+ "Macronix 98713 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_98713,
+ "Macronix 98713A 10/100BaseTX" },
+ { DC_VENDORID_CP, DC_DEVICEID_98713_CP,
+ "Compex RL100-TX 10/100BaseTX" },
+ { DC_VENDORID_CP, DC_DEVICEID_98713_CP,
+ "Compex RL100-TX 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_987x5,
+ "Macronix 98715/98715A 10/100BaseTX" },
+ { DC_VENDORID_MX, DC_DEVICEID_987x5,
+ "Macronix 98725 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C115,
+ "LC82C115 PNIC II 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C168,
+ "82c168 PNIC 10/100BaseTX" },
+ { DC_VENDORID_LO, DC_DEVICEID_82C168,
+ "82c169 PNIC 10/100BaseTX" },
+ { 0, 0, NULL }
+};
+
+static int dc_probe __P((device_t));
+static int dc_attach __P((device_t));
+static int dc_detach __P((device_t));
+static void dc_acpi __P((device_t));
+static struct dc_type *dc_devtype __P((device_t));
+static int dc_newbuf __P((struct dc_softc *, int, struct mbuf *));
+static int dc_encap __P((struct dc_softc *, struct mbuf *,
+ u_int32_t *));
+static void dc_pnic_rx_bug_war __P((struct dc_softc *, int));
+static void dc_rxeof __P((struct dc_softc *));
+static void dc_txeof __P((struct dc_softc *));
+static void dc_tick __P((void *));
+static void dc_intr __P((void *));
+static void dc_start __P((struct ifnet *));
+static int dc_ioctl __P((struct ifnet *, u_long, caddr_t));
+static void dc_init __P((void *));
+static void dc_stop __P((struct dc_softc *));
+static void dc_watchdog __P((struct ifnet *));
+static void dc_shutdown __P((device_t));
+static int dc_ifmedia_upd __P((struct ifnet *));
+static void dc_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
+
+static void dc_delay __P((struct dc_softc *));
+static void dc_eeprom_idle __P((struct dc_softc *));
+static void dc_eeprom_putbyte __P((struct dc_softc *, int));
+static void dc_eeprom_getword __P((struct dc_softc *, int, u_int16_t *));
+static void dc_eeprom_getword_pnic
+ __P((struct dc_softc *, int, u_int16_t *));
+static void dc_read_eeprom __P((struct dc_softc *, caddr_t, int,
+ int, int));
+
+static void dc_mii_writebit __P((struct dc_softc *, int));
+static int dc_mii_readbit __P((struct dc_softc *));
+static void dc_mii_sync __P((struct dc_softc *));
+static void dc_mii_send __P((struct dc_softc *, u_int32_t, int));
+static int dc_mii_readreg __P((struct dc_softc *, struct dc_mii_frame *));
+static int dc_mii_writereg __P((struct dc_softc *, struct dc_mii_frame *));
+static int dc_miibus_readreg __P((device_t, int, int));
+static int dc_miibus_writereg __P((device_t, int, int, int));
+static void dc_miibus_statchg __P((device_t));
+
+static void dc_setcfg __P((struct dc_softc *, int));
+static u_int32_t dc_crc_le __P((struct dc_softc *, caddr_t));
+static u_int32_t dc_crc_be __P((caddr_t));
+static void dc_setfilt_21143 __P((struct dc_softc *));
+static void dc_setfilt_asix __P((struct dc_softc *));
+static void dc_setfilt_admtek __P((struct dc_softc *));
+
+static void dc_setfilt __P((struct dc_softc *));
+
+static void dc_reset __P((struct dc_softc *));
+static int dc_list_rx_init __P((struct dc_softc *));
+static int dc_list_tx_init __P((struct dc_softc *));
+
+#ifdef DC_USEIOSPACE
+#define DC_RES SYS_RES_IOPORT
+#define DC_RID DC_PCI_CFBIO
+#else
+#define DC_RES SYS_RES_MEMORY
+#define DC_RID DC_PCI_CFBMA
+#endif
+
+static device_method_t dc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, dc_probe),
+ DEVMETHOD(device_attach, dc_attach),
+ DEVMETHOD(device_detach, dc_detach),
+ DEVMETHOD(device_shutdown, dc_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, dc_miibus_readreg),
+ DEVMETHOD(miibus_writereg, dc_miibus_writereg),
+ DEVMETHOD(miibus_statchg, dc_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t dc_driver = {
+ "dc",
+ dc_methods,
+ sizeof(struct dc_softc)
+};
+
+static devclass_t dc_devclass;
+
+DRIVER_MODULE(if_dc, pci, dc_driver, dc_devclass, 0, 0);
+DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0);
+
+#define DC_SETBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x))
+
+#define DC_CLRBIT(sc, reg, x) \
+ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x))
+
+#define SIO_SET(x) DC_SETBIT(sc, DC_SIO, (x))
+#define SIO_CLR(x) DC_CLRBIT(sc, DC_SIO, (x))
+
+static void dc_delay(sc)
+ struct dc_softc *sc;
+{
+ int idx;
+
+ for (idx = (300 / 33) + 1; idx > 0; idx--)
+ CSR_READ_4(sc, DC_BUSCTL);
+}
+
+static void dc_eeprom_idle(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+
+ for (i = 0; i < 25; i++) {
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+ CSR_WRITE_4(sc, DC_SIO, 0x00000000);
+
+ return;
+}
+
+/*
+ * Send a read command and address to the EEPROM, check for ACK.
+ */
+static void dc_eeprom_putbyte(sc, addr)
+ struct dc_softc *sc;
+ int addr;
+{
+ register int d, i;
+
+ /*
+ * The AN985 has a 93C66 EEPROM on it instead of
+ * a 93C46. It uses a different bit sequence for
+ * specifying the "read" opcode.
+ */
+ if (DC_IS_CENTAUR(sc))
+ d = addr | (DC_EECMD_READ << 2);
+ else
+ d = addr | DC_EECMD_READ;
+
+ /*
+ * Feed in each bit and strobe the clock.
+ */
+ for (i = 0x400; i; i >>= 1) {
+ if (d & i) {
+ SIO_SET(DC_SIO_EE_DATAIN);
+ } else {
+ SIO_CLR(DC_SIO_EE_DATAIN);
+ }
+ dc_delay(sc);
+ SIO_SET(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ SIO_CLR(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ * The PNIC 82c168/82c169 has its own non-standard way to read
+ * the EEPROM.
+ */
+static void dc_eeprom_getword_pnic(sc, addr, dest)
+ struct dc_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int32_t r;
+
+ CSR_WRITE_4(sc, DC_PN_SIOCTL, DC_PN_EEOPCODE_READ|addr);
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(1);
+ r = CSR_READ_4(sc, DC_SIO);
+ if (!(r & DC_PN_SIOCTL_BUSY)) {
+ *dest = (u_int16_t)(r & 0xFFFF);
+ return;
+ }
+ }
+
+ return;
+}
+
+/*
+ * Read a word of data stored in the EEPROM at address 'addr.'
+ */
+static void dc_eeprom_getword(sc, addr, dest)
+ struct dc_softc *sc;
+ int addr;
+ u_int16_t *dest;
+{
+ register int i;
+ u_int16_t word = 0;
+
+ /* Force EEPROM to idle state. */
+ dc_eeprom_idle(sc);
+
+ /* Enter EEPROM access mode. */
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+
+ /*
+ * Send address of word we want to read.
+ */
+ dc_eeprom_putbyte(sc, addr);
+
+ /*
+ * Start reading bits from EEPROM.
+ */
+ for (i = 0x8000; i; i >>= 1) {
+ SIO_SET(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ if (CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT)
+ word |= i;
+ dc_delay(sc);
+ SIO_CLR(DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ /* Turn off EEPROM access mode. */
+ dc_eeprom_idle(sc);
+
+ *dest = word;
+
+ return;
+}
+
+/*
+ * Read a sequence of words from the EEPROM.
+ */
+static void dc_read_eeprom(sc, dest, off, cnt, swap)
+ struct dc_softc *sc;
+ caddr_t dest;
+ int off;
+ int cnt;
+ int swap;
+{
+ int i;
+ u_int16_t word = 0, *ptr;
+
+ for (i = 0; i < cnt; i++) {
+ if (DC_IS_PNIC(sc))
+ dc_eeprom_getword_pnic(sc, off + i, &word);
+ else
+ dc_eeprom_getword(sc, off + i, &word);
+ ptr = (u_int16_t *)(dest + (i * 2));
+ if (swap)
+ *ptr = ntohs(word);
+ else
+ *ptr = word;
+ }
+
+ return;
+}
+
+/*
+ * The following two routines are taken from the Macronix 98713
+ * Application Notes pp.19-21.
+ */
+/*
+ * Write a bit to the MII bus.
+ */
+static void dc_mii_writebit(sc, bit)
+ struct dc_softc *sc;
+ int bit;
+{
+ if (bit)
+ CSR_WRITE_4(sc, DC_SIO,
+ DC_SIO_ROMCTL_WRITE|DC_SIO_MII_DATAOUT);
+ else
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE);
+
+ DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+
+ return;
+}
+
+/*
+ * Read a bit from the MII bus.
+ */
+static int dc_mii_readbit(sc)
+ struct dc_softc *sc;
+{
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_READ|DC_SIO_MII_DIR);
+ CSR_READ_4(sc, DC_SIO);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+ if (CSR_READ_4(sc, DC_SIO) & DC_SIO_MII_DATAIN)
+ return(1);
+
+ return(0);
+}
+
+/*
+ * Sync the PHYs by setting data bit and strobing the clock 32 times.
+ */
+static void dc_mii_sync(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE);
+
+ for (i = 0; i < 32; i++)
+ dc_mii_writebit(sc, 1);
+
+ return;
+}
+
+/*
+ * Clock a series of bits through the MII.
+ */
+static void dc_mii_send(sc, bits, cnt)
+ struct dc_softc *sc;
+ u_int32_t bits;
+ int cnt;
+{
+ int i;
+
+ for (i = (0x1 << (cnt - 1)); i; i >>= 1)
+ dc_mii_writebit(sc, bits & i);
+}
+
+/*
+ * Read an PHY register through the MII.
+ */
+static int dc_mii_readreg(sc, frame)
+ struct dc_softc *sc;
+ struct dc_mii_frame *frame;
+
+{
+ int i, ack, s;
+
+ s = splimp();
+
+ /*
+ * Set up frame for RX.
+ */
+ frame->mii_stdelim = DC_MII_STARTDELIM;
+ frame->mii_opcode = DC_MII_READOP;
+ frame->mii_turnaround = 0;
+ frame->mii_data = 0;
+
+ /*
+ * Sync the PHYs.
+ */
+ dc_mii_sync(sc);
+
+ /*
+ * Send command/address info.
+ */
+ dc_mii_send(sc, frame->mii_stdelim, 2);
+ dc_mii_send(sc, frame->mii_opcode, 2);
+ dc_mii_send(sc, frame->mii_phyaddr, 5);
+ dc_mii_send(sc, frame->mii_regaddr, 5);
+
+#ifdef notdef
+ /* Idle bit */
+ dc_mii_writebit(sc, 1);
+ dc_mii_writebit(sc, 0);
+#endif
+
+ /* Check for ack */
+ ack = dc_mii_readbit(sc);
+
+ /*
+ * Now try reading data bits. If the ack failed, we still
+ * need to clock through 16 cycles to keep the PHY(s) in sync.
+ */
+ if (ack) {
+ for(i = 0; i < 16; i++) {
+ dc_mii_readbit(sc);
+ }
+ goto fail;
+ }
+
+ for (i = 0x8000; i; i >>= 1) {
+ if (!ack) {
+ if (dc_mii_readbit(sc))
+ frame->mii_data |= i;
+ }
+ }
+
+fail:
+
+ dc_mii_writebit(sc, 0);
+ dc_mii_writebit(sc, 0);
+
+ splx(s);
+
+ if (ack)
+ return(1);
+ return(0);
+}
+
+/*
+ * Write to a PHY register through the MII.
+ */
+static int dc_mii_writereg(sc, frame)
+ struct dc_softc *sc;
+ struct dc_mii_frame *frame;
+
+{
+ int s;
+
+ s = splimp();
+ /*
+ * Set up frame for TX.
+ */
+
+ frame->mii_stdelim = DC_MII_STARTDELIM;
+ frame->mii_opcode = DC_MII_WRITEOP;
+ frame->mii_turnaround = DC_MII_TURNAROUND;
+
+ /*
+ * Sync the PHYs.
+ */
+ dc_mii_sync(sc);
+
+ dc_mii_send(sc, frame->mii_stdelim, 2);
+ dc_mii_send(sc, frame->mii_opcode, 2);
+ dc_mii_send(sc, frame->mii_phyaddr, 5);
+ dc_mii_send(sc, frame->mii_regaddr, 5);
+ dc_mii_send(sc, frame->mii_turnaround, 2);
+ dc_mii_send(sc, frame->mii_data, 16);
+
+ /* Idle bit. */
+ dc_mii_writebit(sc, 0);
+ dc_mii_writebit(sc, 0);
+
+ splx(s);
+
+ return(0);
+}
+
+static int dc_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
+{
+ struct dc_mii_frame frame;
+ struct dc_softc *sc;
+ int i, rval, phy_reg;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ /*
+ * Note: both the AL981 and AN985 have internal PHYs,
+ * however the AL981 provides direct access to the PHY
+ * registers while the AN985 uses a serial MII interface.
+ * The AN985's MII interface is also buggy in that you
+ * can read from any MII address (0 to 31), but only address 1
+ * behaves normally. To deal with both cases, we pretend
+ * that the PHY is at MII address 1.
+ */
+ if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR)
+ return(0);
+
+ if (sc->dc_pmode == DC_PMODE_SYM) {
+ if (phy == (MII_NPHY - 1)) {
+ switch(reg) {
+ case MII_BMSR:
+ /*
+ * Fake something to make the probe
+ * code think there's a PHY here.
+ */
+ return(BMSR_MEDIAMASK);
+ break;
+ case MII_PHYIDR1:
+ if (DC_IS_PNIC(sc))
+ return(DC_VENDORID_LO);
+ return(DC_VENDORID_DEC);
+ break;
+ case MII_PHYIDR2:
+ if (DC_IS_PNIC(sc))
+ return(DC_DEVICEID_82C168);
+ return(DC_DEVICEID_21143);
+ break;
+ default:
+ return(0);
+ break;
+ }
+ } else
+ return(0);
+ }
+
+ if (DC_IS_PNIC(sc)) {
+ CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_READ |
+ (phy << 23) | (reg << 18));
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(1);
+ rval = CSR_READ_4(sc, DC_PN_MII);
+ if (!(rval & DC_PN_MII_BUSY)) {
+ rval &= 0xFFFF;
+ return(rval == 0xFFFF ? 0 : rval);
+ }
+ }
+ return(0);
+ }
+
+ if (DC_IS_COMET(sc)) {
+ switch(reg) {
+ case MII_BMCR:
+ phy_reg = DC_AL_BMCR;
+ break;
+ case MII_BMSR:
+ phy_reg = DC_AL_BMSR;
+ break;
+ case MII_PHYIDR1:
+ phy_reg = DC_AL_VENID;
+ break;
+ case MII_PHYIDR2:
+ phy_reg = DC_AL_DEVID;
+ break;
+ case MII_ANAR:
+ phy_reg = DC_AL_ANAR;
+ break;
+ case MII_ANLPAR:
+ phy_reg = DC_AL_LPAR;
+ break;
+ case MII_ANER:
+ phy_reg = DC_AL_ANER;
+ break;
+ default:
+ printf("dc%d: phy_read: bad phy register %x\n",
+ sc->dc_unit, reg);
+ return(0);
+ break;
+ }
+
+ rval = CSR_READ_4(sc, phy_reg) & 0x0000FFFF;
+
+ if (rval == 0xFFFF)
+ return(0);
+ return(rval);
+ }
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ dc_mii_readreg(sc, &frame);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+
+ return(frame.mii_data);
+}
+
+static int dc_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ int phy, reg, data;
+{
+ struct dc_softc *sc;
+ struct dc_mii_frame frame;
+ int i, phy_reg;
+
+ sc = device_get_softc(dev);
+ bzero((char *)&frame, sizeof(frame));
+
+ if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR)
+ return(0);
+
+ if (DC_IS_PNIC(sc)) {
+ CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_WRITE |
+ (phy << 23) | (reg << 10) | data);
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ if (!(CSR_READ_4(sc, DC_PN_MII) & DC_PN_MII_BUSY))
+ break;
+ }
+ return(0);
+ }
+
+ if (DC_IS_COMET(sc)) {
+ switch(reg) {
+ case MII_BMCR:
+ phy_reg = DC_AL_BMCR;
+ break;
+ case MII_BMSR:
+ phy_reg = DC_AL_BMSR;
+ break;
+ case MII_PHYIDR1:
+ phy_reg = DC_AL_VENID;
+ break;
+ case MII_PHYIDR2:
+ phy_reg = DC_AL_DEVID;
+ break;
+ case MII_ANAR:
+ phy_reg = DC_AL_ANAR;
+ break;
+ case MII_ANLPAR:
+ phy_reg = DC_AL_LPAR;
+ break;
+ case MII_ANER:
+ phy_reg = DC_AL_ANER;
+ break;
+ default:
+ printf("dc%d: phy_write: bad phy register %x\n",
+ sc->dc_unit, reg);
+ return(0);
+ break;
+ }
+
+ CSR_WRITE_4(sc, phy_reg, data);
+ return(0);
+ }
+
+ frame.mii_phyaddr = phy;
+ frame.mii_regaddr = reg;
+ frame.mii_data = data;
+
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ dc_mii_writereg(sc, &frame);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+
+ return(0);
+}
+
+static void dc_miibus_statchg(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ if (DC_IS_ADMTEK(sc))
+ return;
+ mii = device_get_softc(sc->dc_miibus);
+ dc_setcfg(sc, mii->mii_media_active);
+ sc->dc_if_media = mii->mii_media_active;
+
+ return;
+}
+
+#define DC_POLY 0xEDB88320
+#define DC_BITS 9
+#define DC_BITS_PNIC_II 7
+
+static u_int32_t dc_crc_le(sc, addr)
+ struct dc_softc *sc;
+ caddr_t addr;
+{
+ u_int32_t idx, bit, data, crc;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (idx = 0; idx < 6; idx++) {
+ for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DC_POLY : 0);
+ }
+
+ /* The hash table on the PNIC II is only 128 bits wide. */
+ if (DC_IS_PNICII(sc))
+ return (crc & ((1 << DC_BITS_PNIC_II) - 1));
+
+ return (crc & ((1 << DC_BITS) - 1));
+}
+
+/*
+ * Calculate CRC of a multicast group address, return the lower 6 bits.
+ */
+static u_int32_t dc_crc_be(addr)
+ caddr_t addr;
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return((crc >> 26) & 0x0000003F);
+}
+
+/*
+ * 21143-style RX filter setup routine. Filter programming is done by
+ * downloading a special setup frame into the TX engine. 21143, Macronix,
+ * PNIC, PNIC II and Davicom chips are programmed this way.
+ *
+ * We always program the chip using 'hash perfect' mode, i.e. one perfect
+ * address (our node address) and a 512-bit hash filter for multicast
+ * frames. We also sneak the broadcast address into the hash filter since
+ * we need that too.
+ */
+void dc_setfilt_21143(sc)
+ struct dc_softc *sc;
+{
+ struct dc_desc *sframe;
+ u_int32_t h, *sp;
+ struct ifmultiaddr *ifma;
+ struct ifnet *ifp;
+ int i;
+
+ ifp = &sc->arpcom.ac_if;
+
+ i = sc->dc_cdata.dc_tx_prod;
+ DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
+ sc->dc_cdata.dc_tx_cnt++;
+ sframe = &sc->dc_ldata->dc_tx_list[i];
+ sp = (u_int32_t *)&sc->dc_cdata.dc_sbuf;
+ bzero((char *)sp, DC_SFRAME_LEN);
+
+ sframe->dc_data = vtophys(&sc->dc_cdata.dc_sbuf);
+ sframe->dc_ctl = DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK |
+ DC_FILTER_HASHPERF | DC_TXCTL_FINT;
+
+ sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)&sc->dc_cdata.dc_sbuf;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
+ ifma = ifma->ifma_link.le_next) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_le(sc,
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ if (ifp->if_flags & IFF_BROADCAST) {
+ h = dc_crc_le(sc, (caddr_t)&etherbroadcastaddr);
+ sp[h >> 4] |= 1 << (h & 0xF);
+ }
+
+ /* Set our MAC address */
+ sp[39] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0];
+ sp[40] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1];
+ sp[41] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2];
+
+ sframe->dc_status = DC_TXSTAT_OWN;
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ /*
+ * The PNIC takes an exceedingly long time to process its
+ * setup frame; wait 10ms after posting the setup frame
+ * before proceeding, just so it has time to swallow its
+ * medicine.
+ */
+ DELAY(10000);
+
+ ifp->if_timer = 5;
+
+ return;
+}
+
+void dc_setfilt_admtek(sc)
+ struct dc_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Init our MAC address */
+ CSR_WRITE_4(sc, DC_AL_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
+ CSR_WRITE_4(sc, DC_AL_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, DC_AL_MAR0, 0);
+ CSR_WRITE_4(sc, DC_AL_MAR1, 0);
+
+ /*
+ * If we're already in promisc or allmulti mode, we
+ * don't have to bother programming the multicast filter.
+ */
+ if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
+ return;
+
+ /* now program new ones */
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
+ ifma = ifma->ifma_link.le_next) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+
+ CSR_WRITE_4(sc, DC_AL_MAR0, hashes[0]);
+ CSR_WRITE_4(sc, DC_AL_MAR1, hashes[1]);
+
+ return;
+}
+
+void dc_setfilt_asix(sc)
+ struct dc_softc *sc;
+{
+ struct ifnet *ifp;
+ int h = 0;
+ u_int32_t hashes[2] = { 0, 0 };
+ struct ifmultiaddr *ifma;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Init our MAC address */
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA,
+ *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA,
+ *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC);
+
+ if (ifp->if_flags & IFF_ALLMULTI)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI);
+
+ /*
+ * The ASIX chip has a special bit to enable reception
+ * of broadcast frames.
+ */
+ if (ifp->if_flags & IFF_BROADCAST)
+ DC_SETBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD);
+ else
+ DC_CLRBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD);
+
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, 0);
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, 0);
+
+ /*
+ * If we're already in promisc or allmulti mode, we
+ * don't have to bother programming the multicast filter.
+ */
+ if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
+ return;
+
+ /* now program new ones */
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
+ ifma = ifma->ifma_link.le_next) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = dc_crc_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
+ }
+
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[0]);
+ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1);
+ CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[1]);
+
+ return;
+}
+
+static void dc_setfilt(sc)
+ struct dc_softc *sc;
+{
+ if (DC_IS_INTEL(sc) || DC_IS_MACRONIX(sc) || DC_IS_PNIC(sc) ||
+ DC_IS_PNICII(sc) || DC_IS_DAVICOM(sc))
+ dc_setfilt_21143(sc);
+
+ if (DC_IS_ASIX(sc))
+ dc_setfilt_asix(sc);
+
+ if (DC_IS_ADMTEK(sc))
+ dc_setfilt_admtek(sc);
+
+ return;
+}
+
+/*
+ * In order to fiddle with the
+ * 'full-duplex' and '100Mbps' bits in the netconfig register, we
+ * first have to put the transmit and/or receive logic in the idle state.
+ */
+static void dc_setcfg(sc, media)
+ struct dc_softc *sc;
+ int media;
+{
+ int i, restart = 0;
+ u_int32_t isr;
+
+ if (IFM_SUBTYPE(media) == IFM_NONE)
+ return;
+
+ if (CSR_READ_4(sc, DC_NETCFG) & (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON)) {
+ restart = 1;
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON));
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(10);
+ isr = CSR_READ_4(sc, DC_ISR);
+ if (isr & DC_ISR_TX_IDLE ||
+ (isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED)
+ break;
+ }
+
+ if (i == DC_TIMEOUT)
+ printf("dc%d: failed to force tx and "
+ "rx to idle state\n", sc->dc_unit);
+
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_100_TX) {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT);
+ if (sc->dc_pmode == DC_PMODE_MII) {
+ DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS);
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_PORTSEL|DC_NETCFG_SCRAMBLER));
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_SCRAMBLER));
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF);
+ } else {
+ if (DC_IS_PNIC(sc)) {
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_SPEEDSEL);
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP);
+ DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL);
+ }
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL|
+ DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER);
+ }
+ }
+
+ if (IFM_SUBTYPE(media) == IFM_10_T) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT);
+ if (sc->dc_pmode == DC_PMODE_MII) {
+ DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS);
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS|
+ DC_NETCFG_PORTSEL|DC_NETCFG_SCRAMBLER));
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF);
+ } else {
+ if (DC_IS_PNIC(sc)) {
+ DC_PN_GPIO_CLRBIT(sc, DC_PN_GPIO_SPEEDSEL);
+ DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP);
+ DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL);
+ }
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER);
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS);
+ }
+ }
+
+ if ((media & IFM_GMASK) == IFM_FDX) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc))
+ DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX);
+ } else {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
+ if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc))
+ DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX);
+ }
+
+ if (restart)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON|DC_NETCFG_RX_ON);
+
+ return;
+}
+
+static void dc_reset(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+
+ DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET);
+
+ for (i = 0; i < DC_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_4(sc, DC_BUSCTL) & DC_BUSCTL_RESET))
+ break;
+ }
+
+ if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc)) {
+ DELAY(10000);
+ DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET);
+ i = 0;
+ }
+
+ if (i == DC_TIMEOUT)
+ printf("dc%d: reset never completed!\n", sc->dc_unit);
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ CSR_WRITE_4(sc, DC_BUSCTL, 0x00000000);
+ CSR_WRITE_4(sc, DC_NETCFG, 0x00000000);
+
+ return;
+}
+
+static struct dc_type *dc_devtype(dev)
+ device_t dev;
+{
+ struct dc_type *t;
+ u_int32_t rev;
+
+ t = dc_devs;
+
+ while(t->dc_name != NULL) {
+ if ((pci_get_vendor(dev) == t->dc_vid) &&
+ (pci_get_device(dev) == t->dc_did)) {
+ /* Check the PCI revision */
+ rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF;
+ if (t->dc_did == DC_DEVICEID_98713 &&
+ rev >= DC_REVISION_98713A)
+ t++;
+ if (t->dc_did == DC_DEVICEID_98713_CP &&
+ rev >= DC_REVISION_98713A)
+ t++;
+ if (t->dc_did == DC_DEVICEID_987x5 &&
+ rev >= DC_REVISION_98725)
+ t++;
+ if (t->dc_did == DC_DEVICEID_AX88140A &&
+ rev >= DC_REVISION_88141)
+ t++;
+ if (t->dc_did == DC_DEVICEID_82C168 &&
+ rev >= DC_REVISION_82C169)
+ t++;
+ return(t);
+ }
+ t++;
+ }
+
+ return(NULL);
+}
+
+/*
+ * Probe for a 21143 or clone chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ * We do a little bit of extra work to identify the exact type of
+ * chip. The MX98713 and MX98713A have the same PCI vendor/device ID,
+ * but different revision IDs. The same is true for 98715/98715A
+ * chips and the 98725, as well as the ASIX and ADMtek chips. In some
+ * cases, the exact chip revision affects driver behavior.
+ */
+static int dc_probe(dev)
+ device_t dev;
+{
+ struct dc_type *t;
+
+ t = dc_devtype(dev);
+
+ if (t != NULL) {
+ device_set_desc(dev, t->dc_name);
+ return(0);
+ }
+
+ return(ENXIO);
+}
+
+static void dc_acpi(dev)
+ device_t dev;
+{
+ u_int32_t r, cptr;
+ int unit;
+
+ unit = device_get_unit(dev);
+
+ /* Find the location of the capabilities block */
+ cptr = pci_read_config(dev, DC_PCI_CCAP, 4) & 0xFF;
+
+ r = pci_read_config(dev, cptr, 4) & 0xFF;
+ if (r == 0x01) {
+
+ r = pci_read_config(dev, cptr + 4, 4);
+ if (r & DC_PSTATE_D3) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_read_config(dev, DC_PCI_CFBIO, 4);
+ membase = pci_read_config(dev, DC_PCI_CFBMA, 4);
+ irq = pci_read_config(dev, DC_PCI_CFIT, 4);
+
+ /* Reset the power state. */
+ printf("dc%d: chip is in D%d power mode "
+ "-- setting to D0\n", unit, r & DC_PSTATE_D3);
+ r &= 0xFFFFFFFC;
+ pci_write_config(dev, cptr + 4, r, 4);
+
+ /* Restore PCI config data. */
+ pci_write_config(dev, DC_PCI_CFBIO, iobase, 4);
+ pci_write_config(dev, DC_PCI_CFBMA, membase, 4);
+ pci_write_config(dev, DC_PCI_CFIT, irq, 4);
+ }
+ }
+ return;
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int dc_attach(dev)
+ device_t dev;
+{
+ int s;
+ u_char eaddr[ETHER_ADDR_LEN];
+ u_int32_t command;
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t revision;
+ int unit, error = 0, rid, mac_offset;
+
+ s = splimp();
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ bzero(sc, sizeof(struct dc_softc));
+
+ /*
+ * Handle power management nonsense.
+ */
+ dc_acpi(dev);
+
+ /*
+ * Map control/status registers.
+ */
+ command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
+ command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
+ pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
+ command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
+
+#ifdef DC_USEIOSPACE
+ if (!(command & PCIM_CMD_PORTEN)) {
+ printf("dc%d: failed to enable I/O ports!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#else
+ if (!(command & PCIM_CMD_MEMEN)) {
+ printf("dc%d: failed to enable memory mapping!\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ rid = DC_RID;
+ sc->dc_res = bus_alloc_resource(dev, DC_RES, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->dc_res == NULL) {
+ printf("dc%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->dc_btag = rman_get_bustag(sc->dc_res);
+ sc->dc_bhandle = rman_get_bushandle(sc->dc_res);
+
+ /* Allocate interrupt */
+ rid = 0;
+ sc->dc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->dc_irq == NULL) {
+ printf("dc%d: couldn't map interrupt\n", unit);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET,
+ dc_intr, sc, &sc->dc_intrhand);
+
+ if (error) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ printf("dc%d: couldn't set up irq\n", unit);
+ goto fail;
+ }
+
+ /* Need this info to decide on a chip type. */
+ sc->dc_info = dc_devtype(dev);
+ revision = pci_read_config(dev, DC_PCI_CFRV, 4) & 0x000000FF;
+
+ switch(sc->dc_info->dc_did) {
+ case DC_DEVICEID_21143:
+ sc->dc_type = DC_TYPE_21143;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ break;
+ case DC_DEVICEID_DM9100:
+ case DC_DEVICEID_DM9102:
+ sc->dc_type = DC_TYPE_DM9102;
+ sc->dc_flags |= DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_AL981:
+ sc->dc_type = DC_TYPE_AL981;
+ sc->dc_flags |= DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_TX_ADMTEK_WAR;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_AN985:
+ sc->dc_type = DC_TYPE_AN985;
+ sc->dc_flags |= DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_TX_ADMTEK_WAR;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ case DC_DEVICEID_98713:
+ case DC_DEVICEID_98713_CP:
+ if (revision < DC_REVISION_98713A) {
+ sc->dc_type = DC_TYPE_98713;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ }
+ if (revision >= DC_REVISION_98713A)
+ sc->dc_type = DC_TYPE_98713A;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ break;
+ case DC_DEVICEID_987x5:
+ sc->dc_type = DC_TYPE_987x5;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ break;
+ case DC_DEVICEID_82C115:
+ sc->dc_type = DC_TYPE_PNICII;
+ sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
+ break;
+ case DC_DEVICEID_82C168:
+ sc->dc_type = DC_TYPE_PNIC;
+ sc->dc_flags |= DC_TX_STORENFWD|DC_TX_USE_TX_INTR;
+ sc->dc_flags |= DC_PNIC_RX_BUG_WAR;
+ sc->dc_pnic_rx_buf = malloc(DC_RXLEN * 5, M_DEVBUF, M_NOWAIT);
+ if (revision < DC_REVISION_82C169)
+ sc->dc_pmode = DC_PMODE_SYM;
+ break;
+ case DC_DEVICEID_AX88140A:
+ sc->dc_type = DC_TYPE_ASIX;
+ sc->dc_flags |= DC_TX_USE_TX_INTR|DC_TX_INTR_FIRSTFRAG;
+ sc->dc_flags |= DC_REDUCED_MII_POLL;
+ sc->dc_pmode = DC_PMODE_MII;
+ break;
+ default:
+ printf("dc%d: unknown device: %x\n", sc->dc_unit,
+ sc->dc_info->dc_did);
+ break;
+ }
+
+ /* Save the cache line size. */
+ sc->dc_cachesize = pci_read_config(dev, DC_PCI_CFLT, 4) & 0xFF;
+
+ /* Reset the adapter. */
+ dc_reset(sc);
+
+ /* Take 21143 out of snooze mode */
+ if (DC_IS_INTEL(sc)) {
+ command = pci_read_config(dev, DC_PCI_CFDD, 4);
+ command &= ~(DC_CFDD_SNOOZE_MODE|DC_CFDD_SLEEP_MODE);
+ pci_write_config(dev, DC_PCI_CFDD, command, 4);
+ }
+
+ /*
+ * Try to learn something about the supported media.
+ * We know that ASIX and ADMtek and Davicom devices
+ * will *always* be using MII media, so that's a no-brainer.
+ * The tricky ones are the Macronix/PNIC II and the
+ * Intel 21143.
+ */
+ if (DC_IS_INTEL(sc)) {
+ u_int32_t media, cwuc;
+ cwuc = pci_read_config(dev, DC_PCI_CWUC, 4);
+ cwuc |= DC_CWUC_FORCE_WUL;
+ pci_write_config(dev, DC_PCI_CWUC, cwuc, 4);
+ DELAY(10000);
+ media = pci_read_config(dev, DC_PCI_CWUC, 4);
+ cwuc &= ~DC_CWUC_FORCE_WUL;
+ pci_write_config(dev, DC_PCI_CWUC, cwuc, 4);
+ DELAY(10000);
+ if (media & DC_CWUC_MII_ABILITY)
+ sc->dc_pmode = DC_PMODE_MII;
+ if (media & DC_CWUC_SYM_ABILITY)
+ sc->dc_pmode = DC_PMODE_SYM;
+ /*
+ * If none of the bits are set, then this NIC
+ * isn't meant to support 'wake up LAN' mode.
+ * This is usually only the case on multiport
+ * cards, and these cards almost always have
+ * MII transceivers.
+ */
+ if (media == 0)
+ sc->dc_pmode = DC_PMODE_MII;
+ } else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) {
+ if (sc->dc_type == DC_TYPE_98713)
+ sc->dc_pmode = DC_PMODE_MII;
+ else
+ sc->dc_pmode = DC_PMODE_SYM;
+ } else if (!sc->dc_pmode)
+ sc->dc_pmode = DC_PMODE_MII;
+
+ /*
+ * Get station address from the EEPROM.
+ */
+ switch(sc->dc_type) {
+ case DC_TYPE_98713:
+ case DC_TYPE_98713A:
+ case DC_TYPE_987x5:
+ case DC_TYPE_PNICII:
+ dc_read_eeprom(sc, (caddr_t)&mac_offset,
+ (DC_EE_NODEADDR_OFFSET / 2), 1, 0);
+ dc_read_eeprom(sc, (caddr_t)&eaddr, (mac_offset / 2), 3, 0);
+ break;
+ case DC_TYPE_PNIC:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 1);
+ break;
+ case DC_TYPE_DM9102:
+ case DC_TYPE_21143:
+ case DC_TYPE_ASIX:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
+ break;
+ case DC_TYPE_AL981:
+ case DC_TYPE_AN985:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_AL_EE_NODEADDR, 3, 0);
+ break;
+ default:
+ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
+ break;
+ }
+
+ /*
+ * A 21143 or clone chip was detected. Inform the world.
+ */
+ printf("dc%d: Ethernet address: %6D\n", unit, eaddr, ":");
+
+ sc->dc_unit = unit;
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ sc->dc_ldata = contigmalloc(sizeof(struct dc_list_data), M_DEVBUF,
+ M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->dc_ldata == NULL) {
+ printf("dc%d: no memory for list buffers!\n", unit);
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ bzero(sc->dc_ldata, sizeof(struct dc_list_data));
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = "dc";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = dc_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = dc_start;
+ ifp->if_watchdog = dc_watchdog;
+ ifp->if_init = dc_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = DC_TX_LIST_CNT - 1;
+
+ /*
+ * Do MII setup.
+ */
+ error = mii_phy_probe(dev, &sc->dc_miibus,
+ dc_ifmedia_upd, dc_ifmedia_sts);
+
+ if (error && DC_IS_INTEL(sc)) {
+ sc->dc_pmode = DC_PMODE_SYM;
+ mii_phy_probe(dev, &sc->dc_miibus,
+ dc_ifmedia_upd, dc_ifmedia_sts);
+ error = 0;
+ }
+
+ if (error) {
+ printf("dc%d: MII without any PHY!\n", sc->dc_unit);
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * Call MI attach routines.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ callout_handle_init(&sc->dc_stat_ch);
+
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+
+fail:
+ splx(s);
+
+ return(error);
+}
+
+static int dc_detach(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ int s;
+
+ s = splimp();
+
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ dc_stop(sc);
+ if_detach(ifp);
+
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->dc_miibus);
+
+ bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq);
+ bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res);
+
+ contigfree(sc->dc_ldata, sizeof(struct dc_list_data), M_DEVBUF);
+ if (sc->dc_pnic_rx_buf != NULL)
+ free(sc->dc_pnic_rx_buf, M_DEVBUF);
+
+ splx(s);
+
+ return(0);
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int dc_list_tx_init(sc)
+ struct dc_softc *sc;
+{
+ struct dc_chain_data *cd;
+ struct dc_list_data *ld;
+ int i;
+
+ cd = &sc->dc_cdata;
+ ld = sc->dc_ldata;
+ for (i = 0; i < DC_TX_LIST_CNT; i++) {
+ if (i == (DC_TX_LIST_CNT - 1)) {
+ ld->dc_tx_list[i].dc_next =
+ vtophys(&ld->dc_tx_list[0]);
+ } else {
+ ld->dc_tx_list[i].dc_next =
+ vtophys(&ld->dc_tx_list[i + 1]);
+ }
+ cd->dc_tx_chain[i] = NULL;
+ ld->dc_tx_list[i].dc_data = 0;
+ ld->dc_tx_list[i].dc_ctl = 0;
+ }
+
+ cd->dc_tx_prod = cd->dc_tx_cons = cd->dc_tx_cnt = 0;
+
+ return(0);
+}
+
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int dc_list_rx_init(sc)
+ struct dc_softc *sc;
+{
+ struct dc_chain_data *cd;
+ struct dc_list_data *ld;
+ int i;
+
+ cd = &sc->dc_cdata;
+ ld = sc->dc_ldata;
+
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ if (dc_newbuf(sc, i, NULL) == ENOBUFS)
+ return(ENOBUFS);
+ if (i == (DC_RX_LIST_CNT - 1)) {
+ ld->dc_rx_list[i].dc_next =
+ vtophys(&ld->dc_rx_list[0]);
+ } else {
+ ld->dc_rx_list[i].dc_next =
+ vtophys(&ld->dc_rx_list[i + 1]);
+ }
+ }
+
+ cd->dc_rx_prod = 0;
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int dc_newbuf(sc, i, m)
+ struct dc_softc *sc;
+ int i;
+ struct mbuf *m;
+{
+ struct mbuf *m_new = NULL;
+ struct dc_desc *c;
+
+ c = &sc->dc_ldata->dc_rx_list[i];
+
+ if (m == NULL) {
+ MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+ if (m_new == NULL) {
+ printf("dc%d: no memory for rx list "
+ "-- packet dropped!\n", sc->dc_unit);
+ return(ENOBUFS);
+ }
+
+ MCLGET(m_new, M_DONTWAIT);
+ if (!(m_new->m_flags & M_EXT)) {
+ printf("dc%d: no memory for rx list "
+ "-- packet dropped!\n", sc->dc_unit);
+ m_freem(m_new);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, sizeof(u_int64_t));
+
+ /*
+ * If this is a PNIC chip, zero the buffer. This is part
+ * of the workaround for the receive bug in the 82c168 and
+ * 82c169 chips.
+ */
+ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR)
+ bzero((char *)mtod(m_new, char *), m_new->m_len);
+
+ sc->dc_cdata.dc_rx_chain[i] = m_new;
+ c->dc_data = vtophys(mtod(m_new, caddr_t));
+ c->dc_ctl = DC_RXCTL_RLINK | DC_RXLEN;
+ c->dc_status = DC_RXSTAT_OWN;
+
+ return(0);
+}
+
+/*
+ * Grrrrr.
+ * The PNIC chip has a terrible bug in it that manifests itself during
+ * periods of heavy activity. The exact mode of failure if difficult to
+ * pinpoint: sometimes it only happens in promiscuous mode, sometimes it
+ * will happen on slow machines. The bug is that sometimes instead of
+ * uploading one complete frame during reception, it uploads what looks
+ * like the entire contents of its FIFO memory. The frame we want is at
+ * the end of the whole mess, but we never know exactly how much data has
+ * been uploaded, so salvaging the frame is hard.
+ *
+ * There is only one way to do it reliably, and it's disgusting.
+ * Here's what we know:
+ *
+ * - We know there will always be somewhere between one and three extra
+ * descriptors uploaded.
+ *
+ * - We know the desired received frame will always be at the end of the
+ * total data upload.
+ *
+ * - We know the size of the desired received frame because it will be
+ * provided in the length field of the status word in the last descriptor.
+ *
+ * Here's what we do:
+ *
+ * - When we allocate buffers for the receive ring, we bzero() them.
+ * This means that we know that the buffer contents should be all
+ * zeros, except for data uploaded by the chip.
+ *
+ * - We also force the PNIC chip to upload frames that include the
+ * ethernet CRC at the end.
+ *
+ * - We gather all of the bogus frame data into a single buffer.
+ *
+ * - We then position a pointer at the end of this buffer and scan
+ * backwards until we encounter the first non-zero byte of data.
+ * This is the end of the received frame. We know we will encounter
+ * some data at the end of the frame because the CRC will always be
+ * there, so even if the sender transmits a packet of all zeros,
+ * we won't be fooled.
+ *
+ * - We know the size of the actual received frame, so we subtract
+ * that value from the current pointer location. This brings us
+ * to the start of the actual received packet.
+ *
+ * - We copy this into an mbuf and pass it on, along with the actual
+ * frame length.
+ *
+ * The performance hit is tremendous, but it beats dropping frames all
+ * the time.
+ */
+
+#define DC_WHOLEFRAME (DC_RXSTAT_FIRSTFRAG|DC_RXSTAT_LASTFRAG)
+static void dc_pnic_rx_bug_war(sc, idx)
+ struct dc_softc *sc;
+ int idx;
+{
+ struct dc_desc *cur_rx;
+ struct dc_desc *c = NULL;
+ struct mbuf *m = NULL;
+ unsigned char *ptr;
+ int i, total_len;
+ u_int32_t rxstat = 0;
+
+ i = sc->dc_pnic_rx_bug_save;
+ cur_rx = &sc->dc_ldata->dc_rx_list[idx];
+ ptr = sc->dc_pnic_rx_buf;
+ bzero(ptr, sizeof(DC_RXLEN * 5));
+
+ /* Copy all the bytes from the bogus buffers. */
+ while (1) {
+ c = &sc->dc_ldata->dc_rx_list[i];
+ rxstat = c->dc_status;
+ m = sc->dc_cdata.dc_rx_chain[i];
+ bcopy(mtod(m, char *), ptr, DC_RXLEN);
+ ptr += DC_RXLEN;
+ /* If this is the last buffer, break out. */
+ if (i == idx || rxstat & DC_RXSTAT_LASTFRAG)
+ break;
+ dc_newbuf(sc, i, m);
+ DC_INC(i, DC_RX_LIST_CNT);
+ }
+
+ /* Find the length of the actual receive frame. */
+ total_len = DC_RXBYTES(rxstat);
+
+ /* Scan backwards until we hit a non-zero byte. */
+ while(*ptr == 0x00)
+ ptr--;
+
+ /* Round off. */
+ if ((uintptr_t)(ptr) & 0x3)
+ ptr -= 1;
+
+ /* Now find the start of the frame. */
+ ptr -= total_len;
+ if (ptr < sc->dc_pnic_rx_buf)
+ ptr = sc->dc_pnic_rx_buf;
+
+ /*
+ * Now copy the salvaged frame to the last mbuf and fake up
+ * the status word to make it look like a successful
+ * frame reception.
+ */
+ dc_newbuf(sc, i, m);
+ bcopy(ptr, mtod(m, char *), total_len);
+ cur_rx->dc_status = rxstat | DC_RXSTAT_FIRSTFRAG;
+
+ return;
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+static void dc_rxeof(sc)
+ struct dc_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ struct dc_desc *cur_rx;
+ int i, total_len = 0;
+ u_int32_t rxstat;
+
+ ifp = &sc->arpcom.ac_if;
+ i = sc->dc_cdata.dc_rx_prod;
+
+ while(!(sc->dc_ldata->dc_rx_list[i].dc_status & DC_RXSTAT_OWN)) {
+ struct mbuf *m0 = NULL;
+
+ cur_rx = &sc->dc_ldata->dc_rx_list[i];
+ rxstat = cur_rx->dc_status;
+ m = sc->dc_cdata.dc_rx_chain[i];
+ total_len = DC_RXBYTES(rxstat);
+
+ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) {
+ if ((rxstat & DC_WHOLEFRAME) != DC_WHOLEFRAME) {
+ if (rxstat & DC_RXSTAT_FIRSTFRAG)
+ sc->dc_pnic_rx_bug_save = i;
+ if ((rxstat & DC_RXSTAT_LASTFRAG) == 0) {
+ DC_INC(i, DC_RX_LIST_CNT);
+ continue;
+ }
+ dc_pnic_rx_bug_war(sc, i);
+ rxstat = cur_rx->dc_status;
+ total_len = DC_RXBYTES(rxstat);
+ }
+ }
+
+ sc->dc_cdata.dc_rx_chain[i] = NULL;
+
+ /*
+ * If an error occurs, update stats, clear the
+ * status word and leave the mbuf cluster in place:
+ * it should simply get re-used next time this descriptor
+ * comes up in the ring.
+ */
+ if (rxstat & DC_RXSTAT_RXERR) {
+ ifp->if_ierrors++;
+ if (rxstat & DC_RXSTAT_COLLSEEN)
+ ifp->if_collisions++;
+ dc_newbuf(sc, i, m);
+ if (rxstat & DC_RXSTAT_CRCERR) {
+ DC_INC(i, DC_RX_LIST_CNT);
+ continue;
+ } else {
+ dc_init(sc);
+ return;
+ }
+ }
+
+ /* No errors; receive the packet. */
+ total_len -= ETHER_CRC_LEN;
+
+ m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
+ total_len + ETHER_ALIGN, 0, ifp, NULL);
+ dc_newbuf(sc, i, m);
+ DC_INC(i, DC_RX_LIST_CNT);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ continue;
+ }
+ m_adj(m0, ETHER_ALIGN);
+ m = m0;
+
+ ifp->if_ipackets++;
+ eh = mtod(m, struct ether_header *);
+
+ /*
+ * Handle BPF listeners. Let the BPF user see the packet, but
+ * don't pass it up to the ether_input() layer unless it's
+ * a broadcast packet, multicast packet, matches our ethernet
+ * address or the interface is in promiscuous mode.
+ */
+ if (ifp->if_bpf) {
+ bpf_mtap(ifp, m);
+ if (ifp->if_flags & IFF_PROMISC &&
+ (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ ETHER_ADDR_LEN) &&
+ (eh->ether_dhost[0] & 1) == 0)) {
+ m_freem(m);
+ continue;
+ }
+ }
+
+ /* Remove header from mbuf and pass it on. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+ }
+
+ sc->dc_cdata.dc_rx_prod = i;
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+static void dc_txeof(sc)
+ struct dc_softc *sc;
+{
+ struct dc_desc *cur_tx = NULL;
+ struct ifnet *ifp;
+ int idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ /* Clear the timeout timer. */
+ ifp->if_timer = 0;
+
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ idx = sc->dc_cdata.dc_tx_cons;
+ while(idx != sc->dc_cdata.dc_tx_prod) {
+ u_int32_t txstat;
+
+ cur_tx = &sc->dc_ldata->dc_tx_list[idx];
+ txstat = cur_tx->dc_status;
+
+ if (txstat & DC_TXSTAT_OWN)
+ break;
+
+ if (!(cur_tx->dc_ctl & DC_TXCTL_LASTFRAG) ||
+ cur_tx->dc_ctl & DC_TXCTL_SETUP) {
+ sc->dc_cdata.dc_tx_cnt--;
+ if (cur_tx->dc_ctl & DC_TXCTL_SETUP) {
+ /*
+ * Yes, the PNIC is so brain damaged
+ * that it will sometimes generate a TX
+ * underrun error while DMAing the RX
+ * filter setup frame. If we detect this,
+ * we have to send the setup frame again,
+ * or else the filter won't be programmed
+ * correctly.
+ */
+ if (DC_IS_PNIC(sc)) {
+ if (txstat & DC_TXSTAT_ERRSUM)
+ dc_setfilt(sc);
+ }
+ sc->dc_cdata.dc_tx_chain[idx] = NULL;
+ }
+ DC_INC(idx, DC_TX_LIST_CNT);
+ continue;
+ }
+
+ if (/*sc->dc_type == DC_TYPE_21143 &&*/
+ sc->dc_pmode == DC_PMODE_MII &&
+ ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM|
+ DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST)))
+ txstat &= ~DC_TXSTAT_ERRSUM;
+
+ if (txstat & DC_TXSTAT_ERRSUM) {
+ ifp->if_oerrors++;
+ if (txstat & DC_TXSTAT_EXCESSCOLL)
+ ifp->if_collisions++;
+ if (txstat & DC_TXSTAT_LATECOLL)
+ ifp->if_collisions++;
+ if (!(txstat & DC_TXSTAT_UNDERRUN)) {
+ dc_init(sc);
+ return;
+ }
+ }
+
+ ifp->if_collisions += (txstat & DC_TXSTAT_COLLCNT) >> 3;
+
+ ifp->if_opackets++;
+ if (sc->dc_cdata.dc_tx_chain[idx] != NULL) {
+ m_freem(sc->dc_cdata.dc_tx_chain[idx]);
+ sc->dc_cdata.dc_tx_chain[idx] = NULL;
+ }
+
+ sc->dc_cdata.dc_tx_cnt--;
+ DC_INC(idx, DC_TX_LIST_CNT);
+ }
+
+ sc->dc_cdata.dc_tx_cons = idx;
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
+static void dc_tick(xsc)
+ void *xsc;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ int s;
+ u_int32_t r;
+
+ s = splimp();
+
+ sc = xsc;
+ ifp = &sc->arpcom.ac_if;
+ mii = device_get_softc(sc->dc_miibus);
+
+ if (sc->dc_flags & DC_REDUCED_MII_POLL) {
+ r = CSR_READ_4(sc, DC_ISR);
+ if (DC_IS_INTEL(sc)) {
+ if (r & DC_ISR_LINKFAIL) {
+ sc->dc_link = 0;
+ mii_tick(mii);
+ }
+ } else {
+ if ((r & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT &&
+ sc->dc_cdata.dc_tx_prod == 0)
+ mii_tick(mii);
+ }
+ } else
+ mii_tick(mii);
+
+ /*
+ * When the init routine completes, we expect to be able to send
+ * packets right away, and in fact the network code will send a
+ * gratuitous ARP the moment the init routine marks the interface
+ * as running. However, even though the MAC may have been initialized,
+ * there may be a delay of a few seconds before the PHY completes
+ * autonegotiation and the link is brought up. Any transmissions
+ * made during that delay will be lost. Dealing with this is tricky:
+ * we can't just pause in the init routine while waiting for the
+ * PHY to come ready since that would bring the whole system to
+ * a screeching halt for several seconds.
+ *
+ * What we do here is prevent the TX start routine from sending
+ * any packets until a link has been established. After the
+ * interface has been initialized, the tick routine will poll
+ * the state of the PHY until the IFM_ACTIVE flag is set. Until
+ * that time, packets will stay in the send queue, and once the
+ * link comes up, they will be flushed out to the wire.
+ */
+ if (!sc->dc_link) {
+ mii_pollstat(mii);
+ if (mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->dc_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+ }
+ }
+
+ sc->dc_stat_ch = timeout(dc_tick, sc, hz);
+
+ splx(s);
+
+ return;
+}
+
+static void dc_intr(arg)
+ void *arg;
+{
+ struct dc_softc *sc;
+ struct ifnet *ifp;
+ u_int32_t status;
+
+ sc = arg;
+ ifp = &sc->arpcom.ac_if;
+
+ /* Supress unwanted interrupts */
+ if (!(ifp->if_flags & IFF_UP)) {
+ if (CSR_READ_4(sc, DC_ISR) & DC_INTRS)
+ dc_stop(sc);
+ return;
+ }
+
+ /* Disable interrupts. */
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+
+ while((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) {
+
+ CSR_WRITE_4(sc, DC_ISR, status);
+
+ if (status & DC_ISR_RX_OK)
+ dc_rxeof(sc);
+
+ if (status & (DC_ISR_TX_OK|DC_ISR_TX_NOBUF))
+ dc_txeof(sc);
+
+ if (status & DC_ISR_TX_IDLE) {
+ dc_txeof(sc);
+ if (sc->dc_cdata.dc_tx_cnt) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+ }
+ }
+
+ if (status & DC_ISR_TX_UNDERRUN) {
+ u_int32_t cfg;
+
+ printf("dc%d: TX underrun -- ", sc->dc_unit);
+ if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc))
+ dc_init(sc);
+ cfg = CSR_READ_4(sc, DC_NETCFG);
+ cfg &= ~DC_NETCFG_TX_THRESH;
+ if (sc->dc_txthresh == DC_TXTHRESH_160BYTES) {
+ printf("using store and forward mode\n");
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ } else {
+ sc->dc_txthresh += 0x4000;
+ printf("increasing TX threshold\n");
+ CSR_WRITE_4(sc, DC_NETCFG, cfg);
+ DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ }
+ }
+
+ if ((status & DC_ISR_RX_WATDOGTIMEO)
+ || (status & DC_ISR_RX_NOBUF))
+ dc_rxeof(sc);
+
+ if (status & DC_ISR_BUS_ERR) {
+ dc_reset(sc);
+ dc_init(sc);
+ }
+ }
+
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+
+ return;
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int dc_encap(sc, m_head, txidx)
+ struct dc_softc *sc;
+ struct mbuf *m_head;
+ u_int32_t *txidx;
+{
+ struct dc_desc *f = NULL;
+ struct mbuf *m;
+ int frag, cur, cnt = 0;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ m = m_head;
+ cur = frag = *txidx;
+
+ for (m = m_head; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (sc->dc_flags & DC_TX_ADMTEK_WAR) {
+ if (*txidx != sc->dc_cdata.dc_tx_prod &&
+ frag == (DC_TX_LIST_CNT - 1))
+ return(ENOBUFS);
+ }
+ if ((DC_TX_LIST_CNT -
+ (sc->dc_cdata.dc_tx_cnt + cnt)) < 5)
+ return(ENOBUFS);
+
+ f = &sc->dc_ldata->dc_tx_list[frag];
+ f->dc_ctl = DC_TXCTL_TLINK | m->m_len;
+ if (cnt == 0) {
+ f->dc_status = 0;
+ f->dc_ctl |= DC_TXCTL_FIRSTFRAG;
+ } else
+ f->dc_status = DC_TXSTAT_OWN;
+ f->dc_data = vtophys(mtod(m, vm_offset_t));
+ cur = frag;
+ DC_INC(frag, DC_TX_LIST_CNT);
+ cnt++;
+ }
+ }
+
+ if (m != NULL)
+ return(ENOBUFS);
+
+ sc->dc_cdata.dc_tx_cnt += cnt;
+ sc->dc_cdata.dc_tx_chain[cur] = m_head;
+ sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_LASTFRAG;
+ if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG)
+ sc->dc_ldata->dc_tx_list[*txidx].dc_ctl |= DC_TXCTL_FINT;
+ if (sc->dc_flags & DC_TX_USE_TX_INTR && sc->dc_cdata.dc_tx_cnt > 64)
+ sc->dc_ldata->dc_tx_list[cur].dc_ctl |= DC_TXCTL_FINT;
+ sc->dc_ldata->dc_tx_list[*txidx].dc_status = DC_TXSTAT_OWN;
+ *txidx = frag;
+
+ return(0);
+}
+
+/*
+ * Main transmit routine. To avoid having to do mbuf copies, we put pointers
+ * to the mbuf data regions directly in the transmit lists. We also save a
+ * copy of the pointers since the transmit list fragment pointers are
+ * physical addresses.
+ */
+
+static void dc_start(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+ struct mbuf *m_head = NULL;
+ int idx;
+
+ sc = ifp->if_softc;
+
+ if (!sc->dc_link)
+ return;
+
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ idx = sc->dc_cdata.dc_tx_prod;
+
+ while(sc->dc_cdata.dc_tx_chain[idx] == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ if (dc_encap(sc, m_head, &idx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m_head);
+ }
+
+ /* Transmit */
+ sc->dc_cdata.dc_tx_prod = idx;
+ if (!(sc->dc_flags & DC_TX_POLL))
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ return;
+}
+
+static void dc_init(xsc)
+ void *xsc;
+{
+ struct dc_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mii_data *mii;
+ int s;
+
+ s = splimp();
+
+ mii = device_get_softc(sc->dc_miibus);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+ dc_stop(sc);
+ dc_reset(sc);
+
+ /*
+ * Set cache alignment and burst length.
+ */
+ if (DC_IS_ASIX(sc))
+ CSR_WRITE_4(sc, DC_BUSCTL, 0);
+ else
+ CSR_WRITE_4(sc, DC_BUSCTL, DC_BUSCTL_MRME|DC_BUSCTL_MRLE);
+ if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc)) {
+ DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_USECA);
+ } else {
+ DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_16LONG);
+ }
+ if (sc->dc_flags & DC_TX_POLL)
+ DC_SETBIT(sc, DC_BUSCTL, DC_TXPOLL_1);
+ switch(sc->dc_cachesize) {
+ case 32:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_32LONG);
+ break;
+ case 16:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_16LONG);
+ break;
+ case 8:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_8LONG);
+ break;
+ case 0:
+ default:
+ DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_NONE);
+ break;
+ }
+
+ if (sc->dc_flags & DC_TX_STORENFWD)
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ else {
+ if (sc->dc_txthresh == DC_TXTHRESH_160BYTES) {
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ } else {
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD);
+ DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh);
+ }
+ }
+
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_NO_RXCRC);
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_BACKOFF);
+
+ if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) {
+ /*
+ * The app notes for the 98713 and 98715A say that
+ * in order to have the chips operate properly, a magic
+ * number must be written to CSR16. Macronix does not
+ * document the meaning of these bits so there's no way
+ * to know exactly what they do. The 98713 has a magic
+ * number all its own; the rest all use a different one.
+ */
+ DC_CLRBIT(sc, DC_MX_MAGICPACKET, 0xFFFF0000);
+ if (sc->dc_type == DC_TYPE_98713)
+ DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98713);
+ else
+ DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98715);
+ }
+
+ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH);
+ DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_72BYTES);
+
+ /* Init circular RX list. */
+ if (dc_list_rx_init(sc) == ENOBUFS) {
+ printf("dc%d: initialization failed: no "
+ "memory for rx buffers\n", sc->dc_unit);
+ dc_stop(sc);
+ (void)splx(s);
+ return;
+ }
+
+ /*
+ * Init tx descriptors.
+ */
+ dc_list_tx_init(sc);
+
+ /*
+ * Load the address of the RX list.
+ */
+ CSR_WRITE_4(sc, DC_RXADDR, vtophys(&sc->dc_ldata->dc_rx_list[0]));
+ CSR_WRITE_4(sc, DC_TXADDR, vtophys(&sc->dc_ldata->dc_tx_list[0]));
+
+ /*
+ * Enable interrupts.
+ */
+ CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+ CSR_WRITE_4(sc, DC_ISR, 0xFFFFFFFF);
+
+ /* Enable transmitter. */
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
+
+ /*
+ * Load the RX/multicast filter. We do this sort of late
+ * because the filter programming scheme on the 21143 and
+ * some clones requires DMAing a setup frame via the TX
+ * engine, and we need the transmitter enabled for that.
+ */
+ dc_setfilt(sc);
+
+ /* Enable receiver. */
+ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON);
+ CSR_WRITE_4(sc, DC_RXSTART, 0xFFFFFFFF);
+
+ mii_mediachg(mii);
+ dc_setcfg(sc, sc->dc_if_media);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ (void)splx(s);
+
+ sc->dc_stat_ch = timeout(dc_tick, sc, hz);
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+static int dc_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->dc_miibus);
+ mii_mediachg(mii);
+ sc->dc_link = 0;
+
+ return(0);
+}
+
+/*
+ * Report current media status.
+ */
+static void dc_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct dc_softc *sc;
+ struct mii_data *mii;
+
+ sc = ifp->if_softc;
+ mii = device_get_softc(sc->dc_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+static int dc_ioctl(ifp, command, data)
+ struct ifnet *ifp;
+ u_long command;
+ caddr_t data;
+{
+ struct dc_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch(command) {
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ case SIOCSIFMTU:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->dc_if_flags & IFF_PROMISC)) {
+ dc_setfilt(sc);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->dc_if_flags & IFF_PROMISC) {
+ dc_setfilt(sc);
+ } else if (!(ifp->if_flags & IFF_RUNNING)) {
+ sc->dc_txthresh = 0;
+ dc_init(sc);
+ }
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ dc_stop(sc);
+ }
+ sc->dc_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ dc_setfilt(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->dc_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ (void)splx(s);
+
+ return(error);
+}
+
+static void dc_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct dc_softc *sc;
+
+ sc = ifp->if_softc;
+
+ ifp->if_oerrors++;
+ printf("dc%d: watchdog timeout\n", sc->dc_unit);
+
+ dc_stop(sc);
+ dc_reset(sc);
+ dc_init(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ dc_start(ifp);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+static void dc_stop(sc)
+ struct dc_softc *sc;
+{
+ register int i;
+ struct ifnet *ifp;
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ untimeout(dc_tick, sc, sc->dc_stat_ch);
+
+ DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON|DC_NETCFG_TX_ON));
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ CSR_WRITE_4(sc, DC_TXADDR, 0x00000000);
+ CSR_WRITE_4(sc, DC_RXADDR, 0x00000000);
+ sc->dc_link = 0;
+
+ /*
+ * Free data in the RX lists.
+ */
+ for (i = 0; i < DC_RX_LIST_CNT; i++) {
+ if (sc->dc_cdata.dc_rx_chain[i] != NULL) {
+ m_freem(sc->dc_cdata.dc_rx_chain[i]);
+ sc->dc_cdata.dc_rx_chain[i] = NULL;
+ }
+ }
+ bzero((char *)&sc->dc_ldata->dc_rx_list,
+ sizeof(sc->dc_ldata->dc_rx_list));
+
+ /*
+ * Free the TX list buffers.
+ */
+ for (i = 0; i < DC_TX_LIST_CNT; i++) {
+ if (sc->dc_cdata.dc_tx_chain[i] != NULL) {
+ if (sc->dc_ldata->dc_tx_list[i].dc_ctl &
+ DC_TXCTL_SETUP) {
+ sc->dc_cdata.dc_tx_chain[i] = NULL;
+ continue;
+ }
+ m_freem(sc->dc_cdata.dc_tx_chain[i]);
+ sc->dc_cdata.dc_tx_chain[i] = NULL;
+ }
+ }
+
+ bzero((char *)&sc->dc_ldata->dc_tx_list,
+ sizeof(sc->dc_ldata->dc_tx_list));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+static void dc_shutdown(dev)
+ device_t dev;
+{
+ struct dc_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ dc_stop(sc);
+
+ return;
+}
diff --git a/sys/pci/if_dcreg.h b/sys/pci/if_dcreg.h
new file mode 100644
index 0000000..7994e94
--- /dev/null
+++ b/sys/pci/if_dcreg.h
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 1997, 1998, 1999
+ * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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$
+ */
+
+/*
+ * 21143 and clone common register definitions.
+ */
+
+#define DC_BUSCTL 0x00 /* bus control */
+#define DC_TXSTART 0x08 /* tx start demand */
+#define DC_RXSTART 0x10 /* rx start demand */
+#define DC_RXADDR 0x18 /* rx descriptor list start addr */
+#define DC_TXADDR 0x20 /* tx descriptor list start addr */
+#define DC_ISR 0x28 /* interrupt status register */
+#define DC_NETCFG 0x30 /* network config register */
+#define DC_IMR 0x38 /* interrupt mask */
+#define DC_FRAMESDISCARDED 0x40 /* # of discarded frames */
+#define DC_SIO 0x48 /* MII and ROM/EEPROM access */
+#define DC_ROM 0x50 /* ROM programming address */
+#define DC_TIMER 0x58 /* general timer */
+#define DC_10BTSTAT 0x60 /* SIA status */
+#define DC_SIARESET 0x68 /* SIA connectivity */
+#define DC_10BTCTRL 0x70 /* SIA transmit and receive */
+#define DC_WATCHDOG 0x78 /* SIA and general purpose port */
+
+/*
+ * There are two general 'types' of MX chips that we need to be
+ * concerned with. One is the original 98713, which has its internal
+ * NWAY support controlled via the MDIO bits in the serial I/O
+ * register. The other is everything else (from the 98713A on up),
+ * which has its internal NWAY controlled via CSR13, CSR14 and CSR15,
+ * just like the 21143. This type setting also governs which of the
+ * 'magic' numbers we write to CSR16. The PNIC II falls into the
+ * 98713A/98715/98715A/98725 category.
+ */
+#define DC_TYPE_98713 0x1
+#define DC_TYPE_98713A 0x2
+#define DC_TYPE_987x5 0x3
+
+/* Other type of supported chips. */
+#define DC_TYPE_21143 0x4 /* Intel 21143 */
+#define DC_TYPE_ASIX 0x5 /* ASIX AX88140A/AX88141 */
+#define DC_TYPE_AL981 0x6 /* ADMtek AL981 Comet */
+#define DC_TYPE_AN985 0x7 /* ADMtek AN985 Centaur */
+#define DC_TYPE_DM9102 0x8 /* Davicom DM9102 */
+#define DC_TYPE_PNICII 0x9 /* 82c115 PNIC II */
+#define DC_TYPE_PNIC 0xA /* 82c168/82c169 PNIC I */
+
+#define DC_IS_MACRONIX(x) \
+ (x->dc_type == DC_TYPE_98713 || \
+ x->dc_type == DC_TYPE_98713A || \
+ x->dc_type == DC_TYPE_987x5)
+
+#define DC_IS_ADMTEK(x) \
+ (x->dc_type == DC_TYPE_AL981 || \
+ x->dc_type == DC_TYPE_AN985)
+
+#define DC_IS_INTEL(x) (x->dc_type == DC_TYPE_21143)
+#define DC_IS_ASIX(x) (x->dc_type == DC_TYPE_ASIX)
+#define DC_IS_COMET(x) (x->dc_type == DC_TYPE_AL981)
+#define DC_IS_CENTAUR(x) (x->dc_type == DC_TYPE_AN985)
+#define DC_IS_DAVICOM(x) (x->dc_type == DC_TYPE_DM9102)
+#define DC_IS_PNICII(x) (x->dc_type == DC_TYPE_PNICII)
+#define DC_IS_PNIC(x) (x->dc_type == DC_TYPE_PNIC)
+
+/* MII/symbol mode port types */
+#define DC_PMODE_MII 0x1
+#define DC_PMODE_SYM 0x2
+
+/*
+ * Bus control bits.
+ */
+#define DC_BUSCTL_RESET 0x00000001
+#define DC_BUSCTL_ARBITRATION 0x00000002
+#define DC_BUSCTL_SKIPLEN 0x0000007C
+#define DC_BUSCTL_BUF_BIGENDIAN 0x00000080
+#define DC_BUSCTL_BURSTLEN 0x00003F00
+#define DC_BUSCTL_CACHEALIGN 0x0000C000
+#define DC_BUSCTL_TXPOLL 0x000E0000
+#define DC_BUSCTL_DBO 0x00100000
+#define DC_BUSCTL_MRME 0x00200000
+#define DC_BUSCTL_MRLE 0x00800000
+#define DC_BUSCTL_MWIE 0x01000000
+#define DC_BUSCTL_ONNOW_ENB 0x04000000
+
+#define DC_SKIPLEN_1LONG 0x00000004
+#define DC_SKIPLEN_2LONG 0x00000008
+#define DC_SKIPLEN_3LONG 0x00000010
+#define DC_SKIPLEN_4LONG 0x00000020
+#define DC_SKIPLEN_5LONG 0x00000040
+
+#define DC_CACHEALIGN_NONE 0x00000000
+#define DC_CACHEALIGN_8LONG 0x00004000
+#define DC_CACHEALIGN_16LONG 0x00008000
+#define DC_CACHEALIGN_32LONG 0x0000C000
+
+#define DC_BURSTLEN_USECA 0x00000000
+#define DC_BURSTLEN_1LONG 0x00000100
+#define DC_BURSTLEN_2LONG 0x00000200
+#define DC_BURSTLEN_4LONG 0x00000400
+#define DC_BURSTLEN_8LONG 0x00000800
+#define DC_BURSTLEN_16LONG 0x00001000
+#define DC_BURSTLEN_32LONG 0x00002000
+
+#define DC_TXPOLL_OFF 0x00000000
+#define DC_TXPOLL_1 0x00020000
+#define DC_TXPOLL_2 0x00040000
+#define DC_TXPOLL_3 0x00060000
+#define DC_TXPOLL_4 0x00080000
+#define DC_TXPOLL_5 0x000A0000
+#define DC_TXPOLL_6 0x000C0000
+#define DC_TXPOLL_7 0x000E0000
+
+/*
+ * Interrupt status bits.
+ */
+#define DC_ISR_TX_OK 0x00000001
+#define DC_ISR_TX_IDLE 0x00000002
+#define DC_ISR_TX_NOBUF 0x00000004
+#define DC_ISR_TX_JABBERTIMEO 0x00000008
+#define DC_ISR_LINKGOOD 0x00000010
+#define DC_ISR_TX_UNDERRUN 0x00000020
+#define DC_ISR_RX_OK 0x00000040
+#define DC_ISR_RX_NOBUF 0x00000080
+#define DC_ISR_RX_READ 0x00000100
+#define DC_ISR_RX_WATDOGTIMEO 0x00000200
+#define DC_ISR_TX_EARLY 0x00000400
+#define DC_ISR_TIMER_EXPIRED 0x00000800
+#define DC_ISR_LINKFAIL 0x00001000
+#define DC_ISR_BUS_ERR 0x00002000
+#define DC_ISR_RX_EARLY 0x00004000
+#define DC_ISR_ABNORMAL 0x00008000
+#define DC_ISR_NORMAL 0x00010000
+#define DC_ISR_RX_STATE 0x000E0000
+#define DC_ISR_TX_STATE 0x00700000
+#define DC_ISR_BUSERRTYPE 0x03800000
+#define DC_ISR_100MBPSLINK 0x08000000
+#define DC_ISR_MAGICKPACK 0x10000000
+
+#define DC_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
+#define DC_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
+#define DC_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
+#define DC_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
+#define DC_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
+#define DC_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */
+#define DC_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
+#define DC_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
+
+#define DC_TXSTATE_RESET 0x00000000 /* 000 - reset */
+#define DC_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
+#define DC_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
+#define DC_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
+#define DC_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
+#define DC_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
+#define DC_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
+#define DC_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
+
+/*
+ * Network config bits.
+ */
+#define DC_NETCFG_RX_HASHPERF 0x00000001
+#define DC_NETCFG_RX_ON 0x00000002
+#define DC_NETCFG_RX_HASHONLY 0x00000004
+#define DC_NETCFG_RX_BADFRAMES 0x00000008
+#define DC_NETCFG_RX_INVFILT 0x00000010
+#define DC_NETCFG_BACKOFFCNT 0x00000020
+#define DC_NETCFG_RX_PROMISC 0x00000040
+#define DC_NETCFG_RX_ALLMULTI 0x00000080
+#define DC_NETCFG_FULLDUPLEX 0x00000200
+#define DC_NETCFG_LOOPBACK 0x00000C00
+#define DC_NETCFG_FORCECOLL 0x00001000
+#define DC_NETCFG_TX_ON 0x00002000
+#define DC_NETCFG_TX_THRESH 0x0000C000
+#define DC_NETCFG_TX_BACKOFF 0x00020000
+#define DC_NETCFG_PORTSEL 0x00040000 /* 0 == 10, 1 == 100 */
+#define DC_NETCFG_HEARTBEAT 0x00080000
+#define DC_NETCFG_STORENFWD 0x00200000
+#define DC_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */
+#define DC_NETCFG_PCS 0x00800000
+#define DC_NETCFG_SCRAMBLER 0x01000000
+#define DC_NETCFG_NO_RXCRC 0x02000000
+#define DC_NETCFG_RX_ALL 0x40000000
+#define DC_NETCFG_CAPEFFECT 0x80000000
+
+#define DC_OPMODE_NORM 0x00000000
+#define DC_OPMODE_INTLOOP 0x00000400
+#define DC_OPMODE_EXTLOOP 0x00000800
+
+#define DC_TXTHRESH_72BYTES 0x00000000
+#define DC_TXTHRESH_96BYTES 0x00004000
+#define DC_TXTHRESH_128BYTES 0x00008000
+#define DC_TXTHRESH_160BYTES 0x0000C000
+
+
+/*
+ * Interrupt mask bits.
+ */
+#define DC_IMR_TX_OK 0x00000001
+#define DC_IMR_TX_IDLE 0x00000002
+#define DC_IMR_TX_NOBUF 0x00000004
+#define DC_IMR_TX_JABBERTIMEO 0x00000008
+#define DC_IMR_LINKGOOD 0x00000010
+#define DC_IMR_TX_UNDERRUN 0x00000020
+#define DC_IMR_RX_OK 0x00000040
+#define DC_IMR_RX_NOBUF 0x00000080
+#define DC_IMR_RX_READ 0x00000100
+#define DC_IMR_RX_WATDOGTIMEO 0x00000200
+#define DC_IMR_TX_EARLY 0x00000400
+#define DC_IMR_TIMER_EXPIRED 0x00000800
+#define DC_IMR_LINKFAIL 0x00001000
+#define DC_IMR_BUS_ERR 0x00002000
+#define DC_IMR_RX_EARLY 0x00004000
+#define DC_IMR_ABNORMAL 0x00008000
+#define DC_IMR_NORMAL 0x00010000
+#define DC_IMR_100MBPSLINK 0x08000000
+#define DC_IMR_MAGICKPACK 0x10000000
+
+#define DC_INTRS \
+ (DC_IMR_RX_OK|DC_IMR_TX_OK|DC_IMR_RX_NOBUF|DC_IMR_RX_WATDOGTIMEO|\
+ DC_IMR_TX_NOBUF|DC_IMR_TX_UNDERRUN|DC_IMR_BUS_ERR| \
+ DC_IMR_ABNORMAL|DC_IMR_NORMAL/*|DC_IMR_TX_EARLY*/)
+/*
+ * Serial I/O (EEPROM/ROM) bits.
+ */
+#define DC_SIO_EE_CS 0x00000001 /* EEPROM chip select */
+#define DC_SIO_EE_CLK 0x00000002 /* EEPROM clock */
+#define DC_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */
+#define DC_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */
+#define DC_SIO_ROMDATA4 0x00000010
+#define DC_SIO_ROMDATA5 0x00000020
+#define DC_SIO_ROMDATA6 0x00000040
+#define DC_SIO_ROMDATA7 0x00000080
+#define DC_SIO_EESEL 0x00000800
+#define DC_SIO_ROMSEL 0x00001000
+#define DC_SIO_ROMCTL_WRITE 0x00002000
+#define DC_SIO_ROMCTL_READ 0x00004000
+#define DC_SIO_MII_CLK 0x00010000 /* MDIO clock */
+#define DC_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */
+#define DC_SIO_MII_DIR 0x00040000 /* MDIO dir */
+#define DC_SIO_MII_DATAIN 0x00080000 /* MDIO data in */
+
+#define DC_EECMD_WRITE 0x140
+#define DC_EECMD_READ 0x180
+#define DC_EECMD_ERASE 0x1c0
+
+#define DC_EE_NODEADDR_OFFSET 0x70
+#define DC_EE_NODEADDR 10
+
+/*
+ * General purpose timer register
+ */
+#define DC_TIMER_VALUE 0x0000FFFF
+#define DC_TIMER_CONTINUOUS 0x00010000
+
+/*
+ * 10baseT status register
+ */
+#define DC_TSTAT_MIIACT 0x00000001 /* MII port activity */
+#define DC_TSTAT_LS100 0x00000002 /* link status of 100baseTX */
+#define DC_TSTAT_LS10 0x00000004 /* link status of 10baseT */
+#define DC_TSTAT_AUTOPOLARITY 0x00000008
+#define DC_TSTAT_AUIACT 0x00000100 /* AUI activity */
+#define DC_TSTAT_10BTACT 0x00000200 /* 10baseT activity */
+#define DC_TSTAT_NSN 0x00000400 /* non-stable FLPs detected */
+#define DC_TSTAT_REMFAULT 0x00000800
+#define DC_TSTAT_ANEGSTAT 0x00007000
+#define DC_TSTAT_LP_CAN_NWAY 0x00008000 /* link partner supports NWAY */
+#define DC_TSTAT_LPCODEWORD 0xFFFF0000 /* link partner's code word */
+
+#define DC_ASTAT_DISABLE 0x00000000
+#define DC_ASTAT_TXDISABLE 0x00001000
+#define DC_ASTAT_ABDETECT 0x00002000
+#define DC_ASTAT_ACKDETECT 0x00003000
+#define DC_ASTAT_CMPACKDETECT 0x00004000
+#define DC_ASTAT_AUTONEGCMP 0x00005000
+#define DC_ASTAT_LINKCHECK 0x00006000
+
+/*
+ * PHY reset register
+ */
+#define DC_SIA_RESET 0x00000001
+#define DC_SIA_AUI 0x00000008 /* AUI or 10baseT */
+
+/*
+ * 10baseT control register
+ */
+#define DC_TCTL_ENCODER_ENB 0x00000001
+#define DC_TCTL_LOOPBACK 0x00000002
+#define DC_TCTL_DRIVER_ENB 0x00000004
+#define DC_TCTL_LNKPULSE_ENB 0x00000008
+#define DC_TCTL_HALFDUPLEX 0x00000040
+#define DC_TCTL_AUTONEGENBL 0x00000080
+#define DC_TCTL_RX_SQUELCH 0x00000100
+#define DC_TCTL_COLL_SQUELCH 0x00000200
+#define DC_TCTL_COLL_DETECT 0x00000400
+#define DC_TCTL_SQE_ENB 0x00000800
+#define DC_TCTL_LINKTEST 0x00001000
+#define DC_TCTL_AUTOPOLARITY 0x00002000
+#define DC_TCTL_SET_POL_PLUS 0x00004000
+#define DC_TCTL_AUTOSENSE 0x00008000 /* 10bt/AUI autosense */
+#define DC_TCTL_100BTXHALF 0x00010000
+#define DC_TCTL_100BTXFULL 0x00020000
+#define DC_TCTL_100BT4 0x00040000
+
+/*
+ * Watchdog timer register
+ */
+#define DC_WDOG_JABBERDIS 0x00000001
+#define DC_WDOG_HOSTUNJAB 0x00000002
+#define DC_WDOG_JABBERCLK 0x00000004
+#define DC_WDOG_RXWDOGDIS 0x00000010
+#define DC_WDOG_RXWDOGCLK 0x00000020
+#define DC_WDOG_MUSTBEZERO 0x00000100
+
+/*
+ * Size of a setup frame.
+ */
+#define DC_SFRAME_LEN 192
+
+/*
+ * 21x4x TX/RX list structure.
+ */
+
+struct dc_desc {
+ u_int32_t dc_status;
+ u_int32_t dc_ctl;
+ u_int32_t dc_ptr1;
+ u_int32_t dc_ptr2;
+};
+
+#define dc_data dc_ptr1
+#define dc_next dc_ptr2
+
+#define DC_RXSTAT_FIFOOFLOW 0x00000001
+#define DC_RXSTAT_CRCERR 0x00000002
+#define DC_RXSTAT_DRIBBLE 0x00000004
+#define DC_RXSTAT_WATCHDOG 0x00000010
+#define DC_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */
+#define DC_RXSTAT_COLLSEEN 0x00000040
+#define DC_RXSTAT_GIANT 0x00000080
+#define DC_RXSTAT_LASTFRAG 0x00000100
+#define DC_RXSTAT_FIRSTFRAG 0x00000200
+#define DC_RXSTAT_MULTICAST 0x00000400
+#define DC_RXSTAT_RUNT 0x00000800
+#define DC_RXSTAT_RXTYPE 0x00003000
+#define DC_RXSTAT_RXERR 0x00008000
+#define DC_RXSTAT_RXLEN 0x3FFF0000
+#define DC_RXSTAT_OWN 0x80000000
+
+#define DC_RXBYTES(x) ((x & DC_RXSTAT_RXLEN) >> 16)
+#define DC_RXSTAT (DC_RXSTAT_FIRSTFRAG|DC_RXSTAT_LASTFRAG|DC_RXSTAT_OWN)
+
+#define DC_RXCTL_BUFLEN1 0x00000FFF
+#define DC_RXCTL_BUFLEN2 0x00FFF000
+#define DC_RXCTL_RLINK 0x01000000
+#define DC_RXCTL_RLAST 0x02000000
+
+#define DC_TXSTAT_DEFER 0x00000001
+#define DC_TXSTAT_UNDERRUN 0x00000002
+#define DC_TXSTAT_LINKFAIL 0x00000003
+#define DC_TXSTAT_COLLCNT 0x00000078
+#define DC_TXSTAT_SQE 0x00000080
+#define DC_TXSTAT_EXCESSCOLL 0x00000100
+#define DC_TXSTAT_LATECOLL 0x00000200
+#define DC_TXSTAT_NOCARRIER 0x00000400
+#define DC_TXSTAT_CARRLOST 0x00000800
+#define DC_TXSTAT_JABTIMEO 0x00004000
+#define DC_TXSTAT_ERRSUM 0x00008000
+#define DC_TXSTAT_OWN 0x80000000
+
+#define DC_TXCTL_BUFLEN1 0x000007FF
+#define DC_TXCTL_BUFLEN2 0x003FF800
+#define DC_TXCTL_FILTTYPE0 0x00400000
+#define DC_TXCTL_PAD 0x00800000
+#define DC_TXCTL_TLINK 0x01000000
+#define DC_TXCTL_TLAST 0x02000000
+#define DC_TXCTL_NOCRC 0x04000000
+#define DC_TXCTL_SETUP 0x08000000
+#define DC_TXCTL_FILTTYPE1 0x10000000
+#define DC_TXCTL_FIRSTFRAG 0x20000000
+#define DC_TXCTL_LASTFRAG 0x40000000
+#define DC_TXCTL_FINT 0x80000000
+
+#define DC_FILTER_PERFECT 0x00000000
+#define DC_FILTER_HASHPERF 0x00400000
+#define DC_FILTER_INVERSE 0x10000000
+#define DC_FILTER_HASHONLY 0x10400000
+
+#define DC_MAXFRAGS 16
+#define DC_RX_LIST_CNT 64
+#define DC_TX_LIST_CNT 256
+#define DC_MIN_FRAMELEN 60
+#define DC_RXLEN 1536
+
+#define DC_INC(x, y) (x) = (x + 1) % y
+
+struct dc_list_data {
+ struct dc_desc dc_rx_list[DC_RX_LIST_CNT];
+ struct dc_desc dc_tx_list[DC_TX_LIST_CNT];
+};
+
+struct dc_chain_data {
+ struct mbuf *dc_rx_chain[DC_RX_LIST_CNT];
+ struct mbuf *dc_tx_chain[DC_TX_LIST_CNT];
+ u_int32_t dc_sbuf[DC_SFRAME_LEN/sizeof(u_int32_t)];
+ u_int8_t dc_pad[DC_MIN_FRAMELEN];
+ int dc_tx_prod;
+ int dc_tx_cons;
+ int dc_tx_cnt;
+ int dc_rx_prod;
+};
+
+struct dc_type {
+ u_int16_t dc_vid;
+ u_int16_t dc_did;
+ char *dc_name;
+};
+
+struct dc_mii_frame {
+ u_int8_t mii_stdelim;
+ u_int8_t mii_opcode;
+ u_int8_t mii_phyaddr;
+ u_int8_t mii_regaddr;
+ u_int8_t mii_turnaround;
+ u_int16_t mii_data;
+};
+
+/*
+ * MII constants
+ */
+#define DC_MII_STARTDELIM 0x01
+#define DC_MII_READOP 0x02
+#define DC_MII_WRITEOP 0x01
+#define DC_MII_TURNAROUND 0x02
+
+
+/*
+ * Registers specific to clone devices.
+ * This mainly relates to RX filter programming: not all 21x4x clones
+ * use the standard DEC filter programming mechanism.
+ */
+
+/*
+ * ADMtek specific registers and constants for the AL981 and AN985.
+ * The AN985 doesn't use the magic PHY registers.
+ */
+#define DC_AL_PAR0 0xA4 /* station address */
+#define DC_AL_PAR1 0xA8 /* station address */
+#define DC_AL_MAR0 0xAC /* multicast hash filter */
+#define DC_AL_MAR1 0xB0 /* multicast hash filter */
+#define DC_AL_BMCR 0xB4 /* built in PHY control */
+#define DC_AL_BMSR 0xB8 /* built in PHY status */
+#define DC_AL_VENID 0xBC /* built in PHY ID0 */
+#define DC_AL_DEVID 0xC0 /* built in PHY ID1 */
+#define DC_AL_ANAR 0xC4 /* built in PHY autoneg advert */
+#define DC_AL_LPAR 0xC8 /* bnilt in PHY link part. ability */
+#define DC_AL_ANER 0xCC /* built in PHY autoneg expansion */
+
+#define DC_ADMTEK_PHYADDR 0x1
+#define DC_AL_EE_NODEADDR 4
+/* End of ADMtek specific registers */
+
+/*
+ * ASIX specific registers.
+ */
+#define DC_AX_FILTIDX 0x68 /* RX filter index */
+#define DC_AX_FILTDATA 0x70 /* RX filter data */
+
+/*
+ * Special ASIX-specific bits in the ASIX NETCFG register (CSR6).
+ */
+#define DC_AX_NETCFG_RX_BROAD 0x00000100
+
+/*
+ * RX Filter Index Register values
+ */
+#define DC_AX_FILTIDX_PAR0 0x00000000
+#define DC_AX_FILTIDX_PAR1 0x00000001
+#define DC_AX_FILTIDX_MAR0 0x00000002
+#define DC_AX_FILTIDX_MAR1 0x00000003
+/* End of ASIX specific registers */
+
+/*
+ * Macronix specific registers. The Macronix chips have a special
+ * register for reading the NWAY status, which we don't use, plus
+ * a magic packet register, which we need to tweak a bit per the
+ * Macronix application notes.
+ */
+#define DC_MX_MAGICPACKET 0x80
+#define DC_MX_NWAYSTAT 0xA0
+
+/*
+ * Magic packet register
+ */
+#define DC_MX_MPACK_DISABLE 0x00400000
+
+/*
+ * NWAY status register.
+ */
+#define DC_MX_NWAY_10BTHALF 0x08000000
+#define DC_MX_NWAY_10BTFULL 0x10000000
+#define DC_MX_NWAY_100BTHALF 0x20000000
+#define DC_MX_NWAY_100BTFULL 0x40000000
+#define DC_MX_NWAY_100BT4 0x80000000
+
+/*
+ * These are magic values that must be written into CSR16
+ * (DC_MX_MAGICPACKET) in order to put the chip into proper
+ * operating mode. The magic numbers are documented in the
+ * Macronix 98715 application notes.
+ */
+#define DC_MX_MAGIC_98713 0x0F370000
+#define DC_MX_MAGIC_98713A 0x0B3C0000
+#define DC_MX_MAGIC_98715 0x0B3C0000
+#define DC_MX_MAGIC_98725 0x0B3C0000
+/* End of Macronix specific registers */
+
+/*
+ * PNIC 82c168/82c169 specific registers.
+ * The PNIC has its own special NWAY support, which doesn't work,
+ * and shortcut ways of reading the EEPROM and MII bus.
+ */
+#define DC_PN_GPIO 0x60 /* general purpose pins control */
+#define DC_PN_PWRUP_CFG 0x90 /* config register, set by EEPROM */
+#define DC_PN_SIOCTL 0x98 /* serial EEPROM control register */
+#define DC_PN_MII 0xA0 /* MII access register */
+#define DC_PN_NWAY 0xB8 /* Internal NWAY register */
+
+/* Serial I/O EEPROM register */
+#define DC_PN_SIOCTL_DATA 0x0000003F
+#define DC_PN_SIOCTL_OPCODE 0x00000300
+#define DC_PN_SIOCTL_BUSY 0x80000000
+
+#define DC_PN_EEOPCODE_ERASE 0x00000300
+#define DC_PN_EEOPCODE_READ 0x00000600
+#define DC_PN_EEOPCODE_WRITE 0x00000100
+
+/*
+ * The first two general purpose pins control speed selection and
+ * 100Mbps loopback on the 82c168 chip. The control bits should always
+ * be set (to make the data pins outputs) and the speed selction and
+ * loopback bits set accordingly when changing media. Physically, this
+ * will set the state of a relay mounted on the card.
+ */
+#define DC_PN_GPIO_DATA0 0x000000001
+#define DC_PN_GPIO_DATA1 0x000000002
+#define DC_PN_GPIO_DATA2 0x000000004
+#define DC_PN_GPIO_DATA3 0x000000008
+#define DC_PN_GPIO_CTL0 0x000000010
+#define DC_PN_GPIO_CTL1 0x000000020
+#define DC_PN_GPIO_CTL2 0x000000040
+#define DC_PN_GPIO_CTL3 0x000000080
+#define DC_PN_GPIO_SPEEDSEL DC_PN_GPIO_DATA0/* 1 == 100Mbps, 0 == 10Mbps */
+#define DC_PN_GPIO_100TX_LOOP DC_PN_GPIO_DATA1/* 1 == normal, 0 == loop */
+#define DC_PN_GPIO_BNC_ENB DC_PN_GPIO_DATA2
+#define DC_PN_GPIO_100TX_LNK DC_PN_GPIO_DATA3
+#define DC_PN_GPIO_SETBIT(sc, r) \
+ DC_SETBIT(sc, DC_PN_GPIO, ((r) | (r << 4)))
+#define DC_PN_GPIO_CLRBIT(sc, r) \
+ { \
+ DC_SETBIT(sc, DC_PN_GPIO, ((r) << 4)); \
+ DC_CLRBIT(sc, DC_PN_GPIO, (r)); \
+ }
+
+/* shortcut MII access register */
+#define DC_PN_MII_DATA 0x0000FFFF
+#define DC_PN_MII_RESERVER 0x00020000
+#define DC_PN_MII_REGADDR 0x007C0000
+#define DC_PN_MII_PHYADDR 0x0F800000
+#define DC_PN_MII_OPCODE 0x30000000
+#define DC_PN_MII_BUSY 0x80000000
+
+#define DC_PN_MIIOPCODE_READ 0x60020000
+#define DC_PN_MIIOPCODE_WRITE 0x50020000
+
+/* Internal NWAY bits */
+#define DC_PN_NWAY_RESET 0x00000001 /* reset */
+#define DC_PN_NWAY_PDOWN 0x00000002 /* power down */
+#define DC_PN_NWAY_BYPASS 0x00000004 /* bypass */
+#define DC_PN_NWAY_AUILOWCUR 0x00000008 /* AUI low current */
+#define DC_PN_NWAY_TPEXTEND 0x00000010 /* low squelch voltage */
+#define DC_PN_NWAY_POLARITY 0x00000020 /* 0 == on, 1 == off */
+#define DC_PN_NWAY_TP 0x00000040 /* 1 == tp, 0 == AUI */
+#define DC_PN_NWAY_AUIVOLT 0x00000080 /* 1 == full, 0 == half */
+#define DC_PN_NWAY_DUPLEX 0x00000100 /* LED, 1 == full, 0 == half */
+#define DC_PN_NWAY_LINKTEST 0x00000200 /* 0 == on, 1 == off */
+#define DC_PN_NWAY_AUTODETECT 0x00000400 /* 1 == off, 0 == on */
+#define DC_PN_NWAY_SPEEDSEL 0x00000800 /* LED, 0 = 10, 1 == 100 */
+#define DC_PN_NWAY_NWAY_ENB 0x00001000 /* 0 == off, 1 == on */
+#define DC_PN_NWAY_CAP10HDX 0x00002000
+#define DC_PN_NWAY_CAP10FDX 0x00004000
+#define DC_PN_NWAY_CAP100FDX 0x00008000
+#define DC_PN_NWAY_CAP100HDX 0x00010000
+#define DC_PN_NWAY_CAP100T4 0x00020000
+#define DC_PN_NWAY_ANEGRESTART 0x02000000 /* resets when aneg done */
+#define DC_PN_NWAY_REMFAULT 0x04000000
+#define DC_PN_NWAY_LPAR10HDX 0x08000000
+#define DC_PN_NWAY_LPAR10FDX 0x10000000
+#define DC_PN_NWAY_LPAR100FDX 0x20000000
+#define DC_PN_NWAY_LPAR100HDX 0x40000000
+#define DC_PN_NWAY_LPAR100T4 0x80000000
+
+/* End of PNIC specific registers */
+
+struct dc_softc {
+ struct arpcom arpcom; /* interface info */
+ bus_space_handle_t dc_bhandle; /* bus space handle */
+ bus_space_tag_t dc_btag; /* bus space tag */
+ void *dc_intrhand;
+ struct resource *dc_irq;
+ struct resource *dc_res;
+ struct dc_type *dc_info; /* adapter info */
+ device_t dc_miibus;
+ u_int8_t dc_unit; /* interface number */
+ u_int8_t dc_type;
+ u_int8_t dc_pmode;
+ u_int8_t dc_link;
+ u_int8_t dc_cachesize;
+ int dc_pnic_rx_bug_save;
+ unsigned char *dc_pnic_rx_buf;
+ int dc_if_flags;
+ int dc_if_media;
+ u_int32_t dc_flags;
+ u_int32_t dc_txthresh;
+ struct dc_list_data *dc_ldata;
+ struct dc_chain_data dc_cdata;
+ struct callout_handle dc_stat_ch;
+};
+
+#define DC_TX_POLL 0x00000001
+#define DC_TX_COALESCE 0x00000002
+#define DC_TX_ADMTEK_WAR 0x00000004
+#define DC_TX_USE_TX_INTR 0x00000008
+#define DC_RX_FILTER_TULIP 0x00000010
+#define DC_TX_INTR_FIRSTFRAG 0x00000020
+#define DC_PNIC_RX_BUG_WAR 0x00000040
+#define DC_TX_FIXED_RING 0x00000080
+#define DC_TX_STORENFWD 0x00000100
+#define DC_REDUCED_MII_POLL 0x00000200
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->dc_btag, sc->dc_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->dc_btag, sc->dc_bhandle, reg)
+
+#define DC_TIMEOUT 1000
+#define ETHER_ALIGN 2
+
+/*
+ * General constants that are fun to know.
+ */
+
+/*
+ * DEC PCI vendor ID
+ */
+#define DC_VENDORID_DEC 0x1011
+
+/*
+ * DEC/Intel 21143 PCI device ID
+ */
+#define DC_DEVICEID_21143 0x0019
+
+/*
+ * Macronix PCI vendor ID
+ */
+#define DC_VENDORID_MX 0x10D9
+
+/*
+ * Macronix PMAC device IDs.
+ */
+#define DC_DEVICEID_98713 0x0512
+#define DC_DEVICEID_987x5 0x0531
+
+/* Macronix PCI revision codes. */
+#define DC_REVISION_98713 0x00
+#define DC_REVISION_98713A 0x10
+#define DC_REVISION_98715 0x20
+#define DC_REVISION_98725 0x30
+
+/*
+ * Compex PCI vendor ID.
+ */
+#define DC_VENDORID_CP 0x11F6
+
+/*
+ * Compex PMAC PCI device IDs.
+ */
+#define DC_DEVICEID_98713_CP 0x9881
+
+/*
+ * Lite-On PNIC PCI vendor ID
+ */
+#define DC_VENDORID_LO 0x11AD
+
+/*
+ * 82c168/82c169 PNIC device IDs. Both chips have the same device
+ * ID but different revisions. Revision 0x10 is the 82c168, and
+ * 0x20 is the 82c169.
+ */
+#define DC_DEVICEID_82C168 0x0002
+
+#define DC_REVISION_82C168 0x10
+#define DC_REVISION_82C169 0x20
+
+/*
+ * Lite-On PNIC II device ID. Note: this is actually a Macronix 98715A
+ * with wake on lan/magic packet support.
+ */
+#define DC_DEVICEID_82C115 0xc115
+
+/*
+ * Davicom vendor ID.
+ */
+#define DC_VENDORID_DAVICOM 0x1282
+
+/*
+ * Davicom device IDs.
+ */
+#define DC_DEVICEID_DM9100 0x9100
+#define DC_DEVICEID_DM9102 0x9102
+
+/*
+ * ADMtek vendor ID.
+ */
+#define DC_VENDORID_ADMTEK 0x1317
+
+/*
+ * ADMtek device IDs.
+ */
+#define DC_DEVICEID_AL981 0x0981
+#define DC_DEVICEID_AN985 0x0985
+
+/*
+ * ASIX vendor ID.
+ */
+#define DC_VENDORID_ASIX 0x125B
+
+/*
+ * ASIX device IDs.
+ */
+#define DC_DEVICEID_AX88140A 0x1400
+
+/*
+ * The ASIX AX88140 and ASIX AX88141 have the same vendor and
+ * device IDs but different revision values.
+ */
+#define DC_REVISION_88140 0x00
+#define DC_REVISION_88141 0x10
+
+/*
+ * PCI low memory base and low I/O base register, and
+ * other PCI registers.
+ */
+
+#define DC_PCI_CFID 0x00 /* Id */
+#define DC_PCI_CFCS 0x04 /* Command and status */
+#define DC_PCI_CFRV 0x08 /* Revision */
+#define DC_PCI_CFLT 0x0C /* Latency timer */
+#define DC_PCI_CFBIO 0x10 /* Base I/O address */
+#define DC_PCI_CFBMA 0x14 /* Base memory address */
+#define DC_PCI_CCIS 0x28 /* Card info struct */
+#define DC_PCI_CSID 0x2C /* Subsystem ID */
+#define DC_PCI_CBER 0x30 /* Expansion ROM base address */
+#define DC_PCI_CCAP 0x34 /* Caps pointer - PD/TD chip only */
+#define DC_PCI_CFIT 0x3C /* Interrupt */
+#define DC_PCI_CFDD 0x40 /* Device and driver area */
+#define DC_PCI_CWUA0 0x44 /* Wake-Up LAN addr 0 */
+#define DC_PCI_CWUA1 0x48 /* Wake-Up LAN addr 1 */
+#define DC_PCI_SOP0 0x4C /* SecureON passwd 0 */
+#define DC_PCI_SOP1 0x50 /* SecureON passwd 1 */
+#define DC_PCI_CWUC 0x54 /* Configuration Wake-Up cmd */
+#define DC_PCI_CCID 0xDC /* Capability ID - PD/TD only */
+#define DC_PCI_CPMC 0xE0 /* Pwrmgmt ctl & sts - PD/TD only */
+
+/* PCI ID register */
+#define DC_CFID_VENDOR 0x0000FFFF
+#define DC_CFID_DEVICE 0xFFFF0000
+
+/* PCI command/status register */
+#define DC_CFCS_IOSPACE 0x00000001 /* I/O space enable */
+#define DC_CFCS_MEMSPACE 0x00000002 /* memory space enable */
+#define DC_CFCS_BUSMASTER 0x00000004 /* bus master enable */
+#define DC_CFCS_MWI_ENB 0x00000008 /* mem write and inval enable */
+#define DC_CFCS_PARITYERR_ENB 0x00000020 /* parity error enable */
+#define DC_CFCS_SYSERR_ENB 0x00000080 /* system error enable */
+#define DC_CFCS_NEWCAPS 0x00100000 /* new capabilities */
+#define DC_CFCS_FAST_B2B 0x00800000 /* fast back-to-back capable */
+#define DC_CFCS_DATAPARITY 0x01000000 /* Parity error report */
+#define DC_CFCS_DEVSELTIM 0x06000000 /* devsel timing */
+#define DC_CFCS_TGTABRT 0x10000000 /* received target abort */
+#define DC_CFCS_MASTERABRT 0x20000000 /* received master abort */
+#define DC_CFCS_SYSERR 0x40000000 /* asserted system error */
+#define DC_CFCS_PARITYERR 0x80000000 /* asserted parity error */
+
+/* PCI revision register */
+#define DC_CFRV_STEPPING 0x0000000F
+#define DC_CFRV_REVISION 0x000000F0
+#define DC_CFRV_SUBCLASS 0x00FF0000
+#define DC_CFRV_BASECLASS 0xFF000000
+
+#define DC_21143_PB_REV 0x00000030
+#define DC_21143_TB_REV 0x00000030
+#define DC_21143_PC_REV 0x00000030
+#define DC_21143_TC_REV 0x00000030
+#define DC_21143_PD_REV 0x00000041
+#define DC_21143_TD_REV 0x00000041
+
+/* PCI latency timer register */
+#define DC_CFLT_CACHELINESIZE 0x000000FF
+#define DC_CFLT_LATENCYTIMER 0x0000FF00
+
+/* PCI subsystem ID register */
+#define DC_CSID_VENDOR 0x0000FFFF
+#define DC_CSID_DEVICE 0xFFFF0000
+
+/* PCI cababilities pointer */
+#define DC_CCAP_OFFSET 0x000000FF
+
+/* PCI interrupt config register */
+#define DC_CFIT_INTLINE 0x000000FF
+#define DC_CFIT_INTPIN 0x0000FF00
+#define DC_CFIT_MIN_GNT 0x00FF0000
+#define DC_CFIT_MAX_LAT 0xFF000000
+
+/* PCI capability register */
+#define DC_CCID_CAPID 0x000000FF
+#define DC_CCID_NEXTPTR 0x0000FF00
+#define DC_CCID_PM_VERS 0x00070000
+#define DC_CCID_PME_CLK 0x00080000
+#define DC_CCID_DVSPEC_INT 0x00200000
+#define DC_CCID_STATE_D1 0x02000000
+#define DC_CCID_STATE_D2 0x04000000
+#define DC_CCID_PME_D0 0x08000000
+#define DC_CCID_PME_D1 0x10000000
+#define DC_CCID_PME_D2 0x20000000
+#define DC_CCID_PME_D3HOT 0x40000000
+#define DC_CCID_PME_D3COLD 0x80000000
+
+/* PCI power management control/status register */
+#define DC_CPMC_STATE 0x00000003
+#define DC_CPMC_PME_ENB 0x00000100
+#define DC_CPMC_PME_STS 0x00008000
+
+#define DC_PSTATE_D0 0x0
+#define DC_PSTATE_D1 0x1
+#define DC_PSTATE_D2 0x2
+#define DC_PSTATE_D3 0x3
+
+/* Device specific region */
+/* Configuration and driver area */
+#define DC_CFDD_DRVUSE 0x0000FFFF
+#define DC_CFDD_SNOOZE_MODE 0x40000000
+#define DC_CFDD_SLEEP_MODE 0x80000000
+
+/* Configuration wake-up command register */
+#define DC_CWUC_MUST_BE_ZERO 0x00000001
+#define DC_CWUC_SECUREON_ENB 0x00000002
+#define DC_CWUC_FORCE_WUL 0x00000004
+#define DC_CWUC_BNC_ABILITY 0x00000008
+#define DC_CWUC_AUI_ABILITY 0x00000010
+#define DC_CWUC_TP10_ABILITY 0x00000020
+#define DC_CWUC_MII_ABILITY 0x00000040
+#define DC_CWUC_SYM_ABILITY 0x00000080
+#define DC_CWUC_LOCK 0x00000100
+
+#ifdef __alpha__
+#undef vtophys
+#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
+#endif
diff --git a/sys/pci/if_dm.c b/sys/pci/if_dm.c
deleted file mode 100644
index 96cd885..0000000
--- a/sys/pci/if_dm.c
+++ /dev/null
@@ -1,1709 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * Davicom DM9102 fast ethernet PCI NIC driver.
- *
- * Written by Bill Paul <wpaul@ee.columbia.edu>
- * Electrical Engineering Department
- * Columbia University, New York City
- */
-
-/*
- * The Davicom DM9102 is yet another DEC 21x4x clone. This one is actually
- * a pretty faithful copy. Same RX filter programming, same SROM layout,
- * same everything. Datasheets available from www.davicom8.com. Only
- * MII-based transceivers are supported.
- *
- * The DM9102's DMA engine seems pretty weak. Multi-fragment transmits
- * don't seem to work well, and on slow machines you get lots of RX
- * overruns.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sockio.h>
-#include <sys/mbuf.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ethernet.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
-
-#include <net/bpf.h>
-
-#include <vm/vm.h> /* for vtophys */
-#include <vm/pmap.h> /* for vtophys */
-#include <machine/clock.h> /* for DELAY */
-#include <machine/bus_pio.h>
-#include <machine/bus_memio.h>
-#include <machine/bus.h>
-#include <machine/resource.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
-
-#include <dev/mii/mii.h>
-#include <dev/mii/miivar.h>
-
-#include <pci/pcireg.h>
-#include <pci/pcivar.h>
-
-#define DM_USEIOSPACE
-
-#include <pci/if_dmreg.h>
-
-/* "controller miibus0" required. See GENERIC if you get errors here. */
-#include "miibus_if.h"
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-/*
- * Various supported device vendors/types and their names.
- */
-static struct dm_type dm_devs[] = {
- { DM_VENDORID, DM_DEVICEID_DM9100, "Davicom DM9100 10/100BaseTX" },
- { DM_VENDORID, DM_DEVICEID_DM9102, "Davicom DM9102 10/100BaseTX" },
- { 0, 0, NULL }
-};
-
-static int dm_probe __P((device_t));
-static int dm_attach __P((device_t));
-static int dm_detach __P((device_t));
-
-static int dm_newbuf __P((struct dm_softc *,
- struct dm_desc *,
- struct mbuf *));
-static int dm_encap __P((struct dm_softc *,
- struct mbuf **, u_int32_t *));
-
-static void dm_rxeof __P((struct dm_softc *));
-static void dm_rxeoc __P((struct dm_softc *));
-static void dm_txeof __P((struct dm_softc *));
-static void dm_intr __P((void *));
-static void dm_tick __P((void *));
-static void dm_start __P((struct ifnet *));
-static int dm_ioctl __P((struct ifnet *, u_long, caddr_t));
-static void dm_init __P((void *));
-static void dm_stop __P((struct dm_softc *));
-static void dm_watchdog __P((struct ifnet *));
-static void dm_shutdown __P((device_t));
-static int dm_ifmedia_upd __P((struct ifnet *));
-static void dm_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
-
-static void dm_delay __P((struct dm_softc *));
-static void dm_eeprom_idle __P((struct dm_softc *));
-static void dm_eeprom_putbyte __P((struct dm_softc *, int));
-static void dm_eeprom_getword __P((struct dm_softc *, int, u_int16_t *));
-static void dm_read_eeprom __P((struct dm_softc *, caddr_t, int,
- int, int));
-
-static void dm_mii_writebit __P((struct dm_softc *, int));
-static int dm_mii_readbit __P((struct dm_softc *));
-static void dm_mii_sync __P((struct dm_softc *));
-static void dm_mii_send __P((struct dm_softc *, u_int32_t, int));
-static int dm_mii_readreg __P((struct dm_softc *, struct dm_mii_frame *));
-static int dm_mii_writereg __P((struct dm_softc *, struct dm_mii_frame *));
-static int dm_miibus_readreg __P((device_t, int, int));
-static int dm_miibus_writereg __P((device_t, int, int, int));
-static void dm_miibus_statchg __P((device_t));
-
-static u_int32_t dm_calchash __P((caddr_t));
-static void dm_setfilt __P((struct dm_softc *));
-static void dm_reset __P((struct dm_softc *));
-static int dm_list_rx_init __P((struct dm_softc *));
-static int dm_list_tx_init __P((struct dm_softc *));
-
-#ifdef DM_USEIOSPACE
-#define DM_RES SYS_RES_IOPORT
-#define DM_RID DM_PCI_LOIO
-#else
-#define DM_RES SYS_RES_MEMORY
-#define DM_RID DM_PCI_LOMEM
-#endif
-
-static device_method_t dm_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, dm_probe),
- DEVMETHOD(device_attach, dm_attach),
- DEVMETHOD(device_detach, dm_detach),
- DEVMETHOD(device_shutdown, dm_shutdown),
-
- /* bus interface */
- DEVMETHOD(bus_print_child, bus_generic_print_child),
- DEVMETHOD(bus_driver_added, bus_generic_driver_added),
-
- /* MII interface */
- DEVMETHOD(miibus_readreg, dm_miibus_readreg),
- DEVMETHOD(miibus_writereg, dm_miibus_writereg),
- DEVMETHOD(miibus_statchg, dm_miibus_statchg),
-
- { 0, 0 }
-};
-
-static driver_t dm_driver = {
- "dm",
- dm_methods,
- sizeof(struct dm_softc)
-};
-
-static devclass_t dm_devclass;
-
-DRIVER_MODULE(if_dm, pci, dm_driver, dm_devclass, 0, 0);
-DRIVER_MODULE(miibus, dm, miibus_driver, miibus_devclass, 0, 0);
-
-#define DM_SETBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) | x)
-
-#define DM_CLRBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) & ~x)
-
-#define SIO_SET(x) \
- CSR_WRITE_4(sc, DM_SIO, \
- CSR_READ_4(sc, DM_SIO) | x)
-
-#define SIO_CLR(x) \
- CSR_WRITE_4(sc, DM_SIO, \
- CSR_READ_4(sc, DM_SIO) & ~x)
-
-static void dm_delay(sc)
- struct dm_softc *sc;
-{
- int idx;
-
- for (idx = (300 / 33) + 1; idx > 0; idx--)
- CSR_READ_4(sc, DM_BUSCTL);
-}
-
-static void dm_eeprom_idle(sc)
- struct dm_softc *sc;
-{
- register int i;
-
- CSR_WRITE_4(sc, DM_SIO, DM_SIO_EESEL);
- dm_delay(sc);
- DM_SETBIT(sc, DM_SIO, DM_SIO_ROMCTL_READ);
- dm_delay(sc);
- DM_SETBIT(sc, DM_SIO, DM_SIO_EE_CS);
- dm_delay(sc);
- DM_SETBIT(sc, DM_SIO, DM_SIO_EE_CLK);
- dm_delay(sc);
-
- for (i = 0; i < 25; i++) {
- DM_CLRBIT(sc, DM_SIO, DM_SIO_EE_CLK);
- dm_delay(sc);
- DM_SETBIT(sc, DM_SIO, DM_SIO_EE_CLK);
- dm_delay(sc);
- }
-
- DM_CLRBIT(sc, DM_SIO, DM_SIO_EE_CLK);
- dm_delay(sc);
- DM_CLRBIT(sc, DM_SIO, DM_SIO_EE_CS);
- dm_delay(sc);
- CSR_WRITE_4(sc, DM_SIO, 0x00000000);
-
- return;
-}
-
-/*
- * Send a read command and address to the EEPROM, check for ACK.
- */
-static void dm_eeprom_putbyte(sc, addr)
- struct dm_softc *sc;
- int addr;
-{
- register int d, i;
-
- d = addr | DM_EECMD_READ;
-
- /*
- * Feed in each bit and stobe the clock.
- */
- for (i = 0x400; i; i >>= 1) {
- if (d & i) {
- SIO_SET(DM_SIO_EE_DATAIN);
- } else {
- SIO_CLR(DM_SIO_EE_DATAIN);
- }
- dm_delay(sc);
- SIO_SET(DM_SIO_EE_CLK);
- dm_delay(sc);
- SIO_CLR(DM_SIO_EE_CLK);
- dm_delay(sc);
- }
-
- return;
-}
-
-/*
- * Read a word of data stored in the EEPROM at address 'addr.'
- */
-static void dm_eeprom_getword(sc, addr, dest)
- struct dm_softc *sc;
- int addr;
- u_int16_t *dest;
-{
- register int i;
- u_int16_t word = 0;
-
- /* Force EEPROM to idle state. */
- dm_eeprom_idle(sc);
-
- /* Enter EEPROM access mode. */
- CSR_WRITE_4(sc, DM_SIO, DM_SIO_EESEL);
- dm_delay(sc);
- DM_SETBIT(sc, DM_SIO, DM_SIO_ROMCTL_READ);
- dm_delay(sc);
- DM_SETBIT(sc, DM_SIO, DM_SIO_EE_CS);
- dm_delay(sc);
- DM_SETBIT(sc, DM_SIO, DM_SIO_EE_CLK);
- dm_delay(sc);
-
- /*
- * Send address of word we want to read.
- */
- dm_eeprom_putbyte(sc, addr);
-
- /*
- * Start reading bits from EEPROM.
- */
- for (i = 0x8000; i; i >>= 1) {
- SIO_SET(DM_SIO_EE_CLK);
- dm_delay(sc);
- if (CSR_READ_4(sc, DM_SIO) & DM_SIO_EE_DATAOUT)
- word |= i;
- dm_delay(sc);
- SIO_CLR(DM_SIO_EE_CLK);
- dm_delay(sc);
- }
-
- /* Turn off EEPROM access mode. */
- dm_eeprom_idle(sc);
-
- *dest = word;
-
- return;
-}
-
-/*
- * Read a sequence of words from the EEPROM.
- */
-static void dm_read_eeprom(sc, dest, off, cnt, swap)
- struct dm_softc *sc;
- caddr_t dest;
- int off;
- int cnt;
- int swap;
-{
- int i;
- u_int16_t word = 0, *ptr;
-
- for (i = 0; i < cnt; i++) {
- dm_eeprom_getword(sc, off + i, &word);
- ptr = (u_int16_t *)(dest + (i * 2));
- if (swap)
- *ptr = ntohs(word);
- else
- *ptr = word;
- }
-
- return;
-}
-
-/*
- * Write a bit to the MII bus.
- */
-static void dm_mii_writebit(sc, bit)
- struct dm_softc *sc;
- int bit;
-{
- if (bit)
- CSR_WRITE_4(sc, DM_SIO, DM_SIO_ROMCTL_WRITE|DM_SIO_MII_DATAOUT);
- else
- CSR_WRITE_4(sc, DM_SIO, DM_SIO_ROMCTL_WRITE);
-
- DM_SETBIT(sc, DM_SIO, DM_SIO_MII_CLK);
- DM_CLRBIT(sc, DM_SIO, DM_SIO_MII_CLK);
-
- return;
-}
-
-/*
- * Read a bit from the MII bus.
- */
-static int dm_mii_readbit(sc)
- struct dm_softc *sc;
-{
- CSR_WRITE_4(sc, DM_SIO, DM_SIO_ROMCTL_READ|DM_SIO_MII_DIR);
- CSR_READ_4(sc, DM_SIO);
- DM_SETBIT(sc, DM_SIO, DM_SIO_MII_CLK);
- DM_CLRBIT(sc, DM_SIO, DM_SIO_MII_CLK);
- if (CSR_READ_4(sc, DM_SIO) & DM_SIO_MII_DATAIN)
- return(1);
-
- return(0);
-}
-
-/*
- * Sync the PHYs by setting data bit and strobing the clock 32 times.
- */
-static void dm_mii_sync(sc)
- struct dm_softc *sc;
-{
- register int i;
-
- CSR_WRITE_4(sc, DM_SIO, DM_SIO_ROMCTL_WRITE);
-
- for (i = 0; i < 32; i++)
- dm_mii_writebit(sc, 1);
-
- return;
-}
-
-/*
- * Clock a series of bits through the MII.
- */
-static void dm_mii_send(sc, bits, cnt)
- struct dm_softc *sc;
- u_int32_t bits;
- int cnt;
-{
- int i;
-
- for (i = (0x1 << (cnt - 1)); i; i >>= 1)
- dm_mii_writebit(sc, bits & i);
-}
-
-/*
- * Read an PHY register through the MII.
- */
-static int dm_mii_readreg(sc, frame)
- struct dm_softc *sc;
- struct dm_mii_frame *frame;
-
-{
- int i, ack, s;
-
- s = splimp();
-
- /*
- * Set up frame for RX.
- */
- frame->mii_stdelim = DM_MII_STARTDELIM;
- frame->mii_opcode = DM_MII_READOP;
- frame->mii_turnaround = 0;
- frame->mii_data = 0;
-
- /*
- * Sync the PHYs.
- */
- dm_mii_sync(sc);
-
- /*
- * Send command/address info.
- */
- dm_mii_send(sc, frame->mii_stdelim, 2);
- dm_mii_send(sc, frame->mii_opcode, 2);
- dm_mii_send(sc, frame->mii_phyaddr, 5);
- dm_mii_send(sc, frame->mii_regaddr, 5);
-
-#ifdef notdef
- /* Idle bit */
- dm_mii_writebit(sc, 1);
- dm_mii_writebit(sc, 0);
-#endif
-
- /* Check for ack */
- ack = dm_mii_readbit(sc);
-
- /*
- * Now try reading data bits. If the ack failed, we still
- * need to clock through 16 cycles to keep the PHY(s) in sync.
- */
- if (ack) {
- for(i = 0; i < 16; i++) {
- dm_mii_readbit(sc);
- }
- goto fail;
- }
-
- for (i = 0x8000; i; i >>= 1) {
- if (!ack) {
- if (dm_mii_readbit(sc))
- frame->mii_data |= i;
- }
- }
-
-fail:
-
- dm_mii_writebit(sc, 0);
- dm_mii_writebit(sc, 0);
-
- splx(s);
-
- if (ack)
- return(1);
- return(0);
-}
-
-/*
- * Write to a PHY register through the MII.
- */
-static int dm_mii_writereg(sc, frame)
- struct dm_softc *sc;
- struct dm_mii_frame *frame;
-
-{
- int s;
-
- s = splimp();
- /*
- * Set up frame for TX.
- */
-
- frame->mii_stdelim = DM_MII_STARTDELIM;
- frame->mii_opcode = DM_MII_WRITEOP;
- frame->mii_turnaround = DM_MII_TURNAROUND;
-
- /*
- * Sync the PHYs.
- */
- dm_mii_sync(sc);
-
- dm_mii_send(sc, frame->mii_stdelim, 2);
- dm_mii_send(sc, frame->mii_opcode, 2);
- dm_mii_send(sc, frame->mii_phyaddr, 5);
- dm_mii_send(sc, frame->mii_regaddr, 5);
- dm_mii_send(sc, frame->mii_turnaround, 2);
- dm_mii_send(sc, frame->mii_data, 16);
-
- /* Idle bit. */
- dm_mii_writebit(sc, 0);
- dm_mii_writebit(sc, 0);
-
- splx(s);
-
- return(0);
-}
-
-static int dm_miibus_readreg(dev, phy, reg)
- device_t dev;
- int phy, reg;
-{
- struct dm_softc *sc;
- struct dm_mii_frame frame;
-
- sc = device_get_softc(dev);
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- dm_mii_readreg(sc, &frame);
-
- return(frame.mii_data);
-}
-
-static int dm_miibus_writereg(dev, phy, reg, data)
- device_t dev;
- int phy, reg, data;
-{
- struct dm_softc *sc;
- struct dm_mii_frame frame;
-
- sc = device_get_softc(dev);
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- frame.mii_data = data;
-
- dm_mii_writereg(sc, &frame);
-
- return(0);
-}
-
-static void dm_miibus_statchg(dev)
- device_t dev;
-{
- struct dm_softc *sc;
- struct mii_data *mii;
-
- sc = device_get_softc(dev);
- mii = device_get_softc(sc->dm_miibus);
-
- if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_SPEEDSEL);
- else
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_SPEEDSEL);
-
- if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_FULLDUPLEX);
- else
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_FULLDUPLEX);
-
- return;
-}
-
-#define DM_POLY 0xEDB88320
-#define DM_BITS 9
-
-static u_int32_t dm_calchash(addr)
- caddr_t addr;
-{
- u_int32_t idx, bit, data, crc;
-
- /* Compute CRC for the address value. */
- crc = 0xFFFFFFFF; /* initial value */
-
- for (idx = 0; idx < 6; idx++) {
- for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
- crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DM_POLY : 0);
- }
-
- return (crc & ((1 << DM_BITS) - 1));
-}
-
-void dm_setfilt(sc)
- struct dm_softc *sc;
-{
- struct dm_desc *sframe;
- u_int32_t h, *sp;
- struct ifmultiaddr *ifma;
- struct ifnet *ifp;
- int i;
-
- ifp = &sc->arpcom.ac_if;
-
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_TX_ON);
- DM_SETBIT(sc, DM_ISR, DM_ISR_TX_IDLE);
-
- sframe = &sc->dm_ldata->dm_sframe;
- sp = (u_int32_t *)&sc->dm_cdata.dm_sbuf;
- bzero((char *)sp, DM_SFRAME_LEN);
-
- sframe->dm_next = vtophys(&sc->dm_ldata->dm_tx_list[0]);
- sframe->dm_data = vtophys(&sc->dm_cdata.dm_sbuf);
- sframe->dm_ctl = DM_SFRAME_LEN | DM_TXCTL_TLINK |
- DM_TXCTL_SETUP | DM_FILTER_HASHPERF;
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC)
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_RX_PROMISC);
- else
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_RX_PROMISC);
-
- if (ifp->if_flags & IFF_ALLMULTI)
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_RX_ALLMULTI);
-
- for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
- ifma = ifma->ifma_link.le_next) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- h = dm_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
- sp[h >> 4] |= 1 << (h & 0xF);
- }
-
- if (ifp->if_flags & IFF_BROADCAST) {
- h = dm_calchash((caddr_t)&etherbroadcastaddr);
- sp[h >> 4] |= 1 << (h & 0xF);
- }
-
- sp[39] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0];
- sp[40] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1];
- sp[41] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2];
-
- CSR_WRITE_4(sc, DM_TXADDR, vtophys(sframe));
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_TX_ON);
- sframe->dm_status = DM_TXSTAT_OWN;
- CSR_WRITE_4(sc, DM_TXSTART, 0xFFFFFFFF);
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_TX_ON);
-
- /*
- * Wait for chip to clear the 'own' bit.
- */
- for (i = 0; i < DM_TIMEOUT; i++) {
- DELAY(10);
- if (sframe->dm_status != DM_TXSTAT_OWN)
- break;
- }
-
- if (i == DM_TIMEOUT)
- printf("dm%d: failed to send setup frame\n", sc->dm_unit);
-
- DM_SETBIT(sc, DM_ISR, DM_ISR_TX_NOBUF|DM_ISR_TX_IDLE);
-
- return;
-}
-
-static void dm_reset(sc)
- struct dm_softc *sc;
-{
- register int i;
-
- DM_SETBIT(sc, DM_BUSCTL, DM_BUSCTL_RESET);
-
- for (i = 0; i < DM_TIMEOUT; i++) {
- DELAY(10);
- if (!(CSR_READ_4(sc, DM_BUSCTL) & DM_BUSCTL_RESET))
- break;
- }
-
- if (i == DM_TIMEOUT)
- printf("dm%d: reset never completed!\n", sc->dm_unit);
-
- CSR_WRITE_4(sc, DM_BUSCTL, 0);
-
- /* Wait a little while for the chip to get its brains in order. */
- DELAY(1000);
- return;
-}
-
-/*
- * Probe for an Davicom chip. Check the PCI vendor and device
- * IDs against our list and return a device name if we find a match.
- */
-static int dm_probe(dev)
- device_t dev;
-{
- struct dm_type *t;
-
- t = dm_devs;
-
- while(t->dm_name != NULL) {
- if ((pci_get_vendor(dev) == t->dm_vid) &&
- (pci_get_device(dev) == t->dm_did)) {
- device_set_desc(dev, t->dm_name);
- return(0);
- }
- t++;
- }
-
- return(ENXIO);
-}
-
-/*
- * Attach the interface. Allocate softc structures, do ifmedia
- * setup and ethernet/BPF attach.
- */
-static int dm_attach(dev)
- device_t dev;
-{
- int s;
- u_char eaddr[ETHER_ADDR_LEN];
- u_int32_t command;
- struct dm_softc *sc;
- struct ifnet *ifp;
- int unit, error = 0, rid;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- unit = device_get_unit(dev);
- bzero(sc, sizeof(struct dm_softc));
-
- /*
- * Handle power management nonsense.
- */
-
- command = pci_read_config(dev, DM_PCI_CAPID, 4) & 0x000000FF;
- if (command == 0x01) {
-
- command = pci_read_config(dev, DM_PCI_PWRMGMTCTRL, 4);
- if (command & DM_PSTATE_MASK) {
- u_int32_t iobase, membase, irq;
-
- /* Save important PCI config data. */
- iobase = pci_read_config(dev, DM_PCI_LOIO, 4);
- membase = pci_read_config(dev, DM_PCI_LOMEM, 4);
- irq = pci_read_config(dev, DM_PCI_INTLINE, 4);
-
- /* Reset the power state. */
- printf("dm%d: chip is in D%d power mode "
- "-- setting to D0\n", unit, command & DM_PSTATE_MASK);
- command &= 0xFFFFFFFC;
- pci_write_config(dev, DM_PCI_PWRMGMTCTRL, command, 4);
-
- /* Restore PCI config data. */
- pci_write_config(dev, DM_PCI_LOIO, iobase, 4);
- pci_write_config(dev, DM_PCI_LOMEM, membase, 4);
- pci_write_config(dev, DM_PCI_INTLINE, irq, 4);
- }
- }
-
- /*
- * Map control/status registers.
- */
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
- command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
- pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
-
-#ifdef DM_USEIOSPACE
- if (!(command & PCIM_CMD_PORTEN)) {
- printf("dm%d: failed to enable I/O ports!\n", unit);
- error = ENXIO;;
- goto fail;
- }
-#else
- if (!(command & PCIM_CMD_MEMEN)) {
- printf("dm%d: failed to enable memory mapping!\n", unit);
- error = ENXIO;;
- goto fail;
- }
-#endif
-
- rid = DM_RID;
- sc->dm_res = bus_alloc_resource(dev, DM_RES, &rid,
- 0, ~0, 1, RF_ACTIVE);
-
- if (sc->dm_res == NULL) {
- printf("dm%d: couldn't map ports/memory\n", unit);
- error = ENXIO;
- goto fail;
- }
-
- sc->dm_btag = rman_get_bustag(sc->dm_res);
- sc->dm_bhandle = rman_get_bushandle(sc->dm_res);
-
- /* Allocate interrupt */
- rid = 0;
- sc->dm_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
- RF_SHAREABLE | RF_ACTIVE);
-
- if (sc->dm_irq == NULL) {
- printf("dm%d: couldn't map interrupt\n", unit);
- bus_release_resource(dev, DM_RES, DM_RID, sc->dm_res);
- error = ENXIO;
- goto fail;
- }
-
- error = bus_setup_intr(dev, sc->dm_irq, INTR_TYPE_NET,
- dm_intr, sc, &sc->dm_intrhand);
-
- if (error) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dm_res);
- bus_release_resource(dev, DM_RES, DM_RID, sc->dm_res);
- printf("dm%d: couldn't set up irq\n", unit);
- goto fail;
- }
-
- /* Save the cache line size. */
- sc->dm_cachesize = pci_read_config(dev, DM_PCI_CACHELEN, 4) & 0xFF;
-
- /* Reset the adapter. */
- dm_reset(sc);
-
- /*
- * Get station address from the EEPROM.
- */
- dm_read_eeprom(sc, (caddr_t)&eaddr, DM_EE_NODEADDR, 3, 0);
-
- /*
- * A Davicom chip was detected. Inform the world.
- */
- printf("dm%d: Ethernet address: %6D\n", unit, eaddr, ":");
-
- sc->dm_unit = unit;
- callout_handle_init(&sc->dm_stat_ch);
- bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
-
- sc->dm_ldata = contigmalloc(sizeof(struct dm_list_data), M_DEVBUF,
- M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
-
- if (sc->dm_ldata == NULL) {
- printf("dm%d: no memory for list buffers!\n", unit);
- bus_teardown_intr(dev, sc->dm_irq, sc->dm_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dm_irq);
- bus_release_resource(dev, DM_RES, DM_RID, sc->dm_res);
- error = ENXIO;
- goto fail;
- }
- bzero(sc->dm_ldata, sizeof(struct dm_list_data));
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_softc = sc;
- ifp->if_unit = unit;
- ifp->if_name = "dm";
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = dm_ioctl;
- ifp->if_output = ether_output;
- ifp->if_start = dm_start;
- ifp->if_watchdog = dm_watchdog;
- ifp->if_init = dm_init;
- ifp->if_baudrate = 10000000;
- ifp->if_snd.ifq_maxlen = DM_TX_LIST_CNT - 1;
-
- /*
- * Do MII setup.
- */
- if (mii_phy_probe(dev, &sc->dm_miibus,
- dm_ifmedia_upd, dm_ifmedia_sts)) {
- printf("dm%d: MII without any PHY!\n", sc->dm_unit);
- bus_teardown_intr(dev, sc->dm_irq, sc->dm_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dm_irq);
- bus_release_resource(dev, DM_RES, DM_RID, sc->dm_res);
- error = ENXIO;
- goto fail;
- }
-
- /*
- * Call MI attach routines.
- */
- if_attach(ifp);
- ether_ifattach(ifp);
-
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-
-fail:
- splx(s);
- return(error);
-}
-
-static int dm_detach(dev)
- device_t dev;
-{
- struct dm_softc *sc;
- struct ifnet *ifp;
- int s;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- ifp = &sc->arpcom.ac_if;
-
- dm_reset(sc);
- dm_stop(sc);
- if_detach(ifp);
-
- bus_generic_detach(dev);
- device_delete_child(dev, sc->dm_miibus);
-
- bus_teardown_intr(dev, sc->dm_irq, sc->dm_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dm_irq);
- bus_release_resource(dev, DM_RES, DM_RID, sc->dm_res);
-
- contigfree(sc->dm_ldata, sizeof(struct dm_list_data), M_DEVBUF);
-
- splx(s);
-
- return(0);
-}
-
-/*
- * Initialize the transmit descriptors.
- */
-static int dm_list_tx_init(sc)
- struct dm_softc *sc;
-{
- struct dm_chain_data *cd;
- struct dm_list_data *ld;
- int i;
-
- cd = &sc->dm_cdata;
- ld = sc->dm_ldata;
- for (i = 0; i < DM_TX_LIST_CNT; i++) {
- if (i == (DM_TX_LIST_CNT - 1)) {
- ld->dm_tx_list[i].dm_nextdesc =
- &ld->dm_tx_list[0];
- ld->dm_tx_list[i].dm_next =
- vtophys(&ld->dm_tx_list[0]);
- } else {
- ld->dm_tx_list[i].dm_nextdesc =
- &ld->dm_tx_list[i + 1];
- ld->dm_tx_list[i].dm_next =
- vtophys(&ld->dm_tx_list[i + 1]);
- }
- ld->dm_tx_list[i].dm_mbuf = NULL;
- ld->dm_tx_list[i].dm_data = 0;
- ld->dm_tx_list[i].dm_ctl = 0;
- }
-
- cd->dm_tx_prod = cd->dm_tx_cons = cd->dm_tx_cnt = 0;
-
- return(0);
-}
-
-
-/*
- * Initialize the RX descriptors and allocate mbufs for them. Note that
- * we arrange the descriptors in a closed ring, so that the last descriptor
- * points back to the first.
- */
-static int dm_list_rx_init(sc)
- struct dm_softc *sc;
-{
- struct dm_chain_data *cd;
- struct dm_list_data *ld;
- int i;
-
- cd = &sc->dm_cdata;
- ld = sc->dm_ldata;
-
- for (i = 0; i < DM_RX_LIST_CNT; i++) {
- if (dm_newbuf(sc, &ld->dm_rx_list[i], NULL) == ENOBUFS)
- return(ENOBUFS);
- if (i == (DM_RX_LIST_CNT - 1)) {
- ld->dm_rx_list[i].dm_nextdesc =
- &ld->dm_rx_list[0];
- ld->dm_rx_list[i].dm_next =
- vtophys(&ld->dm_rx_list[0]);
- } else {
- ld->dm_rx_list[i].dm_nextdesc =
- &ld->dm_rx_list[i + 1];
- ld->dm_rx_list[i].dm_next =
- vtophys(&ld->dm_rx_list[i + 1]);
- }
- }
-
- cd->dm_rx_prod = 0;
-
- return(0);
-}
-
-/*
- * Initialize an RX descriptor and attach an MBUF cluster.
- * Note: the length fields are only 11 bits wide, which means the
- * largest size we can specify is 2047. This is important because
- * MCLBYTES is 2048, so we have to subtract one otherwise we'll
- * overflow the field and make a mess.
- */
-static int dm_newbuf(sc, c, m)
- struct dm_softc *sc;
- struct dm_desc *c;
- struct mbuf *m;
-{
- struct mbuf *m_new = NULL;
-
- if (m == NULL) {
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("dm%d: no memory for rx list "
- "-- packet dropped!\n", sc->dm_unit);
- return(ENOBUFS);
- }
-
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- printf("dm%d: no memory for rx list "
- "-- packet dropped!\n", sc->dm_unit);
- m_freem(m_new);
- return(ENOBUFS);
- }
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- } else {
- m_new = m;
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- m_new->m_data = m_new->m_ext.ext_buf;
- }
-
- m_adj(m_new, sizeof(u_int64_t));
-
- c->dm_mbuf = m_new;
- c->dm_data = vtophys(mtod(m_new, caddr_t));
- c->dm_ctl = DM_RXCTL_RLINK | DM_RXLEN;
- c->dm_status = DM_RXSTAT_OWN;
-
- return(0);
-}
-
-/*
- * A frame has been uploaded: pass the resulting mbuf chain up to
- * the higher level protocols.
- */
-static void dm_rxeof(sc)
- struct dm_softc *sc;
-{
- struct ether_header *eh;
- struct mbuf *m;
- struct ifnet *ifp;
- struct dm_desc *cur_rx;
- int i, total_len = 0;
- u_int32_t rxstat;
-
- ifp = &sc->arpcom.ac_if;
- i = sc->dm_cdata.dm_rx_prod;
-
- while(!(sc->dm_ldata->dm_rx_list[i].dm_status & DM_RXSTAT_OWN)) {
- struct mbuf *m0 = NULL;
-
- cur_rx = &sc->dm_ldata->dm_rx_list[i];
- rxstat = cur_rx->dm_status;
- m = cur_rx->dm_mbuf;
- cur_rx->dm_mbuf = NULL;
- total_len = DM_RXBYTES(rxstat);
- DM_INC(i, DM_RX_LIST_CNT);
-
- /*
- * If an error occurs, update stats, clear the
- * status word and leave the mbuf cluster in place:
- * it should simply get re-used next time this descriptor
- * comes up in the ring.
- */
- if (rxstat & DM_RXSTAT_RXERR) {
- ifp->if_ierrors++;
- if (rxstat & DM_RXSTAT_COLLSEEN)
- ifp->if_collisions++;
- dm_newbuf(sc, cur_rx, m);
- dm_init(sc);
- return;
- }
-
- /* No errors; receive the packet. */
- total_len -= ETHER_CRC_LEN;
-
- m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
- total_len + ETHER_ALIGN, 0, ifp, NULL);
- dm_newbuf(sc, cur_rx, m);
- if (m0 == NULL) {
- ifp->if_ierrors++;
- continue;
- }
- m_adj(m0, ETHER_ALIGN);
- m = m0;
-
- ifp->if_ipackets++;
- eh = mtod(m, struct ether_header *);
-
- /*
- * Handle BPF listeners. Let the BPF user see the packet, but
- * don't pass it up to the ether_input() layer unless it's
- * a broadcast packet, multicast packet, matches our ethernet
- * address or the interface is in promiscuous mode.
- */
- if (ifp->if_bpf) {
- bpf_mtap(ifp, m);
- if (ifp->if_flags & IFF_PROMISC &&
- (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
- ETHER_ADDR_LEN) &&
- (eh->ether_dhost[0] & 1) == 0)) {
- m_freem(m);
- continue;
- }
- }
-
- /* Remove header from mbuf and pass it on. */
- m_adj(m, sizeof(struct ether_header));
- ether_input(ifp, eh, m);
- }
-
- sc->dm_cdata.dm_rx_prod = i;
-
- return;
-}
-
-void dm_rxeoc(sc)
- struct dm_softc *sc;
-{
- dm_rxeof(sc);
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_RX_ON);
- CSR_WRITE_4(sc, DM_RXSTART, 0xFFFFFFFF);
- return;
-}
-
-/*
- * A frame was downloaded to the chip. It's safe for us to clean up
- * the list buffers.
- */
-
-static void dm_txeof(sc)
- struct dm_softc *sc;
-{
- struct dm_desc *cur_tx = NULL;
- struct ifnet *ifp;
- int idx;
-
- ifp = &sc->arpcom.ac_if;
-
- /* Clear the timeout timer. */
- ifp->if_timer = 0;
-
- /*
- * Go through our tx list and free mbufs for those
- * frames that have been transmitted.
- */
- idx = sc->dm_cdata.dm_tx_cons;
- while(idx != sc->dm_cdata.dm_tx_prod) {
- u_int32_t txstat;
-
- cur_tx = &sc->dm_ldata->dm_tx_list[idx];
- txstat = cur_tx->dm_status;
-
- if (txstat & DM_TXSTAT_OWN)
- break;
-
- if (!(cur_tx->dm_ctl & DM_TXCTL_LASTFRAG)) {
- sc->dm_cdata.dm_tx_cnt--;
- DM_INC(idx, DM_TX_LIST_CNT);
- continue;
- }
-
- if (txstat & DM_TXSTAT_ERRSUM) {
- ifp->if_oerrors++;
- if (txstat & DM_TXSTAT_EXCESSCOLL)
- ifp->if_collisions++;
- if (txstat & DM_TXSTAT_LATECOLL)
- ifp->if_collisions++;
- dm_init(sc);
- return;
- }
-
- ifp->if_collisions += (txstat & DM_TXSTAT_COLLCNT) >> 3;
-
- ifp->if_opackets++;
- if (cur_tx->dm_mbuf != NULL) {
- m_freem(cur_tx->dm_mbuf);
- cur_tx->dm_mbuf = NULL;
- }
-
- sc->dm_cdata.dm_tx_cnt--;
- DM_INC(idx, DM_TX_LIST_CNT);
- ifp->if_timer = 0;
- }
-
- sc->dm_cdata.dm_tx_cons = idx;
-
- if (cur_tx != NULL)
- ifp->if_flags &= ~IFF_OACTIVE;
-
- return;
-}
-
-static void dm_tick(xsc)
- void *xsc;
-{
- struct dm_softc *sc;
- struct mii_data *mii;
- int s;
-
- s = splimp();
-
- sc = xsc;
- mii = device_get_softc(sc->dm_miibus);
- mii_tick(mii);
-
- sc->dm_stat_ch = timeout(dm_tick, sc, hz);
-
- splx(s);
-
- return;
-}
-
-static void dm_intr(arg)
- void *arg;
-{
- struct dm_softc *sc;
- struct ifnet *ifp;
- u_int32_t status;
-
- sc = arg;
- ifp = &sc->arpcom.ac_if;
-
- /* Supress unwanted interrupts */
- if (!(ifp->if_flags & IFF_UP)) {
- dm_stop(sc);
- return;
- }
-
- /* Disable interrupts. */
- CSR_WRITE_4(sc, DM_IMR, 0x00000000);
-
- for (;;) {
- status = CSR_READ_4(sc, DM_ISR);
- if (status)
- CSR_WRITE_4(sc, DM_ISR, status);
-
- if ((status & DM_INTRS) == 0)
- break;
-
- if ((status & DM_ISR_TX_OK) || (status & DM_ISR_TX_EARLY))
- dm_txeof(sc);
-
- if (status & DM_ISR_TX_NOBUF)
- dm_txeof(sc);
-
- if (status & DM_ISR_TX_IDLE) {
- dm_txeof(sc);
- if (sc->dm_cdata.dm_tx_cnt) {
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_TX_ON);
- CSR_WRITE_4(sc, DM_TXSTART, 0xFFFFFFFF);
- }
- }
-
- if (status & DM_ISR_TX_UNDERRUN) {
- u_int32_t cfg;
- cfg = CSR_READ_4(sc, DM_NETCFG);
- if ((cfg & DM_NETCFG_TX_THRESH) == DM_TXTHRESH_160BYTES)
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_STORENFWD);
- else
- CSR_WRITE_4(sc, DM_NETCFG, cfg + 0x4000);
- }
-
- if (status & DM_ISR_RX_OK) {
- dm_rxeof(sc);
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_RX_ON);
- CSR_WRITE_4(sc, DM_RXSTART, 0xFFFFFFFF);
- }
-
- if ((status & DM_ISR_RX_WATDOGTIMEO)
- || (status & DM_ISR_RX_NOBUF))
- dm_rxeoc(sc);
-
- if (status & DM_ISR_BUS_ERR) {
- dm_reset(sc);
- dm_init(sc);
- }
- }
-
- /* Re-enable interrupts. */
- CSR_WRITE_4(sc, DM_IMR, DM_INTRS);
-
- if (ifp->if_snd.ifq_head != NULL)
- dm_start(ifp);
-
- return;
-}
-
-/*
- * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
- * pointers to the fragment pointers.
- */
-static int dm_encap(sc, m_head, txidx)
- struct dm_softc *sc;
- struct mbuf **m_head;
- u_int32_t *txidx;
-{
- struct dm_desc *f = NULL;
- struct mbuf *m;
- int frag, cur, cnt = 0;
- struct mbuf *m_new = NULL;
-
- m = *m_head;
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("dm%d: no memory for tx list", sc->dm_unit);
- return(ENOBUFS);
- }
- if (m->m_pkthdr.len > MHLEN) {
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- printf("dm%d: no memory for tx list", sc->dm_unit);
- return(ENOBUFS);
- }
- }
- m_copydata(m, 0, m->m_pkthdr.len, mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len = m->m_pkthdr.len;
- m_freem(m);
- *m_head = m_new;
-
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- cur = frag = *txidx;
-
- for (m = m_new; m != NULL; m = m->m_next) {
- if (m->m_len != 0) {
- if ((DM_TX_LIST_CNT -
- (sc->dm_cdata.dm_tx_cnt + cnt)) < 2)
- return(ENOBUFS);
- f = &sc->dm_ldata->dm_tx_list[frag];
- f->dm_ctl = DM_TXCTL_TLINK | m->m_len;
- if (cnt == 0) {
- f->dm_status = 0;
- f->dm_ctl |= DM_TXCTL_FIRSTFRAG;
- } else
- f->dm_status = DM_TXSTAT_OWN;
- f->dm_data = vtophys(mtod(m, vm_offset_t));
- cur = frag;
- DM_INC(frag, DM_TX_LIST_CNT);
- cnt++;
- }
- }
-
- if (m != NULL)
- return(ENOBUFS);
-
- sc->dm_ldata->dm_tx_list[cur].dm_mbuf = *m_head;
- sc->dm_ldata->dm_tx_list[cur].dm_ctl |=
- DM_TXCTL_LASTFRAG|DM_TXCTL_FINT;
- sc->dm_ldata->dm_tx_list[*txidx].dm_status |= DM_TXSTAT_OWN;
- sc->dm_cdata.dm_tx_cnt += cnt;
- *txidx = frag;
-
- return(0);
-}
-
-/*
- * Main transmit routine. To avoid having to do mbuf copies, we put pointers
- * to the mbuf data regions directly in the transmit lists. We also save a
- * copy of the pointers since the transmit list fragment pointers are
- * physical addresses.
- */
-
-static void dm_start(ifp)
- struct ifnet *ifp;
-{
- struct dm_softc *sc;
- struct mbuf *m_head = NULL;
- u_int32_t idx;
-
- sc = ifp->if_softc;
-
- if (ifp->if_flags & IFF_OACTIVE)
- return;
-
- idx = sc->dm_cdata.dm_tx_prod;
-
- while(sc->dm_ldata->dm_tx_list[idx].dm_mbuf == NULL) {
- IF_DEQUEUE(&ifp->if_snd, m_head);
- if (m_head == NULL)
- break;
-
- if (dm_encap(sc, &m_head, &idx)) {
- IF_PREPEND(&ifp->if_snd, m_head);
- ifp->if_flags |= IFF_OACTIVE;
- break;
- }
-
- /*
- * If there's a BPF listener, bounce a copy of this frame
- * to him.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp, m_head);
- }
-
- sc->dm_cdata.dm_tx_prod = idx;
- CSR_WRITE_4(sc, DM_TXSTART, 0xFFFFFFFF);
-
- /*
- * Set a timeout in case the chip goes out to lunch.
- */
- ifp->if_timer = 5;
-
- return;
-}
-
-static void dm_init(xsc)
- void *xsc;
-{
- struct dm_softc *sc = xsc;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- struct mii_data *mii;
- int s;
-
- s = splimp();
-
- /*
- * Cancel pending I/O and free all RX/TX buffers.
- */
- dm_stop(sc);
- dm_reset(sc);
-
- mii = device_get_softc(sc->dm_miibus);
-
- /*
- * Set cache alignment and burst length.
- */
- CSR_WRITE_4(sc, DM_BUSCTL, DM_BURSTLEN_32LONG);
- switch(sc->dm_cachesize) {
- case 32:
- DM_SETBIT(sc, DM_BUSCTL, DM_CACHEALIGN_32LONG);
- break;
- case 16:
- DM_SETBIT(sc, DM_BUSCTL, DM_CACHEALIGN_16LONG);
- break;
- case 8:
- DM_SETBIT(sc, DM_BUSCTL, DM_CACHEALIGN_8LONG);
- break;
- case 0:
- default:
- DM_SETBIT(sc, DM_BUSCTL, DM_CACHEALIGN_NONE);
- break;
- }
-
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_HEARTBEAT);
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_STORENFWD);
-
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_TX_THRESH);
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_SPEEDSEL);
-
- if (IFM_SUBTYPE(mii->mii_media.ifm_media) == IFM_10_T)
- DM_SETBIT(sc, DM_NETCFG, DM_TXTHRESH_160BYTES);
- else
- DM_SETBIT(sc, DM_NETCFG, DM_TXTHRESH_72BYTES);
-
- /* Init circular RX list. */
- if (dm_list_rx_init(sc) == ENOBUFS) {
- printf("dm%d: initialization failed: no "
- "memory for rx buffers\n", sc->dm_unit);
- dm_stop(sc);
- (void)splx(s);
- return;
- }
-
- /*
- * Init tx descriptors.
- */
- dm_list_tx_init(sc);
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC) {
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_RX_PROMISC);
- } else {
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_RX_PROMISC);
- }
-
- /*
- * Set the capture broadcast bit to capture broadcast frames.
- */
- if (ifp->if_flags & IFF_BROADCAST) {
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_RX_BROAD);
- } else {
- DM_CLRBIT(sc, DM_NETCFG, DM_NETCFG_RX_BROAD);
- }
-
- /*
- * Load the RX/multicast filter.
- */
- dm_setfilt(sc);
-
- /*
- * Load the address of the RX and TX lists.
- */
- CSR_WRITE_4(sc, DM_RXADDR, vtophys(&sc->dm_ldata->dm_rx_list[0]));
- /*CSR_WRITE_4(sc, DM_TXADDR, vtophys(&sc->dm_ldata->dm_tx_list[0]));*/
-
- /*
- * Enable interrupts.
- */
- CSR_WRITE_4(sc, DM_IMR, DM_INTRS);
- CSR_WRITE_4(sc, DM_ISR, 0xFFFFFFFF);
-
- /* Enable receiver and transmitter. */
- DM_SETBIT(sc, DM_NETCFG, DM_NETCFG_TX_ON|DM_NETCFG_RX_ON);
- CSR_WRITE_4(sc, DM_RXSTART, 0xFFFFFFFF);
-
- mii_mediachg(mii);
-
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
-
- (void)splx(s);
-
- sc->dm_stat_ch = timeout(dm_tick, sc, hz);
-
- return;
-}
-
-/*
- * Set media options.
- */
-static int dm_ifmedia_upd(ifp)
- struct ifnet *ifp;
-{
- struct dm_softc *sc;
-
- sc = ifp->if_softc;
-
- if (ifp->if_flags & IFF_UP)
- dm_init(sc);
-
- return(0);
-}
-
-/*
- * Report current media status.
- */
-static void dm_ifmedia_sts(ifp, ifmr)
- struct ifnet *ifp;
- struct ifmediareq *ifmr;
-{
- struct dm_softc *sc;
- struct mii_data *mii;
-
- sc = ifp->if_softc;
-
- mii = device_get_softc(sc->dm_miibus);
- mii_pollstat(mii);
- ifmr->ifm_active = mii->mii_media_active;
- ifmr->ifm_status = mii->mii_media_status;
-
- return;
-}
-
-static int dm_ioctl(ifp, command, data)
- struct ifnet *ifp;
- u_long command;
- caddr_t data;
-{
- struct dm_softc *sc = ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *) data;
- struct mii_data *mii;
- int s, error = 0;
-
- s = splimp();
-
- switch(command) {
- case SIOCSIFADDR:
- case SIOCGIFADDR:
- case SIOCSIFMTU:
- error = ether_ioctl(ifp, command, data);
- break;
- case SIOCSIFFLAGS:
- if (ifp->if_flags & IFF_UP) {
- dm_init(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- dm_stop(sc);
- }
- error = 0;
- break;
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- dm_init(sc);
- error = 0;
- break;
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- mii = device_get_softc(sc->dm_miibus);
- error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
- break;
- default:
- error = EINVAL;
- break;
- }
-
- (void)splx(s);
-
- return(error);
-}
-
-static void dm_watchdog(ifp)
- struct ifnet *ifp;
-{
- struct dm_softc *sc;
-
- sc = ifp->if_softc;
-
- ifp->if_oerrors++;
- printf("dm%d: watchdog timeout\n", sc->dm_unit);
-
- dm_stop(sc);
- dm_reset(sc);
- dm_init(sc);
-
- if (ifp->if_snd.ifq_head != NULL)
- dm_start(ifp);
-
- return;
-}
-
-/*
- * Stop the adapter and free any mbufs allocated to the
- * RX and TX lists.
- */
-static void dm_stop(sc)
- struct dm_softc *sc;
-{
- register int i;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_timer = 0;
-
- untimeout(dm_tick, sc, sc->dm_stat_ch);
-
- DM_CLRBIT(sc, DM_NETCFG, (DM_NETCFG_RX_ON|DM_NETCFG_TX_ON));
- CSR_WRITE_4(sc, DM_IMR, 0x00000000);
- CSR_WRITE_4(sc, DM_TXADDR, 0x00000000);
- CSR_WRITE_4(sc, DM_RXADDR, 0x00000000);
-
- /*
- * Free data in the RX lists.
- */
- for (i = 0; i < DM_RX_LIST_CNT; i++) {
- if (sc->dm_ldata->dm_rx_list[i].dm_mbuf != NULL) {
- m_freem(sc->dm_ldata->dm_rx_list[i].dm_mbuf);
- sc->dm_ldata->dm_rx_list[i].dm_mbuf = NULL;
- }
- }
- bzero((char *)&sc->dm_ldata->dm_rx_list,
- sizeof(sc->dm_ldata->dm_rx_list));
-
- /*
- * Free the TX list buffers.
- */
- for (i = 0; i < DM_TX_LIST_CNT; i++) {
- if (sc->dm_ldata->dm_tx_list[i].dm_mbuf != NULL) {
- m_freem(sc->dm_ldata->dm_tx_list[i].dm_mbuf);
- sc->dm_ldata->dm_tx_list[i].dm_mbuf = NULL;
- }
- }
-
- bzero((char *)&sc->dm_ldata->dm_tx_list,
- sizeof(sc->dm_ldata->dm_tx_list));
-
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-
- return;
-}
-
-/*
- * Stop all chip I/O so that the kernel's probe routines don't
- * get confused by errant DMAs when rebooting.
- */
-static void dm_shutdown(dev)
- device_t dev;
-{
- struct dm_softc *sc;
-
- sc = device_get_softc(dev);
-
- dm_reset(sc);
- dm_stop(sc);
-
- return;
-}
diff --git a/sys/pci/if_dmreg.h b/sys/pci/if_dmreg.h
deleted file mode 100644
index 2d79ebb..0000000
--- a/sys/pci/if_dmreg.h
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * Davicom register definitions.
- */
-
-#define DM_BUSCTL 0x00 /* bus control */
-#define DM_TXSTART 0x08 /* tx start demand */
-#define DM_RXSTART 0x10 /* rx start demand */
-#define DM_RXADDR 0x18 /* rx descriptor list start addr */
-#define DM_TXADDR 0x20 /* tx descriptor list start addr */
-#define DM_ISR 0x28 /* interrupt status register */
-#define DM_NETCFG 0x30 /* network config register */
-#define DM_IMR 0x38 /* interrupt mask */
-#define DM_FRAMESDISCARDED 0x40 /* # of discarded frames */
-#define DM_SIO 0x48 /* MII and ROM/EEPROM access */
-#define DM_RESERVED 0x50
-#define DM_GENTIMER 0x58 /* general timer */
-#define DM_GENPORT 0x60 /* general purpose port */
-
-/*
- * Bus control bits.
- */
-#define DM_BUSCTL_RESET 0x00000001
-#define DM_BUSCTL_ARBITRATION 0x00000002
-#define WB_BUSCTL_SKIPLEN 0x0000007C
-#define DM_BUSCTL_BIGENDIAN 0x00000080
-#define DM_BUSCTL_BURSTLEN 0x00003F00
-#define DM_BUSCTL_CACHEALIGN 0x0000C000
-#define DM_BUSCTL_BUF_BIGENDIAN 0x00100000
-#define DM_BUSCTL_READMULTI 0x00200000
-
-#define DM_SKIPLEN_1LONG 0x00000004
-#define DM_SKIPLEN_2LONG 0x00000008
-#define DM_SKIPLEN_3LONG 0x00000010
-#define DM_SKIPLEN_4LONG 0x00000020
-#define DM_SKIPLEN_5LONG 0x00000040
-
-#define DM_CACHEALIGN_NONE 0x00000000
-#define DM_CACHEALIGN_8LONG 0x00004000
-#define DM_CACHEALIGN_16LONG 0x00008000
-#define DM_CACHEALIGN_32LONG 0x0000C000
-
-#define DM_BURSTLEN_UNLIMIT 0x00000000
-#define DM_BURSTLEN_1LONG 0x00000100
-#define DM_BURSTLEN_2LONG 0x00000200
-#define DM_BURSTLEN_4LONG 0x00000400
-#define DM_BURSTLEN_8LONG 0x00000800
-#define DM_BURSTLEN_16LONG 0x00001000
-#define DM_BURSTLEN_32LONG 0x00002000
-
-/*
- * Interrupt status bits.
- */
-#define DM_ISR_TX_OK 0x00000001
-#define DM_ISR_TX_IDLE 0x00000002
-#define DM_ISR_TX_NOBUF 0x00000004
-#define DM_ISR_TX_JABBERTIMEO 0x00000008
-#define DM_ISR_TX_UNDERRUN 0x00000020
-#define DM_ISR_RX_OK 0x00000040
-#define DM_ISR_RX_NOBUF 0x00000080
-#define DM_ISR_RX_IDLE 0x00000100
-#define DM_ISR_RX_WATDOGTIMEO 0x00000200
-#define DM_ISR_TX_EARLY 0x00000400
-#define DM_ISR_TIMER_EXPIRED 0x00000800
-#define DM_ISR_BUS_ERR 0x00002000
-#define DM_ISR_ABNORMAL 0x00008000
-#define DM_ISR_NORMAL 0x00010000
-#define DM_ISR_RX_STATE 0x000E0000
-#define DM_ISR_TX_STATE 0x00700000
-#define DM_ISR_BUSERRTYPE 0x03800000
-
-#define DM_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
-#define DM_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
-#define DM_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
-#define DM_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
-#define DM_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
-#define DM_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */
-#define DM_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
-#define DM_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
-
-#define DM_TXSTATE_RESET 0x00000000 /* 000 - reset */
-#define DM_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
-#define DM_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
-#define DM_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
-#define DM_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
-#define DM_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
-#define DM_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
-#define DM_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
-
-/*
- * Network config bits.
- */
-#define DM_NETCFG_LINKSTAT_PCS 0x00000001
-#define DM_NETCFG_RX_ON 0x00000002
-#define DM_NETCFG_RX_BADFRAMES 0x00000008
-#define DM_NETCFG_RX_PROMISC 0x00000040
-#define DM_NETCFG_RX_ALLMULTI 0x00000080
-#define DM_NETCFG_RX_BROAD 0x00000100
-#define DM_NETCFG_FULLDUPLEX 0x00000200
-#define DM_NETCFG_LOOPBACK 0x00000C00
-#define DM_NETCFG_FORCECOLL 0x00001000
-#define DM_NETCFG_TX_ON 0x00002000
-#define DM_NETCFG_TX_THRESH 0x0000C000
-#define DM_NETCFG_PORTSEL 0x00040000 /* 0 == SRL, 1 == MII/SYM */
-#define DM_NETCFG_HEARTBEAT 0x00080000 /* 0 == ON, 1 == OFF */
-#define DM_NETCFG_STORENFWD 0x00200000
-#define DM_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */
-#define DM_NETCFG_PCS 0x00800000
-#define DM_NETCFG_SCRAMBLER 0x01000000
-#define DM_NETCFG_RX_ALL 0x40000000
-
-#define DM_OPMODE_NORM 0x00000000
-#define DM_OPMODE_INTLOOP 0x00000400
-#define DM_OPMODE_EXTLOOP 0x00000800
-
-#define DM_TXTHRESH_72BYTES 0x00000000
-#define DM_TXTHRESH_96BYTES 0x00004000
-#define DM_TXTHRESH_128BYTES 0x00008000
-#define DM_TXTHRESH_160BYTES 0x0000C000
-
-/*
- * Interrupt mask bits.
- */
-#define DM_IMR_TX_OK 0x00000001
-#define DM_IMR_TX_IDLE 0x00000002
-#define DM_IMR_TX_NOBUF 0x00000004
-#define DM_IMR_TX_JABBERTIMEO 0x00000008
-#define DM_IMR_TX_UNDERRUN 0x00000020
-#define DM_IMR_RX_OK 0x00000040
-#define DM_IMR_RX_NOBUF 0x00000080
-#define DM_IMR_RX_IDLE 0x00000100
-#define DM_IMR_RX_WATDOGTIMEO 0x00000200
-#define DM_IMR_TX_EARLY 0x00000400
-#define DM_IMR_TIMER_EXPIRED 0x00000800
-#define DM_IMR_BUS_ERR 0x00002000
-#define DM_IMR_RX_EARLY 0x00004000
-#define DM_IMR_ABNORMAL 0x00008000
-#define DM_IMR_NORMAL 0x00010000
-
-#define DM_INTRS \
- (DM_IMR_RX_OK|DM_IMR_TX_OK|DM_IMR_RX_NOBUF|DM_IMR_RX_WATDOGTIMEO|\
- DM_IMR_TX_NOBUF|DM_IMR_TX_UNDERRUN|DM_IMR_BUS_ERR| \
- DM_IMR_ABNORMAL|DM_IMR_NORMAL|/*DM_IMR_TX_EARLY*/ \
- DM_IMR_TX_IDLE|DM_IMR_RX_IDLE)
-
-/*
- * Serial I/O (EEPROM/ROM) bits.
- */
-#define DM_SIO_EE_CS 0x00000001 /* EEPROM chip select */
-#define DM_SIO_EE_CLK 0x00000002 /* EEPROM clock */
-#define DM_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */
-#define DM_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */
-#define DM_SIO_EESEL 0x00000800
-#define DM_SIO_ROMSEL 0x00001000
-#define DM_SIO_ROMCTL_WRITE 0x00002000
-#define DM_SIO_ROMCTL_READ 0x00004000
-#define DM_SIO_MII_CLK 0x00010000 /* MDIO clock */
-#define DM_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */
-#define DM_SIO_MII_DIR 0x00040000 /* MDIO dir */
-#define DM_SIO_MII_DATAIN 0x00080000 /* MDIO data in */
-
-#define DM_EECMD_WRITE 0x140
-#define DM_EECMD_READ 0x180
-#define DM_EECMD_ERASE 0x1c0
-
-#define DM_EE_NODEADDR_OFFSET 0x70
-#define DM_EE_NODEADDR 10
-
-/*
- * General purpose timer register
- */
-#define DM_TIMER_VALUE 0x0000FFFF
-#define DM_TIMER_CONTINUOUS 0x00010000
-
-/*
- * Size of a setup frame.
- */
-#define DM_SFRAME_LEN 192
-
-/*
- * Davicom TX/RX list structure.
- */
-
-struct dm_desc {
- u_int32_t dm_status;
- u_int32_t dm_ctl;
- u_int32_t dm_ptr1;
- u_int32_t dm_ptr2;
- struct mbuf *dm_mbuf;
- struct dm_desc *dm_nextdesc;
-};
-
-#define dm_data dm_ptr1
-#define dm_next dm_ptr2
-
-#define DM_RXSTAT_FIFOOFLOW 0x00000001
-#define DM_RXSTAT_CRCERR 0x00000002
-#define DM_RXSTAT_DRIBBLE 0x00000004
-#define DM_RXSTAT_WATCHDOG 0x00000010
-#define DM_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */
-#define DM_RXSTAT_COLLSEEN 0x00000040
-#define DM_RXSTAT_GIANT 0x00000080
-#define DM_RXSTAT_LASTFRAG 0x00000100
-#define DM_RXSTAT_FIRSTFRAG 0x00000200
-#define DM_RXSTAT_MULTICAST 0x00000400
-#define DM_RXSTAT_RUNT 0x00000800
-#define DM_RXSTAT_RXTYPE 0x00003000
-#define DM_RXSTAT_RXERR 0x00008000
-#define DM_RXSTAT_RXLEN 0x3FFF0000
-#define DM_RXSTAT_OWN 0x80000000
-
-#define DM_RXBYTES(x) ((x & DM_RXSTAT_RXLEN) >> 16)
-#define DM_RXSTAT (DM_RXSTAT_FIRSTFRAG|DM_RXSTAT_LASTFRAG|DM_RXSTAT_OWN)
-
-#define DM_RXCTL_BUFLEN1 0x00000FFF
-#define DM_RXCTL_BUFLEN2 0x00FFF000
-#define DM_RXCTL_RLINK 0x01000000
-#define DM_RXCTL_RLAST 0x02000000
-
-#define DM_TXSTAT_DEFER 0x00000001
-#define DM_TXSTAT_UNDERRUN 0x00000002
-#define DM_TXSTAT_LINKFAIL 0x00000003
-#define DM_TXSTAT_COLLCNT 0x00000078
-#define DM_TXSTAT_SQE 0x00000080
-#define DM_TXSTAT_EXCESSCOLL 0x00000100
-#define DM_TXSTAT_LATECOLL 0x00000200
-#define DM_TXSTAT_NOCARRIER 0x00000400
-#define DM_TXSTAT_CARRLOST 0x00000800
-#define DM_TXSTAT_JABTIMEO 0x00004000
-#define DM_TXSTAT_ERRSUM 0x00008000
-#define DM_TXSTAT_OWN 0x80000000
-
-#define DM_TXCTL_BUFLEN1 0x000007FF
-#define DM_TXCTL_BUFLEN2 0x003FF800
-#define DM_TXCTL_FILTTYPE0 0x00400000
-#define DM_TXCTL_PAD 0x00800000
-#define DM_TXCTL_TLINK 0x01000000
-#define DM_TXCTL_TLAST 0x02000000
-#define DM_TXCTL_NOCRC 0x04000000
-#define DM_TXCTL_SETUP 0x08000000
-#define DM_TXCTL_FILTTYPE1 0x10000000
-#define DM_TXCTL_FIRSTFRAG 0x20000000
-#define DM_TXCTL_LASTFRAG 0x40000000
-#define DM_TXCTL_FINT 0x80000000
-
-#define DM_FILTER_PERFECT 0x00000000
-#define DM_FILTER_HASHPERF 0x00400000
-#define DM_FILTER_INVERSE 0x10000000
-#define DM_FILTER_HASHONLY 0x10400000
-
-#define DM_MAXFRAGS 16
-#define DM_RX_LIST_CNT 64
-#define DM_TX_LIST_CNT 128
-#define DM_MIN_FRAMELEN 60
-#define DM_RXLEN 1536
-
-#define DM_INC(x, y) (x) = (x + 1) % y
-
-struct dm_list_data {
- struct dm_desc dm_rx_list[DM_RX_LIST_CNT];
- struct dm_desc dm_tx_list[DM_TX_LIST_CNT];
- struct dm_desc dm_sframe;
-};
-
-struct dm_chain_data {
- u_int32_t dm_sbuf[DM_SFRAME_LEN/sizeof(u_int32_t)];
- u_int8_t dm_pad[DM_MIN_FRAMELEN];
- int dm_tx_prod;
- int dm_tx_cons;
- int dm_tx_cnt;
- int dm_rx_prod;
-};
-
-struct dm_type {
- u_int16_t dm_vid;
- u_int16_t dm_did;
- char *dm_name;
-};
-
-struct dm_mii_frame {
- u_int8_t mii_stdelim;
- u_int8_t mii_opcode;
- u_int8_t mii_phyaddr;
- u_int8_t mii_regaddr;
- u_int8_t mii_turnaround;
- u_int16_t mii_data;
-};
-
-/*
- * MII constants
- */
-#define DM_MII_STARTDELIM 0x01
-#define DM_MII_READOP 0x02
-#define DM_MII_WRITEOP 0x01
-#define DM_MII_TURNAROUND 0x02
-
-struct dm_softc {
- struct arpcom arpcom; /* interface info */
- bus_space_handle_t dm_bhandle; /* bus space handle */
- bus_space_tag_t dm_btag; /* bus space tag */
- void *dm_intrhand;
- struct resource *dm_irq;
- struct resource *dm_res;
- device_t dm_miibus;
- u_int8_t dm_unit; /* interface number */
- int dm_cachesize;
- struct dm_list_data *dm_ldata;
- struct dm_chain_data dm_cdata;
- struct callout_handle dm_stat_ch;
-};
-
-/*
- * register space access macros
- */
-#define CSR_WRITE_4(sc, reg, val) \
- bus_space_write_4(sc->dm_btag, sc->dm_bhandle, reg, val)
-#define CSR_WRITE_2(sc, reg, val) \
- bus_space_write_2(sc->dm_btag, sc->dm_bbhandle, reg, val)
-#define CSR_WRITE_1(sc, reg, val) \
- bus_space_write_1(sc->dm_btag, sc->dm_bhandle, reg, val)
-
-#define CSR_READ_4(sc, reg) \
- bus_space_read_4(sc->dm_btag, sc->dm_bhandle, reg)
-#define CSR_READ_2(sc, reg) \
- bus_space_read_2(sc->dm_btag, sc->dm_bhandle, reg)
-#define CSR_READ_1(sc, reg) \
- bus_space_read_1(sc->dm_btag, sc->dm_bhandle, reg)
-
-#define DM_TIMEOUT 1000
-#define ETHER_ALIGN 2
-
-/*
- * General constants that are fun to know.
- *
- * Davicom PCI vendor ID
- */
-#define DM_VENDORID 0x1282
-
-/*
- * Davicom DM9102 device ID.
- */
-#define DM_DEVICEID_DM9102 0x9102
-#define DM_DEVICEID_DM9100 0x9100
-
-/*
- * PCI low memory base and low I/O base register, and
- * other PCI registers.
- */
-
-#define DM_PCI_VENDOR_ID 0x00
-#define DM_PCI_DEVICE_ID 0x02
-#define DM_PCI_COMMAND 0x04
-#define DM_PCI_STATUS 0x06
-#define DM_PCI_REVID 0x08
-#define DM_PCI_CLASSCODE 0x09
-#define DM_PCI_CACHELEN 0x0C
-#define DM_PCI_LATENCY_TIMER 0x0D
-#define DM_PCI_HEADER_TYPE 0x0E
-#define DM_PCI_LOIO 0x10
-#define DM_PCI_LOMEM 0x14
-#define DM_PCI_BIOSROM 0x30
-#define DM_PCI_INTLINE 0x3C
-#define DM_PCI_INTPIN 0x3D
-#define DM_PCI_MINGNT 0x3E
-#define DM_PCI_MINLAT 0x0F
-#define DM_PCI_RESETOPT 0x48
-#define DM_PCI_EEPROM_DATA 0x4C
-
-/* power management registers */
-#define DM_PCI_CAPID 0x50 /* 8 bits */
-#define DM_PCI_NEXTPTR 0x51 /* 8 bits */
-#define DM_PCI_PWRMGMTCAP 0x52 /* 16 bits */
-#define DM_PCI_PWRMGMTCTRL 0x54 /* 16 bits */
-
-#define DM_PSTATE_MASK 0x0003
-#define DM_PSTATE_D0 0x0000
-#define DM_PSTATE_D1 0x0001
-#define DM_PSTATE_D2 0x0002
-#define DM_PSTATE_D3 0x0003
-#define DM_PME_EN 0x0010
-#define DM_PME_STATUS 0x8000
-
-#ifdef __alpha__
-#undef vtophys
-#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
-#endif
diff --git a/sys/pci/if_mx.c b/sys/pci/if_mx.c
deleted file mode 100644
index b1fe66f..0000000
--- a/sys/pci/if_mx.c
+++ /dev/null
@@ -1,1992 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * Macronix PMAC fast ethernet PCI NIC driver
- *
- * Written by Bill Paul <wpaul@ee.columbia.edu>
- * Electrical Engineering Department
- * Columbia University, New York City
- */
-
-/*
- * The Macronix 98713, 98715 and 98725 chips are still more tulip clones.
- * The 98713 has an internal transceiver and an MII bus for external PHYs.
- * The other two chips have only the internal transceiver. All have
- * support for built-in autonegotiation. Additionally, there are 98713A
- * and 98715A chips which support power management. The 98725 chip
- * supports power management as well.
- *
- * Datasheets for the Macronix parts can be obtained from www.macronix.com.
- * Note however that the datasheets do not describe the TX and RX
- * descriptor structures or the setup frame format(s). For this, you should
- * obtain a DEC 21x4x datasheet from developer.intel.com. The Macronix
- * chips look to be fairly straightforward tulip clones, except for
- * the NWAY support.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sockio.h>
-#include <sys/mbuf.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ethernet.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
-
-#include <net/bpf.h>
-
-#include <vm/vm.h> /* for vtophys */
-#include <vm/pmap.h> /* for vtophys */
-#include <machine/clock.h> /* for DELAY */
-#include <machine/bus_pio.h>
-#include <machine/bus_memio.h>
-#include <machine/bus.h>
-#include <machine/resource.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
-
-#include <dev/mii/mii.h>
-#include <dev/mii/miivar.h>
-
-#include <pci/pcireg.h>
-#include <pci/pcivar.h>
-
-#define MX_USEIOSPACE
-
-#include <pci/if_mxreg.h>
-
-/* "controller miibus0" required. See GENERIC if you get errors here. */
-#include "miibus_if.h"
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-/*
- * Various supported device vendors/types and their names.
- */
-static struct mx_type mx_devs[] = {
- { MX_VENDORID, MX_DEVICEID_98713,
- "Macronix 98713 10/100BaseTX" },
- { MX_VENDORID, MX_DEVICEID_98713,
- "Macronix 98713A 10/100BaseTX" },
- { CP_VENDORID, CP_DEVICEID_98713,
- "Compex RL100-TX 10/100BaseTX" },
- { CP_VENDORID, CP_DEVICEID_98713,
- "Compex RL100-TX 10/100BaseTX" },
- { MX_VENDORID, MX_DEVICEID_987x5,
- "Macronix 98715/98715A 10/100BaseTX" },
- { MX_VENDORID, MX_DEVICEID_987x5,
- "Macronix 98725 10/100BaseTX" },
- { PN_VENDORID, PN_DEVICEID_PNIC_II,
- "LC82C115 PNIC II 10/100BaseTX" },
- { 0, 0, NULL }
-};
-
-static int mx_probe __P((device_t));
-static int mx_attach __P((device_t));
-static int mx_detach __P((device_t));
-static struct mx_type *mx_devtype __P((device_t));
-static int mx_newbuf __P((struct mx_softc *,
- struct mx_chain_onefrag *,
- struct mbuf *));
-static int mx_encap __P((struct mx_softc *, struct mx_chain *,
- struct mbuf *));
-
-static void mx_rxeof __P((struct mx_softc *));
-static void mx_rxeoc __P((struct mx_softc *));
-static void mx_txeof __P((struct mx_softc *));
-static void mx_txeoc __P((struct mx_softc *));
-static void mx_tick __P((void *));
-static void mx_intr __P((void *));
-static void mx_start __P((struct ifnet *));
-static int mx_ioctl __P((struct ifnet *, u_long, caddr_t));
-static void mx_init __P((void *));
-static void mx_stop __P((struct mx_softc *));
-static void mx_watchdog __P((struct ifnet *));
-static void mx_shutdown __P((device_t));
-static int mx_ifmedia_upd __P((struct ifnet *));
-static void mx_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
-
-static void mx_delay __P((struct mx_softc *));
-static void mx_eeprom_idle __P((struct mx_softc *));
-static void mx_eeprom_putbyte __P((struct mx_softc *, int));
-static void mx_eeprom_getword __P((struct mx_softc *, int, u_int16_t *));
-static void mx_read_eeprom __P((struct mx_softc *, caddr_t, int,
- int, int));
-
-static void mx_mii_writebit __P((struct mx_softc *, int));
-static int mx_mii_readbit __P((struct mx_softc *));
-static void mx_mii_sync __P((struct mx_softc *));
-static void mx_mii_send __P((struct mx_softc *, u_int32_t, int));
-static int mx_mii_readreg __P((struct mx_softc *, struct mx_mii_frame *));
-static int mx_mii_writereg __P((struct mx_softc *, struct mx_mii_frame *));
-
-static int mx_miibus_readreg __P((device_t, int, int));
-static int mx_miibus_writereg __P((device_t, int, int, int));
-static void mx_miibus_statchg __P((device_t));
-
-static void mx_setcfg __P((struct mx_softc *, int));
-static u_int32_t mx_calchash __P((struct mx_softc *, caddr_t));
-static void mx_setfilt __P((struct mx_softc *));
-static void mx_reset __P((struct mx_softc *));
-static int mx_list_rx_init __P((struct mx_softc *));
-static int mx_list_tx_init __P((struct mx_softc *));
-
-#ifdef MX_USEIOSPACE
-#define MX_RES SYS_RES_IOPORT
-#define MX_RID MX_PCI_LOIO
-#else
-#define MX_RES SYS_RES_MEMORY
-#define MX_RID MX_PCI_LOMEM
-#endif
-
-static device_method_t mx_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, mx_probe),
- DEVMETHOD(device_attach, mx_attach),
- DEVMETHOD(device_detach, mx_detach),
- DEVMETHOD(device_shutdown, mx_shutdown),
-
- /* bus interface */
- DEVMETHOD(bus_print_child, bus_generic_print_child),
- DEVMETHOD(bus_driver_added, bus_generic_driver_added),
-
- /* MII interface */
- DEVMETHOD(miibus_readreg, mx_miibus_readreg),
- DEVMETHOD(miibus_writereg, mx_miibus_writereg),
- DEVMETHOD(miibus_statchg, mx_miibus_statchg),
-
- { 0, 0 }
-};
-
-static driver_t mx_driver = {
- "mx",
- mx_methods,
- sizeof(struct mx_softc)
-};
-
-static devclass_t mx_devclass;
-
-DRIVER_MODULE(if_mx, pci, mx_driver, mx_devclass, 0, 0);
-DRIVER_MODULE(miibus, mx, miibus_driver, miibus_devclass, 0, 0);
-
-#define MX_SETBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) | x)
-
-#define MX_CLRBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) & ~x)
-
-#define SIO_SET(x) \
- CSR_WRITE_4(sc, MX_SIO, \
- CSR_READ_4(sc, MX_SIO) | x)
-
-#define SIO_CLR(x) \
- CSR_WRITE_4(sc, MX_SIO, \
- CSR_READ_4(sc, MX_SIO) & ~x)
-
-static void mx_delay(sc)
- struct mx_softc *sc;
-{
- int idx;
-
- for (idx = (300 / 33) + 1; idx > 0; idx--)
- CSR_READ_4(sc, MX_BUSCTL);
-}
-
-static void mx_eeprom_idle(sc)
- struct mx_softc *sc;
-{
- register int i;
-
- CSR_WRITE_4(sc, MX_SIO, MX_SIO_EESEL);
- mx_delay(sc);
- MX_SETBIT(sc, MX_SIO, MX_SIO_ROMCTL_READ);
- mx_delay(sc);
- MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CS);
- mx_delay(sc);
- MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CLK);
- mx_delay(sc);
-
- for (i = 0; i < 25; i++) {
- MX_CLRBIT(sc, MX_SIO, MX_SIO_EE_CLK);
- mx_delay(sc);
- MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CLK);
- mx_delay(sc);
- }
-
- MX_CLRBIT(sc, MX_SIO, MX_SIO_EE_CLK);
- mx_delay(sc);
- MX_CLRBIT(sc, MX_SIO, MX_SIO_EE_CS);
- mx_delay(sc);
- CSR_WRITE_4(sc, MX_SIO, 0x00000000);
-
- return;
-}
-
-/*
- * Send a read command and address to the EEPROM, check for ACK.
- */
-static void mx_eeprom_putbyte(sc, addr)
- struct mx_softc *sc;
- int addr;
-{
- register int d, i;
-
- d = addr | MX_EECMD_READ;
-
- /*
- * Feed in each bit and stobe the clock.
- */
- for (i = 0x400; i; i >>= 1) {
- if (d & i) {
- SIO_SET(MX_SIO_EE_DATAIN);
- } else {
- SIO_CLR(MX_SIO_EE_DATAIN);
- }
- mx_delay(sc);
- SIO_SET(MX_SIO_EE_CLK);
- mx_delay(sc);
- SIO_CLR(MX_SIO_EE_CLK);
- mx_delay(sc);
- }
-
- return;
-}
-
-/*
- * Read a word of data stored in the EEPROM at address 'addr.'
- */
-static void mx_eeprom_getword(sc, addr, dest)
- struct mx_softc *sc;
- int addr;
- u_int16_t *dest;
-{
- register int i;
- u_int16_t word = 0;
-
- /* Force EEPROM to idle state. */
- mx_eeprom_idle(sc);
-
- /* Enter EEPROM access mode. */
- CSR_WRITE_4(sc, MX_SIO, MX_SIO_EESEL);
- mx_delay(sc);
- MX_SETBIT(sc, MX_SIO, MX_SIO_ROMCTL_READ);
- mx_delay(sc);
- MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CS);
- mx_delay(sc);
- MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CLK);
- mx_delay(sc);
-
- /*
- * Send address of word we want to read.
- */
- mx_eeprom_putbyte(sc, addr);
-
- /*
- * Start reading bits from EEPROM.
- */
- for (i = 0x8000; i; i >>= 1) {
- SIO_SET(MX_SIO_EE_CLK);
- mx_delay(sc);
- if (CSR_READ_4(sc, MX_SIO) & MX_SIO_EE_DATAOUT)
- word |= i;
- mx_delay(sc);
- SIO_CLR(MX_SIO_EE_CLK);
- mx_delay(sc);
- }
-
- /* Turn off EEPROM access mode. */
- mx_eeprom_idle(sc);
-
- *dest = word;
-
- return;
-}
-
-/*
- * Read a sequence of words from the EEPROM.
- */
-static void mx_read_eeprom(sc, dest, off, cnt, swap)
- struct mx_softc *sc;
- caddr_t dest;
- int off;
- int cnt;
- int swap;
-{
- int i;
- u_int16_t word = 0, *ptr;
-
- for (i = 0; i < cnt; i++) {
- mx_eeprom_getword(sc, off + i, &word);
- ptr = (u_int16_t *)(dest + (i * 2));
- if (swap)
- *ptr = ntohs(word);
- else
- *ptr = word;
- }
-
- return;
-}
-
-/*
- * The following two routines are taken from the Macronix 98713
- * Application Notes pp.19-21.
- */
-/*
- * Write a bit to the MII bus.
- */
-static void mx_mii_writebit(sc, bit)
- struct mx_softc *sc;
- int bit;
-{
- if (bit)
- CSR_WRITE_4(sc, MX_SIO, MX_SIO_ROMCTL_WRITE|MX_SIO_MII_DATAOUT);
- else
- CSR_WRITE_4(sc, MX_SIO, MX_SIO_ROMCTL_WRITE);
-
- MX_SETBIT(sc, MX_SIO, MX_SIO_MII_CLK);
- MX_CLRBIT(sc, MX_SIO, MX_SIO_MII_CLK);
-
- return;
-}
-
-/*
- * Read a bit from the MII bus.
- */
-static int mx_mii_readbit(sc)
- struct mx_softc *sc;
-{
- CSR_WRITE_4(sc, MX_SIO, MX_SIO_ROMCTL_READ|MX_SIO_MII_DIR);
- CSR_READ_4(sc, MX_SIO);
- MX_SETBIT(sc, MX_SIO, MX_SIO_MII_CLK);
- MX_CLRBIT(sc, MX_SIO, MX_SIO_MII_CLK);
- if (CSR_READ_4(sc, MX_SIO) & MX_SIO_MII_DATAIN)
- return(1);
-
- return(0);
-}
-
-/*
- * Sync the PHYs by setting data bit and strobing the clock 32 times.
- */
-static void mx_mii_sync(sc)
- struct mx_softc *sc;
-{
- register int i;
-
- CSR_WRITE_4(sc, MX_SIO, MX_SIO_ROMCTL_WRITE);
-
- for (i = 0; i < 32; i++)
- mx_mii_writebit(sc, 1);
-
- return;
-}
-
-/*
- * Clock a series of bits through the MII.
- */
-static void mx_mii_send(sc, bits, cnt)
- struct mx_softc *sc;
- u_int32_t bits;
- int cnt;
-{
- int i;
-
- for (i = (0x1 << (cnt - 1)); i; i >>= 1)
- mx_mii_writebit(sc, bits & i);
-}
-
-/*
- * Read an PHY register through the MII.
- */
-static int mx_mii_readreg(sc, frame)
- struct mx_softc *sc;
- struct mx_mii_frame *frame;
-
-{
- int i, ack, s;
-
- s = splimp();
-
- /*
- * Set up frame for RX.
- */
- frame->mii_stdelim = MX_MII_STARTDELIM;
- frame->mii_opcode = MX_MII_READOP;
- frame->mii_turnaround = 0;
- frame->mii_data = 0;
-
- /*
- * Sync the PHYs.
- */
- mx_mii_sync(sc);
-
- /*
- * Send command/address info.
- */
- mx_mii_send(sc, frame->mii_stdelim, 2);
- mx_mii_send(sc, frame->mii_opcode, 2);
- mx_mii_send(sc, frame->mii_phyaddr, 5);
- mx_mii_send(sc, frame->mii_regaddr, 5);
-
-#ifdef notdef
- /* Idle bit */
- mx_mii_writebit(sc, 1);
- mx_mii_writebit(sc, 0);
-#endif
-
- /* Check for ack */
- ack = mx_mii_readbit(sc);
-
- /*
- * Now try reading data bits. If the ack failed, we still
- * need to clock through 16 cycles to keep the PHY(s) in sync.
- */
- if (ack) {
- for(i = 0; i < 16; i++) {
- mx_mii_readbit(sc);
- }
- goto fail;
- }
-
- for (i = 0x8000; i; i >>= 1) {
- if (!ack) {
- if (mx_mii_readbit(sc))
- frame->mii_data |= i;
- }
- }
-
-fail:
-
- mx_mii_writebit(sc, 0);
- mx_mii_writebit(sc, 0);
-
- splx(s);
-
- if (ack)
- return(1);
- return(0);
-}
-
-/*
- * Write to a PHY register through the MII.
- */
-static int mx_mii_writereg(sc, frame)
- struct mx_softc *sc;
- struct mx_mii_frame *frame;
-
-{
- int s;
-
- s = splimp();
- /*
- * Set up frame for TX.
- */
-
- frame->mii_stdelim = MX_MII_STARTDELIM;
- frame->mii_opcode = MX_MII_WRITEOP;
- frame->mii_turnaround = MX_MII_TURNAROUND;
-
- /*
- * Sync the PHYs.
- */
- mx_mii_sync(sc);
-
- mx_mii_send(sc, frame->mii_stdelim, 2);
- mx_mii_send(sc, frame->mii_opcode, 2);
- mx_mii_send(sc, frame->mii_phyaddr, 5);
- mx_mii_send(sc, frame->mii_regaddr, 5);
- mx_mii_send(sc, frame->mii_turnaround, 2);
- mx_mii_send(sc, frame->mii_data, 16);
-
- /* Idle bit. */
- mx_mii_writebit(sc, 0);
- mx_mii_writebit(sc, 0);
-
- splx(s);
-
- return(0);
-}
-
-static int mx_miibus_readreg(dev, phy, reg)
- device_t dev;
- int phy, reg;
-{
- struct mx_softc *sc;
- struct mx_mii_frame frame;
-
- sc = device_get_softc(dev);
- bzero((char *)&frame, sizeof(frame));
-
- if (sc->mx_type != MX_TYPE_98713) {
- if (phy == (MII_NPHY - 1)) {
- switch(reg) {
- case MII_BMSR:
- /*
- * Fake something to make the probe
- * code think there's a PHY here.
- */
- return(BMSR_MEDIAMASK);
- break;
- case MII_PHYIDR1:
- return(MX_VENDORID);
- break;
- case MII_PHYIDR2:
- return(MX_DEVICEID_987x5);
- break;
- default:
- return(0);
- break;
- }
- }
- }
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
- mx_mii_readreg(sc, &frame);
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
-
- return(frame.mii_data);
-}
-
-static int mx_miibus_writereg(dev, phy, reg, data)
- device_t dev;
- int phy, reg, data;
-{
- struct mx_mii_frame frame;
- struct mx_softc *sc;
-
- sc = device_get_softc(dev);
- bzero((char *)&frame, sizeof(frame));
-
- frame.mii_phyaddr = phy;
- frame.mii_regaddr = reg;
- frame.mii_data = data;
-
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
- mx_mii_writereg(sc, &frame);
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
-
- return(0);
-}
-
-static void mx_miibus_statchg(dev)
- device_t dev;
-{
- struct mx_softc *sc;
- struct mii_data *mii;
-
- sc = device_get_softc(dev);
- mii = device_get_softc(sc->mx_miibus);
- mx_setcfg(sc, mii->mii_media_active);
-
- return;
-}
-
-#define MX_POLY 0xEDB88320
-#define MX_BITS 9
-#define MX_BITS_PNIC_II 7
-
-static u_int32_t mx_calchash(sc, addr)
- struct mx_softc *sc;
- caddr_t addr;
-{
- u_int32_t idx, bit, data, crc;
-
- /* Compute CRC for the address value. */
- crc = 0xFFFFFFFF; /* initial value */
-
- for (idx = 0; idx < 6; idx++) {
- for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
- crc = (crc >> 1) ^ (((crc ^ data) & 1) ? MX_POLY : 0);
- }
-
- /* The hash table on the PNIC II is only 128 bits wide. */
- if (sc->mx_info->mx_vid == PN_VENDORID)
- return (crc & ((1 << MX_BITS_PNIC_II) - 1));
-
- return (crc & ((1 << MX_BITS) - 1));
-}
-
-/*
- * Programming the receiver filter on the tulip/PMAC is gross. You
- * have to construct a special setup frame and download it to the
- * chip via the transmit DMA engine. This routine is also somewhat
- * gross, as the setup frame is sent synchronously rather than putting
- * on the transmit queue. The transmitter has to be stopped, then we
- * can download the frame and wait for the 'owned' bit to clear.
- *
- * We always program the chip using 'hash perfect' mode, i.e. one perfect
- * address (our node address) and a 512-bit hash filter for multicast
- * frames. We also sneak the broadcast address into the hash filter since
- * we need that too.
- */
-void mx_setfilt(sc)
- struct mx_softc *sc;
-{
- struct mx_desc *sframe;
- u_int32_t h, *sp;
- struct ifmultiaddr *ifma;
- struct ifnet *ifp;
- int i;
-
- ifp = &sc->arpcom.ac_if;
-
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON);
- MX_SETBIT(sc, MX_ISR, MX_ISR_TX_IDLE);
-
- sframe = &sc->mx_cdata.mx_sframe;
- sp = (u_int32_t *)&sc->mx_cdata.mx_sbuf;
- bzero((char *)sp, MX_SFRAME_LEN);
-
- sframe->mx_next = vtophys(&sc->mx_ldata->mx_tx_list[0]);
- sframe->mx_data = vtophys(&sc->mx_cdata.mx_sbuf);
- sframe->mx_ctl = MX_SFRAME_LEN | MX_TXCTL_TLINK |
- MX_TXCTL_SETUP | MX_FILTER_HASHPERF;
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC)
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_PROMISC);
- else
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_RX_PROMISC);
-
- if (ifp->if_flags & IFF_ALLMULTI)
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_ALLMULTI);
-
- for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
- ifma = ifma->ifma_link.le_next) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- h = mx_calchash(sc,
- LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
- sp[h >> 4] |= 1 << (h & 0xF);
- }
-
- if (ifp->if_flags & IFF_BROADCAST) {
- h = mx_calchash(sc, (caddr_t)&etherbroadcastaddr);
- sp[h >> 4] |= 1 << (h & 0xF);
- }
-
- sp[39] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0];
- sp[40] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1];
- sp[41] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2];
-
- CSR_WRITE_4(sc, MX_TXADDR, vtophys(sframe));
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON);
- sframe->mx_status = MX_TXSTAT_OWN;
- CSR_WRITE_4(sc, MX_TXSTART, 0xFFFFFFFF);
-
- /*
- * Wait for chip to clear the 'own' bit.
- */
- for (i = 0; i < MX_TIMEOUT; i++) {
- DELAY(10);
- if (sframe->mx_status != MX_TXSTAT_OWN)
- break;
- }
-
- if (i == MX_TIMEOUT)
- printf("mx%d: failed to send setup frame\n", sc->mx_unit);
-
- MX_SETBIT(sc, MX_ISR, MX_ISR_TX_NOBUF|MX_ISR_TX_IDLE);
-
- return;
-}
-
-/*
- * In order to fiddle with the
- * 'full-duplex' and '100Mbps' bits in the netconfig register, we
- * first have to put the transmit and/or receive logic in the idle state.
- */
-static void mx_setcfg(sc, media)
- struct mx_softc *sc;
- int media;
-{
- int i, restart = 0;
-
- if (CSR_READ_4(sc, MX_NETCFG) & (MX_NETCFG_TX_ON|MX_NETCFG_RX_ON)) {
- restart = 1;
- MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_TX_ON|MX_NETCFG_RX_ON));
-
- for (i = 0; i < MX_TIMEOUT; i++) {
- DELAY(10);
- if (CSR_READ_4(sc, MX_ISR) & MX_ISR_TX_IDLE)
- break;
- }
-
- if (i == MX_TIMEOUT)
- printf("mx%d: failed to force tx and "
- "rx to idle state\n", sc->mx_unit);
-
- }
-
- if (IFM_SUBTYPE(media) == IFM_100_TX) {
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL);
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_HEARTBEAT);
- if (sc->mx_type == MX_TYPE_98713) {
- MX_SETBIT(sc, MX_WATCHDOG, MX_WDOG_JABBERDIS);
- MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
- MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
- MX_SETBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
- MX_NETCFG_SCRAMBLER));
- } else {
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL|
- MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER);
- }
- }
-
- if (IFM_SUBTYPE(media) == IFM_10_T) {
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL);
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_HEARTBEAT);
- if (sc->mx_type == MX_TYPE_98713) {
- MX_SETBIT(sc, MX_WATCHDOG, MX_WDOG_JABBERDIS);
- MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
- MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PCS);
- } else {
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL);
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PCS);
- }
- }
-
- if ((media & IFM_GMASK) == IFM_FDX) {
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX);
- } else {
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX);
- }
-
- if (restart)
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON|MX_NETCFG_RX_ON);
-
- return;
-}
-
-static void mx_reset(sc)
- struct mx_softc *sc;
-{
- register int i;
-
- MX_SETBIT(sc, MX_BUSCTL, MX_BUSCTL_RESET);
-
- for (i = 0; i < MX_TIMEOUT; i++) {
- DELAY(10);
- if (!(CSR_READ_4(sc, MX_BUSCTL) & MX_BUSCTL_RESET))
- break;
- }
- if (i == MX_TIMEOUT)
- printf("mx%d: reset never completed!\n", sc->mx_unit);
-
- /* Wait a little while for the chip to get its brains in order. */
- DELAY(1000);
- return;
-}
-
-static struct mx_type *mx_devtype(dev)
- device_t dev;
-{
- struct mx_type *t;
- u_int32_t rev;
-
- t = mx_devs;
-
- while(t->mx_name != NULL) {
- if ((pci_get_vendor(dev) == t->mx_vid) &&
- (pci_get_device(dev) == t->mx_did)) {
- /* Check the PCI revision */
- rev = pci_read_config(dev, MX_PCI_REVID, 4) & 0xFF;
- if (t->mx_did == MX_DEVICEID_98713 &&
- rev >= MX_REVISION_98713A)
- t++;
- if (t->mx_did == CP_DEVICEID_98713 &&
- rev >= MX_REVISION_98713A)
- t++;
- if (t->mx_did == MX_DEVICEID_987x5 &&
- rev >= MX_REVISION_98725)
- t++;
- return(t);
- }
- t++;
- }
-
- return(NULL);
-}
-
-/*
- * Probe for a Macronix PMAC chip. Check the PCI vendor and device
- * IDs against our list and return a device name if we find a match.
- * We do a little bit of extra work to identify the exact type of
- * chip. The MX98713 and MX98713A have the same PCI vendor/device ID,
- * but different revision IDs. The same is true for 98715/98715A
- * chips and the 98725. This doesn't affect a whole lot, but it
- * lets us tell the user exactly what type of device they have
- * in the probe output.
- */
-int mx_probe(dev)
- device_t dev;
-{
- struct mx_type *t;
-
- t = mx_devtype(dev);
-
- if (t != NULL) {
- device_set_desc(dev, t->mx_name);
- return(0);
- }
-
- return(ENXIO);
-}
-
-/*
- * Attach the interface. Allocate softc structures, do ifmedia
- * setup and ethernet/BPF attach.
- */
-int mx_attach(dev)
- device_t dev;
-{
- int s, i;
- u_char eaddr[ETHER_ADDR_LEN];
- u_int32_t command;
- struct mx_softc *sc;
- struct ifnet *ifp;
- unsigned int round;
- caddr_t roundptr;
- u_int16_t mac_offset = 0;
- u_int32_t revision, pci_id;
- int unit, error = 0, rid;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- unit = device_get_unit(dev);
- bzero(sc, sizeof(struct mx_softc));
-
- /*
- * Handle power management nonsense.
- */
-
- command = pci_read_config(dev, MX_PCI_CAPID, 4) & 0x000000FF;
- if (command == 0x01) {
-
- command = pci_read_config(dev, MX_PCI_PWRMGMTCTRL, 4);
- if (command & MX_PSTATE_MASK) {
- u_int32_t iobase, membase, irq;
-
- /* Save important PCI config data. */
- iobase = pci_read_config(dev, MX_PCI_LOIO, 4);
- membase = pci_read_config(dev, MX_PCI_LOMEM, 4);
- irq = pci_read_config(dev, MX_PCI_INTLINE, 4);
-
- /* Reset the power state. */
- printf("mx%d: chip is in D%d power mode "
- "-- setting to D0\n", unit, command & MX_PSTATE_MASK);
- command &= 0xFFFFFFFC;
- pci_write_config(dev, MX_PCI_PWRMGMTCTRL, command, 4);
-
- /* Restore PCI config data. */
- pci_write_config(dev, MX_PCI_LOIO, iobase, 4);
- pci_write_config(dev, MX_PCI_LOMEM, membase, 4);
- pci_write_config(dev, MX_PCI_INTLINE, irq, 4);
- }
- }
-
- /*
- * Map control/status registers.
- */
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
- command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
- pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
-
-#ifdef MX_USEIOSPACE
- if (!(command & PCIM_CMD_PORTEN)) {
- printf("mx%d: failed to enable I/O ports!\n", unit);
- error = ENXIO;
- goto fail;
- }
-#else
- if (!(command & PCIM_CMD_MEMEN)) {
- printf("mx%d: failed to enable memory mapping!\n", unit);
- error = ENXIO;
- goto fail;
- }
-#endif
-
- rid = MX_RID;
- sc->mx_res = bus_alloc_resource(dev, MX_RES, &rid,
- 0, ~0, 1, RF_ACTIVE);
-
- if (sc->mx_res == NULL) {
- printf("mx%d: couldn't map ports/memory\n", unit);
- error = ENXIO;
- goto fail;
- }
-
- sc->mx_btag = rman_get_bustag(sc->mx_res);
- sc->mx_bhandle = rman_get_bushandle(sc->mx_res);
-
- /* Allocate interrupt */
- rid = 0;
- sc->mx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
- RF_SHAREABLE | RF_ACTIVE);
-
- if (sc->mx_irq == NULL) {
- printf("mx%d: couldn't map interrupt\n", unit);
- bus_release_resource(dev, MX_RES, MX_RID, sc->mx_res);
- error = ENXIO;
- goto fail;
- }
-
- error = bus_setup_intr(dev, sc->mx_irq, INTR_TYPE_NET,
- mx_intr, sc, &sc->mx_intrhand);
-
- if (error) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->mx_irq);
- bus_release_resource(dev, MX_RES, MX_RID, sc->mx_res);
- printf("mx%d: couldn't set up irq\n", unit);
- goto fail;
- }
-
- /* Need this info to decide on a chip type. */
- revision = pci_read_config(dev, MX_PCI_REVID, 4) & 0x000000FF;
- pci_id = (pci_read_config(dev,MX_PCI_VENDOR_ID, 4) >> 16) & 0x0000FFFF;
-
- if (pci_id == MX_DEVICEID_98713 && revision < MX_REVISION_98713A)
- sc->mx_type = MX_TYPE_98713;
- else if (pci_id == CP_DEVICEID_98713 && revision < MX_REVISION_98713A)
- sc->mx_type = MX_TYPE_98713;
- else if (pci_id == MX_DEVICEID_98713 && revision >= MX_REVISION_98713A)
- sc->mx_type = MX_TYPE_98713A;
- else
- sc->mx_type = MX_TYPE_987x5;
-
- /* Save the cache line size. */
- sc->mx_cachesize = pci_read_config(dev, MX_PCI_CACHELEN, 4) & 0xFF;
-
- /* Save the device info; the PNIC II requires special handling. */
- pci_id = pci_read_config(dev,MX_PCI_VENDOR_ID, 4);
- sc->mx_info = mx_devtype(dev);
-
- /* Reset the adapter. */
- mx_reset(sc);
-
- /*
- * Get station address from the EEPROM.
- */
- mx_read_eeprom(sc, (caddr_t)&mac_offset,
- (MX_EE_NODEADDR_OFFSET / 2), 1, 0);
- mx_read_eeprom(sc, (caddr_t)&eaddr, (mac_offset / 2), 3, 0);
-
- /*
- * A PMAC chip was detected. Inform the world.
- */
- printf("mx%d: Ethernet address: %6D\n", unit, eaddr, ":");
-
- sc->mx_unit = unit;
- bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
-
- sc->mx_ldata_ptr = malloc(sizeof(struct mx_list_data) + 8,
- M_DEVBUF, M_NOWAIT);
- if (sc->mx_ldata_ptr == NULL) {
- printf("mx%d: no memory for list buffers!\n", unit);
- bus_teardown_intr(dev, sc->mx_irq, sc->mx_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->mx_irq);
- bus_release_resource(dev, MX_RES, MX_RID, sc->mx_res);
- error = ENXIO;
- goto fail;
- }
-
- sc->mx_ldata = (struct mx_list_data *)sc->mx_ldata_ptr;
- round = (uintptr_t)sc->mx_ldata_ptr & 0xF;
- roundptr = sc->mx_ldata_ptr;
- for (i = 0; i < 8; i++) {
- if (round % 8) {
- round++;
- roundptr++;
- }
- break;
- }
- sc->mx_ldata = (struct mx_list_data *)roundptr;
- bzero(sc->mx_ldata, sizeof(struct mx_list_data));
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_softc = sc;
- ifp->if_unit = unit;
- ifp->if_name = "mx";
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = mx_ioctl;
- ifp->if_output = ether_output;
- ifp->if_start = mx_start;
- ifp->if_watchdog = mx_watchdog;
- ifp->if_init = mx_init;
- ifp->if_baudrate = 10000000;
- ifp->if_snd.ifq_maxlen = MX_TX_LIST_CNT - 1;
-
- /*
- * Do ifmedia setup.
- */
-
- if (mii_phy_probe(dev, &sc->mx_miibus,
- mx_ifmedia_upd, mx_ifmedia_sts)) {
- printf("mx%d: MII without any PHY!\n", sc->mx_unit);
- bus_teardown_intr(dev, sc->mx_irq, sc->mx_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->mx_irq);
- bus_release_resource(dev, MX_RES, MX_RID, sc->mx_res);
- error = ENXIO;
- goto fail;
- }
-
- /*
- * Call MI attach routines.
- */
- if_attach(ifp);
- ether_ifattach(ifp);
- callout_handle_init(&sc->mx_stat_ch);
-
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-
-fail:
- splx(s);
-
- return(error);
-}
-
-static int mx_detach(dev)
- device_t dev;
-{
- struct mx_softc *sc;
- struct ifnet *ifp;
- int s;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- ifp = &sc->arpcom.ac_if;
-
- mx_stop(sc);
- if_detach(ifp);
-
- bus_generic_detach(dev);
- device_delete_child(dev, sc->mx_miibus);
-
- bus_teardown_intr(dev, sc->mx_irq, sc->mx_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->mx_irq);
- bus_release_resource(dev, MX_RES, MX_RID, sc->mx_res);
-
- free(sc->mx_ldata_ptr, M_DEVBUF);
-
- splx(s);
-
- return(0);
-}
-
-/*
- * Initialize the transmit descriptors.
- */
-static int mx_list_tx_init(sc)
- struct mx_softc *sc;
-{
- struct mx_chain_data *cd;
- struct mx_list_data *ld;
- int i;
-
- cd = &sc->mx_cdata;
- ld = sc->mx_ldata;
- for (i = 0; i < MX_TX_LIST_CNT; i++) {
- cd->mx_tx_chain[i].mx_ptr = &ld->mx_tx_list[i];
- if (i == (MX_TX_LIST_CNT - 1))
- cd->mx_tx_chain[i].mx_nextdesc =
- &cd->mx_tx_chain[0];
- else
- cd->mx_tx_chain[i].mx_nextdesc =
- &cd->mx_tx_chain[i + 1];
- }
-
- cd->mx_tx_free = &cd->mx_tx_chain[0];
- cd->mx_tx_tail = cd->mx_tx_head = NULL;
-
- return(0);
-}
-
-
-/*
- * Initialize the RX descriptors and allocate mbufs for them. Note that
- * we arrange the descriptors in a closed ring, so that the last descriptor
- * points back to the first.
- */
-static int mx_list_rx_init(sc)
- struct mx_softc *sc;
-{
- struct mx_chain_data *cd;
- struct mx_list_data *ld;
- int i;
-
- cd = &sc->mx_cdata;
- ld = sc->mx_ldata;
-
- for (i = 0; i < MX_RX_LIST_CNT; i++) {
- cd->mx_rx_chain[i].mx_ptr =
- (struct mx_desc *)&ld->mx_rx_list[i];
- if (mx_newbuf(sc, &cd->mx_rx_chain[i], NULL) == ENOBUFS)
- return(ENOBUFS);
- if (i == (MX_RX_LIST_CNT - 1)) {
- cd->mx_rx_chain[i].mx_nextdesc =
- &cd->mx_rx_chain[0];
- ld->mx_rx_list[i].mx_next =
- vtophys(&ld->mx_rx_list[0]);
- } else {
- cd->mx_rx_chain[i].mx_nextdesc =
- &cd->mx_rx_chain[i + 1];
- ld->mx_rx_list[i].mx_next =
- vtophys(&ld->mx_rx_list[i + 1]);
- }
- }
-
- cd->mx_rx_head = &cd->mx_rx_chain[0];
-
- return(0);
-}
-
-/*
- * Initialize an RX descriptor and attach an MBUF cluster.
- * Note: the length fields are only 11 bits wide, which means the
- * largest size we can specify is 2047. This is important because
- * MCLBYTES is 2048, so we have to subtract one otherwise we'll
- * overflow the field and make a mess.
- */
-static int mx_newbuf(sc, c, m)
- struct mx_softc *sc;
- struct mx_chain_onefrag *c;
- struct mbuf *m;
-{
- struct mbuf *m_new = NULL;
-
- if (m == NULL) {
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("mx%d: no memory for rx list "
- "-- packet dropped!\n", sc->mx_unit);
- return(ENOBUFS);
- }
-
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- printf("mx%d: no memory for rx list "
- "-- packet dropped!\n", sc->mx_unit);
- m_freem(m_new);
- return(ENOBUFS);
- }
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- } else {
- m_new = m;
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- m_new->m_data = m_new->m_ext.ext_buf;
- }
-
- m_adj(m_new, sizeof(u_int64_t));
-
- c->mx_mbuf = m_new;
- c->mx_ptr->mx_status = MX_RXSTAT;
- c->mx_ptr->mx_data = vtophys(mtod(m_new, caddr_t));
- c->mx_ptr->mx_ctl = MX_RXCTL_RLINK | (MCLBYTES - 1);
-
- return(0);
-}
-
-/*
- * A frame has been uploaded: pass the resulting mbuf chain up to
- * the higher level protocols.
- */
-static void mx_rxeof(sc)
- struct mx_softc *sc;
-{
- struct ether_header *eh;
- struct mbuf *m;
- struct ifnet *ifp;
- struct mx_chain_onefrag *cur_rx;
- int total_len = 0;
- u_int32_t rxstat;
-
- ifp = &sc->arpcom.ac_if;
-
- while(!((rxstat = sc->mx_cdata.mx_rx_head->mx_ptr->mx_status) &
- MX_RXSTAT_OWN)) {
- struct mbuf *m0 = NULL;
-
- cur_rx = sc->mx_cdata.mx_rx_head;
- sc->mx_cdata.mx_rx_head = cur_rx->mx_nextdesc;
- m = cur_rx->mx_mbuf;
-
- /*
- * If an error occurs, update stats, clear the
- * status word and leave the mbuf cluster in place:
- * it should simply get re-used next time this descriptor
- * comes up in the ring.
- */
- if (rxstat & MX_RXSTAT_RXERR) {
- ifp->if_ierrors++;
- if (rxstat & MX_RXSTAT_COLLSEEN)
- ifp->if_collisions++;
- mx_newbuf(sc, cur_rx, m);
- continue;
- }
-
- /* No errors; receive the packet. */
- total_len = MX_RXBYTES(cur_rx->mx_ptr->mx_status);
-
- /*
- * XXX The Macronix chips includes the CRC with every
- * received frame, and there's no way to turn this
- * behavior off (at least, I can't find anything in
- * the manual that explains how to do it) so we have
- * to trim off the CRC manually.
- */
- total_len -= ETHER_CRC_LEN;
-
- m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
- total_len + ETHER_ALIGN, 0, ifp, NULL);
- mx_newbuf(sc, cur_rx, m);
- if (m0 == NULL) {
- ifp->if_ierrors++;
- continue;
- }
- m_adj(m0, ETHER_ALIGN);
- m = m0;
-
- ifp->if_ipackets++;
- eh = mtod(m, struct ether_header *);
-
- /*
- * Handle BPF listeners. Let the BPF user see the packet, but
- * don't pass it up to the ether_input() layer unless it's
- * a broadcast packet, multicast packet, matches our ethernet
- * address or the interface is in promiscuous mode.
- */
- if (ifp->if_bpf) {
- bpf_mtap(ifp, m);
- if (ifp->if_flags & IFF_PROMISC &&
- (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
- ETHER_ADDR_LEN) &&
- (eh->ether_dhost[0] & 1) == 0)) {
- m_freem(m);
- continue;
- }
- }
-
- /* Remove header from mbuf and pass it on. */
- m_adj(m, sizeof(struct ether_header));
- ether_input(ifp, eh, m);
- }
-
- return;
-}
-
-void mx_rxeoc(sc)
- struct mx_softc *sc;
-{
-
- mx_rxeof(sc);
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_RX_ON);
- CSR_WRITE_4(sc, MX_RXADDR, vtophys(sc->mx_cdata.mx_rx_head->mx_ptr));
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_ON);
- CSR_WRITE_4(sc, MX_RXSTART, 0xFFFFFFFF);
-
- return;
-}
-
-/*
- * A frame was downloaded to the chip. It's safe for us to clean up
- * the list buffers.
- */
-
-static void mx_txeof(sc)
- struct mx_softc *sc;
-{
- struct mx_chain *cur_tx;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- /* Clear the timeout timer. */
- ifp->if_timer = 0;
-
- if (sc->mx_cdata.mx_tx_head == NULL)
- return;
-
- /*
- * Go through our tx list and free mbufs for those
- * frames that have been transmitted.
- */
- while(sc->mx_cdata.mx_tx_head->mx_mbuf != NULL) {
- u_int32_t txstat;
-
- cur_tx = sc->mx_cdata.mx_tx_head;
- txstat = MX_TXSTATUS(cur_tx);
-
- if (txstat & MX_TXSTAT_OWN)
- break;
-
- if (txstat & MX_TXSTAT_ERRSUM) {
- ifp->if_oerrors++;
- if (txstat & MX_TXSTAT_EXCESSCOLL)
- ifp->if_collisions++;
- if (txstat & MX_TXSTAT_LATECOLL)
- ifp->if_collisions++;
- }
-
- ifp->if_collisions += (txstat & MX_TXSTAT_COLLCNT) >> 3;
-
- ifp->if_opackets++;
- m_freem(cur_tx->mx_mbuf);
- cur_tx->mx_mbuf = NULL;
-
- if (sc->mx_cdata.mx_tx_head == sc->mx_cdata.mx_tx_tail) {
- sc->mx_cdata.mx_tx_head = NULL;
- sc->mx_cdata.mx_tx_tail = NULL;
- break;
- }
-
- sc->mx_cdata.mx_tx_head = cur_tx->mx_nextdesc;
- }
-
- return;
-}
-
-/*
- * TX 'end of channel' interrupt handler.
- */
-static void mx_txeoc(sc)
- struct mx_softc *sc;
-{
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- ifp->if_timer = 0;
-
- if (sc->mx_cdata.mx_tx_head == NULL) {
- ifp->if_flags &= ~IFF_OACTIVE;
- sc->mx_cdata.mx_tx_tail = NULL;
- }
-
- return;
-}
-
-static void mx_tick(xsc)
- void *xsc;
-{
- struct mx_softc *sc;
- struct mii_data *mii;
- struct ifnet *ifp;
- int s;
-
- s = splimp();
-
- sc = xsc;
- ifp = &sc->arpcom.ac_if;
- mii = device_get_softc(sc->mx_miibus);
- mii_tick(mii);
-
- if (!sc->mx_link) {
- mii_pollstat(mii);
- if (mii->mii_media_status & IFM_ACTIVE &&
- IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
- sc->mx_link++;
- if (ifp->if_snd.ifq_head != NULL)
- mx_start(ifp);
- }
- }
-
- sc->mx_stat_ch = timeout(mx_tick, sc, hz);
-
- splx(s);
-
- return;
-}
-
-static void mx_intr(arg)
- void *arg;
-{
- struct mx_softc *sc;
- struct ifnet *ifp;
- u_int32_t status;
-
- sc = arg;
- ifp = &sc->arpcom.ac_if;
-
- /* Supress unwanted interrupts */
- if (!(ifp->if_flags & IFF_UP)) {
- mx_stop(sc);
- return;
- }
-
- /* Disable interrupts. */
- CSR_WRITE_4(sc, MX_IMR, 0x00000000);
-
- for (;;) {
- status = CSR_READ_4(sc, MX_ISR);
- if (status)
- CSR_WRITE_4(sc, MX_ISR, status);
-
- if ((status & MX_INTRS) == 0)
- break;
-
- if (status & MX_ISR_TX_OK)
- mx_txeof(sc);
-
- if (status & MX_ISR_TX_NOBUF)
- mx_txeoc(sc);
-
- if (status & MX_ISR_TX_IDLE) {
- mx_txeof(sc);
- if (sc->mx_cdata.mx_tx_head != NULL) {
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON);
- CSR_WRITE_4(sc, MX_TXSTART, 0xFFFFFFFF);
- }
- }
-
- if (status & MX_ISR_TX_UNDERRUN) {
- u_int32_t cfg;
- cfg = CSR_READ_4(sc, MX_NETCFG);
- if ((cfg & MX_NETCFG_TX_THRESH) == MX_TXTHRESH_160BYTES)
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_STORENFWD);
- else
- CSR_WRITE_4(sc, MX_NETCFG, cfg + 0x4000);
- }
-
- if (status & MX_ISR_RX_OK)
- mx_rxeof(sc);
-
- if ((status & MX_ISR_RX_WATDOGTIMEO)
- || (status & MX_ISR_RX_NOBUF))
- mx_rxeoc(sc);
-
- if (status & MX_ISR_BUS_ERR) {
- mx_reset(sc);
- mx_init(sc);
- }
- }
-
- /* Re-enable interrupts. */
- CSR_WRITE_4(sc, MX_IMR, MX_INTRS);
-
- if (ifp->if_snd.ifq_head != NULL) {
- mx_start(ifp);
- }
-
- return;
-}
-
-/*
- * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
- * pointers to the fragment pointers.
- */
-static int mx_encap(sc, c, m_head)
- struct mx_softc *sc;
- struct mx_chain *c;
- struct mbuf *m_head;
-{
- int frag = 0;
- struct mx_desc *f = NULL;
- int total_len;
- struct mbuf *m;
-
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- m = m_head;
- total_len = 0;
-
- for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
- if (m->m_len != 0) {
- if (frag == MX_MAXFRAGS)
- break;
- total_len += m->m_len;
- f = &c->mx_ptr->mx_frag[frag];
- f->mx_ctl = MX_TXCTL_TLINK | m->m_len;
- if (frag == 0) {
- f->mx_status = 0;
- f->mx_ctl |= MX_TXCTL_FIRSTFRAG;
- } else
- f->mx_status = MX_TXSTAT_OWN;
- f->mx_next = vtophys(&c->mx_ptr->mx_frag[frag + 1]);
- f->mx_data = vtophys(mtod(m, vm_offset_t));
- frag++;
- }
- }
-
- /*
- * Handle special case: we ran out of fragments,
- * but we have more mbufs left in the chain. Copy the
- * data into an mbuf cluster. Note that we don't
- * bother clearing the values in the other fragment
- * pointers/counters; it wouldn't gain us anything,
- * and would waste cycles.
- */
- if (m != NULL) {
- struct mbuf *m_new = NULL;
-
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("mx%d: no memory for tx list", sc->mx_unit);
- return(1);
- }
- if (m_head->m_pkthdr.len > MHLEN) {
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- printf("mx%d: no memory for tx list",
- sc->mx_unit);
- return(1);
- }
- }
- m_copydata(m_head, 0, m_head->m_pkthdr.len,
- mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
- m_freem(m_head);
- m_head = m_new;
- f = &c->mx_ptr->mx_frag[0];
- f->mx_status = 0;
- f->mx_data = vtophys(mtod(m_new, caddr_t));
- f->mx_ctl = total_len = m_new->m_len;
- f->mx_ctl |= MX_TXCTL_TLINK|MX_TXCTL_FIRSTFRAG;
- frag = 1;
- }
-
-
- if (total_len < MX_MIN_FRAMELEN) {
- f = &c->mx_ptr->mx_frag[frag];
- f->mx_ctl = MX_MIN_FRAMELEN - total_len;
- f->mx_data = vtophys(&sc->mx_cdata.mx_pad);
- f->mx_ctl |= MX_TXCTL_TLINK;
- f->mx_status = MX_TXSTAT_OWN;
- frag++;
- }
-
- c->mx_mbuf = m_head;
- c->mx_lastdesc = frag - 1;
- MX_TXCTL(c) |= MX_TXCTL_LASTFRAG|MX_TXCTL_FINT;
- MX_TXNEXT(c) = vtophys(&c->mx_nextdesc->mx_ptr->mx_frag[0]);
- return(0);
-}
-
-/*
- * Main transmit routine. To avoid having to do mbuf copies, we put pointers
- * to the mbuf data regions directly in the transmit lists. We also save a
- * copy of the pointers since the transmit list fragment pointers are
- * physical addresses.
- */
-
-static void mx_start(ifp)
- struct ifnet *ifp;
-{
- struct mx_softc *sc;
- struct mbuf *m_head = NULL;
- struct mx_chain *cur_tx = NULL, *start_tx;
-
- sc = ifp->if_softc;
-
- if (!sc->mx_link)
- return;
-
- if (ifp->if_flags & IFF_OACTIVE)
- return;
-
- /*
- * Check for an available queue slot. If there are none,
- * punt.
- */
- if (sc->mx_cdata.mx_tx_free->mx_mbuf != NULL) {
- ifp->if_flags |= IFF_OACTIVE;
- return;
- }
-
- start_tx = sc->mx_cdata.mx_tx_free;
-
- while(sc->mx_cdata.mx_tx_free->mx_mbuf == NULL) {
- IF_DEQUEUE(&ifp->if_snd, m_head);
- if (m_head == NULL)
- break;
-
- /* Pick a descriptor off the free list. */
- cur_tx = sc->mx_cdata.mx_tx_free;
- sc->mx_cdata.mx_tx_free = cur_tx->mx_nextdesc;
-
- /* Pack the data into the descriptor. */
- mx_encap(sc, cur_tx, m_head);
- if (cur_tx != start_tx)
- MX_TXOWN(cur_tx) = MX_TXSTAT_OWN;
-
- /*
- * If there's a BPF listener, bounce a copy of this frame
- * to him.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp, cur_tx->mx_mbuf);
-
- MX_TXOWN(cur_tx) = MX_TXSTAT_OWN;
- CSR_WRITE_4(sc, MX_TXSTART, 0xFFFFFFFF);
-
- }
-
- /*
- * If there are no frames queued, bail.
- */
- if (cur_tx == NULL)
- return;
-
- sc->mx_cdata.mx_tx_tail = cur_tx;
-
- if (sc->mx_cdata.mx_tx_head == NULL)
- sc->mx_cdata.mx_tx_head = start_tx;
-
- /*
- * Set a timeout in case the chip goes out to lunch.
- */
- ifp->if_timer = 5;
-
- return;
-}
-
-static void mx_init(xsc)
- void *xsc;
-{
- struct mx_softc *sc = xsc;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- struct mii_data *mii;
- int s;
-
- s = splimp();
-
- mii = device_get_softc(sc->mx_miibus);
-
- /*
- * Cancel pending I/O and free all RX/TX buffers.
- */
- mx_stop(sc);
- mx_reset(sc);
-
- /*
- * Set cache alignment and burst length.
- */
- CSR_WRITE_4(sc, MX_BUSCTL, MX_BUSCTL_MUSTBEONE|MX_BUSCTL_ARBITRATION);
- MX_SETBIT(sc, MX_BUSCTL, MX_BURSTLEN_16LONG);
- switch(sc->mx_cachesize) {
- case 32:
- MX_SETBIT(sc, MX_BUSCTL, MX_CACHEALIGN_32LONG);
- break;
- case 16:
- MX_SETBIT(sc, MX_BUSCTL, MX_CACHEALIGN_16LONG);
- break;
- case 8:
- MX_SETBIT(sc, MX_BUSCTL, MX_CACHEALIGN_8LONG);
- break;
- case 0:
- default:
- MX_SETBIT(sc, MX_BUSCTL, MX_CACHEALIGN_NONE);
- break;
- }
-
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_NO_RXCRC);
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_STORENFWD);
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_TX_BACKOFF);
-
- /*
- * The app notes for the 98713 and 98715A say that
- * in order to have the chips operate properly, a magic
- * number must be written to CSR16. Macronix does not
- * document the meaning of these bits so there's no way
- * to know exactly what they mean. The 98713 has a magic
- * number all its own; the rest all use a different one.
- */
- MX_CLRBIT(sc, MX_MAGICPACKET, 0xFFFF0000);
- if (sc->mx_type == MX_TYPE_98713)
- MX_SETBIT(sc, MX_MAGICPACKET, MX_MAGIC_98713);
- else
- MX_SETBIT(sc, MX_MAGICPACKET, MX_MAGIC_98715);
-
-#ifdef notdef
- if (sc->mx_type == MX_TYPE_98713) {
- MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
- MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
- MX_SETBIT(sc, MX_NETCFG, (MX_NETCFG_PCS|
- MX_NETCFG_PORTSEL|MX_NETCFG_SCRAMBLER));
- }
-#endif
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_TX_THRESH);
- /*MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL);*/
-
- if (IFM_SUBTYPE(mii->mii_media.ifm_media) == IFM_10_T)
- MX_SETBIT(sc, MX_NETCFG, MX_TXTHRESH_160BYTES);
- else
- MX_SETBIT(sc, MX_NETCFG, MX_TXTHRESH_72BYTES);
-
- /* Init circular RX list. */
- if (mx_list_rx_init(sc) == ENOBUFS) {
- printf("mx%d: initialization failed: no "
- "memory for rx buffers\n", sc->mx_unit);
- mx_stop(sc);
- (void)splx(s);
- return;
- }
-
- /*
- * Init tx descriptors.
- */
- mx_list_tx_init(sc);
-
- /*
- * Load the address of the RX list.
- */
- CSR_WRITE_4(sc, MX_RXADDR, vtophys(sc->mx_cdata.mx_rx_head->mx_ptr));
-
- /*
- * Load the RX/multicast filter.
- */
- mx_setfilt(sc);
-
- mii_mediachg(mii);
-
- /*
- * Enable interrupts.
- */
- CSR_WRITE_4(sc, MX_IMR, MX_INTRS);
- CSR_WRITE_4(sc, MX_ISR, 0xFFFFFFFF);
-
- /* Enable receiver and transmitter. */
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON|MX_NETCFG_RX_ON);
- CSR_WRITE_4(sc, MX_RXSTART, 0xFFFFFFFF);
-
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
-
- (void)splx(s);
-
- sc->mx_stat_ch = timeout(mx_tick, sc, hz);
-
- return;
-}
-
-/*
- * Set media options.
- */
-static int mx_ifmedia_upd(ifp)
- struct ifnet *ifp;
-{
- struct mx_softc *sc;
- struct mii_data *mii;
-
- sc = ifp->if_softc;
- mii = device_get_softc(sc->mx_miibus);
- mii_mediachg(mii);
- sc->mx_link = 0;
-
- return(0);
-}
-
-/*
- * Report current media status.
- */
-static void mx_ifmedia_sts(ifp, ifmr)
- struct ifnet *ifp;
- struct ifmediareq *ifmr;
-{
- struct mx_softc *sc;
- struct mii_data *mii;
-
- sc = ifp->if_softc;
- mii = device_get_softc(sc->mx_miibus);
- mii_pollstat(mii);
- ifmr->ifm_active = mii->mii_media_active;
- ifmr->ifm_status = mii->mii_media_status;
-
- return;
-}
-
-static int mx_ioctl(ifp, command, data)
- struct ifnet *ifp;
- u_long command;
- caddr_t data;
-{
- struct mx_softc *sc = ifp->if_softc;
- struct mii_data *mii;
- 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:
- if (ifp->if_flags & IFF_UP) {
- if (ifp->if_flags & IFF_RUNNING &&
- ifp->if_flags & IFF_PROMISC &&
- !(sc->mx_if_flags & IFF_PROMISC)) {
- MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_PROMISC);
- } else if (ifp->if_flags & IFF_RUNNING &&
- !(ifp->if_flags & IFF_PROMISC) &&
- sc->mx_if_flags & IFF_PROMISC) {
- MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_RX_PROMISC);
- } else
- mx_init(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- mx_stop(sc);
- }
- sc->mx_if_flags = ifp->if_flags;
- error = 0;
- break;
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- mx_init(sc);
- error = 0;
- break;
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- mii = device_get_softc(sc->mx_miibus);
- error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
- break;
- default:
- error = EINVAL;
- break;
- }
-
- (void)splx(s);
-
- return(error);
-}
-
-static void mx_watchdog(ifp)
- struct ifnet *ifp;
-{
- struct mx_softc *sc;
-
- sc = ifp->if_softc;
-
- ifp->if_oerrors++;
- printf("mx%d: watchdog timeout\n", sc->mx_unit);
-
- mx_stop(sc);
- mx_reset(sc);
- mx_init(sc);
-
- if (ifp->if_snd.ifq_head != NULL)
- mx_start(ifp);
-
- return;
-}
-
-/*
- * Stop the adapter and free any mbufs allocated to the
- * RX and TX lists.
- */
-static void mx_stop(sc)
- struct mx_softc *sc;
-{
- register int i;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_timer = 0;
-
- untimeout(mx_tick, sc, sc->mx_stat_ch);
-
- MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_RX_ON|MX_NETCFG_TX_ON));
- CSR_WRITE_4(sc, MX_IMR, 0x00000000);
- CSR_WRITE_4(sc, MX_TXADDR, 0x00000000);
- CSR_WRITE_4(sc, MX_RXADDR, 0x00000000);
- sc->mx_link = 0;
-
- /*
- * Free data in the RX lists.
- */
- for (i = 0; i < MX_RX_LIST_CNT; i++) {
- if (sc->mx_cdata.mx_rx_chain[i].mx_mbuf != NULL) {
- m_freem(sc->mx_cdata.mx_rx_chain[i].mx_mbuf);
- sc->mx_cdata.mx_rx_chain[i].mx_mbuf = NULL;
- }
- }
- bzero((char *)&sc->mx_ldata->mx_rx_list,
- sizeof(sc->mx_ldata->mx_rx_list));
-
- /*
- * Free the TX list buffers.
- */
- for (i = 0; i < MX_TX_LIST_CNT; i++) {
- if (sc->mx_cdata.mx_tx_chain[i].mx_mbuf != NULL) {
- m_freem(sc->mx_cdata.mx_tx_chain[i].mx_mbuf);
- sc->mx_cdata.mx_tx_chain[i].mx_mbuf = NULL;
- }
- }
-
- bzero((char *)&sc->mx_ldata->mx_tx_list,
- sizeof(sc->mx_ldata->mx_tx_list));
-
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-
- return;
-}
-
-/*
- * Stop all chip I/O so that the kernel's probe routines don't
- * get confused by errant DMAs when rebooting.
- */
-static void mx_shutdown(dev)
- device_t dev;
-{
- struct mx_softc *sc;
-
- sc = device_get_softc(dev);
-
- mx_stop(sc);
-
- return;
-}
diff --git a/sys/pci/if_mxreg.h b/sys/pci/if_mxreg.h
deleted file mode 100644
index 5a3c368..0000000
--- a/sys/pci/if_mxreg.h
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * Copyright (c) 1997, 1998
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * Macronix register definitions.
- */
-
-#define MX_BUSCTL 0x00 /* bus control */
-#define MX_TXSTART 0x08 /* tx start demand */
-#define MX_RXSTART 0x10 /* rx start demand */
-#define MX_RXADDR 0x18 /* rx descriptor list start addr */
-#define MX_TXADDR 0x20 /* tx descriptor list start addr */
-#define MX_ISR 0x28 /* interrupt status register */
-#define MX_NETCFG 0x30 /* network config register */
-#define MX_IMR 0x38 /* interrupt mask */
-#define MX_FRAMESDISCARDED 0x40 /* # of discarded frames */
-#define MX_SIO 0x48 /* MII and ROM/EEPROM access */
-#define MX_RESERVED 0x50
-#define MX_TIMER 0x58 /* general timer */
-#define MX_10BTSTAT 0x60
-#define MX_SIARESET 0x68
-#define MX_10BTCTRL 0x70
-#define MX_WATCHDOG 0x78
-#define MX_MAGICPACKET 0x80
-#define MX_NWAYSTAT 0xA0
-
-/*
- * These are magic values that must be written into CSR16
- * (MX_MAGICPACKET) in order to put the chip into proper
- * operating mode. The magic numbers are documented in the
- * Macronix 98715 application notes.
- */
-#define MX_MAGIC_98713 0x0F370000
-#define MX_MAGIC_98713A 0x0B3C0000
-#define MX_MAGIC_98715 0x0B3C0000
-#define MX_MAGIC_98725 0x0B3C0000
-
-#define MX_REVISION_98713 0x00
-#define MX_REVISION_98713A 0x10
-#define MX_REVISION_98715 0x20
-#define MX_REVISION_98725 0x30
-
-/*
- * As far as the driver is concerned, there are two 'types' of
- * chips to be concerned with. One is a 98713 with an external
- * PHY on the MII. The other covers pretty much everything else,
- * since all the other Macronix chips have built-in transceivers.
- * This type setting governs what which mode selection routines
- * we use (MII or built-in). It also govers which of the 'magic'
- * numbers we write into CSR16.
- */
-#define MX_TYPE_98713 0x1
-#define MX_TYPE_98713A 0x2
-#define MX_TYPE_987x5 0x3
-
-/*
- * Bus control bits.
- */
-#define MX_BUSCTL_RESET 0x00000001
-#define MX_BUSCTL_ARBITRATION 0x00000002
-#define MX_BUSCTL_SKIPLEN 0x0000007C
-#define MX_BUSCTL_BUF_BIGENDIAN 0x00000080
-#define MX_BUSCTL_BURSTLEN 0x00003F00
-#define MX_BUSCTL_CACHEALIGN 0x0000C000
-#define MX_BUSCTL_TXPOLL 0x000E0000
-#define MX_BUSCTL_MUSTBEONE 0x04000000
-
-#define MX_SKIPLEN_1LONG 0x00000004
-#define MX_SKIPLEN_2LONG 0x00000008
-#define MX_SKIPLEN_3LONG 0x00000010
-#define MX_SKIPLEN_4LONG 0x00000020
-#define MX_SKIPLEN_5LONG 0x00000040
-
-#define MX_CACHEALIGN_NONE 0x00000000
-#define MX_CACHEALIGN_8LONG 0x00004000
-#define MX_CACHEALIGN_16LONG 0x00008000
-#define MX_CACHEALIGN_32LONG 0x0000C000
-
-#define MX_BURSTLEN_USECA 0x00000000
-#define MX_BURSTLEN_1LONG 0x00000100
-#define MX_BURSTLEN_2LONG 0x00000200
-#define MX_BURSTLEN_4LONG 0x00000400
-#define MX_BURSTLEN_8LONG 0x00000800
-#define MX_BURSTLEN_16LONG 0x00001000
-#define MX_BURSTLEN_32LONG 0x00002000
-
-#define MX_TXPOLL_OFF 0x00000000
-#define MX_TXPOLL_200U 0x00020000
-#define MX_TXPOLL_800U 0x00040000
-#define MX_TXPOLL_1600U 0x00060000
-
-#define MX_BUSCTL_CONFIG (MX_BUSCTL_ARBITRATION|MX_CACHEALIGN_8LONG| \
- MX_BURSTLEN_8LONG)
-
-/*
- * Interrupt status bits.
- */
-#define MX_ISR_TX_OK 0x00000001
-#define MX_ISR_TX_IDLE 0x00000002
-#define MX_ISR_TX_NOBUF 0x00000004
-#define MX_ISR_TX_JABBERTIMEO 0x00000008
-#define MX_ISR_LINKGOOD 0x00000010
-#define MX_ISR_TX_UNDERRUN 0x00000020
-#define MX_ISR_RX_OK 0x00000040
-#define MX_ISR_RX_NOBUF 0x00000080
-#define MX_ISR_RX_READ 0x00000100
-#define MX_ISR_RX_WATDOGTIMEO 0x00000200
-#define MX_ISR_TX_EARLY 0x00000400
-#define MX_ISR_TIMER_EXPIRED 0x00000800
-#define MX_ISR_LINKFAIL 0x00001000
-#define MX_ISR_BUS_ERR 0x00002000
-#define MX_ISR_RX_EARLY 0x00004000
-#define MX_ISR_ABNORMAL 0x00008000
-#define MX_ISR_NORMAL 0x00010000
-#define MX_ISR_RX_STATE 0x000E0000
-#define MX_ISR_TX_STATE 0x00700000
-#define MX_ISR_BUSERRTYPE 0x03800000
-#define MX_ISR_100MBPSLINK 0x08000000
-#define MX_ISR_MAGICKPACK 0x10000000
-
-#define MX_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
-#define MX_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
-#define MX_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
-#define MX_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
-#define MX_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
-#define MX_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */
-#define MX_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
-#define MX_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
-
-#define MX_TXSTATE_RESET 0x00000000 /* 000 - reset */
-#define MX_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
-#define MX_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
-#define MX_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
-#define MX_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
-#define MX_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
-#define MX_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
-#define MX_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
-
-/*
- * Network config bits.
- */
-#define MX_NETCFG_RX_HASHPERF 0x00000001
-#define MX_NETCFG_RX_ON 0x00000002
-#define MX_NETCFG_RX_HASHONLY 0x00000004
-#define MX_NETCFG_RX_BADFRAMES 0x00000008
-#define MX_NETCFG_RX_INVFILT 0x00000010
-#define MX_NETCFG_BACKOFFCNT 0x00000020
-#define MX_NETCFG_RX_PROMISC 0x00000040
-#define MX_NETCFG_RX_ALLMULTI 0x00000080
-#define MX_NETCFG_FULLDUPLEX 0x00000200
-#define MX_NETCFG_LOOPBACK 0x00000C00
-#define MX_NETCFG_FORCECOLL 0x00001000
-#define MX_NETCFG_TX_ON 0x00002000
-#define MX_NETCFG_TX_THRESH 0x0000C000
-#define MX_NETCFG_TX_BACKOFF 0x00020000
-#define MX_NETCFG_PORTSEL 0x00040000 /* 0 == 10, 1 == 100 */
-#define MX_NETCFG_HEARTBEAT 0x00080000
-#define MX_NETCFG_STORENFWD 0x00200000
-#define MX_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */
-#define MX_NETCFG_PCS 0x00800000
-#define MX_NETCFG_SCRAMBLER 0x01000000
-#define MX_NETCFG_NO_RXCRC 0x02000000
-
-#define MX_OPMODE_NORM 0x00000000
-#define MX_OPMODE_INTLOOP 0x00000400
-#define MX_OPMODE_EXTLOOP 0x00000800
-
-#define MX_TXTHRESH_72BYTES 0x00000000
-#define MX_TXTHRESH_96BYTES 0x00004000
-#define MX_TXTHRESH_128BYTES 0x00008000
-#define MX_TXTHRESH_160BYTES 0x0000C000
-
-
-/*
- * Interrupt mask bits.
- */
-#define MX_IMR_TX_OK 0x00000001
-#define MX_IMR_TX_IDLE 0x00000002
-#define MX_IMR_TX_NOBUF 0x00000004
-#define MX_IMR_TX_JABBERTIMEO 0x00000008
-#define MX_IMR_LINKGOOD 0x00000010
-#define MX_IMR_TX_UNDERRUN 0x00000020
-#define MX_IMR_RX_OK 0x00000040
-#define MX_IMR_RX_NOBUF 0x00000080
-#define MX_IMR_RX_READ 0x00000100
-#define MX_IMR_RX_WATDOGTIMEO 0x00000200
-#define MX_IMR_TX_EARLY 0x00000400
-#define MX_IMR_TIMER_EXPIRED 0x00000800
-#define MX_IMR_LINKFAIL 0x00001000
-#define MX_IMR_BUS_ERR 0x00002000
-#define MX_IMR_RX_EARLY 0x00004000
-#define MX_IMR_ABNORMAL 0x00008000
-#define MX_IMR_NORMAL 0x00010000
-#define MX_IMR_100MBPSLINK 0x08000000
-#define MX_IMR_MAGICKPACK 0x10000000
-
-#define MX_INTRS \
- (MX_IMR_RX_OK|MX_IMR_TX_OK|MX_IMR_RX_NOBUF|MX_IMR_RX_WATDOGTIMEO|\
- MX_IMR_TX_NOBUF|MX_IMR_TX_UNDERRUN|MX_IMR_BUS_ERR| \
- MX_IMR_ABNORMAL|MX_IMR_NORMAL/*|MX_IMR_TX_EARLY*/)
-/*
- * Serial I/O (EEPROM/ROM) bits.
- */
-#define MX_SIO_EE_CS 0x00000001 /* EEPROM chip select */
-#define MX_SIO_EE_CLK 0x00000002 /* EEPROM clock */
-#define MX_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */
-#define MX_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */
-#define MX_SIO_ROMDATA4 0x00000010
-#define MX_SIO_ROMDATA5 0x00000020
-#define MX_SIO_ROMDATA6 0x00000040
-#define MX_SIO_ROMDATA7 0x00000080
-#define MX_SIO_EESEL 0x00000800
-#define MX_SIO_ROMSEL 0x00001000
-#define MX_SIO_ROMCTL_WRITE 0x00002000
-#define MX_SIO_ROMCTL_READ 0x00004000
-#define MX_SIO_MII_CLK 0x00010000 /* MDIO clock */
-#define MX_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */
-#define MX_SIO_MII_DIR 0x00040000 /* MDIO dir */
-#define MX_SIO_MII_DATAIN 0x00080000 /* MDIO data in */
-
-#define MX_EECMD_WRITE 0x140
-#define MX_EECMD_READ 0x180
-#define MX_EECMD_ERASE 0x1c0
-
-#define MX_EE_NODEADDR_OFFSET 0x70
-#define MX_EE_NODEADDR 10
-
-/*
- * General purpose timer register
- */
-#define MX_TIMER_VALUE 0x0000FFFF
-#define MX_TIMER_CONTINUUS 0x00010000
-
-/*
- * 10baseT status register
- */
-#define MX_TSTAT_LS100 0x00000002 /* link status of 100baseTX */
-#define MX_TSTAT_LS10 0x00000004 /* link status of 10baseT */
-#define MX_TSTAT_AUTOPOLARITY 0x00000008
-#define MX_TSTAT_REMFAULT 0x00000800
-#define MX_TSTAT_ANEGSTAT 0x00007000
-#define MX_TSTAT_LP_CAN_NWAY 0x00008000 /* link partner supports NWAY */
-#define MX_TSTAT_LPCODEWORD 0xFFFF0000 /* link partner's code word */
-
-#define MX_ASTAT_DISABLE 0x00000000
-#define MX_ASTAT_TXDISABLE 0x00001000
-#define MX_ASTAT_ABDETECT 0x00002000
-#define MX_ASTAT_ACKDETECT 0x00003000
-#define MX_ASTAT_CMPACKDETECT 0x00004000
-#define MX_ASTAT_AUTONEGCMP 0x00005000
-#define MX_ASTAT_LINKCHECK 0x00006000
-
-/*
- * PHY reset register
- */
-#define MX_SIA_RESET_NWAY 0x00000001
-#define MX_SIA_RESET_100TX 0x00000002
-
-/*
- * 10baseT control register
- */
-#define MX_TCTL_LOOPBACK 0x00000002
-#define MX_TCTL_POWERDOWN 0x00000004
-#define MX_TCTL_HALFDUPLEX 0x00000040
-#define MX_TCTL_AUTONEGENBL 0x00000080
-#define MX_TCTL_RX_SQUELCH 0x00000100
-#define MX_TCTL_LINKTEST 0x00001000
-#define MX_TCTL_100BTXHALF 0x00010000
-#define MX_TCTL_100BTXFULL 0x00020000
-#define MX_TCTL_100BT4 0x00040000
-
-/*
- * Watchdog timer register
- */
-#define MX_WDOG_JABBERDIS 0x00000001
-#define MX_WDOG_HOSTUNJAB 0x00000002
-#define MX_WDOG_JABBERCLK 0x00000004
-#define MX_WDOG_RXWDOGDIS 0x00000010
-#define MX_WDOG_RXWDOGCLK 0x00000020
-#define MX_WDOG_MUSTBEZERO 0x00000100
-
-/*
- * Magic packet register
- */
-#define MX_MPACK_DISABLE 0x00400000
-
-/*
- * NWAY status register.
- */
-#define MX_NWAY_10BTHALF 0x08000000
-#define MX_NWAY_10BTFULL 0x10000000
-#define MX_NWAY_100BTHALF 0x20000000
-#define MX_NWAY_100BTFULL 0x40000000
-#define MX_NWAY_100BT4 0x80000000
-
-/*
- * Size of a setup frame.
- */
-#define MX_SFRAME_LEN 192
-
-/*
- * Macronix TX/RX list structure.
- */
-
-struct mx_desc {
- u_int32_t mx_status;
- u_int32_t mx_ctl;
- u_int32_t mx_ptr1;
- u_int32_t mx_ptr2;
-};
-
-#define mx_data mx_ptr1
-#define mx_next mx_ptr2
-
-#define MX_RXSTAT_FIFOOFLOW 0x00000001
-#define MX_RXSTAT_CRCERR 0x00000002
-#define MX_RXSTAT_DRIBBLE 0x00000004
-#define MX_RXSTAT_WATCHDOG 0x00000010
-#define MX_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */
-#define MX_RXSTAT_COLLSEEN 0x00000040
-#define MX_RXSTAT_GIANT 0x00000080
-#define MX_RXSTAT_LASTFRAG 0x00000100
-#define MX_RXSTAT_FIRSTFRAG 0x00000200
-#define MX_RXSTAT_MULTICAST 0x00000400
-#define MX_RXSTAT_RUNT 0x00000800
-#define MX_RXSTAT_RXTYPE 0x00003000
-#define MX_RXSTAT_RXERR 0x00008000
-#define MX_RXSTAT_RXLEN 0x3FFF0000
-#define MX_RXSTAT_OWN 0x80000000
-
-#define MX_RXBYTES(x) ((x & MX_RXSTAT_RXLEN) >> 16)
-#define MX_RXSTAT (MX_RXSTAT_FIRSTFRAG|MX_RXSTAT_LASTFRAG|MX_RXSTAT_OWN)
-
-#define MX_RXCTL_BUFLEN1 0x00000FFF
-#define MX_RXCTL_BUFLEN2 0x00FFF000
-#define MX_RXCTL_RLINK 0x01000000
-#define MX_RXCTL_RLAST 0x02000000
-
-#define MX_TXSTAT_DEFER 0x00000001
-#define MX_TXSTAT_UNDERRUN 0x00000002
-#define MX_TXSTAT_LINKFAIl 0x00000003
-#define MX_TXSTAT_COLLCNT 0x00000078
-#define MX_TXSTAT_SQE 0x00000080
-#define MX_TXSTAT_EXCESSCOLL 0x00000100
-#define MX_TXSTAT_LATECOLL 0x00000200
-#define MX_TXSTAT_NOCARRIER 0x00000400
-#define MX_TXSTAT_CARRLOST 0x00000800
-#define MX_TXSTAT_JABTIMEO 0x00004000
-#define MX_TXSTAT_ERRSUM 0x00008000
-#define MX_TXSTAT_OWN 0x80000000
-
-#define MX_TXCTL_BUFLEN1 0x000007FF
-#define MX_TXCTL_BUFLEN2 0x003FF800
-#define MX_TXCTL_FILTTYPE0 0x00400000
-#define MX_TXCTL_PAD 0x00800000
-#define MX_TXCTL_TLINK 0x01000000
-#define MX_TXCTL_TLAST 0x02000000
-#define MX_TXCTL_NOCRC 0x04000000
-#define MX_TXCTL_SETUP 0x08000000
-#define MX_TXCTL_FILTTYPE1 0x10000000
-#define MX_TXCTL_FIRSTFRAG 0x20000000
-#define MX_TXCTL_LASTFRAG 0x40000000
-#define MX_TXCTL_FINT 0x80000000
-
-#define MX_FILTER_PERFECT 0x00000000
-#define MX_FILTER_HASHPERF 0x00400000
-#define MX_FILTER_INVERSE 0x10000000
-#define MX_FILTER_HASHONLY 0x10400000
-
-#define MX_MAXFRAGS 16
-#define MX_RX_LIST_CNT 64
-#define MX_TX_LIST_CNT 128
-#define MX_MIN_FRAMELEN 60
-
-/*
- * A tx 'super descriptor' is actually 16 regular descriptors
- * back to back.
- */
-struct mx_txdesc {
- struct mx_desc mx_frag[MX_MAXFRAGS];
-};
-
-#define MX_TXNEXT(x) x->mx_ptr->mx_frag[x->mx_lastdesc].mx_next
-#define MX_TXSTATUS(x) x->mx_ptr->mx_frag[x->mx_lastdesc].mx_status
-#define MX_TXCTL(x) x->mx_ptr->mx_frag[x->mx_lastdesc].mx_ctl
-#define MX_TXDATA(x) x->mx_ptr->mx_frag[x->mx_lastdesc].mx_data
-
-#define MX_TXOWN(x) x->mx_ptr->mx_frag[0].mx_status
-
-struct mx_list_data {
- struct mx_desc mx_rx_list[MX_RX_LIST_CNT];
- struct mx_txdesc mx_tx_list[MX_TX_LIST_CNT];
-};
-
-struct mx_chain {
- struct mx_txdesc *mx_ptr;
- struct mbuf *mx_mbuf;
- struct mx_chain *mx_nextdesc;
- u_int8_t mx_lastdesc;
-};
-
-struct mx_chain_onefrag {
- struct mx_desc *mx_ptr;
- struct mbuf *mx_mbuf;
- struct mx_chain_onefrag *mx_nextdesc;
-};
-
-struct mx_chain_data {
- struct mx_desc mx_sframe;
- u_int32_t mx_sbuf[MX_SFRAME_LEN/sizeof(u_int32_t)];
- u_int8_t mx_pad[MX_MIN_FRAMELEN];
- struct mx_chain_onefrag mx_rx_chain[MX_RX_LIST_CNT];
- struct mx_chain mx_tx_chain[MX_TX_LIST_CNT];
-
- struct mx_chain_onefrag *mx_rx_head;
-
- struct mx_chain *mx_tx_head;
- struct mx_chain *mx_tx_tail;
- struct mx_chain *mx_tx_free;
-};
-
-struct mx_type {
- u_int16_t mx_vid;
- u_int16_t mx_did;
- char *mx_name;
-};
-
-struct mx_mii_frame {
- u_int8_t mii_stdelim;
- u_int8_t mii_opcode;
- u_int8_t mii_phyaddr;
- u_int8_t mii_regaddr;
- u_int8_t mii_turnaround;
- u_int16_t mii_data;
-};
-
-/*
- * MII constants
- */
-#define MX_MII_STARTDELIM 0x01
-#define MX_MII_READOP 0x02
-#define MX_MII_WRITEOP 0x01
-#define MX_MII_TURNAROUND 0x02
-
-#define MX_FLAG_FORCEDELAY 1
-#define MX_FLAG_SCHEDDELAY 2
-#define MX_FLAG_DELAYTIMEO 3
-
-struct mx_softc {
- struct arpcom arpcom; /* interface info */
- bus_space_handle_t mx_bhandle; /* bus space handle */
- bus_space_tag_t mx_btag; /* bus space tag */
- void *mx_intrhand;
- struct resource *mx_irq;
- struct resource *mx_res;
- device_t mx_miibus;
- struct mx_type *mx_info; /* Macronix adapter info */
- u_int8_t mx_unit; /* interface number */
- u_int8_t mx_type;
- u_int8_t mx_cachesize;
- u_int8_t mx_link;
- int mx_if_flags;
- caddr_t mx_ldata_ptr;
- struct mx_list_data *mx_ldata;
- struct mx_chain_data mx_cdata;
- struct callout_handle mx_stat_ch;
-};
-
-/*
- * register space access macros
- */
-#define CSR_WRITE_4(sc, reg, val) \
- bus_space_write_4(sc->mx_btag, sc->mx_bhandle, reg, val)
-#define CSR_WRITE_2(sc, reg, val) \
- bus_space_write_2(sc->mx_btag, sc->mx_bhandle, reg, val)
-#define CSR_WRITE_1(sc, reg, val) \
- bus_space_write_1(sc->mx_btag, sc->mx_bhandle, reg, val)
-
-#define CSR_READ_4(sc, reg) \
- bus_space_read_4(sc->mx_btag, sc->mx_bhandle, reg)
-#define CSR_READ_2(sc, reg) \
- bus_space_read_2(sc->mx_btag, sc->mx_bhandle, reg)
-#define CSR_READ_1(sc, reg) \
- bus_space_read_1(sc->mx_btag, sc->mx_bhandle, reg)
-
-#define MX_TIMEOUT 1000
-#define ETHER_ALIGN 2
-
-/*
- * General constants that are fun to know.
- *
- * Macronix PCI vendor ID
- */
-#define MX_VENDORID 0x10D9
-
-/*
- * Macronix PMAC device IDs.
- */
-#define MX_DEVICEID_98713 0x0512
-#define MX_DEVICEID_987x5 0x0531
-
-/*
- * Compex PCI vendor ID.
- */
-#define CP_VENDORID 0x11F6
-
-/*
- * Compex PMAC PCI device IDs.
- */
-#define CP_DEVICEID_98713 0x9881
-
-/*
- * Lite-On PNIC PCI vendor ID
- */
-#define PN_VENDORID 0x11AD
-
-/*
- * Lite-On PNIC II device ID. Note: this is actually a Macronix 98715A
- * with wake on lan/magic packet support.
- */
-#define PN_DEVICEID_PNIC_II 0xc115
-
-/*
- * PCI low memory base and low I/O base register, and
- * other PCI registers.
- */
-
-#define MX_PCI_VENDOR_ID 0x00
-#define MX_PCI_DEVICE_ID 0x02
-#define MX_PCI_COMMAND 0x04
-#define MX_PCI_STATUS 0x06
-#define MX_PCI_REVID 0x08
-#define MX_PCI_CLASSCODE 0x09
-#define MX_PCI_CACHELEN 0x0C
-#define MX_PCI_LATENCY_TIMER 0x0D
-#define MX_PCI_HEADER_TYPE 0x0E
-#define MX_PCI_LOIO 0x10
-#define MX_PCI_LOMEM 0x14
-#define MX_PCI_BIOSROM 0x30
-#define MX_PCI_INTLINE 0x3C
-#define MX_PCI_INTPIN 0x3D
-#define MX_PCI_MINGNT 0x3E
-#define MX_PCI_MINLAT 0x0F
-#define MX_PCI_RESETOPT 0x48
-#define MX_PCI_EEPROM_DATA 0x4C
-
-/* power management registers */
-#define MX_PCI_CAPID 0x44 /* 8 bits */
-#define MX_PCI_NEXTPTR 0x45 /* 8 bits */
-#define MX_PCI_PWRMGMTCAP 0x46 /* 16 bits */
-#define MX_PCI_PWRMGMTCTRL 0x48 /* 16 bits */
-
-#define MX_PSTATE_MASK 0x0003
-#define MX_PSTATE_D0 0x0000
-#define MX_PSTATE_D1 0x0001
-#define MX_PSTATE_D2 0x0002
-#define MX_PSTATE_D3 0x0003
-#define MX_PME_EN 0x0010
-#define MX_PME_STATUS 0x8000
-
-#ifdef __alpha__
-#undef vtophys
-#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
-#endif
diff --git a/sys/pci/if_pn.c b/sys/pci/if_pn.c
deleted file mode 100644
index 166afba..0000000
--- a/sys/pci/if_pn.c
+++ /dev/null
@@ -1,2326 +0,0 @@
-/*
- * Copyright (c) 1997, 1998
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * 82c168/82c169 PNIC fast ethernet PCI NIC driver
- *
- * Supports various network adapters based on the Lite-On PNIC
- * PCI network controller chip including the LinkSys LNE100TX.
- *
- * Written by Bill Paul <wpaul@ctr.columbia.edu>
- * Electrical Engineering Department
- * Columbia University, New York City
- */
-
-/*
- * The PNIC chip is a DEC tulip clone. This driver uses much of the
- * same code from the driver for the Winbond chip (which is also a
- * tulip clone) except for the MII, EEPROM and filter programming.
- *
- * Technically we could merge support for this chip into the 'de'
- * driver, but it's such a mess that I'm afraid to go near it.
- *
- * The PNIC appears to support both an external MII and an internal
- * transceiver. I think most 100Mbps implementations use a PHY attached
- * the the MII. The LinkSys board that I have uses a Myson MTD972
- * 100BaseTX PHY.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sockio.h>
-#include <sys/mbuf.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/ethernet.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
-
-#include <net/bpf.h>
-
-#include "opt_bdg.h"
-#ifdef BRIDGE
-#include <net/bridge.h>
-#endif
-
-#include <vm/vm.h> /* for vtophys */
-#include <vm/pmap.h> /* for vtophys */
-#include <machine/clock.h> /* for DELAY */
-#include <machine/bus_pio.h>
-#include <machine/bus_memio.h>
-#include <machine/bus.h>
-#include <machine/resource.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
-
-#include <pci/pcireg.h>
-#include <pci/pcivar.h>
-
-#define PN_USEIOSPACE
-
-/* #define PN_BACKGROUND_AUTONEG */
-
-#define PN_RX_BUG_WAR
-
-#include <pci/if_pnreg.h>
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-/*
- * Various supported device vendors/types and their names.
- */
-static struct pn_type pn_devs[] = {
- { PN_VENDORID, PN_DEVICEID_PNIC,
- "82c168 PNIC 10/100BaseTX" },
- { PN_VENDORID, PN_DEVICEID_PNIC,
- "82c169 PNIC 10/100BaseTX" },
- { 0, 0, NULL }
-};
-
-/*
- * Various supported PHY vendors/types and their names. Note that
- * this driver will work with pretty much any MII-compliant PHY,
- * so failure to positively identify the chip is not a fatal error.
- */
-
-static struct pn_type pn_phys[] = {
- { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" },
- { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" },
- { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"},
- { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" },
- { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" },
- { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" },
- { 0, 0, "<MII-compliant physical interface>" }
-};
-
-static int pn_probe __P((device_t));
-static int pn_attach __P((device_t));
-static int pn_detach __P((device_t));
-
-static int pn_newbuf __P((struct pn_softc *,
- struct pn_chain_onefrag *,
- struct mbuf *));
-static int pn_encap __P((struct pn_softc *, struct pn_chain *,
- struct mbuf *));
-
-#ifdef PN_RX_BUG_WAR
-static void pn_rx_bug_war __P((struct pn_softc *,
- struct pn_chain_onefrag *));
-#endif
-static void pn_rxeof __P((struct pn_softc *));
-static void pn_rxeoc __P((struct pn_softc *));
-static void pn_txeof __P((struct pn_softc *));
-static void pn_txeoc __P((struct pn_softc *));
-static void pn_intr __P((void *));
-static void pn_start __P((struct ifnet *));
-static int pn_ioctl __P((struct ifnet *, u_long, caddr_t));
-static void pn_init __P((void *));
-static void pn_stop __P((struct pn_softc *));
-static void pn_watchdog __P((struct ifnet *));
-static void pn_shutdown __P((device_t));
-static int pn_ifmedia_upd __P((struct ifnet *));
-static void pn_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
-
-static void pn_eeprom_getword __P((struct pn_softc *, u_int8_t, u_int16_t *));
-static void pn_read_eeprom __P((struct pn_softc *, caddr_t, int,
- int, int));
-static u_int16_t pn_phy_readreg __P((struct pn_softc *, int));
-static void pn_phy_writereg __P((struct pn_softc *, u_int16_t, u_int16_t));
-
-static void pn_autoneg_xmit __P((struct pn_softc *));
-static void pn_autoneg_mii __P((struct pn_softc *, int, int));
-static void pn_setmode_mii __P((struct pn_softc *, int));
-static void pn_getmode_mii __P((struct pn_softc *));
-static void pn_autoneg __P((struct pn_softc *, int, int));
-static void pn_setmode __P((struct pn_softc *, int));
-static void pn_setcfg __P((struct pn_softc *, u_int32_t));
-static u_int32_t pn_calchash __P((u_int8_t *));
-static void pn_setfilt __P((struct pn_softc *));
-static void pn_reset __P((struct pn_softc *));
-static int pn_list_rx_init __P((struct pn_softc *));
-static int pn_list_tx_init __P((struct pn_softc *));
-
-#ifdef PN_USEIOSPACE
-#define PN_RES SYS_RES_IOPORT
-#define PN_RID PN_PCI_LOIO
-#else
-#define PN_RES SYS_RES_MEMORY
-#define PN_RID PN_PCI_LOMEM
-#endif
-
-static device_method_t pn_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, pn_probe),
- DEVMETHOD(device_attach, pn_attach),
- DEVMETHOD(device_detach, pn_detach),
- DEVMETHOD(device_shutdown, pn_shutdown),
- { 0, 0 }
-};
-
-static driver_t pn_driver = {
- "pn",
- pn_methods,
- sizeof(struct pn_softc),
-};
-
-static devclass_t pn_devclass;
-
-DRIVER_MODULE(if_pn, pci, pn_driver, pn_devclass, 0, 0);
-
-#define PN_SETBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) | (x))
-
-#define PN_CLRBIT(sc, reg, x) \
- CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) & ~(x))
-
-/*
- * Read a word of data stored in the EEPROM at address 'addr.'
- */
-static void pn_eeprom_getword(sc, addr, dest)
- struct pn_softc *sc;
- u_int8_t addr;
- u_int16_t *dest;
-{
- register int i;
- u_int32_t r;
-
- CSR_WRITE_4(sc, PN_SIOCTL, PN_EE_READ|addr);
-
- for (i = 0; i < PN_TIMEOUT; i++) {
- DELAY(1);
- r = CSR_READ_4(sc, PN_SIO);
- if (!(r & PN_SIO_BUSY)) {
- *dest = (u_int16_t)(r & 0x0000FFFF);
- return;
- }
- }
-
- return;
-
-}
-
-/*
- * Read a sequence of words from the EEPROM.
- */
-static void pn_read_eeprom(sc, dest, off, cnt, swap)
- struct pn_softc *sc;
- caddr_t dest;
- int off;
- int cnt;
- int swap;
-{
- int i;
- u_int16_t word = 0, *ptr;
-
- for (i = 0; i < cnt; i++) {
- pn_eeprom_getword(sc, off + i, &word);
- ptr = (u_int16_t *)(dest + (i * 2));
- if (swap)
- *ptr = ntohs(word);
- else
- *ptr = word;
- }
-
- return;
-}
-
-static u_int16_t pn_phy_readreg(sc, reg)
- struct pn_softc *sc;
- int reg;
-{
- int i;
- u_int32_t rval;
-
- CSR_WRITE_4(sc, PN_MII,
- PN_MII_READ | (sc->pn_phy_addr << 23) | (reg << 18));
-
- for (i = 0; i < PN_TIMEOUT; i++) {
- DELAY(1);
- rval = CSR_READ_4(sc, PN_MII);
- if (!(rval & PN_MII_BUSY)) {
- if ((u_int16_t)(rval & 0x0000FFFF) == 0xFFFF)
- return(0);
- else
- return((u_int16_t)(rval & 0x0000FFFF));
- }
- }
-
- return(0);
-}
-
-static void pn_phy_writereg(sc, reg, data)
- struct pn_softc *sc;
- u_int16_t reg;
- u_int16_t data;
-{
- int i;
-
- CSR_WRITE_4(sc, PN_MII,
- PN_MII_WRITE | (sc->pn_phy_addr << 23) | (reg << 18) | data);
-
-
- for (i = 0; i < PN_TIMEOUT; i++) {
- if (!(CSR_READ_4(sc, PN_MII) & PN_MII_BUSY))
- break;
- }
-
- return;
-}
-
-#define PN_POLY 0xEDB88320
-#define PN_BITS 9
-
-static u_int32_t pn_calchash(addr)
- u_int8_t *addr;
-{
- u_int32_t idx, bit, data, crc;
-
- /* Compute CRC for the address value. */
- crc = 0xFFFFFFFF; /* initial value */
-
- for (idx = 0; idx < 6; idx++) {
- for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
- crc = (crc >> 1) ^ (((crc ^ data) & 1) ? PN_POLY : 0);
- }
-
- return (crc & ((1 << PN_BITS) - 1));
-}
-
-/*
- * Initiate an autonegotiation session.
- */
-static void pn_autoneg_xmit(sc)
- struct pn_softc *sc;
-{
- u_int16_t phy_sts;
-
- pn_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(pn_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
-
- phy_sts = pn_phy_readreg(sc, PHY_BMCR);
- phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR;
- pn_phy_writereg(sc, PHY_BMCR, phy_sts);
-
- return;
-}
-
-/*
- * Invoke autonegotiation on a PHY.
- */
-static void pn_autoneg_mii(sc, flag, verbose)
- struct pn_softc *sc;
- int flag;
- int verbose;
-{
- u_int16_t phy_sts = 0, media, advert, ability;
- struct ifnet *ifp;
- struct ifmedia *ifm;
-
- ifm = &sc->ifmedia;
- ifp = &sc->arpcom.ac_if;
-
- ifm->ifm_media = IFM_ETHER | IFM_AUTO;
-
- /*
- * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported'
- * bit cleared in the status register, but has the 'autoneg enabled'
- * bit set in the control register. This is a contradiction, and
- * I'm not sure how to handle it. If you want to force an attempt
- * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR
- * and see what happens.
- */
-#ifndef FORCE_AUTONEG_TFOUR
- /*
- * First, see if autoneg is supported. If not, there's
- * no point in continuing.
- */
- phy_sts = pn_phy_readreg(sc, PHY_BMSR);
- if (!(phy_sts & PHY_BMSR_CANAUTONEG)) {
- if (verbose)
- printf("pn%d: autonegotiation not supported\n",
- sc->pn_unit);
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- return;
- }
-#endif
-
- switch (flag) {
- case PN_FLAG_FORCEDELAY:
- /*
- * XXX Never use this option anywhere but in the probe
- * routine: making the kernel stop dead in its tracks
- * for three whole seconds after we've gone multi-user
- * is really bad manners.
- */
- pn_autoneg_xmit(sc);
- DELAY(5000000);
- break;
- case PN_FLAG_SCHEDDELAY:
- /*
- * Wait for the transmitter to go idle before starting
- * an autoneg session, otherwise pn_start() may clobber
- * our timeout, and we don't want to allow transmission
- * during an autoneg session since that can screw it up.
- */
- if (sc->pn_cdata.pn_tx_head != NULL) {
- sc->pn_want_auto = 1;
- return;
- }
- pn_autoneg_xmit(sc);
- ifp->if_timer = 5;
- sc->pn_autoneg = 1;
- sc->pn_want_auto = 0;
- return;
- break;
- case PN_FLAG_DELAYTIMEO:
- ifp->if_timer = 0;
- sc->pn_autoneg = 0;
- break;
- default:
- printf("pn%d: invalid autoneg flag: %d\n", sc->pn_unit, flag);
- return;
- }
-
- if (pn_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) {
- if (verbose)
- printf("pn%d: autoneg complete, ", sc->pn_unit);
- phy_sts = pn_phy_readreg(sc, PHY_BMSR);
- } else {
- if (verbose)
- printf("pn%d: autoneg not complete, ", sc->pn_unit);
- }
-
- media = pn_phy_readreg(sc, PHY_BMCR);
-
- /* Link is good. Report modes and set duplex mode. */
- if (pn_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) {
- if (verbose)
- printf("link status good ");
- advert = pn_phy_readreg(sc, PHY_ANAR);
- ability = pn_phy_readreg(sc, PHY_LPAR);
-
- if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) {
- ifm->ifm_media = IFM_ETHER|IFM_100_T4;
- media |= PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(100baseT4)\n");
- } else if (advert & PHY_ANAR_100BTXFULL &&
- ability & PHY_ANAR_100BTXFULL) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- media |= PHY_BMCR_SPEEDSEL;
- media |= PHY_BMCR_DUPLEX;
- printf("(full-duplex, 100Mbps)\n");
- } else if (advert & PHY_ANAR_100BTXHALF &&
- ability & PHY_ANAR_100BTXHALF) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
- media |= PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(half-duplex, 100Mbps)\n");
- } else if (advert & PHY_ANAR_10BTFULL &&
- ability & PHY_ANAR_10BTFULL) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
- media &= ~PHY_BMCR_SPEEDSEL;
- media |= PHY_BMCR_DUPLEX;
- printf("(full-duplex, 10Mbps)\n");
- } else if (advert & PHY_ANAR_10BTHALF &&
- ability & PHY_ANAR_10BTHALF) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- media &= ~PHY_BMCR_SPEEDSEL;
- media &= ~PHY_BMCR_DUPLEX;
- printf("(half-duplex, 10Mbps)\n");
- }
-
- media &= ~PHY_BMCR_AUTONEGENBL;
-
- /* Set ASIC's duplex mode to match the PHY. */
- pn_setcfg(sc, ifm->ifm_media);
- pn_phy_writereg(sc, PHY_BMCR, media);
- } else {
- if (verbose)
- printf("no carrier\n");
- }
-
- pn_init(sc);
-
- if (sc->pn_tx_pend) {
- sc->pn_autoneg = 0;
- sc->pn_tx_pend = 0;
- pn_start(ifp);
- }
-
- return;
-}
-
-static void pn_getmode_mii(sc)
- struct pn_softc *sc;
-{
- u_int16_t bmsr;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- bmsr = pn_phy_readreg(sc, PHY_BMSR);
- if (bootverbose)
- printf("pn%d: PHY status word: %x\n", sc->pn_unit, bmsr);
-
- /* fallback */
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
-
- if (bmsr & PHY_BMSR_10BTHALF) {
- if (bootverbose)
- printf("pn%d: 10Mbps half-duplex mode supported\n",
- sc->pn_unit);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
- }
-
- if (bmsr & PHY_BMSR_10BTFULL) {
- if (bootverbose)
- printf("pn%d: 10Mbps full-duplex mode supported\n",
- sc->pn_unit);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
- }
-
- if (bmsr & PHY_BMSR_100BTXHALF) {
- if (bootverbose)
- printf("pn%d: 100Mbps half-duplex mode supported\n",
- sc->pn_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
- }
-
- if (bmsr & PHY_BMSR_100BTXFULL) {
- if (bootverbose)
- printf("pn%d: 100Mbps full-duplex mode supported\n",
- sc->pn_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- }
-
- /* Some also support 100BaseT4. */
- if (bmsr & PHY_BMSR_100BT4) {
- if (bootverbose)
- printf("pn%d: 100baseT4 mode supported\n", sc->pn_unit);
- ifp->if_baudrate = 100000000;
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4;
-#ifdef FORCE_AUTONEG_TFOUR
- if (bootverbose)
- printf("pn%d: forcing on autoneg support for BT4\n",
- sc->pn_unit);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL):
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;
-#endif
- }
-
- if (bmsr & PHY_BMSR_CANAUTONEG) {
- if (bootverbose)
- printf("pn%d: autoneg supported\n", sc->pn_unit);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;
- }
-
- return;
-}
-
-static void pn_autoneg(sc, flag, verbose)
- struct pn_softc *sc;
- int flag;
- int verbose;
-{
- u_int32_t nway = 0, ability;
- struct ifnet *ifp;
- struct ifmedia *ifm;
-
- ifm = &sc->ifmedia;
- ifp = &sc->arpcom.ac_if;
-
- ifm->ifm_media = IFM_ETHER | IFM_AUTO;
-
- switch (flag) {
- case PN_FLAG_FORCEDELAY:
- /*
- * XXX Never use this option anywhere but in the probe
- * routine: making the kernel stop dead in its tracks
- * for three whole seconds after we've gone multi-user
- * is really bad manners.
- */
- CSR_WRITE_4(sc, PN_GEN,
- PN_GEN_MUSTBEONE|PN_GEN_100TX_LOOP);
- PN_CLRBIT(sc, PN_NWAY, PN_NWAY_AUTONEGRSTR);
- PN_SETBIT(sc, PN_NWAY, PN_NWAY_AUTOENB);
- DELAY(5000000);
- break;
- case PN_FLAG_SCHEDDELAY:
- /*
- * Wait for the transmitter to go idle before starting
- * an autoneg session, otherwise pn_start() may clobber
- * our timeout, and we don't want to allow transmission
- * during an autoneg session since that can screw it up.
- */
- if (sc->pn_cdata.pn_tx_head != NULL) {
- sc->pn_want_auto = 1;
- return;
- }
- CSR_WRITE_4(sc, PN_GEN,
- PN_GEN_MUSTBEONE|PN_GEN_100TX_LOOP);
- PN_CLRBIT(sc, PN_NWAY, PN_NWAY_AUTONEGRSTR);
- PN_SETBIT(sc, PN_NWAY, PN_NWAY_AUTOENB);
- ifp->if_timer = 5;
- sc->pn_autoneg = 1;
- sc->pn_want_auto = 0;
- return;
- break;
- case PN_FLAG_DELAYTIMEO:
- ifp->if_timer = 0;
- sc->pn_autoneg = 0;
- break;
- default:
- printf("pn%d: invalid autoneg flag: %d\n", sc->pn_unit, flag);
- return;
- }
-
- if (CSR_READ_4(sc, PN_NWAY) & PN_NWAY_LPAR) {
- if (verbose)
- printf("pn%d: autoneg complete, ", sc->pn_unit);
- } else {
- if (verbose)
- printf("pn%d: autoneg not complete, ", sc->pn_unit);
- }
-
- /* Link is good. Report modes and set duplex mode. */
- if (CSR_READ_4(sc, PN_ISR) & PN_ISR_LINKPASS) {
- if (verbose)
- printf("link status good ");
-
- ability = CSR_READ_4(sc, PN_NWAY);
- if (ability & PN_NWAY_LPAR100T4) {
- ifm->ifm_media = IFM_ETHER|IFM_100_T4;
- nway = PN_NWAY_MODE_100T4;
- printf("(100baseT4)\n");
- } else if (ability & PN_NWAY_LPAR100FULL) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- nway = PN_NWAY_MODE_100FD;
- printf("(full-duplex, 100Mbps)\n");
- } else if (ability & PN_NWAY_LPAR100HALF) {
- ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
- nway = PN_NWAY_MODE_100HD;
- printf("(half-duplex, 100Mbps)\n");
- } else if (ability & PN_NWAY_LPAR10FULL) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
- nway = PN_NWAY_MODE_10FD;
- printf("(full-duplex, 10Mbps)\n");
- } else if (ability & PN_NWAY_LPAR10HALF) {
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- nway = PN_NWAY_MODE_10HD;
- printf("(half-duplex, 10Mbps)\n");
- }
-
- /* Set ASIC's duplex mode to match the PHY. */
- pn_setcfg(sc, ifm->ifm_media);
- CSR_WRITE_4(sc, PN_NWAY, nway);
- } else {
- if (verbose)
- printf("no carrier\n");
- }
-
- pn_init(sc);
-
- if (sc->pn_tx_pend) {
- sc->pn_autoneg = 0;
- sc->pn_tx_pend = 0;
- pn_start(ifp);
- }
-
- return;
-}
-
-static void pn_setmode(sc, media)
- struct pn_softc *sc;
- int media;
-{
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- /*
- * If an autoneg session is in progress, stop it.
- */
- if (sc->pn_autoneg) {
- printf("pn%d: canceling autoneg session\n", sc->pn_unit);
- ifp->if_timer = sc->pn_autoneg = sc->pn_want_auto = 0;
- PN_CLRBIT(sc, PN_NWAY, PN_NWAY_AUTONEGRSTR);
- }
-
- printf("pn%d: selecting NWAY, ", sc->pn_unit);
-
- if (IFM_SUBTYPE(media) == IFM_100_T4) {
- printf("100Mbps/T4, half-duplex\n");
- }
-
- if (IFM_SUBTYPE(media) == IFM_100_TX) {
- printf("100Mbps, ");
- }
-
- if (IFM_SUBTYPE(media) == IFM_10_T) {
- printf("10Mbps, ");
- }
-
- if ((media & IFM_GMASK) == IFM_FDX) {
- printf("full duplex\n");
- } else {
- printf("half duplex\n");
- }
-
- pn_setcfg(sc, media);
-
- return;
-}
-
-static void pn_setmode_mii(sc, media)
- struct pn_softc *sc;
- int media;
-{
- u_int16_t bmcr;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- /*
- * If an autoneg session is in progress, stop it.
- */
- if (sc->pn_autoneg) {
- printf("pn%d: canceling autoneg session\n", sc->pn_unit);
- ifp->if_timer = sc->pn_autoneg = sc->pn_want_auto = 0;
- bmcr = pn_phy_readreg(sc, PHY_BMCR);
- bmcr &= ~PHY_BMCR_AUTONEGENBL;
- pn_phy_writereg(sc, PHY_BMCR, bmcr);
- }
-
- printf("pn%d: selecting MII, ", sc->pn_unit);
-
- bmcr = pn_phy_readreg(sc, PHY_BMCR);
-
- bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL|
- PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK);
-
- if (IFM_SUBTYPE(media) == IFM_100_T4) {
- printf("100Mbps/T4, half-duplex\n");
- bmcr |= PHY_BMCR_SPEEDSEL;
- bmcr &= ~PHY_BMCR_DUPLEX;
- }
-
- if (IFM_SUBTYPE(media) == IFM_100_TX) {
- printf("100Mbps, ");
- bmcr |= PHY_BMCR_SPEEDSEL;
- }
-
- if (IFM_SUBTYPE(media) == IFM_10_T) {
- printf("10Mbps, ");
- bmcr &= ~PHY_BMCR_SPEEDSEL;
- }
-
- if ((media & IFM_GMASK) == IFM_FDX) {
- printf("full duplex\n");
- bmcr |= PHY_BMCR_DUPLEX;
- } else {
- printf("half duplex\n");
- bmcr &= ~PHY_BMCR_DUPLEX;
- }
-
- pn_setcfg(sc, media);
- pn_phy_writereg(sc, PHY_BMCR, bmcr);
-
- return;
-}
-
-/*
- * Programming the receiver filter on the tulip/PNIC is gross. You
- * have to construct a special setup frame and download it to the
- * chip via the transmit DMA engine. This routine is also somewhat
- * gross, as the setup frame is sent synchronously rather than putting
- * on the transmit queue. The transmitter has to be stopped, then we
- * can download the frame and wait for the 'owned' bit to clear.
- *
- * We always program the chip using 'hash perfect' mode, i.e. one perfect
- * address (our node address) and a 512-bit hash filter for multicast
- * frames. We also sneak the broadcast address into the hash filter since
- * we need that too.
- */
-void pn_setfilt(sc)
- struct pn_softc *sc;
-{
- struct pn_desc *sframe;
- u_int32_t h, *sp;
- struct ifmultiaddr *ifma;
- struct ifnet *ifp;
- int i;
-
- ifp = &sc->arpcom.ac_if;
-
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON);
- PN_SETBIT(sc, PN_ISR, PN_ISR_TX_IDLE);
-
- sframe = &sc->pn_cdata.pn_sframe;
- sp = (u_int32_t *)&sc->pn_cdata.pn_sbuf;
- bzero((char *)sp, PN_SFRAME_LEN);
-
- sframe->pn_status = PN_TXSTAT_OWN;
- sframe->pn_next = vtophys(&sc->pn_ldata->pn_tx_list[0]);
- sframe->pn_data = vtophys(&sc->pn_cdata.pn_sbuf);
- sframe->pn_ctl = PN_SFRAME_LEN | PN_TXCTL_TLINK |
- PN_TXCTL_SETUP | PN_FILTER_HASHPERF;
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC)
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_RX_PROMISC);
- else
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_RX_PROMISC);
-
- if (ifp->if_flags & IFF_ALLMULTI)
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_RX_ALLMULTI);
-
- for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
- ifma = ifma->ifma_link.le_next) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- h = pn_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
- sp[h >> 4] |= 1 << (h & 0xF);
- }
-
- if (ifp->if_flags & IFF_BROADCAST) {
- h = pn_calchash(etherbroadcastaddr);
- sp[h >> 4] |= 1 << (h & 0xF);
- }
-
- sp[39] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0];
- sp[40] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1];
- sp[41] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2];
-
- CSR_WRITE_4(sc, PN_TXADDR, vtophys(sframe));
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON);
- CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
-
- /*
- * Wait for chip to clear the 'own' bit.
- */
- for (i = 0; i < PN_TIMEOUT; i++) {
- DELAY(10);
- if (sframe->pn_status != PN_TXSTAT_OWN)
- break;
- }
-
- if (i == PN_TIMEOUT)
- printf("pn%d: failed to send setup frame\n", sc->pn_unit);
-
- PN_SETBIT(sc, PN_ISR, PN_ISR_TX_NOBUF|PN_ISR_TX_IDLE);
-
- return;
-}
-
-/*
- * In order to fiddle with the
- * 'full-duplex' and '100Mbps' bits in the netconfig register, we
- * first have to put the transmit and/or receive logic in the idle state.
- */
-static void pn_setcfg(sc, media)
- struct pn_softc *sc;
- u_int32_t media;
-{
- int i, restart = 0;
-
- if (CSR_READ_4(sc, PN_NETCFG) & (PN_NETCFG_TX_ON|PN_NETCFG_RX_ON)) {
- restart = 1;
- PN_CLRBIT(sc, PN_NETCFG, (PN_NETCFG_TX_ON|PN_NETCFG_RX_ON));
-
- for (i = 0; i < PN_TIMEOUT; i++) {
- DELAY(10);
- if ((CSR_READ_4(sc, PN_ISR) & PN_ISR_TX_IDLE) &&
- (CSR_READ_4(sc, PN_ISR) & PN_ISR_RX_IDLE))
- break;
- }
-
- if (i == PN_TIMEOUT)
- printf("pn%d: failed to force tx and "
- "rx to idle state\n", sc->pn_unit);
-
- }
-
- if (IFM_SUBTYPE(media) == IFM_100_TX) {
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_SPEEDSEL);
- if (sc->pn_pinfo == NULL) {
- CSR_WRITE_4(sc, PN_GEN, PN_GEN_MUSTBEONE|
- PN_GEN_SPEEDSEL|PN_GEN_100TX_LOOP);
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_PCS|
- PN_NETCFG_SCRAMBLER|PN_NETCFG_MIIENB);
- PN_SETBIT(sc, PN_NWAY, PN_NWAY_SPEEDSEL);
- }
- } else {
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_SPEEDSEL);
- if (sc->pn_pinfo == NULL) {
- CSR_WRITE_4(sc, PN_GEN,
- PN_GEN_MUSTBEONE|PN_GEN_100TX_LOOP);
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_PCS|
- PN_NETCFG_SCRAMBLER|PN_NETCFG_MIIENB);
- PN_CLRBIT(sc, PN_NWAY, PN_NWAY_SPEEDSEL);
- }
- }
-
- if ((media & IFM_GMASK) == IFM_FDX) {
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_FULLDUPLEX);
- if (sc->pn_pinfo == NULL)
- PN_SETBIT(sc, PN_NWAY, PN_NWAY_DUPLEX);
- } else {
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_FULLDUPLEX);
- if (sc->pn_pinfo == NULL)
- PN_CLRBIT(sc, PN_NWAY, PN_NWAY_DUPLEX);
- }
-
- if (restart)
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON|PN_NETCFG_RX_ON);
-
- return;
-}
-
-static void pn_reset(sc)
- struct pn_softc *sc;
-{
- register int i;
-
- PN_SETBIT(sc, PN_BUSCTL, PN_BUSCTL_RESET);
-
- for (i = 0; i < PN_TIMEOUT; i++) {
- DELAY(10);
- if (!(CSR_READ_4(sc, PN_BUSCTL) & PN_BUSCTL_RESET))
- break;
- }
- if (i == PN_TIMEOUT)
- printf("pn%d: reset never completed!\n", sc->pn_unit);
-
- /* Wait a little while for the chip to get its brains in order. */
- DELAY(1000);
- return;
-}
-
-/*
- * Probe for a Lite-On PNIC chip. Check the PCI vendor and device
- * IDs against our list and return a device name if we find a match.
- */
-static int pn_probe(dev)
- device_t dev;
-{
- struct pn_type *t;
- u_int32_t rev;
-
- t = pn_devs;
-
- while(t->pn_name != NULL) {
- if ((pci_get_vendor(dev) == t->pn_vid) &&
- (pci_get_device(dev) == t->pn_did)) {
- if (t->pn_did == PN_DEVICEID_PNIC) {
- rev = pci_read_config(dev,
- PN_PCI_REVISION, 4) & 0xFF;
- switch(rev & PN_REVMASK) {
- case PN_REVID_82C168:
- device_set_desc(dev, t->pn_name);
- return(0);
- break;
- case PN_REVID_82C169:
- t++;
- device_set_desc(dev, t->pn_name);
- return(0);
- default:
- printf("unknown PNIC rev: %x\n", rev);
- break;
- }
- }
- device_set_desc(dev, t->pn_name);
- return(0);
- }
- t++;
- }
-
- return(ENXIO);
-}
-
-/*
- * Attach the interface. Allocate softc structures, do ifmedia
- * setup and ethernet/BPF attach.
- */
-static int pn_attach(dev)
- device_t dev;
-{
- int s, i;
- u_char eaddr[ETHER_ADDR_LEN];
- u_int32_t command;
- struct pn_softc *sc;
- struct ifnet *ifp;
- int media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- unsigned int round;
- caddr_t roundptr;
- struct pn_type *p;
- u_int16_t phy_vid, phy_did, phy_sts;
-#ifdef PN_RX_BUG_WAR
- u_int32_t revision = 0;
-#endif
- int unit, error = 0, rid;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- unit = device_get_unit(dev);
- bzero(sc, sizeof(struct pn_softc));
-
- /*
- * Handle power management nonsense.
- */
- command = pci_read_config(dev, PN_PCI_CAPID, 4) & 0x000000FF;
- if (command == 0x01) {
-
- command = pci_read_config(dev, PN_PCI_PWRMGMTCTRL, 4);
- if (command & PN_PSTATE_MASK) {
- u_int32_t iobase, membase, irq;
-
- /* Save important PCI config data. */
- iobase = pci_read_config(dev, PN_PCI_LOIO, 4);
- membase = pci_read_config(dev, PN_PCI_LOMEM, 4);
- irq = pci_read_config(dev, PN_PCI_INTLINE, 4);
-
- /* Reset the power state. */
- printf("pn%d: chip is in D%d power mode "
- "-- setting to D0\n", unit, command & PN_PSTATE_MASK);
- command &= 0xFFFFFFFC;
- pci_write_config(dev, PN_PCI_PWRMGMTCTRL, command, 4);
-
- /* Restore PCI config data. */
- pci_write_config(dev, PN_PCI_LOIO, iobase, 4);
- pci_write_config(dev, PN_PCI_LOMEM, membase, 4);
- pci_write_config(dev, PN_PCI_INTLINE, irq, 4);
- }
- }
-
- /*
- * Map control/status registers.
- */
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
- command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
- pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
- command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
-
-#ifdef PN_USEIOSPACE
- if (!(command & PCIM_CMD_PORTEN)) {
- printf("pn%d: failed to enable I/O ports!\n", unit);
- error = ENXIO;
- goto fail;
- }
-#else
- if (!(command & PCIM_CMD_MEMEN)) {
- printf("pn%d: failed to enable memory mapping!\n", unit);
- error = ENXIO;
- goto fail;
- }
-#endif
-
- rid = PN_RID;
- sc->pn_res = bus_alloc_resource(dev, PN_RES, &rid,
- 0, ~0, 1, RF_ACTIVE);
-
- if (sc->pn_res == NULL) {
- printf ("pn%d: couldn't map ports/memory\n", unit);
- error = ENXIO;
- goto fail;
- }
-
- sc->pn_btag = rman_get_bustag(sc->pn_res);
- sc->pn_bhandle = rman_get_bushandle(sc->pn_res);
-
- /* Allocate interrupt */
- rid = 0;
- sc->pn_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
- RF_SHAREABLE | RF_ACTIVE);
-
- if (sc->pn_irq == NULL) {
- printf("pn%d: couldn't map interrupt\n", unit);
- bus_release_resource(dev, PN_RES, PN_RID, sc->pn_res);
- error = ENXIO;
- goto fail;
- }
-
- error = bus_setup_intr(dev, sc->pn_irq, INTR_TYPE_NET,
- pn_intr, sc, &sc->pn_intrhand);
-
- if (error) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pn_res);
- bus_release_resource(dev, PN_RES, PN_RID, sc->pn_res);
- printf("pn%d: couldn't set up irq\n", unit);
- goto fail;
- }
-
- /* Save the cache line size. */
- sc->pn_cachesize = pci_read_config(dev, PN_PCI_CACHELEN, 4) & 0xFF;
-
- /* Reset the adapter. */
- pn_reset(sc);
-
- /*
- * Get station address from the EEPROM.
- */
- pn_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 1);
-
- /*
- * A PNIC chip was detected. Inform the world.
- */
- printf("pn%d: Ethernet address: %6D\n", unit, eaddr, ":");
-
- sc->pn_unit = unit;
- bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
-
- sc->pn_ldata_ptr = malloc(sizeof(struct pn_list_data) + 8,
- M_DEVBUF, M_NOWAIT);
- if (sc->pn_ldata_ptr == NULL) {
- printf("pn%d: no memory for list buffers!\n", unit);
- bus_teardown_intr(dev, sc->pn_irq, sc->pn_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pn_res);
- bus_release_resource(dev, PN_RES, PN_RID, sc->pn_res);
- error = ENXIO;
- goto fail;
- }
-
- sc->pn_ldata = (struct pn_list_data *)sc->pn_ldata_ptr;
- round = (uintptr_t)sc->pn_ldata_ptr & 0xF;
- roundptr = sc->pn_ldata_ptr;
- for (i = 0; i < 8; i++) {
- if (round % 8) {
- round++;
- roundptr++;
- } else
- break;
- }
- sc->pn_ldata = (struct pn_list_data *)roundptr;
- bzero(sc->pn_ldata, sizeof(struct pn_list_data));
-
-#ifdef PN_RX_BUG_WAR
- revision = pci_read_config(dev, PN_PCI_REVISION, 4) & 0x000000FF;
- if (revision == PN_169B_REV || revision == PN_169_REV ||
- (revision & 0xF0) == PN_168_REV) {
- sc->pn_rx_war = 1;
- sc->pn_rx_buf = malloc(PN_RXLEN * 5, M_DEVBUF, M_NOWAIT);
- if (sc->pn_rx_buf == NULL) {
- printf("pn%d: no memory for workaround buffer\n", unit);
- bus_teardown_intr(dev, sc->pn_irq, sc->pn_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pn_res);
- bus_release_resource(dev, PN_RES, PN_RID, sc->pn_res);
- free(sc->pn_ldata_ptr, M_DEVBUF);
- error = ENXIO;
- goto fail;
- }
- } else {
- sc->pn_rx_war = 0;
- }
-#endif
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_softc = sc;
- ifp->if_unit = unit;
- ifp->if_name = "pn";
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = pn_ioctl;
- ifp->if_output = ether_output;
- ifp->if_start = pn_start;
- ifp->if_watchdog = pn_watchdog;
- ifp->if_init = pn_init;
- ifp->if_baudrate = 10000000;
- ifp->if_snd.ifq_maxlen = PN_TX_LIST_CNT - 1;
-
- ifmedia_init(&sc->ifmedia, 0, pn_ifmedia_upd, pn_ifmedia_sts);
-
- if (bootverbose)
- printf("pn%d: probing for a PHY\n", sc->pn_unit);
- for (i = PN_PHYADDR_MIN; i < PN_PHYADDR_MAX + 1; i++) {
- if (bootverbose)
- printf("pn%d: checking address: %d\n",
- sc->pn_unit, i);
- sc->pn_phy_addr = i;
- pn_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(pn_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
- if ((phy_sts = pn_phy_readreg(sc, PHY_BMSR)))
- break;
- }
- if (phy_sts) {
- phy_vid = pn_phy_readreg(sc, PHY_VENID);
- phy_did = pn_phy_readreg(sc, PHY_DEVID);
- if (bootverbose)
- printf("pn%d: found PHY at address %d, ",
- sc->pn_unit, sc->pn_phy_addr);
- if (bootverbose)
- printf("vendor id: %x device id: %x\n",
- phy_vid, phy_did);
- p = pn_phys;
- while(p->pn_vid) {
- if (phy_vid == p->pn_vid &&
- (phy_did | 0x000F) == p->pn_did) {
- sc->pn_pinfo = p;
- break;
- }
- p++;
- }
- if (sc->pn_pinfo == NULL)
- sc->pn_pinfo = &pn_phys[PHY_UNKNOWN];
- if (bootverbose)
- printf("pn%d: PHY type: %s\n",
- sc->pn_unit, sc->pn_pinfo->pn_name);
-
- pn_getmode_mii(sc);
- if (cold) {
- pn_autoneg_mii(sc, PN_FLAG_FORCEDELAY, 1);
- pn_stop(sc);
- } else {
- pn_init(sc);
- pn_autoneg_mii(sc, PN_FLAG_SCHEDDELAY, 1);
- }
- } else {
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
- ifmedia_add(&sc->ifmedia,
- IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL);
- ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
- pn_init(sc);
- if (cold) {
- pn_autoneg(sc, PN_FLAG_FORCEDELAY, 1);
- pn_stop(sc);
- } else {
- pn_init(sc);
- pn_autoneg(sc, PN_FLAG_SCHEDDELAY, 1);
- }
- }
-
- media = sc->ifmedia.ifm_media;
- ifmedia_set(&sc->ifmedia, media);
-
- /*
- * Call MI attach routines.
- */
- if_attach(ifp);
- ether_ifattach(ifp);
-
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-
-fail:
- splx(s);
- return(error);
-}
-
-static int pn_detach(dev)
- device_t dev;
-{
- struct pn_softc *sc;
- struct ifnet *ifp;
- int s;
-
- s = splimp();
-
- sc = device_get_softc(dev);
- ifp = &sc->arpcom.ac_if;
-
- if_detach(ifp);
- pn_stop(sc);
-
- bus_teardown_intr(dev, sc->pn_irq, sc->pn_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pn_res);
- bus_release_resource(dev, PN_RES, PN_RID, sc->pn_res);
-
- free(sc->pn_ldata_ptr, M_DEVBUF);
-#ifdef PN_RX_BUG_WAR
- if (sc->pn_rx_war)
- free(sc->pn_rx_buf, M_DEVBUF);
-#endif
- ifmedia_removeall(&sc->ifmedia);
-
- splx(s);
-
- return(0);
-}
-
-/*
- * Initialize the transmit descriptors.
- */
-static int pn_list_tx_init(sc)
- struct pn_softc *sc;
-{
- struct pn_chain_data *cd;
- struct pn_list_data *ld;
- int i;
-
- cd = &sc->pn_cdata;
- ld = sc->pn_ldata;
- for (i = 0; i < PN_TX_LIST_CNT; i++) {
- cd->pn_tx_chain[i].pn_ptr = &ld->pn_tx_list[i];
- if (i == (PN_TX_LIST_CNT - 1))
- cd->pn_tx_chain[i].pn_nextdesc =
- &cd->pn_tx_chain[0];
- else
- cd->pn_tx_chain[i].pn_nextdesc =
- &cd->pn_tx_chain[i + 1];
- }
-
- cd->pn_tx_free = &cd->pn_tx_chain[0];
- cd->pn_tx_tail = cd->pn_tx_head = NULL;
-
- return(0);
-}
-
-
-/*
- * Initialize the RX descriptors and allocate mbufs for them. Note that
- * we arrange the descriptors in a closed ring, so that the last descriptor
- * points back to the first.
- */
-static int pn_list_rx_init(sc)
- struct pn_softc *sc;
-{
- struct pn_chain_data *cd;
- struct pn_list_data *ld;
- int i;
-
- cd = &sc->pn_cdata;
- ld = sc->pn_ldata;
-
- for (i = 0; i < PN_RX_LIST_CNT; i++) {
- cd->pn_rx_chain[i].pn_ptr =
- (struct pn_desc *)&ld->pn_rx_list[i];
- if (pn_newbuf(sc, &cd->pn_rx_chain[i], NULL) == ENOBUFS)
- return(ENOBUFS);
- if (i == (PN_RX_LIST_CNT - 1)) {
- cd->pn_rx_chain[i].pn_nextdesc = &cd->pn_rx_chain[0];
- ld->pn_rx_list[i].pn_next =
- vtophys(&ld->pn_rx_list[0]);
- } else {
- cd->pn_rx_chain[i].pn_nextdesc = &cd->pn_rx_chain[i + 1];
- ld->pn_rx_list[i].pn_next =
- vtophys(&ld->pn_rx_list[i + 1]);
- }
- }
-
- cd->pn_rx_head = &cd->pn_rx_chain[0];
-
- return(0);
-}
-
-/*
- * Initialize an RX descriptor and attach an MBUF cluster.
- * Note: the length fields are only 11 bits wide, which means the
- * largest size we can specify is 2047. This is important because
- * MCLBYTES is 2048, so we have to subtract one otherwise we'll
- * overflow the field and make a mess.
- */
-static int pn_newbuf(sc, c, m)
- struct pn_softc *sc;
- struct pn_chain_onefrag *c;
- struct mbuf *m;
-{
- struct mbuf *m_new = NULL;
-
- if (m == NULL) {
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("pn%d: no memory for rx list "
- "-- packet dropped!\n", sc->pn_unit);
- return(ENOBUFS);
- }
-
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- printf("pn%d: no memory for rx list -- "
- "packet dropped!\n", sc->pn_unit);
- m_freem(m_new);
- return(ENOBUFS);
- }
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- } else {
- m_new = m;
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- m_new->m_data = m_new->m_ext.ext_buf;
- }
-
- /*
- * Leave a couple of empty leading bytes; we'll need them later
- * when we fix up things for proper payload alignment.
- */
- m_adj(m_new, sizeof(u_int64_t));
-
-#ifdef PN_RX_BUG_WAR
- /*
- * Zero the buffer. This is part of the workaround for the
- * promiscuous mode bug in the revision 33 PNIC chips.
- */
- if (sc->pn_rx_war)
- bzero((char *)mtod(m_new, char *), m_new->m_len);
-#endif
-
- c->pn_mbuf = m_new;
- c->pn_ptr->pn_data = vtophys(mtod(m_new, caddr_t));
- c->pn_ptr->pn_ctl = PN_RXCTL_RLINK | PN_RXLEN;
- c->pn_ptr->pn_status = PN_RXSTAT;
-
- return(0);
-}
-
-#ifdef PN_RX_BUG_WAR
-/*
- * Grrrrr.
- * The PNIC chip has a terrible bug in it that manifests itself during
- * periods of heavy activity. The exact mode of failure if difficult to
- * pinpoint: sometimes it only happens in promiscuous mode, sometimes it
- * will happen on slow machines. The bug is that sometimes instead of
- * uploading one complete frame during reception, it uploads what looks
- * like the entire contents of its FIFO memory. The frame we want is at
- * the end of the whole mess, but we never know exactly how much data has
- * been uploaded, so salvaging the frame is hard.
- *
- * There is only one way to do it reliably, and it's disgusting.
- * Here's what we know:
- *
- * - We know there will always be somewhere between one and three extra
- * descriptors uploaded.
- *
- * - We know the desired received frame will always be at the end of the
- * total data upload.
- *
- * - We know the size of the desired received frame because it will be
- * provided in the length field of the status word in the last descriptor.
- *
- * Here's what we do:
- *
- * - When we allocate buffers for the receive ring, we bzero() them.
- * This means that we know that the buffer contents should be all
- * zeros, except for data uploaded by the chip.
- *
- * - We also force the PNIC chip to upload frames that include the
- * ethernet CRC at the end.
- *
- * - We gather all of the bogus frame data into a single buffer.
- *
- * - We then position a pointer at the end of this buffer and scan
- * backwards until we encounter the first non-zero byte of data.
- * This is the end of the received frame. We know we will encounter
- * some data at the end of the frame because the CRC will always be
- * there, so even if the sender transmits a packet of all zeros,
- * we won't be fooled.
- *
- * - We know the size of the actual received frame, so we subtract
- * that value from the current pointer location. This brings us
- * to the start of the actual received packet.
- *
- * - We copy this into an mbuf and pass it on, along with the actual
- * frame length.
- *
- * The performance hit is tremendous, but it beats dropping frames all
- * the time.
- */
-
-#define PN_WHOLEFRAME (PN_RXSTAT_FIRSTFRAG|PN_RXSTAT_LASTFRAG)
-static void pn_rx_bug_war(sc, cur_rx)
- struct pn_softc *sc;
- struct pn_chain_onefrag *cur_rx;
-{
- struct pn_chain_onefrag *c;
- unsigned char *ptr;
- int total_len;
- u_int32_t rxstat = 0;
-
- c = sc->pn_rx_bug_save;
- ptr = sc->pn_rx_buf;
- bzero(ptr, sizeof(PN_RXLEN * 5));
-
- /* Copy all the bytes from the bogus buffers. */
- while ((c->pn_ptr->pn_status & PN_WHOLEFRAME) != PN_WHOLEFRAME) {
- rxstat = c->pn_ptr->pn_status;
- m_copydata(c->pn_mbuf, 0, PN_RXLEN, ptr);
- ptr += PN_RXLEN;
- if (c == cur_rx)
- break;
- if (rxstat & PN_RXSTAT_LASTFRAG)
- break;
- c->pn_ptr->pn_status = PN_RXSTAT;
- c->pn_ptr->pn_ctl = PN_RXCTL_RLINK | PN_RXLEN;
- bzero((char *)mtod(c->pn_mbuf, char *), MCLBYTES);
- c = c->pn_nextdesc;
- }
-
- /* Find the length of the actual receive frame. */
- total_len = PN_RXBYTES(rxstat);
-
- /* Scan backwards until we hit a non-zero byte. */
- while(*ptr == 0x00)
- ptr--;
-
- /* Round off. */
- if ((uintptr_t)(ptr) & 0x3)
- ptr -= 1;
-
- /* Now find the start of the frame. */
- ptr -= total_len;
- if (ptr < sc->pn_rx_buf)
- ptr = sc->pn_rx_buf;
-
- /*
- * Now copy the salvaged frame to the last mbuf and fake up
- * the status word to make it look like a successful
- * frame reception.
- */
- m_copyback(cur_rx->pn_mbuf, 0, total_len, ptr);
- cur_rx->pn_mbuf->m_len = c->pn_mbuf->m_pkthdr.len = MCLBYTES;
- cur_rx->pn_ptr->pn_status |= PN_RXSTAT_FIRSTFRAG;
-
- return;
-}
-#endif
-
-/*
- * A frame has been uploaded: pass the resulting mbuf chain up to
- * the higher level protocols.
- */
-static void pn_rxeof(sc)
- struct pn_softc *sc;
-{
- struct ether_header *eh;
- struct mbuf *m;
- struct ifnet *ifp;
- struct pn_chain_onefrag *cur_rx;
- int total_len = 0;
- u_int32_t rxstat;
-
- ifp = &sc->arpcom.ac_if;
-
- while(!((rxstat = sc->pn_cdata.pn_rx_head->pn_ptr->pn_status) &
- PN_RXSTAT_OWN)) {
- struct mbuf *m0 = NULL;
-
- cur_rx = sc->pn_cdata.pn_rx_head;
- sc->pn_cdata.pn_rx_head = cur_rx->pn_nextdesc;
-
-#ifdef PN_RX_BUG_WAR
- /*
- * XXX The PNIC has a nasty receiver bug that manifests
- * under certain conditions (sometimes only in promiscuous
- * mode, sometimes only on slow machines even when not in
- * promiscuous mode). We have to keep an eye out for the
- * failure condition and employ a workaround to recover
- * any mangled frames.
- */
- if (sc->pn_rx_war) {
- if ((rxstat & PN_WHOLEFRAME) != PN_WHOLEFRAME) {
- if (rxstat & PN_RXSTAT_FIRSTFRAG)
- sc->pn_rx_bug_save = cur_rx;
- if ((rxstat & PN_RXSTAT_LASTFRAG) == 0)
- continue;
- pn_rx_bug_war(sc, cur_rx);
- rxstat = cur_rx->pn_ptr->pn_status;
- }
- }
-#endif
-
- /*
- * If an error occurs, update stats, clear the
- * status word and leave the mbuf cluster in place:
- * it should simply get re-used next time this descriptor
- * comes up in the ring.
- */
- if (rxstat & PN_RXSTAT_RXERR) {
- ifp->if_ierrors++;
- if (rxstat & PN_RXSTAT_COLLSEEN)
- ifp->if_collisions++;
- pn_newbuf(sc, cur_rx, cur_rx->pn_mbuf);
- continue;
- }
-
- /* No errors; receive the packet. */
- m = cur_rx->pn_mbuf;
- total_len = PN_RXBYTES(cur_rx->pn_ptr->pn_status);
-
- /* Trim off the CRC. */
- total_len -= ETHER_CRC_LEN;
-
- m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
- total_len + ETHER_ALIGN, 0, ifp, NULL);
- pn_newbuf(sc, cur_rx, m);
- if (m0 == NULL) {
- ifp->if_ierrors++;
- continue;
- }
- m_adj(m0, ETHER_ALIGN);
- m = m0;
- ifp->if_ipackets++;
- eh = mtod(m, struct ether_header *);
-
-#ifdef BRIDGE
- if (do_bridge) {
- struct ifnet *bdg_ifp;
- bdg_ifp = bridge_in(m);
- if (bdg_ifp != BDG_LOCAL && bdg_ifp != BDG_DROP)
- bdg_forward(&m, bdg_ifp);
- if (((bdg_ifp != BDG_LOCAL) && (bdg_ifp != BDG_BCAST) &&
- (bdg_ifp != BDG_MCAST)) || bdg_ifp == BDG_DROP) {
- m_freem(m);
- continue;
- }
- }
-#endif
-
- /*
- * Handle BPF listeners. Let the BPF user see the packet, but
- * don't pass it up to the ether_input() layer unless it's
- * a broadcast packet, multicast packet, matches our ethernet
- * address or the interface is in promiscuous mode.
- */
- if (ifp->if_bpf) {
- bpf_mtap(ifp, m);
- if (ifp->if_flags & IFF_PROMISC &&
- (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
- ETHER_ADDR_LEN) &&
- (eh->ether_dhost[0] & 1) == 0)) {
- m_freem(m);
- continue;
- }
- }
-
- /* Remove header from mbuf and pass it on. */
- m_adj(m, sizeof(struct ether_header));
- ether_input(ifp, eh, m);
- }
-
- return;
-}
-
-void pn_rxeoc(sc)
- struct pn_softc *sc;
-{
-
- pn_rxeof(sc);
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_RX_ON);
- CSR_WRITE_4(sc, PN_RXADDR, vtophys(sc->pn_cdata.pn_rx_head->pn_ptr));
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_RX_ON);
- CSR_WRITE_4(sc, PN_RXSTART, 0xFFFFFFFF);
-
- return;
-}
-
-/*
- * A frame was downloaded to the chip. It's safe for us to clean up
- * the list buffers.
- */
-
-static void pn_txeof(sc)
- struct pn_softc *sc;
-{
- struct pn_chain *cur_tx;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- /* Clear the timeout timer. */
- ifp->if_timer = 0;
-
- if (sc->pn_cdata.pn_tx_head == NULL)
- return;
-
- /*
- * Go through our tx list and free mbufs for those
- * frames that have been transmitted.
- */
- while(sc->pn_cdata.pn_tx_head->pn_mbuf != NULL) {
- u_int32_t txstat;
-
- cur_tx = sc->pn_cdata.pn_tx_head;
- txstat = PN_TXSTATUS(cur_tx);
-
- if (txstat & PN_TXSTAT_OWN)
- break;
-
- if (txstat & PN_TXSTAT_ERRSUM) {
- ifp->if_oerrors++;
- if (txstat & PN_TXSTAT_EXCESSCOLL)
- ifp->if_collisions++;
- if (txstat & PN_TXSTAT_LATECOLL)
- ifp->if_collisions++;
- }
-
- ifp->if_collisions += (txstat & PN_TXSTAT_COLLCNT) >> 3;
-
-
- ifp->if_opackets++;
- m_freem(cur_tx->pn_mbuf);
- cur_tx->pn_mbuf = NULL;
-
- if (sc->pn_cdata.pn_tx_head == sc->pn_cdata.pn_tx_tail) {
- sc->pn_cdata.pn_tx_head = NULL;
- sc->pn_cdata.pn_tx_tail = NULL;
- break;
- }
-
- sc->pn_cdata.pn_tx_head = cur_tx->pn_nextdesc;
- }
-
- return;
-}
-
-/*
- * TX 'end of channel' interrupt handler.
- */
-static void pn_txeoc(sc)
- struct pn_softc *sc;
-{
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- ifp->if_timer = 0;
-
- if (sc->pn_cdata.pn_tx_head == NULL) {
- ifp->if_flags &= ~IFF_OACTIVE;
- sc->pn_cdata.pn_tx_tail = NULL;
- if (sc->pn_want_auto) {
- if (sc->pn_pinfo == NULL)
- pn_autoneg(sc, PN_FLAG_SCHEDDELAY, 1);
- else
- pn_autoneg_mii(sc, PN_FLAG_SCHEDDELAY, 1);
- }
-
- }
-
- return;
-}
-
-static void pn_intr(arg)
- void *arg;
-{
- struct pn_softc *sc;
- struct ifnet *ifp;
- u_int32_t status;
-
- sc = arg;
- ifp = &sc->arpcom.ac_if;
-
- /* Supress unwanted interrupts. */
- if (!(ifp->if_flags & IFF_UP)) {
- pn_stop(sc);
- return;
- }
-
- /* Disable interrupts. */
- CSR_WRITE_4(sc, PN_IMR, 0x00000000);
-
- for (;;) {
- status = CSR_READ_4(sc, PN_ISR);
- if (status)
- CSR_WRITE_4(sc, PN_ISR, status);
-
- if ((status & PN_INTRS) == 0)
- break;
-
- if (status & PN_ISR_RX_OK)
- pn_rxeof(sc);
-
- if ((status & PN_ISR_RX_WATCHDOG) || (status & PN_ISR_RX_IDLE)
- || (status & PN_ISR_RX_NOBUF))
- pn_rxeoc(sc);
-
- if (status & PN_ISR_TX_OK)
- pn_txeof(sc);
-
- if (status & PN_ISR_TX_NOBUF)
- pn_txeoc(sc);
-
- if (status & PN_ISR_TX_IDLE) {
- pn_txeof(sc);
- if (sc->pn_cdata.pn_tx_head != NULL) {
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON);
- CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
- }
- }
-
- if (status & PN_ISR_TX_UNDERRUN) {
- ifp->if_oerrors++;
- pn_txeof(sc);
- if (sc->pn_cdata.pn_tx_head != NULL) {
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON);
- CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
- }
- }
-
- if (status & PN_ISR_BUS_ERR) {
- pn_reset(sc);
- pn_init(sc);
- }
- }
-
- /* Re-enable interrupts. */
- CSR_WRITE_4(sc, PN_IMR, PN_INTRS);
-
- if (ifp->if_snd.ifq_head != NULL) {
- pn_start(ifp);
- }
-
- return;
-}
-
-/*
- * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
- * pointers to the fragment pointers.
- */
-static int pn_encap(sc, c, m_head)
- struct pn_softc *sc;
- struct pn_chain *c;
- struct mbuf *m_head;
-{
- int frag = 0;
- struct pn_desc *f = NULL;
- int total_len;
- struct mbuf *m;
-
- /*
- * Start packing the mbufs in this chain into
- * the fragment pointers. Stop when we run out
- * of fragments or hit the end of the mbuf chain.
- */
- m = m_head;
- total_len = 0;
-
- for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
- if (m->m_len != 0) {
- if (frag == PN_MAXFRAGS)
- break;
- total_len += m->m_len;
- f = &c->pn_ptr->pn_frag[frag];
- f->pn_ctl = PN_TXCTL_TLINK | m->m_len;
- if (frag == 0) {
- f->pn_ctl |= PN_TXCTL_FIRSTFRAG;
- f->pn_status = 0;
- } else
- f->pn_status = PN_TXSTAT_OWN;
- f->pn_data = vtophys(mtod(m, vm_offset_t));
- f->pn_next = vtophys(&c->pn_ptr->pn_frag[frag + 1]);
- frag++;
- }
- }
-
- /*
- * Handle special case: we used up all 16 fragments,
- * but we have more mbufs left in the chain. Copy the
- * data into an mbuf cluster. Note that we don't
- * bother clearing the values in the other fragment
- * pointers/counters; it wouldn't gain us anything,
- * and would waste cycles.
- */
- if (m != NULL) {
- struct mbuf *m_new = NULL;
-
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("pn%d: no memory for tx list", sc->pn_unit);
- return(1);
- }
- if (m_head->m_pkthdr.len > MHLEN) {
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- printf("pn%d: no memory for tx list",
- sc->pn_unit);
- return(1);
- }
- }
- m_copydata(m_head, 0, m_head->m_pkthdr.len,
- mtod(m_new, caddr_t));
- m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
- m_freem(m_head);
- m_head = m_new;
- f = &c->pn_ptr->pn_frag[0];
- f->pn_data = vtophys(mtod(m_new, caddr_t));
- f->pn_ctl = total_len = m_new->m_len;
- f->pn_ctl |= PN_TXCTL_TLINK|PN_TXCTL_FIRSTFRAG;
- frag = 1;
- }
-
-
- c->pn_mbuf = m_head;
- c->pn_lastdesc = frag - 1;
- PN_TXCTL(c) |= PN_TXCTL_LASTFRAG|PN_TXCTL_FINT;
- PN_TXNEXT(c) = vtophys(&c->pn_nextdesc->pn_ptr->pn_frag[0]);
-
- return(0);
-}
-
-/*
- * Main transmit routine. To avoid having to do mbuf copies, we put pointers
- * to the mbuf data regions directly in the transmit lists. We also save a
- * copy of the pointers since the transmit list fragment pointers are
- * physical addresses.
- */
-
-static void pn_start(ifp)
- struct ifnet *ifp;
-{
- struct pn_softc *sc;
- struct mbuf *m_head = NULL;
- struct pn_chain *cur_tx = NULL, *start_tx;
-
- sc = ifp->if_softc;
-
- if (sc->pn_autoneg) {
- sc->pn_tx_pend = 1;
- return;
- }
-
- /*
- * Check for an available queue slot. If there are none,
- * punt.
- */
- if (sc->pn_cdata.pn_tx_free->pn_mbuf != NULL) {
- ifp->if_flags |= IFF_OACTIVE;
- return;
- }
-
- start_tx = sc->pn_cdata.pn_tx_free;
-
- while(sc->pn_cdata.pn_tx_free->pn_mbuf == NULL) {
- IF_DEQUEUE(&ifp->if_snd, m_head);
- if (m_head == NULL)
- break;
-
- /* Pick a descriptor off the free list. */
- cur_tx = sc->pn_cdata.pn_tx_free;
- sc->pn_cdata.pn_tx_free = cur_tx->pn_nextdesc;
-
- /* Pack the data into the descriptor. */
- pn_encap(sc, cur_tx, m_head);
-
- if (cur_tx != start_tx)
- PN_TXOWN(cur_tx) = PN_TXSTAT_OWN;
-
- /*
- * If there's a BPF listener, bounce a copy of this frame
- * to him.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp, cur_tx->pn_mbuf);
-
- PN_TXOWN(cur_tx) = PN_TXSTAT_OWN;
- CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
- }
-
- /*
- * If there are no packets queued, bail.
- */
- if (cur_tx == NULL)
- return;
-
- sc->pn_cdata.pn_tx_tail = cur_tx;
-
- if (sc->pn_cdata.pn_tx_head == NULL)
- sc->pn_cdata.pn_tx_head = start_tx;
-
- /*
- * Set a timeout in case the chip goes out to lunch.
- */
- ifp->if_timer = 5;
-
- return;
-}
-
-static void pn_init(xsc)
- void *xsc;
-{
- struct pn_softc *sc = xsc;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- u_int16_t phy_bmcr = 0;
- int s;
-
- if (sc->pn_autoneg)
- return;
-
- s = splimp();
-
- if (sc->pn_pinfo != NULL)
- phy_bmcr = pn_phy_readreg(sc, PHY_BMCR);
-
- /*
- * Cancel pending I/O and free all RX/TX buffers.
- */
- pn_stop(sc);
- pn_reset(sc);
-
- /*
- * Set cache alignment and burst length.
- */
- CSR_WRITE_4(sc, PN_BUSCTL, PN_BUSCTL_MUSTBEONE|PN_BUSCTL_ARBITRATION);
- PN_SETBIT(sc, PN_BUSCTL, PN_BURSTLEN_16LONG);
- switch(sc->pn_cachesize) {
- case 32:
- PN_SETBIT(sc, PN_BUSCTL, PN_CACHEALIGN_32LONG);
- break;
- case 16:
- PN_SETBIT(sc, PN_BUSCTL, PN_CACHEALIGN_16LONG);
- break;
- case 8:
- PN_SETBIT(sc, PN_BUSCTL, PN_CACHEALIGN_8LONG);
- break;
- case 0:
- default:
- PN_SETBIT(sc, PN_BUSCTL, PN_CACHEALIGN_NONE);
- break;
- }
-
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_IMMEDIATE);
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_NO_RXCRC);
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_HEARTBEAT);
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_STORENFWD);
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_BACKOFF);
-
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_THRESH);
- PN_SETBIT(sc, PN_NETCFG, PN_TXTHRESH_72BYTES);
-
- if (sc->pn_pinfo == NULL) {
- PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_MIIENB);
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_BACKOFF);
- } else {
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_MIIENB);
- PN_SETBIT(sc, PN_ENDEC, PN_ENDEC_JABBERDIS);
- }
-
- pn_setcfg(sc, sc->ifmedia.ifm_media);
-
- /* Init circular RX list. */
- if (pn_list_rx_init(sc) == ENOBUFS) {
- printf("pn%d: initialization failed: no "
- "memory for rx buffers\n", sc->pn_unit);
- pn_stop(sc);
- (void)splx(s);
- return;
- }
-
- /*
- * Init tx descriptors.
- */
- pn_list_tx_init(sc);
-
- /*
- * Load the address of the RX list.
- */
- CSR_WRITE_4(sc, PN_RXADDR, vtophys(sc->pn_cdata.pn_rx_head->pn_ptr));
-
- /*
- * Load the RX/multicast filter.
- */
- pn_setfilt(sc);
-
- /*
- * Enable interrupts.
- */
- CSR_WRITE_4(sc, PN_IMR, PN_INTRS);
- CSR_WRITE_4(sc, PN_ISR, 0xFFFFFFFF);
-
- /* Enable receiver and transmitter. */
- PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON|PN_NETCFG_RX_ON);
- CSR_WRITE_4(sc, PN_RXSTART, 0xFFFFFFFF);
-
- /* Restore state of BMCR */
- if (sc->pn_pinfo != NULL)
- pn_phy_writereg(sc, PHY_BMCR, phy_bmcr);
-
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
-
- (void)splx(s);
-
- return;
-}
-
-/*
- * Set media options.
- */
-static int pn_ifmedia_upd(ifp)
- struct ifnet *ifp;
-{
- struct pn_softc *sc;
- struct ifmedia *ifm;
-
- sc = ifp->if_softc;
- ifm = &sc->ifmedia;
-
- if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
- return(EINVAL);
-
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
- if (sc->pn_pinfo == NULL)
- pn_autoneg(sc, PN_FLAG_SCHEDDELAY, 1);
- else
- pn_autoneg_mii(sc, PN_FLAG_SCHEDDELAY, 1);
- } else {
- if (sc->pn_pinfo == NULL)
- pn_setmode(sc, ifm->ifm_media);
- else
- pn_setmode_mii(sc, ifm->ifm_media);
- }
-
- return(0);
-}
-
-/*
- * Report current media status.
- */
-static void pn_ifmedia_sts(ifp, ifmr)
- struct ifnet *ifp;
- struct ifmediareq *ifmr;
-{
- struct pn_softc *sc;
- u_int16_t advert = 0, ability = 0;
-
- sc = ifp->if_softc;
-
- ifmr->ifm_active = IFM_ETHER;
-
- if (sc->pn_pinfo == NULL) {
- if (CSR_READ_4(sc, PN_NETCFG) & PN_NETCFG_SPEEDSEL)
- ifmr->ifm_active = IFM_ETHER|IFM_10_T;
- else
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX;
- if (CSR_READ_4(sc, PN_NETCFG) & PN_NETCFG_FULLDUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- return;
- }
-
- if (!(pn_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) {
- if (pn_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL)
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX;
- else
- ifmr->ifm_active = IFM_ETHER|IFM_10_T;
- if (pn_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- return;
- }
-
- ability = pn_phy_readreg(sc, PHY_LPAR);
- advert = pn_phy_readreg(sc, PHY_ANAR);
- if (advert & PHY_ANAR_100BT4 &&
- ability & PHY_ANAR_100BT4) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_T4;
- } else if (advert & PHY_ANAR_100BTXFULL &&
- ability & PHY_ANAR_100BTXFULL) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX;
- } else if (advert & PHY_ANAR_100BTXHALF &&
- ability & PHY_ANAR_100BTXHALF) {
- ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX;
- } else if (advert & PHY_ANAR_10BTFULL &&
- ability & PHY_ANAR_10BTFULL) {
- ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX;
- } else if (advert & PHY_ANAR_10BTHALF &&
- ability & PHY_ANAR_10BTHALF) {
- ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX;
- }
-
- return;
-}
-
-static int pn_ioctl(ifp, command, data)
- struct ifnet *ifp;
- u_long command;
- caddr_t data;
-{
- struct pn_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:
- if (ifp->if_flags & IFF_UP) {
- pn_init(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- pn_stop(sc);
- }
- error = 0;
- break;
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- pn_init(sc);
- error = 0;
- break;
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
- break;
- default:
- error = EINVAL;
- break;
- }
-
- (void)splx(s);
-
- return(error);
-}
-
-static void pn_watchdog(ifp)
- struct ifnet *ifp;
-{
- struct pn_softc *sc;
-
- sc = ifp->if_softc;
-
- if (sc->pn_autoneg) {
- if (sc->pn_pinfo == NULL)
- pn_autoneg(sc, PN_FLAG_DELAYTIMEO, 1);
- else
- pn_autoneg_mii(sc, PN_FLAG_DELAYTIMEO, 1);
- if (!(ifp->if_flags & IFF_UP))
- pn_stop(sc);
- return;
- }
-
- ifp->if_oerrors++;
- printf("pn%d: watchdog timeout\n", sc->pn_unit);
-
- if (!(pn_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
- printf("pn%d: no carrier - transceiver cable problem?\n",
- sc->pn_unit);
- pn_stop(sc);
- pn_reset(sc);
- pn_init(sc);
-
- if (ifp->if_snd.ifq_head != NULL)
- pn_start(ifp);
-
- return;
-}
-
-/*
- * Stop the adapter and free any mbufs allocated to the
- * RX and TX lists.
- */
-static void pn_stop(sc)
- struct pn_softc *sc;
-{
- register int i;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
- ifp->if_timer = 0;
-
- PN_CLRBIT(sc, PN_NETCFG, (PN_NETCFG_RX_ON|PN_NETCFG_TX_ON));
- CSR_WRITE_4(sc, PN_IMR, 0x00000000);
- CSR_WRITE_4(sc, PN_TXADDR, 0x00000000);
- CSR_WRITE_4(sc, PN_RXADDR, 0x00000000);
-
- /*
- * Free data in the RX lists.
- */
- for (i = 0; i < PN_RX_LIST_CNT; i++) {
- if (sc->pn_cdata.pn_rx_chain[i].pn_mbuf != NULL) {
- m_freem(sc->pn_cdata.pn_rx_chain[i].pn_mbuf);
- sc->pn_cdata.pn_rx_chain[i].pn_mbuf = NULL;
- }
- }
- bzero((char *)&sc->pn_ldata->pn_rx_list,
- sizeof(sc->pn_ldata->pn_rx_list));
-
- /*
- * Free the TX list buffers.
- */
- for (i = 0; i < PN_TX_LIST_CNT; i++) {
- if (sc->pn_cdata.pn_tx_chain[i].pn_mbuf != NULL) {
- m_freem(sc->pn_cdata.pn_tx_chain[i].pn_mbuf);
- sc->pn_cdata.pn_tx_chain[i].pn_mbuf = NULL;
- }
- }
-
- bzero((char *)&sc->pn_ldata->pn_tx_list,
- sizeof(sc->pn_ldata->pn_tx_list));
-
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-
- return;
-}
-
-/*
- * Stop all chip I/O so that the kernel's probe routines don't
- * get confused by errant DMAs when rebooting.
- */
-static void pn_shutdown(dev)
- device_t dev;
-{
- struct pn_softc *sc;
-
- sc = device_get_softc(dev);
-
- pn_stop(sc);
-
- return;
-}
diff --git a/sys/pci/if_pnreg.h b/sys/pci/if_pnreg.h
deleted file mode 100644
index 0c567d0..0000000
--- a/sys/pci/if_pnreg.h
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * Copyright (c) 1997, 1998
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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$
- */
-
-/*
- * PNIC register definitions.
- */
-
-#define PN_BUSCTL 0x00 /* bus control */
-#define PN_TXSTART 0x08 /* tx start demand */
-#define PN_RXSTART 0x10 /* rx start demand */
-#define PN_RXADDR 0x18 /* rx descriptor list start addr */
-#define PN_TXADDR 0x20 /* tx descriptor list start addr */
-#define PN_ISR 0x28 /* interrupt status register */
-#define PN_NETCFG 0x30 /* network config register */
-#define PN_IMR 0x38 /* interrupt mask */
-#define PN_FRAMESDISCARDED 0x40 /* # of discarded frames */
-#define PN_SIO 0x48 /* MII and ROM/EEPROM access */
-#define PN_GEN 0x60 /* general purpose register */
-#define PN_ENDEC 0x78 /* ENDEC general register */
-#define PN_SIOPWR 0x90 /* serial eeprom power up */
-#define PN_SIOCTL 0x98 /* EEPROM control register */
-#define PN_MII 0xA0 /* MII access register */
-#define PN_NWAY 0xB8 /* Internal NWAY register */
-
-/*
- * Bus control bits.
- */
-#define PN_BUSCTL_RESET 0x00000001
-#define PN_BUSCTL_ARBITRATION 0x00000002
-#define PN_BUSCTL_SKIPLEN 0x0000007C
-#define PN_BUSCTL_BUF_BIGENDIAN 0x00000080
-#define PN_BUSCTL_BURSTLEN 0x00003F00
-#define PN_BUSCTL_CACHEALIGN 0x0000C000
-#define PN_BUSCTL_TXPOLL 0x000E0000
-#define PN_BUSCTL_MUSTBEONE 0x04000000
-
-#define PN_SKIPLEN_1LONG 0x00000004
-#define PN_SKIPLEN_2LONG 0x00000008
-#define PN_SKIPLEN_3LONG 0x00000010
-#define PN_SKIPLEN_4LONG 0x00000020
-#define PN_SKIPLEN_5LONG 0x00000040
-
-#define PN_CACHEALIGN_NONE 0x00000000
-#define PN_CACHEALIGN_8LONG 0x00004000
-#define PN_CACHEALIGN_16LONG 0x00008000
-#define PN_CACHEALIGN_32LONG 0x0000C000
-
-#define PN_BURSTLEN_USECA 0x00000000
-#define PN_BURSTLEN_1LONG 0x00000100
-#define PN_BURSTLEN_2LONG 0x00000200
-#define PN_BURSTLEN_4LONG 0x00000400
-#define PN_BURSTLEN_8LONG 0x00000800
-#define PN_BURSTLEN_16LONG 0x00001000
-#define PN_BURSTLEN_32LONG 0x00002000
-
-#define PN_TXPOLL_OFF 0x00000000
-#define PN_TXPOLL_200U 0x00020000
-#define PN_TXPOLL_800U 0x00040000
-#define PN_TXPOLL_1600U 0x00060000
-#define PN_TXPOLL_12_8M 0x00080000
-#define PN_TXPOLL_25_6M 0x000A0000
-#define PN_TXPOLL_51_2M 0x000C0000
-#define PN_TXPOLL_102_4M 0x000E0000
-
-#define PN_BUSCTL_CONFIG \
- (PN_CACHEALIGN_8LONG|PN_BURSTLEN_8LONG)
-
-/*
- * Interrupt status bits.
- */
-#define PN_ISR_TX_OK 0x00000001 /* packet tx ok */
-#define PN_ISR_TX_IDLE 0x00000002 /* tx stopped */
-#define PN_ISR_TX_NOBUF 0x00000004 /* no tx buffer available */
-#define PN_ISR_TX_JABTIMEO 0x00000008 /* jabber timeout */
-#define PN_ISR_LINKPASS 0x00000010 /* link test pass */
-#define PN_ISR_TX_UNDERRUN 0x00000020 /* transmit underrun */
-#define PN_ISR_RX_OK 0x00000040 /* packet rx ok */
-#define PN_ISR_RX_NOBUF 0x00000080 /* rx buffer unavailable */
-#define PN_ISR_RX_IDLE 0x00000100 /* rx stopped */
-#define PN_ISR_RX_WATCHDOG 0x00000200 /* rx watchdog timeo */
-#define PN_ISR_TX_EARLY 0x00000400 /* rx watchdog timeo */
-#define PN_ISR_LINKFAIL 0x00001000
-#define PN_ISR_BUS_ERR 0x00002000
-#define PN_ISR_ABNORMAL 0x00008000
-#define PN_ISR_NORMAL 0x00010000
-#define PN_ISR_RX_STATE 0x000E0000
-#define PN_ISR_TX_STATE 0x00700000
-#define PN_ISR_BUSERRTYPE 0x03800000
-#define PN_ISR_TXABORT 0x04000000 /* tx abort */
-
-#define PN_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */
-#define PN_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */
-#define PN_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */
-#define PN_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */
-#define PN_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */
-#define PN_RXSTATE_CLOSE 0x000A0000 /* 101 - close rx desc */
-#define PN_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */
-#define PN_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */
-
-#define PN_TXSTATE_RESET 0x00000000 /* 000 - reset */
-#define PN_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */
-#define PN_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */
-#define PN_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */
-#define PN_TXSTATE_RSVD 0x00400000 /* 100 - reserved */
-#define PN_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */
-#define PN_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */
-#define PN_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */
-
-#define PN_BUSERR_PARITY 0x00000000
-#define PN_BUSERR_MASTABRT 0x00800000
-#define PN_BUSERR_TGTABRT 0x01000000
-#define PN_BUSERR_RSVD1 0x01800000
-#define PN_BUSERR_RSVD2 0x02000000
-
-/*
- * Network config bits.
- */
-#define PN_NETCFG_HASHPERF 0x00000001 /* 0 == perf, 1 == hash */
-#define PN_NETCFG_RX_ON 0x00000002
-#define PN_NETCFG_HASHONLY 0x00000004 /* 1 == allhash */
-#define PN_NETCFG_RX_PASSERR 0x00000008
-#define PN_NETCFG_INVERSFILT 0x00000010
-#define PN_NETCFG_BACKOFF 0x00000020
-#define PN_NETCFG_RX_PROMISC 0x00000040
-#define PN_NETCFG_RX_ALLMULTI 0x00000080
-#define PN_NETCFG_FLAKYOSC 0x00000100
-#define PN_NETCFG_FULLDUPLEX 0x00000200
-#define PN_NETCFG_OPERMODE 0x00000C00
-#define PN_NETCFG_FORCECOLL 0x00001000
-#define PN_NETCFG_TX_ON 0x00002000
-#define PN_NETCFG_TX_THRESH 0x0000C000
-#define PN_NETCFG_TX_BACKOFF 0x00020000
-#define PN_NETCFG_MIIENB 0x00040000 /* 1 == MII, 0 == internal */
-#define PN_NETCFG_HEARTBEAT 0x00080000 /* 1 == disabled */
-#define PN_NETCFG_TX_IMMEDIATE 0x00100000
-#define PN_NETCFG_STORENFWD 0x00200000
-#define PN_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10Mbps 0 == 100Mbps */
-#define PN_NETCFG_PCS 0x00800000 /* 1 == 100baseTX */
-#define PN_NETCFG_SCRAMBLER 0x01000000
-#define PN_NETCFG_NO_RXCRC 0x20000000
-#define PN_NETCFG_EXT_ENDEC 0x40000000 /* 1 == ext, 0 == int PHY */
-
-#define PN_OPMODE_NORM 0x00000000
-#define PN_OPMODE_INTLOOP 0x00000400
-#define PN_OPMODE_EXTLOOP 0x00000800
-
-#define PN_TXTHRESH_72BYTES 0x00000000
-#define PN_TXTHRESH_96BYTES 0x00004000
-#define PN_TXTHRESH_128BYTES 0x00008000
-#define PN_TXTHRESH_160BYTES 0x0000C000
-
-/*
- * Interrupt mask bits.
- */
-#define PN_IMR_TX_OK 0x00000001 /* packet tx ok */
-#define PN_IMR_TX_IDLE 0x00000002 /* tx stopped */
-#define PN_IMR_TX_NOBUF 0x00000004 /* no tx buffer available */
-#define PN_IMR_TX_JABTIMEO 0x00000008 /* jabber timeout */
-#define PN_IMR_LINKPASS 0x00000010 /* link test pass */
-#define PN_IMR_TX_UNDERRUN 0x00000020 /* transmit underrun */
-#define PN_IMR_RX_OK 0x00000040 /* packet rx ok */
-#define PN_IMR_RX_NOBUF 0x00000080 /* rx buffer unavailable */
-#define PN_IMR_RX_IDLE 0x00000100 /* rx stopped */
-#define PN_IMR_RX_WATCHDOG 0x00000200 /* rx watchdog timeo */
-#define PN_IMR_TX_EARLY 0x00000400 /* rx watchdog timeo */
-#define PN_IMR_BUS_ERR 0x00002000
-#define PN_IMR_ABNORMAL 0x00008000
-#define PN_IMR_NORMAL 0x00010000
-#define PN_ISR_TXABORT 0x04000000 /* tx abort */
-
-#define PN_INTRS \
- (PN_IMR_RX_OK|PN_IMR_TX_OK|PN_IMR_RX_NOBUF| \
- PN_IMR_TX_NOBUF|PN_IMR_TX_UNDERRUN|PN_IMR_BUS_ERR| \
- PN_IMR_ABNORMAL|PN_IMR_NORMAL)
-
-/*
- * Serial I/O (EEPROM/ROM) bits.
- */
-#define PN_SIO_DATA 0x0000003F
-#define PN_SIO_OPCODE 0x00000300
-#define PN_SIO_BUSY 0x80000000
-
-/*
- * SIOCTL/EEPROM bits
- */
-#define PN_EE_READ 0x600
-
-/*
- * General purpose register bits.
- */
-#define PN_GEN_CTL 0x000000F0
-#define PN_GEN_100TX_LINK 0x00000008
-#define PN_GEN_BNC_ENB 0x00000004
-#define PN_GEN_100TX_LOOP 0x00000002 /* 1 == normal, 0 == loop */
-#define PN_GEN_SPEEDSEL 0x00000001 /* 1 == 100Mbps, 0 == 10Mbps */
-#define PN_GEN_MUSTBEONE 0x00000030
-
-/*
- * General ENDEC bits.
- */
-#define PN_ENDEC_JABBERDIS 0x000000001 /* 1 == disable, 0 == enable */
-
-/*
- * MII bits.
- */
-#define PN_MII_DATA 0x0000FFFF
-#define PN_MII_REGADDR 0x007C0000
-#define PN_MII_PHYADDR 0x0F800000
-#define PN_MII_OPCODE 0x30000000
-#define PN_MII_RESERVED 0x00020000
-#define PN_MII_BUSY 0x80000000
-
-#define PN_MII_READ 0x60020000 /* read PHY command */
-#define PN_MII_WRITE 0x50020000 /* write PHY command */
-
-/*
- * Internal PHY NWAY register bits.
- */
-#define PN_NWAY_RESET 0x00000001 /* reset */
-#define PN_NWAY_PDOWN 0x00000002 /* power down */
-#define PN_NWAY_BYPASS 0x00000004 /* bypass */
-#define PN_NWAY_AUILOWCUR 0x00000008 /* AUI low current */
-#define PN_NWAY_TPEXTEND 0x00000010 /* low squelch voltage */
-#define PN_NWAY_POLARITY 0x00000020 /* 0 == on, 1 == off */
-#define PN_NWAY_TP 0x00000040 /* 1 == tp, 0 == AUI */
-#define PN_NWAY_AUIVOLT 0x00000080 /* 1 == full, 0 == half */
-#define PN_NWAY_DUPLEX 0x00000100 /* 1 == full, 0 == half */
-#define PN_NWAY_LINKTEST 0x00000200 /* 0 == on, 1 == off */
-#define PN_NWAY_AUTODETECT 0x00000400 /* 1 == off, 0 == on */
-#define PN_NWAY_SPEEDSEL 0x00000800 /* 0 == 10, 1 == 100 */
-#define PN_NWAY_NWAY_ENB 0x00001000 /* 0 == off, 1 == on */
-#define PN_NWAY_CAP10HALF 0x00002000
-#define PN_NWAY_CAP10FULL 0x00004000
-#define PN_NWAY_CAP100FULL 0x00008000
-#define PN_NWAY_CAP100HALF 0x00010000
-#define PN_NWAY_CAP100T4 0x00020000
-#define PN_NWAY_AUTONEGRSTR 0x02000000
-#define PN_NWAY_REMFAULT 0x04000000
-#define PN_NWAY_LPAR10HALF 0x08000000
-#define PN_NWAY_LPAR10FULL 0x10000000
-#define PN_NWAY_LPAR100FULL 0x20000000
-#define PN_NWAY_LPAR100HALF 0x40000000
-#define PN_NWAY_LPAR100T4 0x80000000
-
-/*
- * Nway register bits that must be set to turn on to initiate
- * an autoneg session with all modes advertized and AUI disabled.
- */
-#define PN_NWAY_AUTOENB \
- (PN_NWAY_AUILOWCUR|PN_NWAY_TPEXTEND|PN_NWAY_POLARITY|PN_NWAY_TP \
- |PN_NWAY_NWAY_ENB|PN_NWAY_CAP10HALF|PN_NWAY_CAP10FULL| \
- PN_NWAY_CAP100FULL|PN_NWAY_CAP100HALF|PN_NWAY_CAP100T4| \
- PN_NWAY_AUTONEGRSTR)
-
-#define PN_NWAY_MODE_10HD \
- (PN_NWAY_CAP10HALF|PN_NWAY_CAP10FULL| \
- PN_NWAY_CAP100FULL|PN_NWAY_CAP100HALF|PN_NWAY_CAP100T4| \
- PN_NWAY_AUILOWCUR|PN_NWAY_TPEXTEND|PN_NWAY_POLARITY| \
- PN_NWAY_TP)
-
-#define PN_NWAY_MODE_10FD \
- (PN_NWAY_CAP10HALF|PN_NWAY_CAP10FULL| \
- PN_NWAY_CAP100FULL|PN_NWAY_CAP100HALF|PN_NWAY_CAP100T4| \
- PN_NWAY_AUILOWCUR|PN_NWAY_TPEXTEND|PN_NWAY_POLARITY| \
- PN_NWAY_TP|PN_NWAY_DUPLEX)
-
-#define PN_NWAY_MODE_100HD \
- (PN_NWAY_CAP10HALF|PN_NWAY_CAP10FULL| \
- PN_NWAY_CAP100FULL|PN_NWAY_CAP100HALF|PN_NWAY_CAP100T4| \
- PN_NWAY_AUILOWCUR|PN_NWAY_TPEXTEND|PN_NWAY_POLARITY| \
- PN_NWAY_TP|PN_NWAY_SPEEDSEL)
-
-#define PN_NWAY_MODE_100FD \
- (PN_NWAY_CAP10HALF|PN_NWAY_CAP10FULL| \
- PN_NWAY_CAP100FULL|PN_NWAY_CAP100HALF|PN_NWAY_CAP100T4| \
- PN_NWAY_AUILOWCUR|PN_NWAY_TPEXTEND|PN_NWAY_POLARITY| \
- PN_NWAY_TP|PN_NWAY_SPEEDSEL|PN_NWAY_DUPLEX)
-
-#define PN_NWAY_MODE_100T4 PN_NWAY_MODE_100HD
-
-#define PN_NWAY_LPAR \
- (PN_NWAY_LPAR10HALF|PN_NWAY_LPAR10FULL|PN_NWAY_LPAR100HALF| \
- PN_NWAY_LPAR100FULL|PN_NWAY_LPAR100T4)
-
-/*
- * Size of a setup frame.
- */
-#define PN_SFRAME_LEN 192
-
-/*
- * PNIC TX/RX list structure.
- */
-
-struct pn_desc {
- u_int32_t pn_status;
- u_int32_t pn_ctl;
- u_int32_t pn_ptr1;
- u_int32_t pn_ptr2;
-};
-
-#define pn_data pn_ptr1
-#define pn_next pn_ptr2
-
-
-#define RX_RXSTAT_FIFOOFLOW 0x00000001
-#define PN_RXSTAT_CRCERR 0x00000002
-#define PN_RXSTAT_DRIBBLE 0x00000004
-#define PN_RXSTAT_WATCHDOG 0x00000010
-#define PN_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */
-#define PN_RXSTAT_COLLSEEN 0x00000040
-#define PN_RXSTAT_GIANT 0x00000080
-#define PN_RXSTAT_LASTFRAG 0x00000100
-#define PN_RXSTAT_FIRSTFRAG 0x00000200
-#define PN_RXSTAT_MULTICAST 0x00000400
-#define PN_RXSTAT_RUNT 0x00000800
-#define PN_RXSTAT_RXTYPE 0x00003000
-#define PN_RXSTAT_RXERR 0x00008000
-#define PN_RXSTAT_RXLEN 0x7FFF0000
-#define PN_RXSTAT_OWN 0x80000000
-
-#define PN_RXBYTES(x) ((x & PN_RXSTAT_RXLEN) >> 16)
-#define PN_RXSTAT (PN_RXSTAT_FIRSTFRAG|PN_RXSTAT_LASTFRAG|PN_RXSTAT_OWN)
-
-#define PN_RXCTL_BUFLEN1 0x00000FFF
-#define PN_RXCTL_BUFLEN2 0x00FFF000
-#define PN_RXCTL_RLINK 0x01000000
-#define PN_RXCTL_RLAST 0x02000000
-
-#define PN_TXSTAT_DEFER 0x00000001
-#define PN_TXSTAT_UNDERRUN 0x00000002
-#define PN_TXSTAT_LINKFAIL 0x00000003
-#define PN_TXSTAT_COLLCNT 0x00000078
-#define PN_TXSTAT_SQE 0x00000080
-#define PN_TXSTAT_EXCESSCOLL 0x00000100
-#define PN_TXSTAT_LATECOLL 0x00000200
-#define PN_TXSTAT_NOCARRIER 0x00000400
-#define PN_TXSTAT_CARRLOST 0x00000800
-#define PN_TXSTAT_JABTIMEO 0x00004000
-#define PN_TXSTAT_ERRSUM 0x00008000
-#define PN_TXSTAT_OWN 0x80000000
-
-#define PN_TXCTL_BUFLEN1 0x000007FF
-#define PN_TXCTL_BUFLEN2 0x003FF800
-#define PN_TXCTL_FILTTYPE0 0x00400000
-#define PN_TXCTL_PAD 0x00800000
-#define PN_TXCTL_TLINK 0x01000000
-#define PN_TXCTL_TLAST 0x02000000
-#define PN_TXCTL_NOCRC 0x04000000
-#define PN_TXCTL_SETUP 0x08000000
-#define PN_TXCTL_FILTTYPE1 0x10000000
-#define PN_TXCTL_FIRSTFRAG 0x20000000
-#define PN_TXCTL_LASTFRAG 0x40000000
-#define PN_TXCTL_FINT 0x80000000
-
-#define PN_FILTER_PERFECT 0x00000000
-#define PN_FILTER_HASHPERF 0x00400000
-#define PN_FILTER_INVERSE 0x10000000
-#define PN_FILTER_HASHONLY 0x10400000
-
-#define PN_MAXFRAGS 16
-#define PN_RX_LIST_CNT 64
-#define PN_TX_LIST_CNT 128
-#define PN_MIN_FRAMELEN 60
-#define PN_FRAMELEN 1536
-#define PN_RXLEN 1536
-#define ETHER_ALIGN 2
-
-/*
- * A tx 'super descriptor' is actually 16 regular descriptors
- * back to back.
- */
-struct pn_txdesc {
- struct pn_desc pn_frag[PN_MAXFRAGS];
-};
-
-#define PN_TXNEXT(x) x->pn_ptr->pn_frag[x->pn_lastdesc].pn_next
-#define PN_TXSTATUS(x) x->pn_ptr->pn_frag[x->pn_lastdesc].pn_status
-#define PN_TXCTL(x) x->pn_ptr->pn_frag[x->pn_lastdesc].pn_ctl
-#define PN_TXDATA(x) x->pn_ptr->pn_frag[x->pn_lastdesc].pn_data
-
-#define PN_TXOWN(x) x->pn_ptr->pn_frag[0].pn_status
-
-struct pn_list_data {
- struct pn_desc pn_rx_list[PN_RX_LIST_CNT];
- struct pn_txdesc pn_tx_list[PN_TX_LIST_CNT];
-};
-
-struct pn_chain {
- struct pn_txdesc *pn_ptr;
- struct mbuf *pn_mbuf;
- struct pn_chain *pn_nextdesc;
- u_int8_t pn_lastdesc;
-};
-
-struct pn_chain_onefrag {
- struct pn_desc *pn_ptr;
- struct mbuf *pn_mbuf;
- struct pn_chain_onefrag *pn_nextdesc;
-};
-
-struct pn_chain_data {
- struct pn_desc pn_sframe;
- u_int32_t pn_sbuf[PN_SFRAME_LEN/sizeof(u_int32_t)];
- struct pn_chain_onefrag pn_rx_chain[PN_RX_LIST_CNT];
- struct pn_chain pn_tx_chain[PN_TX_LIST_CNT];
-
- struct pn_chain_onefrag *pn_rx_head;
-
- struct pn_chain *pn_tx_head;
- struct pn_chain *pn_tx_tail;
- struct pn_chain *pn_tx_free;
-};
-
-struct pn_type {
- u_int16_t pn_vid;
- u_int16_t pn_did;
- char *pn_name;
-};
-
-struct pn_mii_frame {
- u_int8_t mii_stdelim;
- u_int8_t mii_opcode;
- u_int8_t mii_phyaddr;
- u_int8_t mii_regaddr;
- u_int8_t mii_turnaround;
- u_int16_t mii_data;
-};
-
-/*
- * MII constants
- */
-#define PN_MII_STARTDELIM 0x01
-#define PN_MII_READOP 0x02
-#define PN_MII_WRITEOP 0x01
-#define PN_MII_TURNAROUND 0x02
-
-#define PN_FLAG_FORCEDELAY 1
-#define PN_FLAG_SCHEDDELAY 2
-#define PN_FLAG_DELAYTIMEO 3
-
-struct pn_softc {
- struct arpcom arpcom; /* interface info */
- struct ifmedia ifmedia; /* media info */
- bus_space_handle_t pn_bhandle; /* bus space handle */
- bus_space_tag_t pn_btag; /* bus space tag */
- void *pn_intrhand;
- struct resource *pn_irq;
- struct resource *pn_res;
- struct pn_type *pn_info; /* PNIC adapter info */
- struct pn_type *pn_pinfo; /* phy info */
- u_int8_t pn_unit; /* interface number */
- u_int8_t pn_type;
- u_int8_t pn_phy_addr; /* PHY address */
- u_int8_t pn_tx_pend; /* TX pending */
- u_int8_t pn_want_auto;
- u_int8_t pn_autoneg;
- u_int8_t pn_cachesize;
-#ifdef PN_RX_BUG_WAR
-#define PN_168_REV 16
-#define PN_169_REV 32
-#define PN_169B_REV 33
- u_int8_t pn_rx_war;
- struct pn_chain_onefrag *pn_rx_bug_save;
- unsigned char *pn_rx_buf;
-#endif
- caddr_t pn_ldata_ptr;
- struct pn_list_data *pn_ldata;
- struct pn_chain_data pn_cdata;
-};
-
-/*
- * register space access macros
- */
-#define CSR_WRITE_4(sc, reg, val) \
- bus_space_write_4(sc->pn_btag, sc->pn_bhandle, reg, val)
-#define CSR_WRITE_2(sc, reg, val) \
- bus_space_write_2(sc->pn_btag, sc->pn_bhandle, reg, val)
-#define CSR_WRITE_1(sc, reg, val) \
- bus_space_write_1(sc->pn_btag, sc->pn_bhandle, reg, val)
-
-#define CSR_READ_4(sc, reg) \
- bus_space_read_4(sc->pn_btag, sc->pn_bhandle, reg)
-#define CSR_READ_2(sc, reg) \
- bus_space_read_2(sc->pn_btag, sc->pn_bhandle, reg)
-#define CSR_READ_1(sc, reg) \
- bus_space_read_1(sc->pn_btag, sc->pn_bhandle, reg)
-
-#define PN_TIMEOUT 1000
-
-/*
- * General constants that are fun to know.
- *
- * Lite-On PNIC PCI vendor ID
- */
-#define PN_VENDORID 0x11AD
-
-/*
- * Lite-On PNIC PCI device ID.
- */
-#define PN_DEVICEID_PNIC 0x0002
-
-/*
- * The 82c168 chip has the same PCI vendor/device ID as the
- * 82c169, but a different revision. Assume that any revision
- * between 0x10 an 0x1F is an 82c168.
- */
-#define PN_REVMASK 0xF0
-#define PN_REVID_82C168 0x10
-#define PN_REVID_82C169 0x20
-
-/*
- * Texas Instruments PHY identifiers
- */
-#define TI_PHY_VENDORID 0x4000
-#define TI_PHY_10BT 0x501F
-#define TI_PHY_100VGPMI 0x502F
-
-/*
- * These ID values are for the NS DP83840A 10/100 PHY
- */
-#define NS_PHY_VENDORID 0x2000
-#define NS_PHY_83840A 0x5C0F
-
-/*
- * Level 1 10/100 PHY
- */
-#define LEVEL1_PHY_VENDORID 0x7810
-#define LEVEL1_PHY_LXT970 0x000F
-
-/*
- * Intel 82555 10/100 PHY
- */
-#define INTEL_PHY_VENDORID 0x0A28
-#define INTEL_PHY_82555 0x015F
-
-/*
- * SEEQ 80220 10/100 PHY
- */
-#define SEEQ_PHY_VENDORID 0x0016
-#define SEEQ_PHY_80220 0xF83F
-
-
-/*
- * PCI low memory base and low I/O base register, and
- * other PCI registers.
- */
-
-#define PN_PCI_VENDOR_ID 0x00
-#define PN_PCI_DEVICE_ID 0x02
-#define PN_PCI_COMMAND 0x04
-#define PN_PCI_STATUS 0x06
-#define PN_PCI_REVISION 0x08
-#define PN_PCI_CLASSCODE 0x09
-#define PN_PCI_CACHELEN 0x0C
-#define PN_PCI_LATENCY_TIMER 0x0D
-#define PN_PCI_HEADER_TYPE 0x0E
-#define PN_PCI_LOIO 0x10
-#define PN_PCI_LOMEM 0x14
-#define PN_PCI_BIOSROM 0x30
-#define PN_PCI_INTLINE 0x3C
-#define PN_PCI_INTPIN 0x3D
-#define PN_PCI_MINGNT 0x3E
-#define PN_PCI_MINLAT 0x0F
-#define PN_PCI_RESETOPT 0x48
-#define PN_PCI_EEPROM_DATA 0x4C
-
-/* power management registers */
-#define PN_PCI_CAPID 0xDC /* 8 bits */
-#define PN_PCI_NEXTPTR 0xDD /* 8 bits */
-#define PN_PCI_PWRMGMTCAP 0xDE /* 16 bits */
-#define PN_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */
-
-#define PN_PSTATE_MASK 0x0003
-#define PN_PSTATE_D0 0x0000
-#define PN_PSTATE_D1 0x0002
-#define PN_PSTATE_D2 0x0002
-#define PN_PSTATE_D3 0x0003
-#define PN_PME_EN 0x0010
-#define PN_PME_STATUS 0x8000
-
-#define PHY_UNKNOWN 6
-
-#define PN_PHYADDR_MIN 0x00
-#define PN_PHYADDR_MAX 0x1F
-
-#define PHY_BMCR 0x00
-#define PHY_BMSR 0x01
-#define PHY_VENID 0x02
-#define PHY_DEVID 0x03
-#define PHY_ANAR 0x04
-#define PHY_LPAR 0x05
-#define PHY_ANEXP 0x06
-
-#define PHY_ANAR_NEXTPAGE 0x8000
-#define PHY_ANAR_RSVD0 0x4000
-#define PHY_ANAR_TLRFLT 0x2000
-#define PHY_ANAR_RSVD1 0x1000
-#define PHY_ANAR_RSVD2 0x0800
-#define PHY_ANAR_RSVD3 0x0400
-#define PHY_ANAR_100BT4 0x0200
-#define PHY_ANAR_100BTXFULL 0x0100
-#define PHY_ANAR_100BTXHALF 0x0080
-#define PHY_ANAR_10BTFULL 0x0040
-#define PHY_ANAR_10BTHALF 0x0020
-#define PHY_ANAR_PROTO4 0x0010
-#define PHY_ANAR_PROTO3 0x0008
-#define PHY_ANAR_PROTO2 0x0004
-#define PHY_ANAR_PROTO1 0x0002
-#define PHY_ANAR_PROTO0 0x0001
-
-/*
- * These are the register definitions for the PHY (physical layer
- * interface chip).
- */
-/*
- * PHY BMCR Basic Mode Control Register
- */
-#define PHY_BMCR_RESET 0x8000
-#define PHY_BMCR_LOOPBK 0x4000
-#define PHY_BMCR_SPEEDSEL 0x2000
-#define PHY_BMCR_AUTONEGENBL 0x1000
-#define PHY_BMCR_RSVD0 0x0800 /* write as zero */
-#define PHY_BMCR_ISOLATE 0x0400
-#define PHY_BMCR_AUTONEGRSTR 0x0200
-#define PHY_BMCR_DUPLEX 0x0100
-#define PHY_BMCR_COLLTEST 0x0080
-#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */
-#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */
-#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */
-#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */
-#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */
-#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */
-#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */
-/*
- * RESET: 1 == software reset, 0 == normal operation
- * Resets status and control registers to default values.
- * Relatches all hardware config values.
- *
- * LOOPBK: 1 == loopback operation enabled, 0 == normal operation
- *
- * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s
- * Link speed is selected byt his bit or if auto-negotiation if bit
- * 12 (AUTONEGENBL) is set (in which case the value of this register
- * is ignored).
- *
- * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled
- * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13
- * determine speed and mode. Should be cleared and then set if PHY configured
- * for no autoneg on startup.
- *
- * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation
- *
- * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation
- *
- * DUPLEX: 1 == full duplex mode, 0 == half duplex mode
- *
- * COLLTEST: 1 == collision test enabled, 0 == normal operation
- */
-
-/*
- * PHY, BMSR Basic Mode Status Register
- */
-#define PHY_BMSR_100BT4 0x8000
-#define PHY_BMSR_100BTXFULL 0x4000
-#define PHY_BMSR_100BTXHALF 0x2000
-#define PHY_BMSR_10BTFULL 0x1000
-#define PHY_BMSR_10BTHALF 0x0800
-#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */
-#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */
-#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */
-#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */
-#define PHY_BMSR_MFPRESUP 0x0040
-#define PHY_BMSR_AUTONEGCOMP 0x0020
-#define PHY_BMSR_REMFAULT 0x0010
-#define PHY_BMSR_CANAUTONEG 0x0008
-#define PHY_BMSR_LINKSTAT 0x0004
-#define PHY_BMSR_JABBER 0x0002
-#define PHY_BMSR_EXTENDED 0x0001
-
-#ifdef __alpha__
-#undef vtophys
-#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
-#endif
OpenPOWER on IntegriCloud