From owner-freebsd-mobile Tue Dec 5 17:21: 2 2000 From owner-freebsd-mobile@FreeBSD.ORG Tue Dec 5 17:20:49 2000 Return-Path: Delivered-To: freebsd-mobile@freebsd.org Received: from salmon.maths.tcd.ie (salmon.maths.tcd.ie [134.226.81.11]) by hub.freebsd.org (Postfix) with SMTP id C5C9237B400 for ; Tue, 5 Dec 2000 17:20:48 -0800 (PST) Received: from walton.maths.tcd.ie by salmon.maths.tcd.ie with SMTP id ; 6 Dec 2000 01:20:47 +0000 (GMT) To: Scott Stegmiller Cc: freebsd-mobile@freebsd.org, iedowse@maths.tcd.ie Subject: Re: Netgear FA410TXC In-Reply-To: Your message of "Tue, 05 Dec 2000 16:47:45 MST." Date: Wed, 06 Dec 2000 01:20:47 +0000 From: Ian Dowse Message-ID: <200012060120.aa34104@salmon.maths.tcd.ie> Sender: owner-freebsd-mobile@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org In message , Scot t Stegmiller writes: > >I am running 4.2 Release and am having some issues with device timeouts >with the card > >/kernel: ed0: device timeout I posted a patch to freebsd-mobile yesterday which may cure this problem (without the need for the fa_select program). I'd be interested to hear if it works with your card. Apply the patch in /usr/src/sys/dev/ed, then recompile + install the kernel and reboot (the patch below has a few extra cosmetic changes I made since yesterday). Ian Index: if_ed.c =================================================================== RCS file: /home/iedowse/CVS/src/sys/dev/ed/if_ed.c,v retrieving revision 1.173.2.8 diff -u -r1.173.2.8 if_ed.c --- if_ed.c 2000/09/10 08:45:11 1.173.2.8 +++ if_ed.c 2000/12/04 15:51:24 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,11 @@ #include #include #include +#include +#include +#include + #include #include "opt_bdg.h" #ifdef BRIDGE @@ -74,6 +79,7 @@ static void ed_start __P((struct ifnet *)); static void ed_reset __P((struct ifnet *)); static void ed_watchdog __P((struct ifnet *)); +static void ed_tick __P((void *)); static void ds_getmcaf __P((struct ed_softc *, u_int32_t *)); @@ -1617,6 +1623,8 @@ { struct ifnet *ifp = &sc->arpcom.ac_if; + callout_handle_init(&sc->tick_ch); + /* * Set interface to stopped condition (reset) */ @@ -1726,6 +1734,8 @@ { int n = 5000; + untimeout(ed_tick, sc, sc->tick_ch); + if (sc->gone) return; /* @@ -1760,6 +1770,26 @@ ed_reset(ifp); } +static void +ed_tick(arg) + void *arg; +{ + struct ed_softc *sc = arg; + struct mii_data *mii; + int s; + + if (sc->gone) + return; + + s = splimp(); + if (sc->miibus != NULL) { + mii = device_get_softc(sc->miibus); + mii_tick(mii); + } + sc->tick_ch = timeout(ed_tick, sc, hz); + splx(s); +} + /* * Initialize device. */ @@ -1912,6 +1942,8 @@ */ ed_start(ifp); + sc->tick_ch = timeout(ed_tick, sc, hz); + (void) splx(s); } @@ -2521,6 +2553,7 @@ caddr_t data; { struct ed_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; if (sc == NULL || sc->gone) { @@ -2581,6 +2614,19 @@ */ ed_setrcr(sc); error = 0; + break; + + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + if (sc->miibus != NULL) { + struct mii_data *mii; + + mii = device_get_softc(sc->miibus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, + command); + break; + } + error = EINVAL; break; default: Index: if_ed_pccard.c =================================================================== RCS file: /home/iedowse/CVS/src/sys/dev/ed/if_ed_pccard.c,v retrieving revision 1.9.2.4 diff -u -r1.9.2.4 if_ed_pccard.c --- if_ed_pccard.c 2000/09/10 08:45:11 1.9.2.4 +++ if_ed_pccard.c 2000/12/05 20:40:04 @@ -44,7 +44,13 @@ #include #include #include +#include +#include +#include + +#include "miibus_if.h" + #include #include #include @@ -59,17 +65,35 @@ static int ed_pccard_probe(device_t); static int ed_pccard_attach(device_t); static int ed_pccard_detach(device_t); +static void ed_pccard_child_detached(device_t dev, device_t child); static void ax88190_geteprom(struct ed_softc *); static int ed_pccard_memwrite(device_t dev, off_t offset, u_char byte); static int ed_pccard_memread(device_t dev, off_t offset, u_char *buf, int size); +static int ed_pccard_miibus_readreg(device_t dev, int phy, int reg); +static void ed_pccard_miibus_writereg(device_t dev, int phy, int reg, + int data); +static int ed_pccard_ifmedia_upd(struct ifnet *ifp); +static void ed_pccard_ifmedia_sts(struct ifnet *ifp, + struct ifmediareq *ifmr); +static void ed_pccard_fa410_mii_reset(struct ed_softc *sc); +static u_int32_t ed_pccard_fa410_mii_readbits(struct ed_softc *sc, int nbits); +static void ed_pccard_fa410_mii_writebits(struct ed_softc *sc, u_int32_t val, + int nbits); + static device_method_t ed_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ed_pccard_probe), DEVMETHOD(device_attach, ed_pccard_attach), DEVMETHOD(device_detach, ed_pccard_detach), + DEVMETHOD(bus_child_detached, ed_pccard_child_detached), + + /* MII interface */ + DEVMETHOD(miibus_readreg, ed_pccard_miibus_readreg), + DEVMETHOD(miibus_writereg, ed_pccard_miibus_writereg), + { 0, 0 } }; @@ -82,6 +106,7 @@ static devclass_t ed_pccard_devclass; DRIVER_MODULE(ed, pccard, ed_pccard_driver, ed_pccard_devclass, 0, 0); +DRIVER_MODULE(miibus, ed, miibus_driver, miibus_devclass, 0, 0); /* * ed_pccard_detach - unload the driver and clear the table. @@ -106,6 +131,16 @@ ifp->if_flags &= ~IFF_RUNNING; ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); sc->gone = 1; + + /* + * We rely on ed_pccard_child_detached to set miibus to NULL if + * the miibus has alredy been deleted, as is usually the case. + */ + if (sc->miibus != NULL) { + device_delete_child(dev, sc->miibus); + bus_generic_detach(dev); + } + bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); ed_release_resources(dev); return (0); @@ -186,6 +221,7 @@ int i; u_char sum; u_char ether_addr[ETHER_ADDR_LEN]; + int probe_mii = 0; if (sc->port_used > 0) ed_alloc_port(dev, sc->port_rid, sc->port_used); @@ -201,7 +237,9 @@ return (error); } - if (ed_get_Linksys(sc) == 0) { + if (ed_get_Linksys(sc)) + probe_mii = 1; + else { pccard_get_ether(dev, ether_addr); for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) sum |= ether_addr[i]; @@ -210,6 +248,13 @@ } error = ed_attach(sc, device_get_unit(dev), flags); + + if (probe_mii) { + ed_pccard_fa410_mii_reset(sc); + mii_phy_probe(dev, &sc->miibus, ed_pccard_ifmedia_upd, + ed_pccard_ifmedia_sts); + } + return (error); } @@ -312,4 +357,187 @@ d = makedev(CARD_MAJOR, devi->slt->slotnum); return devsw(d)->d_read(d, &uios, 0); +} + +static void +ed_pccard_child_detached(dev, child) + device_t dev; + device_t child; +{ + struct ed_softc *sc; + + sc = device_get_softc(dev); + + if (child == sc->miibus) + sc->miibus = NULL; +} + +#define FA410_MIISET(sc, x) ed_asic_outb(sc, ED_FA410_MIIBUS, \ + ed_asic_inb(sc, ED_FA410_MIIBUS) | (x)) +#define FA410_MIICLR(sc, x) ed_asic_outb(sc, ED_FA410_MIIBUS, \ + ed_asic_inb(sc, ED_FA410_MIIBUS) & ~(x)) + +static void +ed_pccard_fa410_mii_reset(sc) + struct ed_softc *sc; +{ + /* + * The Linux fa_select.c program performs something close to + * these operations before talking to the MII bus. I've no idea + * if they are necessary... + */ + ed_asic_outb(sc, ED_FA410_MIIBUS, 0); + DELAY(10); + FA410_MIISET(sc, ED_FA410_MII_RESET2); + DELAY(10); + FA410_MIISET(sc, ED_FA410_MII_RESET1); + DELAY(10); + FA410_MIICLR(sc, ED_FA410_MII_RESET1); + DELAY(10); + FA410_MIICLR(sc, ED_FA410_MII_RESET2); + DELAY(10); +} + +static void +ed_pccard_fa410_mii_writebits(sc, val, nbits) + struct ed_softc *sc; + u_int32_t val; + int nbits; +{ + int i; + + FA410_MIISET(sc, ED_FA410_MII_DIROUT); + + for (i = nbits - 1; i >= 0; i--) { + if ((val >> i) & 1) + FA410_MIISET(sc, ED_FA410_MII_DATAOUT); + else + FA410_MIICLR(sc, ED_FA410_MII_DATAOUT); + DELAY(10); + FA410_MIISET(sc, ED_FA410_MII_CLK); + DELAY(10); + FA410_MIICLR(sc, ED_FA410_MII_CLK); + DELAY(10); + } +} + +static u_int32_t +ed_pccard_fa410_mii_readbits(sc, nbits) + struct ed_softc *sc; + int nbits; +{ + int i; + u_int32_t val = 0; + + FA410_MIICLR(sc, ED_FA410_MII_DIROUT); + + for (i = nbits - 1; i >= 0; i--) { + FA410_MIISET(sc, ED_FA410_MII_CLK); + DELAY(10); + val <<= 1; + if (ed_asic_inb(sc, ED_FA410_MIIBUS) & ED_FA410_MII_DATATIN) + val++; + FA410_MIICLR(sc, ED_FA410_MII_CLK); + DELAY(10); + } + + return val; +} + +static int +ed_pccard_miibus_readreg(dev, phy, reg) + device_t dev; + int phy, reg; +{ + struct ed_softc *sc; + int val; + int failed; + + sc = device_get_softc(dev); + + if (sc->gone) + return 0; + + ed_pccard_fa410_mii_writebits(sc, 0xffffffff, 32); + + ed_pccard_fa410_mii_writebits(sc, ED_MII_STARTDELIM, + ED_MII_STARTDELIM_BITS); + ed_pccard_fa410_mii_writebits(sc, ED_MII_READOP, ED_MII_OP_BITS); + ed_pccard_fa410_mii_writebits(sc, phy, ED_MII_PHY_BITS); + ed_pccard_fa410_mii_writebits(sc, reg, ED_MII_REG_BITS); + + failed = ed_pccard_fa410_mii_readbits(sc, ED_MII_ACK_BITS); + + val = ed_pccard_fa410_mii_readbits(sc, ED_MII_DATA_BITS); + + ed_pccard_fa410_mii_readbits(sc, ED_MII_IDLE_BITS); + + return failed ? 0 : val; +} + +static void +ed_pccard_miibus_writereg(dev, phy, reg, data) + device_t dev; + int phy, reg, data; +{ + struct ed_softc *sc; + + sc = device_get_softc(dev); + + if (sc->gone) + return; + + ed_pccard_fa410_mii_writebits(sc, 0xffffffff, 32); + + ed_pccard_fa410_mii_writebits(sc, ED_MII_STARTDELIM, + ED_MII_STARTDELIM_BITS); + ed_pccard_fa410_mii_writebits(sc, ED_MII_WRITEOP, ED_MII_OP_BITS); + ed_pccard_fa410_mii_writebits(sc, phy, ED_MII_PHY_BITS); + ed_pccard_fa410_mii_writebits(sc, reg, ED_MII_REG_BITS); + ed_pccard_fa410_mii_writebits(sc, ED_MII_TURNAROUND, + ED_MII_TURNAROUND_BITS); + ed_pccard_fa410_mii_writebits(sc, data, ED_MII_DATA_BITS); + ed_pccard_fa410_mii_writebits(sc, ED_MII_IDLE, ED_MII_IDLE_BITS); +} + +static int +ed_pccard_ifmedia_upd(ifp) + struct ifnet *ifp; +{ + struct ed_softc *sc; + struct mii_data *mii; + + sc = ifp->if_softc; + + if (sc->gone || sc->miibus == NULL) + return ENXIO; + + mii = device_get_softc(sc->miibus); + + if (mii->mii_instance) { + struct mii_softc *miisc; + for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; + miisc = LIST_NEXT(miisc, mii_list)) + mii_phy_reset(miisc); + } + return mii_mediachg(mii); +} + +static void +ed_pccard_ifmedia_sts(ifp, ifmr) + struct ifnet *ifp; + struct ifmediareq *ifmr; +{ + struct ed_softc *sc; + struct mii_data *mii; + + sc = ifp->if_softc; + + if (sc->gone || sc->miibus == NULL) + return; + + mii = device_get_softc(sc->miibus); + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; } Index: if_edreg.h =================================================================== RCS file: /home/iedowse/CVS/src/sys/dev/ed/if_edreg.h,v retrieving revision 1.27.2.1 diff -u -r1.27.2.1 if_edreg.h --- if_edreg.h 2000/09/10 08:45:11 1.27.2.1 +++ if_edreg.h 2000/12/05 20:39:10 @@ -1112,3 +1112,36 @@ #define ED_AX88190_IOBASE0 0x3ca #define ED_AX88190_IOBASE1 0x3cc + +/* + * Definitions for Netgear FA410TX with MII-based PHYs. + */ +#define ED_FA410_MIIBUS 0x0c + +#define ED_MII_STARTDELIM 0x01 +#define ED_MII_READOP 0x02 +#define ED_MII_WRITEOP 0x01 +#define ED_MII_TURNAROUND 0x02 +#define ED_MII_IDLE 0x01 + +#define ED_MII_STARTDELIM_BITS 2 +#define ED_MII_OP_BITS 2 +#define ED_MII_PHY_BITS 5 +#define ED_MII_REG_BITS 5 +#define ED_MII_TURNAROUND_BITS 2 +#define ED_MII_DATA_BITS 16 +#define ED_MII_ACK_BITS 1 +#define ED_MII_IDLE_BITS 1 + +/* + * These definitions are guesses based on the Linux fa_select.c program + * which was floating around on the internet. + */ +#define ED_FA410_MII_RESET1 0x04 +#define ED_FA410_MII_RESET2 0x08 + +#define ED_FA410_MII_DATATIN 0x10 +#define ED_FA410_MII_DIROUT 0x20 +#define ED_FA410_MII_DATAOUT 0x40 +#define ED_FA410_MII_CLK 0x80 + Index: if_edvar.h =================================================================== RCS file: /home/iedowse/CVS/src/sys/dev/ed/if_edvar.h,v retrieving revision 1.4.2.2 diff -u -r1.4.2.2 if_edvar.h --- if_edvar.h 2000/09/10 08:45:11 1.4.2.2 +++ if_edvar.h 2000/12/03 16:58:07 @@ -47,6 +47,8 @@ int irq_rid; /* resource id for irq */ struct resource* irq_res; /* resource for irq */ void* irq_handle; /* handle for irq handler */ + device_t miibus; /* MII bus for cards with MII. */ + struct callout_handle tick_ch; /* Callout handle for ed_tick */ int nic_offset; /* NIC (DS8390) I/O bus address offset */ int asic_offset; /* ASIC I/O bus address offset */ To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-mobile" in the body of the message