summaryrefslogtreecommitdiffstats
path: root/sys/pci
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1999-09-22 05:07:51 +0000
committerwpaul <wpaul@FreeBSD.org>1999-09-22 05:07:51 +0000
commitef2bc702accfd810fcb93cfb23789816dc7be195 (patch)
treeeeafa344d341bc8d49836772b1468389baa366a6 /sys/pci
parentd651b26a6430a146c8d1ac8d830354cc6fcf6349 (diff)
downloadFreeBSD-src-ef2bc702accfd810fcb93cfb23789816dc7be195.zip
FreeBSD-src-ef2bc702accfd810fcb93cfb23789816dc7be195.tar.gz
Spruce up the ADMtek driver: conver to newbus, miibus and add support
for the AN985 "Centaur" chip, which is apparently the next genetation of the "Comet." The AN985 is also a tulip clone and is similar to the AL981 except that it uses a 99C66 EEPROM and a serial MII interface (instead of direct access to the PHY registers). Also updated various documentation to mention the AN985 and created a loadable module. I don't think there are any cards that use this chip on the market yet: the datasheet I got from ADMtek has boxes with big X's in them where the diagrams should be, and the sample boards I got have chips without any artwork on them.
Diffstat (limited to 'sys/pci')
-rw-r--r--sys/pci/if_al.c1525
-rw-r--r--sys/pci/if_alreg.h217
2 files changed, 680 insertions, 1062 deletions
diff --git a/sys/pci/if_al.c b/sys/pci/if_al.c
index 5d07973..073cd66 100644
--- a/sys/pci/if_al.c
+++ b/sys/pci/if_al.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 1998, 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ * 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
@@ -33,10 +33,10 @@
*/
/*
- * ADMtek AL981 Comet fast ethernet PCI NIC driver. Datasheets for
- * the AL981 are available from http://www.admtek.com.tw.
+ * 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@ctr.columbia.edu>
+ * Written by Bill Paul <wpaul@ee.columbia.edu>
* Electrical Engineering Department
* Columbia University, New York City
*/
@@ -47,13 +47,23 @@
* 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 "bpf.h"
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/eventhandler.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
@@ -76,6 +86,12 @@
#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>
@@ -85,10 +101,10 @@
#define AL_USEIOSPACE
-/* #define AL_BACKGROUND_AUTONEG */
-
#include <pci/if_alreg.h>
+#include "miibus_if.h"
+
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
@@ -98,47 +114,31 @@ static const char rcsid[] =
* 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_AL981, "ADMtek AL981 10/100BaseTX" },
+ { AL_VENDORID, AL_DEVICEID_AN985, "ADMtek AN985 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 al_type al_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 unsigned long al_count = 0;
-static const char *al_probe __P((pcici_t, pcidi_t));
-static void al_attach __P((pcici_t, int));
+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_chain_onefrag *));
-static int al_encap __P((struct al_softc *, struct al_chain *,
- struct mbuf *));
+ 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_rxeoc __P((struct al_softc *));
static void al_txeof __P((struct al_softc *));
-static void al_txeoc __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((void *, int));
+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 *));
@@ -149,19 +149,61 @@ 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 u_int16_t al_phy_readreg __P((struct al_softc *, int));
-static void al_phy_writereg __P((struct al_softc *, 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 void al_autoneg_xmit __P((struct al_softc *));
-static void al_autoneg_mii __P((struct al_softc *, int, int));
-static void al_setmode_mii __P((struct al_softc *, int));
-static void al_getmode_mii __P((struct al_softc *));
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(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)
@@ -226,7 +268,15 @@ static void al_eeprom_putbyte(sc, addr)
{
register int d, i;
- d = addr | AL_EECMD_READ;
+ /*
+ * 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.
@@ -268,7 +318,7 @@ static void al_eeprom_getword(sc, addr, dest)
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_CLRBIT(sc, AL_SIO, AL_SIO_EE_CLK);
al_delay(sc);
/*
@@ -322,83 +372,313 @@ static void al_read_eeprom(sc, dest, off, cnt, swap)
return;
}
-static u_int16_t al_phy_readreg(sc, reg)
+/*
+ * 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;
- int reg;
+ 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 PHY_BMCR:
+ case MII_BMCR:
phy_reg = AL_BMCR;
break;
- case PHY_BMSR:
+ case MII_BMSR:
phy_reg = AL_BMSR;
break;
- case PHY_VENID:
+ case MII_PHYIDR1:
phy_reg = AL_VENID;
break;
- case PHY_DEVID:
+ case MII_PHYIDR2:
phy_reg = AL_DEVID;
break;
- case PHY_ANAR:
+ case MII_ANAR:
phy_reg = AL_ANAR;
break;
- case PHY_LPAR:
+ case MII_ANLPAR:
phy_reg = AL_LPAR;
break;
- case PHY_ANEXP:
+ 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 void al_phy_writereg(sc, reg, data)
- struct al_softc *sc;
- int reg;
- int data;
+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 PHY_BMCR:
+ case MII_BMCR:
phy_reg = AL_BMCR;
break;
- case PHY_BMSR:
+ case MII_BMSR:
phy_reg = AL_BMSR;
break;
- case PHY_VENID:
+ case MII_PHYIDR1:
phy_reg = AL_VENID;
break;
- case PHY_DEVID:
+ case MII_PHYIDR2:
phy_reg = AL_DEVID;
break;
- case PHY_ANAR:
+ case MII_ANAR:
phy_reg = AL_ANAR;
break;
- case PHY_LPAR:
+ case MII_ANLPAR:
phy_reg = AL_LPAR;
break;
- case PHY_ANEXP:
+ 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;
}
@@ -473,311 +753,6 @@ static void al_setmulti(sc)
return;
}
-/*
- * Initiate an autonegotiation session.
- */
-static void al_autoneg_xmit(sc)
- struct al_softc *sc;
-{
- u_int16_t phy_sts;
-
- al_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(al_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
-
- phy_sts = al_phy_readreg(sc, PHY_BMCR);
- phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR;
- al_phy_writereg(sc, PHY_BMCR, phy_sts);
-
- return;
-}
-
-/*
- * Invoke autonegotiation on a PHY.
- */
-static void al_autoneg_mii(sc, flag, verbose)
- struct al_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 = al_phy_readreg(sc, PHY_BMSR);
- if (!(phy_sts & PHY_BMSR_CANAUTONEG)) {
- if (verbose)
- printf("al%d: autonegotiation not supported\n",
- sc->al_unit);
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- return;
- }
-#endif
-
- switch (flag) {
- case AL_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.
- */
- al_autoneg_xmit(sc);
- DELAY(5000000);
- break;
- case AL_FLAG_SCHEDDELAY:
- /*
- * Wait for the transmitter to go idle before starting
- * an autoneg session, otherwise al_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->al_cdata.al_tx_head != NULL) {
- sc->al_want_auto = 1;
- return;
- }
- al_autoneg_xmit(sc);
- ifp->if_timer = 5;
- sc->al_autoneg = 1;
- sc->al_want_auto = 0;
- return;
- break;
- case AL_FLAG_DELAYTIMEO:
- ifp->if_timer = 0;
- sc->al_autoneg = 0;
- break;
- default:
- printf("al%d: invalid autoneg flag: %d\n", sc->al_unit, flag);
- return;
- }
-
- if (al_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) {
- if (verbose)
- printf("al%d: autoneg complete, ", sc->al_unit);
- phy_sts = al_phy_readreg(sc, PHY_BMSR);
- } else {
- if (verbose)
- printf("al%d: autoneg not complete, ", sc->al_unit);
- }
-
- media = al_phy_readreg(sc, PHY_BMCR);
-
- /* Link is good. Report modes and set duplex mode. */
- if (al_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) {
- if (verbose)
- printf("link status good ");
- advert = al_phy_readreg(sc, PHY_ANAR);
- ability = al_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. */
- al_phy_writereg(sc, PHY_BMCR, media);
- } else {
- if (verbose)
- printf("no carrier\n");
- }
-
- al_init(sc);
-
- if (sc->al_tx_pend) {
- sc->al_autoneg = 0;
- sc->al_tx_pend = 0;
- al_start(ifp);
- }
-
- return;
-}
-
-static void al_getmode_mii(sc)
- struct al_softc *sc;
-{
- u_int16_t bmsr;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- bmsr = al_phy_readreg(sc, PHY_BMSR);
- if (bootverbose)
- printf("al%d: PHY status word: %x\n", sc->al_unit, bmsr);
-
- /* fallback */
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
-
- if (bmsr & PHY_BMSR_10BTHALF) {
- if (bootverbose)
- printf("al%d: 10Mbps half-duplex mode supported\n",
- sc->al_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("al%d: 10Mbps full-duplex mode supported\n",
- sc->al_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("al%d: 100Mbps half-duplex mode supported\n",
- sc->al_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("al%d: 100Mbps full-duplex mode supported\n",
- sc->al_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("al%d: 100baseT4 mode supported\n", sc->al_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("al%d: forcing on autoneg support for BT4\n",
- sc->al_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("al%d: autoneg supported\n", sc->al_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 al_setmode_mii(sc, media)
- struct al_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->al_autoneg) {
- printf("al%d: canceling autoneg session\n", sc->al_unit);
- ifp->if_timer = sc->al_autoneg = sc->al_want_auto = 0;
- bmcr = al_phy_readreg(sc, PHY_BMCR);
- bmcr &= ~PHY_BMCR_AUTONEGENBL;
- al_phy_writereg(sc, PHY_BMCR, bmcr);
- }
-
- printf("al%d: selecting MII, ", sc->al_unit);
-
- bmcr = al_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;
- }
-
- al_phy_writereg(sc, PHY_BMCR, bmcr);
-
- return;
-}
-
static void al_reset(sc)
struct al_softc *sc;
{
@@ -805,140 +780,134 @@ static void al_reset(sc)
* 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 const char *
-al_probe(config_id, device_id)
- pcici_t config_id;
- pcidi_t device_id;
+static int al_probe(dev)
+ device_t dev;
{
struct al_type *t;
t = al_devs;
while(t->al_name != NULL) {
- if ((device_id & 0xFFFF) == t->al_vid &&
- ((device_id >> 16) & 0xFFFF) == t->al_did) {
- return(t->al_name);
+ 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(NULL);
+ return(ENXIO);
}
/*
* Attach the interface. Allocate softc structures, do ifmedia
* setup and ethernet/BPF attach.
*/
-static void
-al_attach(config_id, unit)
- pcici_t config_id;
- int unit;
+static int al_attach(dev)
+ device_t dev;
{
- int s, i;
-#ifndef AL_USEIOSPACE
- vm_offset_t pbase, vbase;
-#endif
+ int s;
u_char eaddr[ETHER_ADDR_LEN];
u_int32_t command;
struct al_softc *sc;
struct ifnet *ifp;
- int media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- unsigned int round;
- caddr_t roundptr;
- struct al_type *p;
- u_int16_t phy_vid, phy_did, phy_sts;
+ int unit, error = 0, rid;
s = splimp();
- sc = malloc(sizeof(struct al_softc), M_DEVBUF, M_NOWAIT);
- if (sc == NULL) {
- printf("al%d: no memory for softc struct!\n", unit);
- goto fail;
- }
+ 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_conf_read(config_id, AL_PCI_CAPID) & 0x000000FF;
+ command = pci_read_config(dev, AL_PCI_CAPID, 4) & 0x000000FF;
if (command == 0x01) {
- command = pci_conf_read(config_id, AL_PCI_PWRMGMTCTRL);
+ 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_conf_read(config_id, AL_PCI_LOIO);
- membase = pci_conf_read(config_id, AL_PCI_LOMEM);
- irq = pci_conf_read(config_id, AL_PCI_INTLINE);
+ 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_conf_write(config_id, AL_PCI_PWRMGMTCTRL, command);
+ pci_write_config(dev, AL_PCI_PWRMGMTCTRL, command, 4);
/* Restore PCI config data. */
- pci_conf_write(config_id, AL_PCI_LOIO, iobase);
- pci_conf_write(config_id, AL_PCI_LOMEM, membase);
- pci_conf_write(config_id, AL_PCI_INTLINE, irq);
+ 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_conf_read(config_id, PCI_COMMAND_STATUS_REG);
+ command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
- pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command);
- command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
+ 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);
- free(sc, M_DEVBUF);
+ error = ENXIO;;
goto fail;
}
-
- if (!pci_map_port(config_id, AL_PCI_LOIO,
- (pci_port_t *)&(sc->al_bhandle))) {
- printf ("al%d: couldn't map ports\n", unit);
- goto fail;
- }
-#ifdef __i386__
- sc->al_btag = I386_BUS_SPACE_IO;
-#endif
-#ifdef __alpha__
- sc->al_btag = ALPHA_BUS_SPACE_IO;
-#endif
#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 (!pci_map_mem(config_id, AL_PCI_LOMEM, &vbase, &pbase)) {
- printf ("al%d: couldn't map memory\n", unit);
+ if (sc->al_res == NULL) {
+ printf("al%d: couldn't map ports/memory\n", unit);
+ error = ENXIO;
goto fail;
}
-#ifdef __i386__
- sc->al_btag = I386_BUS_SPACE_MEM;
-#endif
-#ifdef __alpha__
- sc->al_btag = ALPHA_BUS_SPACE_MEM;
-#endif
- sc->al_bhandle = vbase;
-#endif
+
+ sc->al_btag = rman_get_bustag(sc->al_res);
+ sc->al_bhandle = rman_get_bushandle(sc->al_res);
/* Allocate interrupt */
- if (!pci_map_int(config_id, al_intr, sc, &net_imask)) {
+ 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 cache line size. */
- sc->al_cachesize = pci_conf_read(config_id, AL_PCI_CACHELEN) & 0xFF;
+ /* Save the cache line size. */
+ sc->al_cachesize = pci_read_config(dev, AL_PCI_CACHELEN, 4) & 0xFF;
/* Reset the adapter. */
al_reset(sc);
@@ -954,27 +923,20 @@ al_attach(config_id, unit)
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_ptr = malloc(sizeof(struct al_list_data) + 8,
- M_DEVBUF, M_NOWAIT);
- if (sc->al_ldata_ptr == NULL) {
- free(sc, M_DEVBUF);
+ sc->al_ldata = contigmalloc(sizeof(struct al_list_data), M_DEVBUF,
+ M_NOWAIT, 0x100000, 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;
}
-
- sc->al_ldata = (struct al_list_data *)sc->al_ldata_ptr;
- round = (uintptr_t)sc->al_ldata_ptr & 0xF;
- roundptr = sc->al_ldata_ptr;
- for (i = 0; i < 8; i++) {
- if (round % 8) {
- round++;
- roundptr++;
- } else
- break;
- }
- sc->al_ldata = (struct al_list_data *)roundptr;
bzero(sc->al_ldata, sizeof(struct al_list_data));
ifp = &sc->arpcom.ac_if;
@@ -991,76 +953,19 @@ al_attach(config_id, unit)
ifp->if_baudrate = 10000000;
ifp->if_snd.ifq_maxlen = AL_TX_LIST_CNT - 1;
- if (bootverbose)
- printf("al%d: probing for a PHY\n", sc->al_unit);
- for (i = AL_PHYADDR_MIN; i < AL_PHYADDR_MAL + 1; i++) {
- if (bootverbose)
- printf("al%d: checking address: %d\n",
- sc->al_unit, i);
- sc->al_phy_addr = i;
- al_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(al_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
- if ((phy_sts = al_phy_readreg(sc, PHY_BMSR)))
- break;
- }
- if (phy_sts) {
- phy_vid = al_phy_readreg(sc, PHY_VENID);
- phy_did = al_phy_readreg(sc, PHY_DEVID);
- if (bootverbose)
- printf("al%d: found PHY at address %d, ",
- sc->al_unit, sc->al_phy_addr);
- if (bootverbose)
- printf("vendor id: %x device id: %x\n",
- phy_vid, phy_did);
- p = al_phys;
- while(p->al_vid) {
- if (phy_vid == p->al_vid &&
- (phy_did | 0x000F) == p->al_did) {
- sc->al_pinfo = p;
- break;
- }
- p++;
- }
- if (sc->al_pinfo == NULL)
- sc->al_pinfo = &al_phys[PHY_UNKNOWN];
- if (bootverbose)
- printf("al%d: PHY type: %s\n",
- sc->al_unit, sc->al_pinfo->al_name);
- } else {
-#ifdef DIAGNOSTIC
- printf("al%d: MII without any phy!\n", sc->al_unit);
-#endif
- }
-
/*
- * Do ifmedia setup.
+ * Do MII setup.
*/
- ifmedia_init(&sc->ifmedia, 0, al_ifmedia_upd, al_ifmedia_sts);
-
- if (sc->al_pinfo != NULL) {
- al_getmode_mii(sc);
- al_autoneg_mii(sc, AL_FLAG_FORCEDELAY, 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);
+ 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;
}
- media = sc->ifmedia.ifm_media;
- al_stop(sc);
-
- ifmedia_set(&sc->ifmedia, media);
-
/*
* Call MI attach routines.
*/
@@ -1070,12 +975,40 @@ al_attach(config_id, unit)
#if NBPF > 0
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
#endif
- EVENTHANDLER_REGISTER(shutdown_post_sync, al_shutdown, sc,
- SHUTDOWN_PRI_DEFAULT);
fail:
splx(s);
- return;
+ 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);
}
/*
@@ -1091,17 +1024,23 @@ static int al_list_tx_init(sc)
cd = &sc->al_cdata;
ld = sc->al_ldata;
for (i = 0; i < AL_TX_LIST_CNT; i++) {
- cd->al_tx_chain[i].al_ptr = &ld->al_tx_list[i];
- if (i == (AL_TX_LIST_CNT - 1))
- cd->al_tx_chain[i].al_nextdesc =
- &cd->al_tx_chain[0];
- else
- cd->al_tx_chain[i].al_nextdesc =
- &cd->al_tx_chain[i + 1];
+ 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_free = &cd->al_tx_chain[0];
- cd->al_tx_tail = cd->al_tx_head = NULL;
+ cd->al_tx_prod = cd->al_tx_cons = cd->al_tx_cnt = 0;
return(0);
}
@@ -1123,60 +1062,64 @@ static int al_list_rx_init(sc)
ld = sc->al_ldata;
for (i = 0; i < AL_RX_LIST_CNT; i++) {
- cd->al_rx_chain[i].al_ptr =
- (volatile struct al_desc *)&ld->al_rx_list[i];
- if (al_newbuf(sc, &cd->al_rx_chain[i]) == ENOBUFS)
+ if (al_newbuf(sc, &ld->al_rx_list[i], NULL) == ENOBUFS)
return(ENOBUFS);
if (i == (AL_RX_LIST_CNT - 1)) {
- cd->al_rx_chain[i].al_nextdesc =
- &cd->al_rx_chain[0];
+ 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]);
+ vtophys(&ld->al_rx_list[0]);
} else {
- cd->al_rx_chain[i].al_nextdesc =
- &cd->al_rx_chain[i + 1];
+ 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]);
+ vtophys(&ld->al_rx_list[i + 1]);
}
}
- cd->al_rx_head = &cd->al_rx_chain[0];
+ cd->al_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 al_newbuf(sc, c)
+static int al_newbuf(sc, c, m)
struct al_softc *sc;
- struct al_chain_onefrag *c;
+ struct al_desc *c;
+ struct mbuf *m;
{
struct mbuf *m_new = 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);
- }
+ 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);
+ 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_ptr->al_status = AL_RXSTAT;
- c->al_ptr->al_data = vtophys(mtod(m_new, caddr_t));
- c->al_ptr->al_ctl = MCLBYTES - 1;
+ 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);
}
@@ -1191,19 +1134,23 @@ static void al_rxeof(sc)
struct ether_header *eh;
struct mbuf *m;
struct ifnet *ifp;
- struct al_chain_onefrag *cur_rx;
- int total_len = 0;
+ struct al_desc *cur_rx;
+ int i, total_len = 0;
u_int32_t rxstat;
ifp = &sc->arpcom.ac_if;
- while(!((rxstat = sc->al_cdata.al_rx_head->al_ptr->al_status) &
- AL_RXSTAT_OWN)) {
-#ifdef __alpha__
+ i = sc->al_cdata.al_rx_prod;
+
+ while(!(sc->al_ldata->al_rx_list[i].al_status & AL_RXSTAT_OWN)) {
struct mbuf *m0 = NULL;
-#endif
- cur_rx = sc->al_cdata.al_rx_head;
- sc->al_cdata.al_rx_head = cur_rx->al_nextdesc;
+
+ 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
@@ -1215,90 +1162,23 @@ static void al_rxeof(sc)
ifp->if_ierrors++;
if (rxstat & AL_RXSTAT_COLLSEEN)
ifp->if_collisions++;
- cur_rx->al_ptr->al_status = AL_RXSTAT;
- cur_rx->al_ptr->al_ctl = (MCLBYTES - 1);
- continue;
+ al_newbuf(sc, cur_rx, m);
+ al_init(sc);
+ return;
}
/* No errors; receive the packet. */
- m = cur_rx->al_mbuf;
- total_len = AL_RXBYTES(cur_rx->al_ptr->al_status);
-
total_len -= ETHER_CRC_LEN;
-#ifdef __alpha__
- /*
- * Try to conjure up a new mbuf cluster. If that
- * fails, it means we have an out of memory condition and
- * should leave the buffer in place and continue. This will
- * result in a lost packet, but there's little else we
- * can do in this situation.
- */
- if (al_newbuf(sc, cur_rx) == ENOBUFS) {
- ifp->if_ierrors++;
- cur_rx->al_ptr->al_status = AL_RXSTAT;
- cur_rx->al_ptr->al_ctl = (MCLBYTES - 1);
- continue;
- }
-
- /*
- * Sadly, the ADMtek chip doesn't decode the last few
- * bits of the RX DMA buffer address, so we have to
- * cheat in order to obtain proper payload alignment
- * on the alpha.
- */
- MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ 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++;
- cur_rx->al_ptr->al_status = AL_RXSTAT;
- cur_rx->al_ptr->al_ctl = (MCLBYTES - 1);
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;
- }
- m->m_pkthdr.rcvif = ifp;
-#else
- if (total_len < MINCLSIZE) {
- m = m_devget(mtod(cur_rx->al_mbuf, char *),
- total_len, 0, ifp, NULL);
- cur_rx->al_ptr->al_status = AL_RXSTAT;
- cur_rx->al_ptr->al_ctl = (MCLBYTES - 1);
- if (m == NULL) {
- ifp->if_ierrors++;
- continue;
- }
- } else {
- m = cur_rx->al_mbuf;
- /*
- * Try to conjure up a new mbuf cluster. If that
- * fails, it means we have an out of memory condition and
- * should leave the buffer in place and continue. This will
- * result in a lost packet, but there's little else we
- * can do in this situation.
- */
- if (al_newbuf(sc, cur_rx) == ENOBUFS) {
- ifp->if_ierrors++;
- cur_rx->al_ptr->al_status = AL_RXSTAT;
- cur_rx->al_ptr->al_ctl = (MCLBYTES - 1);
- continue;
- }
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len;
- }
-#endif
+ m_adj(m0, ETHER_ALIGN);
+ m = m0;
ifp->if_ipackets++;
eh = mtod(m, struct ether_header *);
@@ -1312,9 +1192,9 @@ static void al_rxeof(sc)
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)) {
+ (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ ETHER_ADDR_LEN) &&
+ (eh->ether_dhost[0] & 1) == 0)) {
m_freem(m);
continue;
}
@@ -1325,18 +1205,7 @@ static void al_rxeof(sc)
ether_input(ifp, eh, m);
}
- return;
-}
-
-void al_rxeoc(sc)
- struct al_softc *sc;
-{
-
- al_rxeof(sc);
- AL_CLRBIT(sc, AL_NETCFG, AL_NETCFG_RX_ON);
- CSR_WRITE_4(sc, AL_RXADDR, vtophys(sc->al_cdata.al_rx_head->al_ptr));
- AL_SETBIT(sc, AL_NETCFG, AL_NETCFG_RX_ON);
- CSR_WRITE_4(sc, AL_RXSTART, 0xFFFFFFFF);
+ sc->al_cdata.al_rx_prod = i;
return;
}
@@ -1349,78 +1218,85 @@ void al_rxeoc(sc)
static void al_txeof(sc)
struct al_softc *sc;
{
- struct al_chain *cur_tx;
+ 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;
- if (sc->al_cdata.al_tx_head == NULL)
- return;
-
/*
* Go through our tx list and free mbufs for those
* frames that have been transmitted.
*/
- while(sc->al_cdata.al_tx_head->al_mbuf != NULL) {
+ idx = sc->al_cdata.al_tx_cons;
+ while(idx != sc->al_cdata.al_tx_prod) {
u_int32_t txstat;
- cur_tx = sc->al_cdata.al_tx_head;
- txstat = AL_TXSTATUS(cur_tx);
+ 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++;
- m_freem(cur_tx->al_mbuf);
- cur_tx->al_mbuf = NULL;
-
- if (sc->al_cdata.al_tx_head == sc->al_cdata.al_tx_tail) {
- sc->al_cdata.al_tx_head = NULL;
- sc->al_cdata.al_tx_tail = NULL;
- ifp->if_flags &= ~IFF_OACTIVE;
- break;
+ if (cur_tx->al_mbuf != NULL) {
+ m_freem(cur_tx->al_mbuf);
+ cur_tx->al_mbuf = NULL;
}
- sc->al_cdata.al_tx_head = cur_tx->al_nextdesc;
+ 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;
}
-/*
- * TX 'end of channel' interrupt handler.
- */
-static void al_txeoc(sc)
- struct al_softc *sc;
+static void al_tick(xsc)
+ void *xsc;
{
- struct ifnet *ifp;
+ struct al_softc *sc;
+ struct mii_data *mii;
+ int s;
- ifp = &sc->arpcom.ac_if;
+ s = splimp();
- ifp->if_timer = 0;
+ sc = xsc;
+ mii = device_get_softc(sc->al_miibus);
+ mii_tick(mii);
- if (sc->al_cdata.al_tx_head == NULL) {
- ifp->if_flags &= ~IFF_OACTIVE;
- sc->al_cdata.al_tx_tail = NULL;
- if (sc->al_want_auto)
- al_autoneg_mii(sc, AL_FLAG_DELAYTIMEO, 1);
- }
+ sc->al_stat_ch = timeout(al_tick, sc, hz);
+
+ splx(s);
return;
-}
+};
static void al_intr(arg)
void *arg;
@@ -1429,6 +1305,7 @@ static void al_intr(arg)
struct ifnet *ifp;
u_int32_t status;
+
sc = arg;
ifp = &sc->arpcom.ac_if;
@@ -1449,15 +1326,13 @@ static void al_intr(arg)
if ((status & AL_INTRS) == 0)
break;
- if (status & AL_ISR_TX_OK)
+ if ((status & AL_ISR_TX_OK) ||
+ (status & AL_ISR_TX_NOBUF))
al_txeof(sc);
- if (status & AL_ISR_TX_NOBUF)
- al_txeoc(sc);
-
if (status & AL_ISR_TX_IDLE) {
al_txeof(sc);
- if (sc->al_cdata.al_tx_head != NULL) {
+ if (sc->al_cdata.al_tx_cnt) {
AL_SETBIT(sc, AL_NETCFG, AL_NETCFG_TX_ON);
CSR_WRITE_4(sc, AL_TXSTART, 0xFFFFFFFF);
}
@@ -1475,9 +1350,12 @@ static void al_intr(arg)
if (status & AL_ISR_RX_OK)
al_rxeof(sc);
- if ((status & AL_ISR_RX_WATDOGTIMEO)
- || (status & AL_ISR_RX_NOBUF))
- al_rxeoc(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);
@@ -1499,15 +1377,14 @@ static void al_intr(arg)
* Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
* pointers to the fragment pointers.
*/
-static int al_encap(sc, c, m_head)
+static int al_encap(sc, m_head, txidx)
struct al_softc *sc;
- struct al_chain *c;
struct mbuf *m_head;
+ u_int32_t *txidx;
{
- int frag = 0;
- volatile struct al_desc *f = NULL;
- int total_len;
+ struct al_desc *f = NULL;
struct mbuf *m;
+ int frag, cur, cnt = 0;
/*
* Start packing the mbufs in this chain into
@@ -1515,68 +1392,52 @@ static int al_encap(sc, c, m_head)
* of fragments or hit the end of the mbuf chain.
*/
m = m_head;
- total_len = 0;
+ cur = frag = *txidx;
- for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ for (m = m_head; m != NULL; m = m->m_next) {
if (m->m_len != 0) {
- if (frag == AL_MAXFRAGS)
- break;
- total_len += m->m_len;
- f = &c->al_ptr->al_frag[frag];
+#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 (frag == 0) {
+ if (cnt == 0) {
f->al_status = 0;
f->al_ctl |= AL_TXCTL_FIRSTFRAG;
} else
f->al_status = AL_TXSTAT_OWN;
- f->al_next = vtophys(&c->al_ptr->al_frag[frag + 1]);
f->al_data = vtophys(mtod(m, vm_offset_t));
- frag++;
+ cur = frag;
+ AL_INC(frag, AL_TX_LIST_CNT);
+ cnt++;
}
}
- /*
- * 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;
+ if (m != NULL)
+ return(ENOBUFS);
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL) {
- printf("al%d: no memory for tx list", sc->al_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("al%d: no memory for tx list",
- sc->al_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->al_ptr->al_frag[0];
- f->al_status = 0;
- f->al_data = vtophys(mtod(m_new, caddr_t));
- f->al_ctl = total_len = m_new->m_len;
- f->al_ctl |= AL_TXCTL_TLINK|AL_TXCTL_FIRSTFRAG;
- frag = 1;
- }
+ 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;
- c->al_mbuf = m_head;
- c->al_lastdesc = frag - 1;
- AL_TXCTL(c) |= AL_TXCTL_LASTFRAG|AL_TXCTL_FINT;
- AL_TXNEXT(c) = vtophys(&c->al_nextdesc->al_ptr->al_frag[0]);
return(0);
}
@@ -1592,40 +1453,25 @@ static void al_start(ifp)
{
struct al_softc *sc;
struct mbuf *m_head = NULL;
- struct al_chain *cur_tx = NULL, *start_tx;
+ u_int32_t idx;
sc = ifp->if_softc;
if (ifp->if_flags & IFF_OACTIVE)
return;
- if (sc->al_autoneg) {
- sc->al_tx_pend = 1;
- return;
- }
-
- /*
- * Check for an available queue slot. If there are none,
- * punt.
- */
- if (sc->al_cdata.al_tx_free->al_mbuf != NULL) {
- ifp->if_flags |= IFF_OACTIVE;
- return;
- }
+ idx = sc->al_cdata.al_tx_prod;
- start_tx = sc->al_cdata.al_tx_free;
-
- while(sc->al_cdata.al_tx_free->al_mbuf == NULL) {
+ while(sc->al_ldata->al_tx_list[idx].al_mbuf == NULL) {
IF_DEQUEUE(&ifp->if_snd, m_head);
if (m_head == NULL)
break;
- /* Pick a descriptor off the free list. */
- cur_tx = sc->al_cdata.al_tx_free;
- sc->al_cdata.al_tx_free = cur_tx->al_nextdesc;
-
- /* Pack the data into the descriptor. */
- al_encap(sc, cur_tx, m_head);
+ if (al_encap(sc, m_head, &idx)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
#if NBPF > 0
/*
@@ -1633,31 +1479,13 @@ static void al_start(ifp)
* to him.
*/
if (ifp->if_bpf)
- bpf_mtap(ifp, cur_tx->al_mbuf);
-#endif
- AL_TXOWN(cur_tx) = AL_TXSTAT_OWN;
- CSR_WRITE_4(sc, AL_TXSTART, 0xFFFFFFFF);
-#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 (cur_tx == &sc->al_cdata.al_tx_chain[AL_TX_LIST_CNT - 1]) {
- ifp->if_flags |= IFF_OACTIVE;
- break;
- }
+ bpf_mtap(ifp, m_head);
#endif
}
- sc->al_cdata.al_tx_tail = cur_tx;
- if (sc->al_cdata.al_tx_head == NULL)
- sc->al_cdata.al_tx_head = start_tx;
+ /* 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.
@@ -1672,16 +1500,12 @@ static void al_init(xsc)
{
struct al_softc *sc = xsc;
struct ifnet *ifp = &sc->arpcom.ac_if;
- u_int16_t phy_bmcr = 0;
+ struct mii_data *mii;
int s;
- if (sc->al_autoneg)
- return;
-
s = splimp();
- if (sc->al_pinfo != NULL)
- phy_bmcr = al_phy_readreg(sc, PHY_BMCR);
+ mii = device_get_softc(sc->al_miibus);
/*
* Cancel pending I/O and free all RX/TX buffers.
@@ -1753,7 +1577,7 @@ static void al_init(xsc)
/*
* Load the address of the RX list.
*/
- CSR_WRITE_4(sc, AL_RXADDR, vtophys(sc->al_cdata.al_rx_head->al_ptr));
+ 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]));
/*
@@ -1766,15 +1590,15 @@ static void al_init(xsc)
AL_SETBIT(sc, AL_NETCFG, AL_NETCFG_TX_ON|AL_NETCFG_RX_ON);
CSR_WRITE_4(sc, AL_RXSTART, 0xFFFFFFFF);
- /* Restore state of BMCR */
- if (sc->al_pinfo != NULL)
- al_phy_writereg(sc, PHY_BMCR, phy_bmcr);
+ 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;
}
@@ -1785,19 +1609,11 @@ static int al_ifmedia_upd(ifp)
struct ifnet *ifp;
{
struct al_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)
- al_autoneg_mii(sc, AL_FLAG_SCHEDDELAY, 1);
- else {
- al_setmode_mii(sc, ifm->ifm_media);
- }
+ if (ifp->if_flags & IFF_UP)
+ al_init(sc);
return(0);
}
@@ -1810,42 +1626,14 @@ static void al_ifmedia_sts(ifp, ifmr)
struct ifmediareq *ifmr;
{
struct al_softc *sc;
- u_int16_t advert = 0, ability = 0;
+ struct mii_data *mii;
sc = ifp->if_softc;
- ifmr->ifm_active = IFM_ETHER;
-
- if (!(al_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) {
- if (al_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 (al_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- return;
- }
-
- ability = al_phy_readreg(sc, PHY_LPAR);
- advert = al_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;
- }
+ 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;
}
@@ -1857,6 +1645,7 @@ static int al_ioctl(ifp, command, data)
{
struct al_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
int s, error = 0;
s = splimp();
@@ -1883,7 +1672,8 @@ static int al_ioctl(ifp, command, data)
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
- error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
+ mii = device_get_softc(sc->al_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
break;
default:
error = EINVAL;
@@ -1902,20 +1692,9 @@ static void al_watchdog(ifp)
sc = ifp->if_softc;
- if (sc->al_autoneg) {
- al_autoneg_mii(sc, AL_FLAG_DELAYTIMEO, 1);
- return;
- }
-
ifp->if_oerrors++;
printf("al%d: watchdog timeout\n", sc->al_unit);
- if (sc->al_pinfo != NULL) {
- if (!(al_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
- printf("al%d: no carrier - transceiver "
- "cable problem?\n", sc->al_unit);
- }
-
al_stop(sc);
al_reset(sc);
al_init(sc);
@@ -1939,6 +1718,7 @@ static void al_stop(sc)
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);
@@ -1948,9 +1728,9 @@ static void al_stop(sc)
* Free data in the RX lists.
*/
for (i = 0; i < AL_RX_LIST_CNT; i++) {
- if (sc->al_cdata.al_rx_chain[i].al_mbuf != NULL) {
- m_freem(sc->al_cdata.al_rx_chain[i].al_mbuf);
- sc->al_cdata.al_rx_chain[i].al_mbuf = NULL;
+ 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,
@@ -1960,9 +1740,9 @@ static void al_stop(sc)
* Free the TX list buffers.
*/
for (i = 0; i < AL_TX_LIST_CNT; i++) {
- if (sc->al_cdata.al_tx_chain[i].al_mbuf != NULL) {
- m_freem(sc->al_cdata.al_tx_chain[i].al_mbuf);
- sc->al_cdata.al_tx_chain[i].al_mbuf = NULL;
+ 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;
}
}
@@ -1978,22 +1758,13 @@ static void al_stop(sc)
* 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(arg, howto)
- void *arg;
- int howto;
+static void al_shutdown(dev)
+ device_t dev;
{
- struct al_softc *sc = (struct al_softc *)arg;
+ struct al_softc *sc;
- al_stop(sc);
+ sc = device_get_softc(dev);
+ /*al_stop(sc); */
return;
}
-
-static struct pci_device al_device = {
- "al",
- al_probe,
- al_attach,
- &al_count,
- NULL
-};
-COMPAT_PCI_DRIVER(al, al_device);
diff --git a/sys/pci/if_alreg.h b/sys/pci/if_alreg.h
index 2af519b..243903e 100644
--- a/sys/pci/if_alreg.h
+++ b/sys/pci/if_alreg.h
@@ -214,6 +214,10 @@
#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
@@ -348,10 +352,16 @@ struct al_wakup_record {
*/
struct al_desc {
- volatile u_int32_t al_status;
- volatile u_int32_t al_ctl;
- volatile u_int32_t al_ptr1;
- volatile u_int32_t al_ptr2;
+ 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
@@ -378,6 +388,7 @@ struct al_desc {
#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
@@ -407,51 +418,20 @@ struct al_desc {
#define AL_RX_LIST_CNT 64
#define AL_TX_LIST_CNT 128
#define AL_MIN_FRAMELEN 60
+#define AL_RXLEN 1536
-/*
- * A tx 'super descriptor' is actually 16 regular descriptors
- * back to back.
- */
-struct al_txdesc {
- volatile struct al_desc al_frag[AL_MAXFRAGS];
-};
-
-#define AL_TXNEXT(x) x->al_ptr->al_frag[x->al_lastdesc].al_next
-#define AL_TXSTATUS(x) x->al_ptr->al_frag[x->al_lastdesc].al_status
-#define AL_TXCTL(x) x->al_ptr->al_frag[x->al_lastdesc].al_ctl
-#define AL_TXDATA(x) x->al_ptr->al_frag[x->al_lastdesc].al_data
-
-#define AL_TXOWN(x) x->al_ptr->al_frag[0].al_status
-
-#define AL_UNSENT 0x12341234
+#define AL_INC(x, y) (x) = (x + 1) % y
struct al_list_data {
- volatile struct al_desc al_rx_list[AL_RX_LIST_CNT];
- volatile struct al_txdesc al_tx_list[AL_TX_LIST_CNT];
-};
-
-struct al_chain {
- volatile struct al_txdesc *al_ptr;
- struct mbuf *al_mbuf;
- struct al_chain *al_nextdesc;
- u_int8_t al_lastdesc;
-};
-
-struct al_chain_onefrag {
- volatile struct al_desc *al_ptr;
- struct mbuf *al_mbuf;
- struct al_chain_onefrag *al_nextdesc;
+ struct al_desc al_rx_list[AL_RX_LIST_CNT];
+ struct al_desc al_tx_list[AL_TX_LIST_CNT];
};
struct al_chain_data {
- struct al_chain_onefrag al_rx_chain[AL_RX_LIST_CNT];
- struct al_chain al_tx_chain[AL_TX_LIST_CNT];
-
- struct al_chain_onefrag *al_rx_head;
-
- struct al_chain *al_tx_head;
- struct al_chain *al_tx_tail;
- struct al_chain *al_tx_free;
+ int al_tx_prod;
+ int al_tx_cons;
+ int al_tx_cnt;
+ int al_rx_prod;
};
struct al_type {
@@ -469,35 +449,27 @@ struct al_mii_frame {
u_int16_t mii_data;
};
-/*
- * MII constants
- */
#define AL_MII_STARTDELIM 0x01
#define AL_MII_READOP 0x02
#define AL_MII_WRITEOP 0x01
#define AL_MII_TURNAROUND 0x02
-#define AL_FLAG_FORCEDELAY 1
-#define AL_FLAG_SCHEDDELAY 2
-#define AL_FLAG_DELAYTIMEO 3
-
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 */
- struct al_type *al_pinfo; /* phy info */
+ int al_did;
u_int8_t al_unit; /* interface number */
- u_int8_t al_type;
- u_int8_t al_phy_addr; /* PHY address */
- u_int8_t al_tx_pend; /* TX pending */
- u_int8_t al_want_auto;
- u_int8_t al_autoneg;
- caddr_t al_ldata_ptr;
struct al_list_data *al_ldata;
struct al_chain_data al_cdata;
u_int8_t al_cachesize;
+ struct callout_handle al_stat_ch;
};
/*
@@ -518,6 +490,7 @@ struct al_softc {
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.
@@ -532,36 +505,9 @@ struct al_softc {
#define AL_DEVICEID_AL981 0x0981
/*
- * 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
+ * AN985 device IDs.
*/
-#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
-
+#define AL_DEVICEID_AN985 0x0985
/*
* PCI low memory base and low I/O base register, and
@@ -601,105 +547,6 @@ struct al_softc {
#define AL_PME_EN 0x0010
#define AL_PME_STATUS 0x8000
-#define PHY_UNKNOWN 6
-
-#define AL_PHYADDR_MIN 0x00
-#define AL_PHYADDR_MAL 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)
OpenPOWER on IntegriCloud