Date: Mon, 23 Jul 2001 15:06:20 -0700 From: Nick Sayer <nsayer@quack.kfu.com> To: Nick Sayer <nsayer@quack.kfu.com> Cc: "Charles N. Owens" <owensc@enc.edu>, freebsd-mobile@FreeBSD.ORG, Gerhard.Sittig@gmx.net Subject: Re: Netgear FA410TXC timeouts Message-ID: <3B5C9FDC.1060102@quack.kfu.com> References: <3B5833B8.EE9CE5B0@enc.edu> <3B5C8C13.50209@quack.kfu.com>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------040100030003040900070209 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit I am pretty sure this has been done before, but I couldn't find where, so I did it myself. This patch is a selective MFC of the ed driver, bringing to -stable the miibus functionality necessary to make an FA410TX work. I have verified that this works on my FA410TX, but I don't know if it breaks other cards. Be sure to give the Linksys flag to the pccard.conf entry and get rid of any fa_select action you may have set up. I certainly will NOT be committing this, as I don't feel like it's my work that I'm horsing around with. You still get a couple of timeouts while the driver tries the various media until one works. --------------040100030003040900070209 Content-Type: text/plain; name="ed_miibus_patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ed_miibus_patch" Index: if_ed.c =================================================================== RCS file: /home/ncvs/src/sys/dev/ed/if_ed.c,v retrieving revision 1.173.2.10 diff -u -r1.173.2.10 if_ed.c --- if_ed.c 2001/02/08 23:00:23 1.173.2.10 +++ if_ed.c 2001/07/23 22:00:15 @@ -41,6 +41,7 @@ #include <sys/systm.h> #include <sys/sockio.h> #include <sys/mbuf.h> +#include <sys/kernel.h> #include <sys/socket.h> #include <sys/syslog.h> @@ -56,7 +57,11 @@ #include <net/if_arp.h> #include <net/if_dl.h> #include <net/if_mib.h> +#include <net/if_media.h> +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + #include <net/bpf.h> #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 *)); @@ -1580,6 +1586,7 @@ { struct ifnet *ifp = &sc->arpcom.ac_if; + callout_handle_init(&sc->tick_ch); /* * Set interface to stopped condition (reset) */ @@ -1689,6 +1696,8 @@ { int n = 5000; + untimeout(ed_tick, sc, sc->tick_ch); + callout_handle_init(&sc->tick_ch); if (sc->gone) return; /* @@ -1723,6 +1732,27 @@ ed_reset(ifp); } +static void +ed_tick(arg) + void *arg; +{ + struct ed_softc *sc = arg; + struct mii_data *mii; + int s; + + if (sc->gone) { + callout_handle_init(&sc->tick_ch); + 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. */ @@ -1864,6 +1894,11 @@ } } + if (sc->miibus != NULL) { + struct mii_data *mii; + mii = device_get_softc(sc->miibus); + mii_mediachg(mii); + } /* * Set 'running' flag, and clear output active flag. */ @@ -1875,6 +1910,8 @@ */ ed_start(ifp); + untimeout(ed_tick, sc, sc->tick_ch); + sc->tick_ch = timeout(ed_tick, sc, hz); (void) splx(s); } @@ -2486,6 +2523,8 @@ caddr_t data; { struct ed_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + struct mii_data *mii; int s, error = 0; if (sc == NULL || sc->gone) { @@ -2548,6 +2587,15 @@ error = 0; break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + if (sc->miibus == NULL) { + error = EINVAL; + break; + } + mii = device_get_softc(sc->miibus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); + break; default: error = EINVAL; } @@ -3165,6 +3213,109 @@ ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); return (total_len); +} +/* + * MII bus support routines. + */ +int +ed_miibus_readreg(dev, phy, reg) + device_t dev; + int phy, reg; +{ + struct ed_softc *sc; + int failed, s, val; + + s = splimp(); + sc = device_get_softc(dev); + if (sc->gone) { + splx(s); + return (0); + } + + (*sc->mii_writebits)(sc, 0xffffffff, 32); + (*sc->mii_writebits)(sc, ED_MII_STARTDELIM, ED_MII_STARTDELIM_BITS); + (*sc->mii_writebits)(sc, ED_MII_READOP, ED_MII_OP_BITS); + (*sc->mii_writebits)(sc, phy, ED_MII_PHY_BITS); + (*sc->mii_writebits)(sc, reg, ED_MII_REG_BITS); + + failed = (*sc->mii_readbits)(sc, ED_MII_ACK_BITS); + val = (*sc->mii_readbits)(sc, ED_MII_DATA_BITS); + (*sc->mii_writebits)(sc, ED_MII_IDLE, ED_MII_IDLE_BITS); + + splx(s); + return (failed ? 0 : val); +} + +void +ed_miibus_writereg(dev, phy, reg, data) + device_t dev; + int phy, reg, data; +{ + struct ed_softc *sc; + int s; + + s = splimp(); + sc = device_get_softc(dev); + if (sc->gone) { + splx(s); + return; + } + + (*sc->mii_writebits)(sc, 0xffffffff, 32); + (*sc->mii_writebits)(sc, ED_MII_STARTDELIM, ED_MII_STARTDELIM_BITS); + (*sc->mii_writebits)(sc, ED_MII_WRITEOP, ED_MII_OP_BITS); + (*sc->mii_writebits)(sc, phy, ED_MII_PHY_BITS); + (*sc->mii_writebits)(sc, reg, ED_MII_REG_BITS); + (*sc->mii_writebits)(sc, ED_MII_TURNAROUND, ED_MII_TURNAROUND_BITS); + (*sc->mii_writebits)(sc, data, ED_MII_DATA_BITS); + (*sc->mii_writebits)(sc, ED_MII_IDLE, ED_MII_IDLE_BITS); + + splx(s); +} + +int +ed_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); + return mii_mediachg(mii); +} + +void +ed_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; +} + +void +ed_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; } static void Index: if_ed_pccard.c =================================================================== RCS file: /home/ncvs/src/sys/dev/ed/if_ed_pccard.c,v retrieving revision 1.9.2.5 diff -u -r1.9.2.5 if_ed_pccard.c --- if_ed_pccard.c 2001/01/17 13:28:50 1.9.2.5 +++ if_ed_pccard.c 2001/07/23 22:00:16 @@ -44,14 +44,22 @@ #include <net/if.h> #include <net/if_arp.h> #include <net/if_mib.h> +#include <net/if_media.h> #include <dev/ed/if_edreg.h> #include <dev/ed/if_edvar.h> #include <dev/pccard/pccardvar.h> #include <pccard/cardinfo.h> #include <pccard/slot.h> +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "card_if.h" +/* "device miibus" required. See GENERIC if you get errors here. */ +#include "miibus_if.h" + #define CARD_MAJOR 50 +MODULE_DEPEND(ed, miibus, 1, 1, 1); /* * PC-Card (PCMCIA) specific code. @@ -72,6 +80,13 @@ DEVMETHOD(device_attach, ed_pccard_attach), DEVMETHOD(device_detach, ed_pccard_detach), + /* Bus interface */ + DEVMETHOD(bus_child_detached, ed_child_detached), + + /* MII interface */ + DEVMETHOD(miibus_readreg, ed_miibus_readreg), + DEVMETHOD(miibus_writereg, ed_miibus_writereg), + { 0, 0 } }; @@ -84,7 +99,12 @@ 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); +static void ed_pccard_dlink_mii_reset(struct ed_softc *sc); +static u_int ed_pccard_dlink_mii_readbits(struct ed_softc *sc, int nbits); +static void ed_pccard_dlink_mii_writebits(struct ed_softc *sc, u_int val, + int nbits); /* * ed_pccard_detach - unload the driver and clear the table. * XXX TODO: @@ -219,6 +239,15 @@ } error = ed_attach(sc, device_get_unit(dev), flags); + if (error == 0 && linksys) { + /* Probe for an MII bus, but ignore errors. */ + ed_pccard_dlink_mii_reset(sc); + sc->mii_readbits = ed_pccard_dlink_mii_readbits; + sc->mii_writebits = ed_pccard_dlink_mii_writebits; + mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, + ed_ifmedia_sts); + } + return (error); } @@ -358,4 +387,72 @@ sc->type = ED_TYPE_NE2000; sc->type_str = "Linksys"; return (1); +} + +/* MII bit-twiddling routines for cards using Dlink chipset */ +#define DLINK_MIISET(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \ + ed_asic_inb(sc, ED_DLINK_MIIBUS) | (x)) +#define DLINK_MIICLR(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \ + ed_asic_inb(sc, ED_DLINK_MIIBUS) & ~(x)) + +static void +ed_pccard_dlink_mii_reset(sc) + struct ed_softc *sc; +{ + ed_asic_outb(sc, ED_DLINK_MIIBUS, 0); + DELAY(10); + DLINK_MIISET(sc, ED_DLINK_MII_RESET2); + DELAY(10); + DLINK_MIISET(sc, ED_DLINK_MII_RESET1); + DELAY(10); + DLINK_MIICLR(sc, ED_DLINK_MII_RESET1); + DELAY(10); + DLINK_MIICLR(sc, ED_DLINK_MII_RESET2); + DELAY(10); +} + +static void +ed_pccard_dlink_mii_writebits(sc, val, nbits) + struct ed_softc *sc; + u_int val; + int nbits; +{ + int i; + + DLINK_MIISET(sc, ED_DLINK_MII_DIROUT); + + for (i = nbits - 1; i >= 0; i--) { + if ((val >> i) & 1) + DLINK_MIISET(sc, ED_DLINK_MII_DATAOUT); + else + DLINK_MIICLR(sc, ED_DLINK_MII_DATAOUT); + DELAY(10); + DLINK_MIISET(sc, ED_DLINK_MII_CLK); + DELAY(10); + DLINK_MIICLR(sc, ED_DLINK_MII_CLK); + DELAY(10); + } +} + +static u_int +ed_pccard_dlink_mii_readbits(sc, nbits) + struct ed_softc *sc; + int nbits; +{ + int i; + u_int val = 0; + + DLINK_MIICLR(sc, ED_DLINK_MII_DIROUT); + + for (i = nbits - 1; i >= 0; i--) { + DLINK_MIISET(sc, ED_DLINK_MII_CLK); + DELAY(10); + val <<= 1; + if (ed_asic_inb(sc, ED_DLINK_MIIBUS) & ED_DLINK_MII_DATATIN) + val++; + DLINK_MIICLR(sc, ED_DLINK_MII_CLK); + DELAY(10); + } + + return val; } Index: if_edreg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/ed/if_edreg.h,v retrieving revision 1.27.2.2 diff -u -r1.27.2.2 if_edreg.h --- if_edreg.h 2001/01/17 13:28:50 1.27.2.2 +++ if_edreg.h 2001/07/23 22:00:17 @@ -577,6 +577,7 @@ #define ED_VENDOR_NOVELL 0x02 /* Novell */ #define ED_VENDOR_PCCARD 0x03 /* PCMCIA/PCCARD */ #define ED_VENDOR_HP 0x04 /* Hewlett Packard */ +#define ED_VENDOR_LINKSYS 0x05 /* Linksys (Dlink) */ /* * Compile-time config flags @@ -1113,3 +1114,32 @@ #define ED_AX88190_IOBASE0 0x3ca #define ED_AX88190_IOBASE1 0x3cc + +/* + * MII bus definitions. + */ +#define ED_MII_STARTDELIM 0x01 +#define ED_MII_WRITEOP 0x01 +#define ED_MII_READOP 0x02 +#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 + +/* Dlink chipset used on some Netgear and Dlink PCMCIA cards */ +#define ED_DLINK_MIIBUS 0x0c /* MII bus register on ASIC */ + +#define ED_DLINK_MII_RESET1 0x04 +#define ED_DLINK_MII_RESET2 0x08 + +#define ED_DLINK_MII_DATATIN 0x10 +#define ED_DLINK_MII_DIROUT 0x20 +#define ED_DLINK_MII_DATAOUT 0x40 +#define ED_DLINK_MII_CLK 0x80 Index: if_edvar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/ed/if_edvar.h,v retrieving revision 1.4.2.3 diff -u -r1.4.2.3 if_edvar.h --- if_edvar.h 2001/01/17 13:28:50 1.4.2.3 +++ if_edvar.h 2001/07/23 22:00:17 @@ -47,6 +47,10 @@ 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 */ + void (*mii_writebits)__P((struct ed_softc*, u_int, int)); + u_int (*mii_readbits)__P((struct ed_softc*, int)); + 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 */ @@ -203,6 +207,11 @@ unsigned short)); void ed_pio_writemem __P((struct ed_softc *, char *, unsigned short, unsigned short)); +int ed_miibus_readreg __P((device_t, int, int)); +void ed_miibus_writereg __P((device_t, int, int, int)); +int ed_ifmedia_upd __P((struct ifnet *)); +void ed_ifmedia_sts __P((struct ifnet*, struct ifmediareq *)); +void ed_child_detached __P((device_t, device_t)); driver_intr_t edintr; --------------040100030003040900070209-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-mobile" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3B5C9FDC.1060102>