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>
