Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 06 Dec 2000 01:20:47 +0000
From:      Ian Dowse <iedowse@maths.tcd.ie>
To:        Scott Stegmiller <stegs@gblx.net>
Cc:        freebsd-mobile@freebsd.org, iedowse@maths.tcd.ie
Subject:   Re: Netgear FA410TXC 
Message-ID:   <200012060120.aa34104@salmon.maths.tcd.ie>
In-Reply-To: Your message of "Tue, 05 Dec 2000 16:47:45 MST." <Pine.GSO.4.21.0012051640440.25609-100000@shell1.phx.gblx.net> 

next in thread | previous in thread | raw e-mail | index | archive | help
In message <Pine.GSO.4.21.0012051640440.25609-100000@shell1.phx.gblx.net>, 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 <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 *));
 
@@ -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 <net/if.h>
 #include <net/if_arp.h>
 #include <net/if_mib.h>
+#include <net/if_media.h>
 
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "miibus_if.h"
+
 #include <dev/ed/if_edreg.h>
 #include <dev/ed/if_edvar.h>
 #include <dev/pccard/pccardvar.h>
@@ -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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi? <200012060120.aa34104>