summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_vr.c
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1999-09-19 22:03:31 +0000
committerwpaul <wpaul@FreeBSD.org>1999-09-19 22:03:31 +0000
commitfc84b1a733b5c4774a2dcd8035e4f71948716a55 (patch)
treee6283556c004444ffa88b017a7e1d60c5b66b4c5 /sys/pci/if_vr.c
parent170f347106454c60c4298a0542c314e4bff3af2b (diff)
downloadFreeBSD-src-fc84b1a733b5c4774a2dcd8035e4f71948716a55.zip
FreeBSD-src-fc84b1a733b5c4774a2dcd8035e4f71948716a55.tar.gz
Convert the VIA Rhine driver to miibus.
Diffstat (limited to 'sys/pci/if_vr.c')
-rw-r--r--sys/pci/if_vr.c608
1 files changed, 111 insertions, 497 deletions
diff --git a/sys/pci/if_vr.c b/sys/pci/if_vr.c
index 1e47ec1..7ed0d86 100644
--- a/sys/pci/if_vr.c
+++ b/sys/pci/if_vr.c
@@ -94,15 +94,19 @@
#include <sys/bus.h>
#include <sys/rman.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
#include <pci/pcireg.h>
#include <pci/pcivar.h>
#define VR_USEIOSPACE
-/* #define VR_BACKGROUND_AUTONEG */
-
#include <pci/if_vrreg.h>
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
@@ -123,22 +127,6 @@ static struct vr_type vr_devs[] = {
{ 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 vr_type vr_phys[] = {
- { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" },
- { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" },
- { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"},
- { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" },
- { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" },
- { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" },
- { 0, 0, "<MII-compliant physical interface>" }
-};
-
static int vr_probe __P((device_t));
static int vr_attach __P((device_t));
static int vr_detach __P((device_t));
@@ -153,6 +141,7 @@ static void vr_rxeof __P((struct vr_softc *));
static void vr_rxeoc __P((struct vr_softc *));
static void vr_txeof __P((struct vr_softc *));
static void vr_txeoc __P((struct vr_softc *));
+static void vr_tick __P((void *));
static void vr_intr __P((void *));
static void vr_start __P((struct ifnet *));
static int vr_ioctl __P((struct ifnet *, u_long, caddr_t));
@@ -167,14 +156,11 @@ static void vr_mii_sync __P((struct vr_softc *));
static void vr_mii_send __P((struct vr_softc *, u_int32_t, int));
static int vr_mii_readreg __P((struct vr_softc *, struct vr_mii_frame *));
static int vr_mii_writereg __P((struct vr_softc *, struct vr_mii_frame *));
-static u_int16_t vr_phy_readreg __P((struct vr_softc *, int));
-static void vr_phy_writereg __P((struct vr_softc *, u_int16_t, u_int16_t));
-
-static void vr_autoneg_xmit __P((struct vr_softc *));
-static void vr_autoneg_mii __P((struct vr_softc *, int, int));
-static void vr_setmode_mii __P((struct vr_softc *, int));
-static void vr_getmode_mii __P((struct vr_softc *));
-static void vr_setcfg __P((struct vr_softc *, u_int16_t));
+static int vr_miibus_readreg __P((device_t, int, int));
+static int vr_miibus_writereg __P((device_t, int, int, int));
+static void vr_miibus_statchg __P((device_t));
+
+static void vr_setcfg __P((struct vr_softc *, int));
static u_int8_t vr_calchash __P((u_int8_t *));
static void vr_setmulti __P((struct vr_softc *));
static void vr_reset __P((struct vr_softc *));
@@ -195,6 +181,16 @@ static device_method_t vr_methods[] = {
DEVMETHOD(device_attach, vr_attach),
DEVMETHOD(device_detach, vr_detach),
DEVMETHOD(device_shutdown, vr_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, vr_miibus_readreg),
+ DEVMETHOD(miibus_writereg, vr_miibus_writereg),
+ DEVMETHOD(miibus_statchg, vr_miibus_statchg),
+
{ 0, 0 }
};
@@ -207,6 +203,7 @@ static driver_t vr_driver = {
static devclass_t vr_devclass;
DRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0);
+DRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
#define VR_SETBIT(sc, reg, x) \
CSR_WRITE_1(sc, reg, \
@@ -432,36 +429,52 @@ static int vr_mii_writereg(sc, frame)
return(0);
}
-static u_int16_t vr_phy_readreg(sc, reg)
- struct vr_softc *sc;
- int reg;
+static int vr_miibus_readreg(dev, phy, reg)
+ device_t dev;
+ int phy, reg;
{
+ struct vr_softc *sc;
struct vr_mii_frame frame;
+ sc = device_get_softc(dev);
bzero((char *)&frame, sizeof(frame));
- frame.mii_phyaddr = sc->vr_phy_addr;
+ frame.mii_phyaddr = phy;
frame.mii_regaddr = reg;
vr_mii_readreg(sc, &frame);
return(frame.mii_data);
}
-static void vr_phy_writereg(sc, reg, data)
- struct vr_softc *sc;
- u_int16_t reg;
- u_int16_t data;
+static int vr_miibus_writereg(dev, phy, reg, data)
+ device_t dev;
+ u_int16_t phy, reg, data;
{
+ struct vr_softc *sc;
struct vr_mii_frame frame;
+ sc = device_get_softc(dev);
bzero((char *)&frame, sizeof(frame));
- frame.mii_phyaddr = sc->vr_phy_addr;
+ frame.mii_phyaddr = phy;
frame.mii_regaddr = reg;
frame.mii_data = data;
vr_mii_writereg(sc, &frame);
+ return(0);
+}
+
+static void vr_miibus_statchg(dev)
+ device_t dev;
+{
+ struct vr_softc *sc;
+ struct mii_data *mii;
+
+ sc = device_get_softc(dev);
+ mii = device_get_softc(sc->vr_miibus);
+ vr_setcfg(sc, mii->mii_media_active);
+
return;
}
@@ -548,319 +561,13 @@ static void vr_setmulti(sc)
}
/*
- * Initiate an autonegotiation session.
- */
-static void vr_autoneg_xmit(sc)
- struct vr_softc *sc;
-{
- u_int16_t phy_sts;
-
- vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(vr_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
-
- phy_sts = vr_phy_readreg(sc, PHY_BMCR);
- phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR;
- vr_phy_writereg(sc, PHY_BMCR, phy_sts);
-
- return;
-}
-
-/*
- * Invoke autonegotiation on a PHY.
- */
-static void vr_autoneg_mii(sc, flag, verbose)
- struct vr_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 = vr_phy_readreg(sc, PHY_BMSR);
- if (!(phy_sts & PHY_BMSR_CANAUTONEG)) {
- if (verbose)
- printf("vr%d: autonegotiation not supported\n",
- sc->vr_unit);
- ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
- return;
- }
-#endif
-
- switch (flag) {
- case VR_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.
- */
- vr_autoneg_xmit(sc);
- DELAY(5000000);
- break;
- case VR_FLAG_SCHEDDELAY:
- /*
- * Wait for the transmitter to go idle before starting
- * an autoneg session, otherwise vr_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->vr_cdata.vr_tx_head != NULL) {
- sc->vr_want_auto = 1;
- return;
- }
- vr_autoneg_xmit(sc);
- ifp->if_timer = 5;
- sc->vr_autoneg = 1;
- sc->vr_want_auto = 0;
- return;
- break;
- case VR_FLAG_DELAYTIMEO:
- ifp->if_timer = 0;
- sc->vr_autoneg = 0;
- break;
- default:
- printf("vr%d: invalid autoneg flag: %d\n", sc->vr_unit, flag);
- return;
- }
-
- if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) {
- if (verbose)
- printf("vr%d: autoneg complete, ", sc->vr_unit);
- phy_sts = vr_phy_readreg(sc, PHY_BMSR);
- } else {
- if (verbose)
- printf("vr%d: autoneg not complete, ", sc->vr_unit);
- }
-
- media = vr_phy_readreg(sc, PHY_BMCR);
-
- /* Link is good. Report modes and set duplex mode. */
- if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) {
- if (verbose)
- printf("link status good ");
- advert = vr_phy_readreg(sc, PHY_ANAR);
- ability = vr_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 {
- 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. */
- vr_setcfg(sc, media);
- vr_phy_writereg(sc, PHY_BMCR, media);
- } else {
- if (verbose)
- printf("no carrier\n");
- }
-
- vr_init(sc);
-
- if (sc->vr_tx_pend) {
- sc->vr_autoneg = 0;
- sc->vr_tx_pend = 0;
- vr_start(ifp);
- }
-
- return;
-}
-
-static void vr_getmode_mii(sc)
- struct vr_softc *sc;
-{
- u_int16_t bmsr;
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
-
- bmsr = vr_phy_readreg(sc, PHY_BMSR);
- if (bootverbose)
- printf("vr%d: PHY status word: %x\n", sc->vr_unit, bmsr);
-
- /* fallback */
- sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
-
- if (bmsr & PHY_BMSR_10BTHALF) {
- if (bootverbose)
- printf("vr%d: 10Mbps half-duplex mode supported\n",
- sc->vr_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("vr%d: 10Mbps full-duplex mode supported\n",
- sc->vr_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("vr%d: 100Mbps half-duplex mode supported\n",
- sc->vr_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("vr%d: 100Mbps full-duplex mode supported\n",
- sc->vr_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("vr%d: 100baseT4 mode supported\n", sc->vr_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("vr%d: forcing on autoneg support for BT4\n",
- sc->vr_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("vr%d: autoneg supported\n", sc->vr_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 vr_setmode_mii(sc, media)
- struct vr_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->vr_autoneg) {
- printf("vr%d: canceling autoneg session\n", sc->vr_unit);
- ifp->if_timer = sc->vr_autoneg = sc->vr_want_auto = 0;
- bmcr = vr_phy_readreg(sc, PHY_BMCR);
- bmcr &= ~PHY_BMCR_AUTONEGENBL;
- vr_phy_writereg(sc, PHY_BMCR, bmcr);
- }
-
- printf("vr%d: selecting MII, ", sc->vr_unit);
-
- bmcr = vr_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;
- }
-
- vr_setcfg(sc, bmcr);
- vr_phy_writereg(sc, PHY_BMCR, bmcr);
-
- return;
-}
-
-/*
* In order to fiddle with the
* 'full-duplex' and '100Mbps' bits in the netconfig register, we
* first have to put the transmit and/or receive logic in the idle state.
*/
-static void vr_setcfg(sc, bmcr)
+static void vr_setcfg(sc, media)
struct vr_softc *sc;
- u_int16_t bmcr;
+ int media;
{
int restart = 0;
@@ -869,7 +576,7 @@ static void vr_setcfg(sc, bmcr)
VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
}
- if (bmcr & PHY_BMCR_DUPLEX)
+ if ((media & IFM_GMASK) == IFM_FDX)
VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
else
VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
@@ -931,16 +638,11 @@ static int vr_probe(dev)
static int vr_attach(dev)
device_t dev;
{
- int s, i;
+ int i, s;
u_char eaddr[ETHER_ADDR_LEN];
u_int32_t command;
struct vr_softc *sc;
struct ifnet *ifp;
- int media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- unsigned int round;
- caddr_t roundptr;
- struct vr_type *p;
- u_int16_t phy_vid, phy_did, phy_sts;
int unit, error = 0, rid;
s = splimp();
@@ -1057,9 +759,10 @@ static int vr_attach(dev)
sc->vr_unit = unit;
bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
- sc->vr_ldata_ptr = malloc(sizeof(struct vr_list_data) + 8,
- M_DEVBUF, M_NOWAIT);
- if (sc->vr_ldata_ptr == NULL) {
+ sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
+ M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->vr_ldata == NULL) {
printf("vr%d: no memory for list buffers!\n", unit);
bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
@@ -1068,17 +771,6 @@ static int vr_attach(dev)
goto fail;
}
- sc->vr_ldata = (struct vr_list_data *)sc->vr_ldata_ptr;
- round = (unsigned int)sc->vr_ldata_ptr & 0xF;
- roundptr = sc->vr_ldata_ptr;
- for (i = 0; i < 8; i++) {
- if (round % 8) {
- round++;
- roundptr++;
- } else
- break;
- }
- sc->vr_ldata = (struct vr_list_data *)roundptr;
bzero(sc->vr_ldata, sizeof(struct vr_list_data));
ifp = &sc->arpcom.ac_if;
@@ -1095,70 +787,22 @@ static int vr_attach(dev)
ifp->if_baudrate = 10000000;
ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
- if (bootverbose)
- printf("vr%d: probing for a PHY\n", sc->vr_unit);
- for (i = VR_PHYADDR_MIN; i < VR_PHYADDR_MAX + 1; i++) {
- if (bootverbose)
- printf("vr%d: checking address: %d\n",
- sc->vr_unit, i);
- sc->vr_phy_addr = i;
- vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
- DELAY(500);
- while(vr_phy_readreg(sc, PHY_BMCR)
- & PHY_BMCR_RESET);
- if ((phy_sts = vr_phy_readreg(sc, PHY_BMSR)))
- break;
- }
- if (phy_sts) {
- phy_vid = vr_phy_readreg(sc, PHY_VENID);
- phy_did = vr_phy_readreg(sc, PHY_DEVID);
- if (bootverbose)
- printf("vr%d: found PHY at address %d, ",
- sc->vr_unit, sc->vr_phy_addr);
- if (bootverbose)
- printf("vendor id: %x device id: %x\n",
- phy_vid, phy_did);
- p = vr_phys;
- while(p->vr_vid) {
- if (phy_vid == p->vr_vid &&
- (phy_did | 0x000F) == p->vr_did) {
- sc->vr_pinfo = p;
- break;
- }
- p++;
- }
- if (sc->vr_pinfo == NULL)
- sc->vr_pinfo = &vr_phys[PHY_UNKNOWN];
- if (bootverbose)
- printf("vr%d: PHY type: %s\n",
- sc->vr_unit, sc->vr_pinfo->vr_name);
- } else {
+ /*
+ * Do MII setup.
+ */
+ if (mii_phy_probe(dev, &sc->vr_miibus,
+ vr_ifmedia_upd, vr_ifmedia_sts)) {
printf("vr%d: MII without any phy!\n", sc->vr_unit);
bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
- free(sc->vr_ldata_ptr, M_DEVBUF);
+ contigfree(sc->vr_ldata,
+ sizeof(struct vr_list_data), M_DEVBUF);
error = ENXIO;
goto fail;
}
- /*
- * Do ifmedia setup.
- */
- ifmedia_init(&sc->ifmedia, 0, vr_ifmedia_upd, vr_ifmedia_sts);
-
- vr_getmode_mii(sc);
- if (cold) {
- vr_autoneg_mii(sc, VR_FLAG_FORCEDELAY, 1);
- vr_stop(sc);
- } else {
- vr_init(sc);
- vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1);
- }
-
- media = sc->ifmedia.ifm_media;
-
- ifmedia_set(&sc->ifmedia, media);
+ callout_handle_init(&sc->vr_stat_ch);
/*
* Call MI attach routines.
@@ -1190,12 +834,14 @@ static int vr_detach(dev)
vr_stop(sc);
if_detach(ifp);
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->vr_miibus);
+
bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
- free(sc->vr_ldata_ptr, M_DEVBUF);
- ifmedia_removeall(&sc->ifmedia);
+ contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
splx(s);
@@ -1466,7 +1112,6 @@ static void vr_txeof(sc)
{
struct vr_chain *cur_tx;
struct ifnet *ifp;
- register struct mbuf *n;
ifp = &sc->arpcom.ac_if;
@@ -1501,8 +1146,10 @@ static void vr_txeof(sc)
ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
ifp->if_opackets++;
- MFREE(cur_tx->vr_mbuf, n);
- cur_tx->vr_mbuf = NULL;
+ if (cur_tx->vr_mbuf != NULL) {
+ m_freem(cur_tx->vr_mbuf);
+ cur_tx->vr_mbuf = NULL;
+ }
if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {
sc->vr_cdata.vr_tx_head = NULL;
@@ -1531,13 +1178,31 @@ static void vr_txeoc(sc)
if (sc->vr_cdata.vr_tx_head == NULL) {
ifp->if_flags &= ~IFF_OACTIVE;
sc->vr_cdata.vr_tx_tail = NULL;
- if (sc->vr_want_auto)
- vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1);
}
return;
}
+static void vr_tick(xsc)
+ void *xsc;
+{
+ struct vr_softc *sc;
+ struct mii_data *mii;
+ int s;
+
+ s = splimp();
+
+ sc = xsc;
+ mii = device_get_softc(sc->vr_miibus);
+ mii_tick(mii);
+
+ sc->vr_stat_ch = timeout(vr_tick, sc, hz);
+
+ splx(s);
+
+ return;
+}
+
static void vr_intr(arg)
void *arg;
{
@@ -1691,10 +1356,8 @@ static void vr_start(ifp)
sc = ifp->if_softc;
- if (sc->vr_autoneg) {
- sc->vr_tx_pend = 1;
+ if (ifp->if_flags & IFF_OACTIVE)
return;
- }
/*
* Check for an available queue slot. If there are none,
@@ -1731,7 +1394,7 @@ static void vr_start(ifp)
bpf_mtap(ifp, cur_tx->vr_mbuf);
#endif
VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
- VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_TX_GO);
+ VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO);
}
/*
@@ -1758,16 +1421,12 @@ static void vr_init(xsc)
{
struct vr_softc *sc = xsc;
struct ifnet *ifp = &sc->arpcom.ac_if;
- u_int16_t phy_bmcr = 0;
+ struct mii_data *mii;
int s;
- if (sc->vr_autoneg)
- return;
-
s = splimp();
- if (sc->vr_pinfo != NULL)
- phy_bmcr = vr_phy_readreg(sc, PHY_BMCR);
+ mii = device_get_softc(sc->vr_miibus);
/*
* Cancel pending I/O and free all RX/TX buffers.
@@ -1822,8 +1481,6 @@ static void vr_init(xsc)
VR_CMD_TX_ON|VR_CMD_RX_ON|
VR_CMD_RX_GO);
- vr_setcfg(sc, vr_phy_readreg(sc, PHY_BMCR));
-
CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
/*
@@ -1832,15 +1489,15 @@ static void vr_init(xsc)
CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
- /* Restore state of BMCR */
- if (sc->vr_pinfo != NULL)
- vr_phy_writereg(sc, PHY_BMCR, phy_bmcr);
+ mii_mediachg(mii);
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
(void)splx(s);
+ sc->vr_stat_ch = timeout(vr_tick, sc, hz);
+
return;
}
@@ -1851,18 +1508,11 @@ static int vr_ifmedia_upd(ifp)
struct ifnet *ifp;
{
struct vr_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)
- vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1);
- else
- vr_setmode_mii(sc, ifm->ifm_media);
+ if (ifp->if_flags & IFF_UP)
+ vr_init(sc);
return(0);
}
@@ -1875,42 +1525,13 @@ static void vr_ifmedia_sts(ifp, ifmr)
struct ifmediareq *ifmr;
{
struct vr_softc *sc;
- u_int16_t advert = 0, ability = 0;
+ struct mii_data *mii;
sc = ifp->if_softc;
-
- ifmr->ifm_active = IFM_ETHER;
-
- if (!(vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) {
- if (vr_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 (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX)
- ifmr->ifm_active |= IFM_FDX;
- else
- ifmr->ifm_active |= IFM_HDX;
- return;
- }
-
- ability = vr_phy_readreg(sc, PHY_LPAR);
- advert = vr_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->vr_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
return;
}
@@ -1922,6 +1543,7 @@ static int vr_ioctl(ifp, command, data)
{
struct vr_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
int s, error = 0;
s = splimp();
@@ -1948,7 +1570,8 @@ static int vr_ioctl(ifp, command, data)
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
- error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
+ mii = device_get_softc(sc->vr_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
break;
default:
error = EINVAL;
@@ -1967,20 +1590,9 @@ static void vr_watchdog(ifp)
sc = ifp->if_softc;
- if (sc->vr_autoneg) {
- vr_autoneg_mii(sc, VR_FLAG_DELAYTIMEO, 1);
- if (!(ifp->if_flags & IFF_UP))
- vr_stop(sc);
- return;
- }
-
ifp->if_oerrors++;
printf("vr%d: watchdog timeout\n", sc->vr_unit);
- if (!(vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
- printf("vr%d: no carrier - transceiver cable problem?\n",
- sc->vr_unit);
-
vr_stop(sc);
vr_reset(sc);
vr_init(sc);
@@ -2004,6 +1616,8 @@ static void vr_stop(sc)
ifp = &sc->arpcom.ac_if;
ifp->if_timer = 0;
+ untimeout(vr_tick, sc, sc->vr_stat_ch);
+
VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
CSR_WRITE_2(sc, VR_IMR, 0x0000);
OpenPOWER on IntegriCloud