summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>1999-06-29 02:28:23 +0000
committerJason Wright <jason@cvs.openbsd.org>1999-06-29 02:28:23 +0000
commitb7fc3d805fb2b43043fd3cf8fef57f17086f4e16 (patch)
tree16b543eeb09e0bb7c9ae89c03f9d55d009332d89 /sys/dev
parent428404334783f465048a00f68ecf9680a2815671 (diff)
Merge with FreeBSD:
workarounds for tx/rx hardware bugs now works on alpha support for phy-less boards (onboard xcvr)
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_pn.c533
-rw-r--r--sys/dev/pci/if_pnreg.h79
2 files changed, 498 insertions, 114 deletions
diff --git a/sys/dev/pci/if_pn.c b/sys/dev/pci/if_pn.c
index cc958eb0da1..5786bd1b730 100644
--- a/sys/dev/pci/if_pn.c
+++ b/sys/dev/pci/if_pn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pn.c,v 1.5 1999/06/28 20:51:10 jason Exp $ */
+/* $OpenBSD: if_pn.c,v 1.6 1999/06/29 02:28:22 jason Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -31,7 +31,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: if_pn.c,v 1.8 1999/02/26 07:50:53 wpaul Exp $
+ * $FreeBSD: if_pn.c,v 1.21 1999/05/28 18:43:10 wpaul Exp $
*/
/*
@@ -121,7 +121,7 @@
/* #define PN_BACKGROUND_AUTONEG */
-#define PN_PROMISC_BUG_WAR
+#define PN_RX_BUG_WAR
#ifdef __FreeBSD__
#include <pci/if_pnreg.h>
@@ -131,7 +131,7 @@
#if !defined(lint) && defined(__FreeBSD__)
static const char rcsid[] =
- "$FreeBSD: if_pn.c,v 1.8 1999/02/26 07:50:53 wpaul Exp $";
+ "$FreeBSD: if_pn.c,v 1.21 1999/05/28 18:43:10 wpaul Exp $";
#endif
#if defined(__FreeBSD__)
@@ -141,8 +141,6 @@ static const char rcsid[] =
static struct pn_type pn_devs[] = {
{ PN_VENDORID, PN_DEVICEID_PNIC,
"82c168/82c169 PNIC 10/100BaseTX" },
- { PN_VENDORID, PN_DEVICEID_PNIC_II,
- "82c115 PNIC II 10/100BaseTX" },
{ 0, 0, NULL }
};
#endif
@@ -181,8 +179,8 @@ static int pn_newbuf __P((struct pn_softc *,
static int pn_encap __P((struct pn_softc *, struct pn_chain *,
struct mbuf *));
-#ifdef PN_PROMISC_BUG_WAR
-static void pn_promisc_bug_war __P((struct pn_softc *,
+#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 *));
@@ -207,7 +205,9 @@ 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_setcfg __P((struct pn_softc *, u_int16_t));
+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 *));
@@ -216,11 +216,11 @@ static int pn_list_tx_init __P((struct pn_softc *));
#define PN_SETBIT(sc, reg, x) \
CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) | x)
+ CSR_READ_4(sc, reg) | (x))
#define PN_CLRBIT(sc, reg, x) \
CSR_WRITE_4(sc, reg, \
- CSR_READ_4(sc, reg) & ~x)
+ CSR_READ_4(sc, reg) & ~(x))
/*
* Read a word of data stored in the EEPROM at address 'addr.'
@@ -307,7 +307,6 @@ static void pn_phy_writereg(sc, reg, data)
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;
@@ -484,7 +483,7 @@ static void pn_autoneg_mii(sc, flag, verbose)
media &= ~PHY_BMCR_AUTONEGENBL;
/* Set ASIC's duplex mode to match the PHY. */
- pn_setcfg(sc, media);
+ pn_setcfg(sc, ifm->ifm_media);
pn_phy_writereg(sc, PHY_BMCR, media);
} else {
if (verbose)
@@ -561,9 +560,160 @@ static void pn_getmode_mii(sc)
return;
}
-/*
- * Set speed and duplex mode.
- */
+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 the modes and set the 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;
@@ -615,7 +765,7 @@ static void pn_setmode_mii(sc, media)
bmcr &= ~PHY_BMCR_DUPLEX;
}
- pn_setcfg(sc, bmcr);
+ pn_setcfg(sc, media);
pn_phy_writereg(sc, PHY_BMCR, bmcr);
return;
@@ -727,9 +877,9 @@ void pn_setfilt(sc)
* '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, bmcr)
+static void pn_setcfg(sc, media)
struct pn_softc *sc;
- u_int16_t bmcr;
+ u_int32_t media;
{
int i, restart = 0;
@@ -750,15 +900,35 @@ static void pn_setcfg(sc, bmcr)
}
- if (bmcr & PHY_BMCR_SPEEDSEL)
+ if (IFM_SUBTYPE(media) == IFM_100_TX) {
PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_SPEEDSEL);
- else
+ 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 (bmcr & PHY_BMCR_DUPLEX)
+ if ((media & IFM_GMASK) == IFM_FDX) {
PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_FULLDUPLEX);
- else
+ 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);
@@ -797,12 +967,28 @@ pn_probe(config_id, device_id)
pcidi_t device_id;
{
struct pn_type *t;
+ u_int32_t rev;
t = pn_devs;
while(t->pn_name != NULL) {
if ((device_id & 0xFFFF) == t->pn_vid &&
((device_id >> 16) & 0xFFFF) == t->pn_did) {
+ if (t->pn_did == PN_DEVICEID_PNIC) {
+ rev = pci_conf_read(config_id,
+ PN_PCI_REVISION) & 0xFF;
+ switch (rev & PN_REVMASK) {
+ case PN_REVID_82C168:
+ return (t->pn_name);
+ break;
+ case PN_REVID_82C169:
+ t++;
+ return (t->pn_name);
+ default:
+ printf("uknown PNIC rev: %x\n", rev);
+ break;
+ }
+ }
return(t->pn_name);
}
t++;
@@ -833,7 +1019,7 @@ pn_attach(config_id, unit)
caddr_t roundptr;
struct pn_type *p;
u_int16_t phy_vid, phy_did, phy_sts;
-#ifdef PN_PROMISC_BUG_WAR
+#ifdef PN_RX_BUG_WAR
u_int32_t revision = 0;
#endif
@@ -895,7 +1081,12 @@ pn_attach(config_id, unit)
printf ("pn%d: couldn't map ports\n", unit);
goto fail;
}
+#ifdef __i386__
sc->pn_btag = I386_BUS_SPACE_IO;
+#endif
+#ifdef __alpha__
+ sc->pn_btag = ALPHA_BUS_SPACE_IO;
+#endif
#else
if (!(command & PCIM_CMD_MEMEN)) {
printf("pn%d: failed to enable memory mapping!\n", unit);
@@ -907,8 +1098,13 @@ pn_attach(config_id, unit)
goto fail;
}
sc->pn_bhandle = vbase;
+#ifdef __i386__
sc->pn_btag = I386_BUS_SPACE_MEM;
#endif
+#ifdef __alpha__
+ sc->pn_btag = ALPHA_BUS_SPACE_MEM;
+#endif
+#endif
/* Allocate interrupt */
if (!pci_map_int(config_id, pn_intr, sc, &net_imask)) {
@@ -916,6 +1112,8 @@ pn_attach(config_id, unit)
goto fail;
}
+ sc->pn_cachesize = pci_conf_read(config_id, PN_PCI_CACHELEN) & 0xFF;
+
/* Reset the adapter. */
pn_reset(sc);
@@ -953,17 +1151,18 @@ pn_attach(config_id, unit)
sc->pn_ldata = (struct pn_list_data *)roundptr;
bzero(sc->pn_ldata, sizeof(struct pn_list_data));
-#ifdef PN_PROMISC_BUG_WAR
+#ifdef PN_RX_BUG_WAR
revision = pci_conf_read(config_id, PN_PCI_REVISION) & 0x000000FF;
- if (revision == PN_169B_REV || revision == PN_169_REV) {
- sc->pn_promisc_war = 1;
- sc->pn_promisc_buf = malloc(PN_RXLEN * 5, M_DEVBUF, M_NOWAIT);
- if (sc->pn_promisc_buf == NULL) {
+ 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);
goto fail;
}
} else {
- sc->pn_promisc_war = 0;
+ sc->pn_rx_war = 0;
}
#endif
@@ -981,6 +1180,10 @@ pn_attach(config_id, unit)
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++) {
sc->pn_phy_addr = i;
pn_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
@@ -1004,21 +1207,24 @@ pn_attach(config_id, unit)
}
if (sc->pn_pinfo == NULL)
sc->pn_pinfo = &pn_phys[PHY_UNKNOWN];
+ pn_getmode_mii(sc);
+ pn_autoneg_mii(sc, PN_FLAG_FORCEDELAY, 1);
} else {
- printf("pn%d: MII without any phy!\n", sc->pn_unit);
- goto fail;
+ 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_autoneg(sc, PN_FLAG_FORCEDELAY, 1);
}
- /*
- * Do ifmedia setup.
- */
- ifmedia_init(&sc->ifmedia, 0, pn_ifmedia_upd, pn_ifmedia_sts);
-
- pn_getmode_mii(sc);
- pn_autoneg_mii(sc, PN_FLAG_FORCEDELAY, 1);
media = sc->ifmedia.ifm_media;
pn_stop(sc);
-
ifmedia_set(&sc->ifmedia, media);
/*
@@ -1146,14 +1352,17 @@ static int pn_newbuf(sc, c)
return(0);
}
-#ifdef PN_PROMISC_BUG_WAR
+#ifdef PN_RX_BUG_WAR
/*
* Grrrrr.
- * Revision 33 of the PNIC chip has a terrible bug in it that manifests
- * itself when you enable promiscuous mode. Sometimes instead of uploading
- * one complete frame, it uploads its entire FIFO memory. The frame we
- * want is at the end of this whole mess, but we never know exactly
- * how much data has been uploaded, so finding it can be hard.
+ * 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:
@@ -1197,7 +1406,7 @@ static int pn_newbuf(sc, c)
*/
#define PN_WHOLEFRAME (PN_RXSTAT_FIRSTFRAG|PN_RXSTAT_LASTFRAG)
-static void pn_promisc_bug_war(sc, cur_rx)
+static void pn_rx_bug_war(sc, cur_rx)
struct pn_softc *sc;
struct pn_chain_onefrag *cur_rx;
{
@@ -1206,8 +1415,8 @@ static void pn_promisc_bug_war(sc, cur_rx)
int total_len;
u_int32_t rxstat = 0;
- c = sc->pn_promisc_bug_save;
- ptr = sc->pn_promisc_buf;
+ 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. */
@@ -1225,22 +1434,28 @@ static void pn_promisc_bug_war(sc, cur_rx)
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) {
+ while(*ptr == 0x00)
ptr--;
- }
+ /* Round off. */
+#if defined(__i386__)
if ((u_int32_t)(ptr) & 0x3)
ptr -= 1;
+#elif defined(__alpha__)
+ if ((u_int64_t)(ptr) & 0x3)
+ ptr -= 1;
+#else
+# error "unsupported architecture"
+#endif
/* Now find the start of the frame. */
ptr -= total_len;
- if (ptr < sc->pn_promisc_buf)
- ptr = sc->pn_promisc_buf;
+ if (ptr < sc->pn_rx_buf)
+ ptr = sc->pn_rx_buf;
/*
* Now copy the salvaged frame to the last mbuf and fake up
@@ -1273,22 +1488,29 @@ static void pn_rxeof(sc)
while(!((rxstat = sc->pn_cdata.pn_rx_head->pn_ptr->pn_status) &
PN_RXSTAT_OWN)) {
+#ifdef __alpha__
+ struct mbuf *m0 = NULL;
+#endif
+
cur_rx = sc->pn_cdata.pn_rx_head;
sc->pn_cdata.pn_rx_head = cur_rx->pn_nextdesc;
-#ifdef PN_PROMISC_BUG_WAR
+#ifdef PN_RX_BUG_WAR
/*
- * XXX The PNIC seems to have a bug that manifests
- * when the promiscuous mode bit is set: we have to
- * watch for it and work around it.
+ * 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_promisc_war && ifp->if_flags & IFF_PROMISC) {
+ if (sc->pn_rx_war) {
if ((rxstat & PN_WHOLEFRAME) != PN_WHOLEFRAME) {
if (rxstat & PN_RXSTAT_FIRSTFRAG)
- sc->pn_promisc_bug_save = cur_rx;
+ sc->pn_rx_bug_save = cur_rx;
if ((rxstat & PN_RXSTAT_LASTFRAG) == 0)
continue;
- pn_promisc_bug_war(sc, cur_rx);
+ pn_rx_bug_war(sc, cur_rx);
rxstat = cur_rx->pn_ptr->pn_status;
}
}
@@ -1332,10 +1554,53 @@ static void pn_rxeof(sc)
continue;
}
+#ifdef __alpha__
+ /*
+ * Grrrr! On the alpha platform, the start of the
+ * packet data must be longword aligned so that ip_input()
+ * doesn't perform any unaligned accesses when it tries
+ * to fiddle with the IP header. But the PNIC is stupid
+ * and wants RX buffers to start on longword boundaries.
+ * So we can't just shift the DMA address over a few
+ * bytes to alter the payload alignment. Instead, we
+ * have to chop out ethernet and IP header parts of
+ * the packet and place then in a separate mbuf with
+ * the alignment fixed up properly.
+ *
+ * As if this chip wasn't broken enough already.
+ */
+ MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ if (m0 == NULL) {
+ ifp->if_ierrors++;
+ cur_rx->pn_ptr->pn_status = PN_RXSTAT;
+ cur_rx->pn_ptr->pn_ctl = PN_RXCTL_RLINK | PN_RXLEN;
+ bzero((char *)mtod(cur_rx->pn_mbuf, char *), MCLBYTES);
+ continue;
+ }
+
+ m0->m_data += 2;
+ if (total_len <= (MHLEN - 2)) {
+ bcopy(mtod(m, caddr_t), mtod(m0, caddr_t), total_len);
+ m_freem(m);
+ m = m0;
+ m->m_pkthdr.len = m->m_len = total_len;
+ } else {
+ bcopy(mtod(m, caddr_t), mtod(m0, caddr_t), (MHLEN - 2));
+ m->m_len = total_len - (MHLEN - 2);
+ m->m_data += (MHLEN - 2);
+ m0->m_next = m;
+ m0->m_len = (MHLEN - 2);
+ m = m0;
+ m->m_pkthdr.len = total_len;
+ }
+#else
+ m->m_pkthdr.len = m->m_len = total_len;
+#endif
+
ifp->if_ipackets++;
eh = mtod(m, struct ether_header *);
m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len;
+
#if NBPFILTER > 0
/*
* Handle BPF listeners. Let the BPF user see the packet.
@@ -1398,7 +1663,7 @@ static void pn_txeof(sc)
cur_tx = sc->pn_cdata.pn_tx_head;
txstat = PN_TXSTATUS(cur_tx);
- if ((txstat & PN_TXSTAT_OWN) || txstat == PN_UNSENT)
+ if (txstat & PN_TXSTAT_OWN)
break;
if (txstat & PN_TXSTAT_ERRSUM) {
@@ -1443,13 +1708,11 @@ static void pn_txeoc(sc)
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)
- pn_autoneg_mii(sc, PN_FLAG_SCHEDDELAY, 1);
- } else {
- if (PN_TXOWN(sc->pn_cdata.pn_tx_head) == PN_UNSENT) {
- PN_TXOWN(sc->pn_cdata.pn_tx_head) = PN_TXSTAT_OWN;
- ifp->if_timer = 5;
- CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
+ 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);
}
}
@@ -1628,7 +1891,7 @@ static int pn_encap(sc, c, m_head)
c->pn_mbuf = m_head;
c->pn_lastdesc = frag - 1;
- PN_TXCTL(c) |= PN_TXCTL_LASTFRAG;
+ PN_TXCTL(c) |= PN_TXCTL_LASTFRAG|PN_TXCTL_FINT;
PN_TXNEXT(c) = vtophys(&c->pn_nextdesc->pn_ptr->pn_frag[0]);
return(0);
@@ -1693,6 +1956,8 @@ static void pn_start(ifp)
bpf_mtap(ifp->if_bpf, cur_tx->pn_mbuf);
#endif
#endif
+ PN_TXOWN(cur_tx) = PN_TXSTAT_OWN;
+ CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
}
/*
@@ -1701,23 +1966,10 @@ static void pn_start(ifp)
if (cur_tx == NULL)
return;
- /*
- * Place the request for the upload interrupt
- * in the last descriptor in the chain. This way, if
- * we're chaining several packets at once, we'll only
- * get an interupt once for the whole chain rather than
- * once for each packet.
- */
- PN_TXCTL(cur_tx) |= PN_TXCTL_FINT;
sc->pn_cdata.pn_tx_tail = cur_tx;
- if (sc->pn_cdata.pn_tx_head == NULL) {
+ if (sc->pn_cdata.pn_tx_head == NULL)
sc->pn_cdata.pn_tx_head = start_tx;
- PN_TXOWN(start_tx) = PN_TXSTAT_OWN;
- CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF);
- } else {
- PN_TXOWN(start_tx) = PN_UNSENT;
- }
/*
* Set a timeout in case the chip goes out to lunch.
@@ -1752,7 +2004,23 @@ static void pn_init(xsc)
/*
* Set cache alignment and burst length.
*/
- CSR_WRITE_4(sc, PN_BUSCTL, PN_BUSCTL_CONFIG);
+ 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);
@@ -1763,13 +2031,16 @@ static void pn_init(xsc)
PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_THRESH);
PN_SETBIT(sc, PN_NETCFG, PN_TXTHRESH_72BYTES);
- pn_setcfg(sc, pn_phy_readreg(sc, PHY_BMCR));
-
- if (sc->pn_pinfo != NULL) {
+ 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 "
@@ -1831,10 +2102,17 @@ static int pn_ifmedia_upd(ifp)
if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
return(EINVAL);
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO)
- pn_autoneg_mii(sc, PN_FLAG_SCHEDDELAY, 1);
- else
- pn_setmode_mii(sc, ifm->ifm_media);
+ 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);
}
@@ -1853,6 +2131,18 @@ static void pn_ifmedia_sts(ifp, ifmr)
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;
@@ -1967,7 +2257,10 @@ static void pn_watchdog(ifp)
sc = ifp->if_softc;
if (sc->pn_autoneg) {
- pn_autoneg_mii(sc, PN_FLAG_DELAYTIMEO, 1);
+ if (sc->pn_pinfo == NULL)
+ pn_autoneg(sc, PN_FLAG_DELAYTIMEO, 1);
+ else
+ pn_autoneg_mii(sc, PN_FLAG_DELAYTIMEO, 1);
return;
}
@@ -2058,7 +2351,7 @@ static struct pci_device pn_device = {
&pn_count,
NULL
};
-DATA_SET(pcidevice_set, pn_device);
+COMPAT_PCI_DRIVER(pn, pn_device);
#endif /* __FreeBSD__ */
#ifdef __OpenBSD__
@@ -2099,6 +2392,9 @@ pn_attach(parent, self, aux)
int s, i, media = IFM_ETHER|IFM_100_TX|IFM_FDX;
u_int round;
caddr_t roundptr;
+#ifdef PN_RX_BUG_WAR
+ u_int32_t revision = 0;
+#endif
s = splimp();
@@ -2159,6 +2455,9 @@ pn_attach(parent, self, aux)
}
printf(": %s", intrstr);
+ sc->pn_cachesize = pci_conf_read(pa->pa_pc, pa->pa_tag,
+ PN_PCI_CACHELEN) & 0xFF;
+
pn_reset(sc);
pn_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr, 0, 3, 1);
@@ -2171,7 +2470,12 @@ pn_attach(parent, self, aux)
goto fail;
}
sc->pn_ldata = (struct pn_list_data *)sc->pn_ldata_ptr;
- round = (unsigned int)sc->pn_ldata_ptr & 0xf;
+#if defined(__i386__)
+ round = (u_int32_t)sc->pn_ldata_ptr & 0xf;
+#elif defined(__alpha__)
+ round = (u_int64_t)sc->pn_ldata_ptr & 0xf;
+#endif
+
roundptr = sc->pn_ldata_ptr;
for (i = 0; i < 8; i++) {
if (round % 8) {
@@ -2184,6 +2488,20 @@ pn_attach(parent, self, aux)
sc->pn_ldata = (struct pn_list_data *)roundptr;
bzero(sc->pn_ldata, sizeof(struct pn_list_data));
+ revision = pci_conf_read(pa->pa_pc, pa->pa_tag, PN_PCI_REVISION)
+ & 0xFF;
+ 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("%s: no memory for workaround buffer\n",
+ sc->sc_dev.dv_xname);
+ goto fail;
+ }
+ } else
+ sc->pn_rx_war = 0;
+
ifp = &sc->arpcom.ac_if;
ifp->if_softc = sc;
ifp->if_mtu = ETHERMTU;
@@ -2196,6 +2514,8 @@ pn_attach(parent, self, aux)
ifp->if_snd.ifq_maxlen = PN_TX_LIST_CNT - 1;
bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifmedia_init(&sc->ifmedia, 0, pn_ifmedia_upd, pn_ifmedia_sts);
+
for (i = PN_PHYADDR_MIN; i < PN_PHYADDR_MAX + 1; i++) {
sc->pn_phy_addr = i;
pn_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
@@ -2218,15 +2538,22 @@ pn_attach(parent, self, aux)
}
if (sc->pn_pinfo == NULL)
sc->pn_pinfo = &pn_phys[PHY_UNKNOWN];
- }
- else {
- printf("%s: MII without any phy!\n", sc->sc_dev.dv_xname);
- goto fail;
+ pn_getmode_mii(sc);
+ pn_autoneg_mii(sc, PN_FLAG_FORCEDELAY, 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_autoneg(sc, PN_FLAG_FORCEDELAY, 1);
}
- ifmedia_init(&sc->ifmedia, 0, pn_ifmedia_upd, pn_ifmedia_sts);
- pn_getmode_mii(sc);
- pn_autoneg_mii(sc, PN_FLAG_FORCEDELAY, 1);
media = sc->ifmedia.ifm_media;
pn_stop(sc);
ifmedia_set(&sc->ifmedia, media);
diff --git a/sys/dev/pci/if_pnreg.h b/sys/dev/pci/if_pnreg.h
index d3218e46c65..162ff414f11 100644
--- a/sys/dev/pci/if_pnreg.h
+++ b/sys/dev/pci/if_pnreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pnreg.h,v 1.2 1999/02/27 18:44:58 jason Exp $ */
+/* $OpenBSD: if_pnreg.h,v 1.3 1999/06/29 02:28:22 jason Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -31,7 +31,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: if_pnreg.h,v 1.5 1999/02/26 07:50:53 wpaul Exp $
+ * $FreeBSD: if_pnreg.h,v 1.13 1999/05/28 18:43:11 wpaul Exp $
*/
/*
@@ -55,7 +55,6 @@
#define PN_MII 0xA0 /* MII access register */
#define PN_NWAY 0xB8 /* Internal NWAY register */
-
/*
* Bus control bits.
*/
@@ -66,6 +65,7 @@
#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
@@ -73,6 +73,7 @@
#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
@@ -111,6 +112,7 @@
#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
@@ -167,6 +169,7 @@
#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 */
@@ -255,7 +258,7 @@
#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 /* 1 == on, 0 == off */
+#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 */
@@ -273,6 +276,46 @@
#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
@@ -369,8 +412,6 @@ struct pn_txdesc {
#define PN_TXOWN(x) x->pn_ptr->pn_frag[0].pn_status
-#define PN_UNSENT 0x12344321
-
struct pn_list_data {
struct pn_desc pn_rx_list[PN_RX_LIST_CNT];
struct pn_txdesc pn_tx_list[PN_TX_LIST_CNT];
@@ -447,12 +488,14 @@ struct pn_softc {
u_int8_t pn_want_auto;
u_int8_t pn_autoneg;
caddr_t pn_ldata_ptr;
-#ifdef PN_PROMISC_BUG_WAR
+#ifdef PN_RX_BUG_WAR
+#define PN_168_REV 16
#define PN_169_REV 32
#define PN_169B_REV 33
- u_int8_t pn_promisc_war;
- struct pn_chain_onefrag *pn_promisc_bug_save;
- unsigned char *pn_promisc_buf;
+ u_int8_t pn_rx_war;
+ u_int8_t pn_cachesize;
+ struct pn_chain_onefrag *pn_rx_bug_save;
+ unsigned char *pn_rx_buf;
#endif
struct pn_list_data *pn_ldata;
struct pn_chain_data pn_cdata;
@@ -488,7 +531,15 @@ struct pn_softc {
* Lite-On PNIC PCI device ID.
*/
#define PN_DEVICEID_PNIC 0x0002
-#define PN_DEVICEID_PNIC_II 0xc115
+
+/*
+ * The 82c168 chip has the same PCI vendor/device ID as the
+ * 82c169, but a different revision. Assume that any revision
+ * between 0x10 and 0x1F is an 82c168.
+ */
+#define PN_REVMASK 0xF0
+#define PN_REVID_82C168 0x10
+#define PN_REVID_82C169 0x20
/*
* Texas Instruments PHY identifiers
@@ -533,6 +584,7 @@ struct pn_softc {
#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
@@ -658,6 +710,11 @@ struct pn_softc {
#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
+
#ifndef ETHER_CRC_LEN
#define ETHER_CRC_LEN 4
#endif