Skip site navigation (1)Skip section navigation (2)
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>