Add support for Dlink DL10022 to the ed driver. This is a mii part

bolted to a ne-2000 chip.  This is necessary for the NetGear FA-410TX
and other cards.

This also requires you add mii to your kernel if you have an ed driver
configured.

This code will result in a couple of timeout messages for ed on the
impacted cards.  Additional work will be needed, but this does work
right now, and many people need these cards.

Submitted by: Ian Dowse <iedowse@maths.tcd.ie>
This commit is contained in:
Warner Losh 2001-03-03 08:31:37 +00:00
parent 8a8d42eebb
commit f2fdbb57ca
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=73374
9 changed files with 298 additions and 10 deletions

View File

@ -182,6 +182,7 @@ device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'')
# ISA Ethernet NICs. pccard nics included.
device cs # Crystal Semiconductor CS89x0 NIC
# 'device ed' requires 'device miibus'
device ed # NE[12]000, SMC Ultra, 3c503, DS8390 cards
device ex # Intel EtherExpress Pro/10 and Pro/10+
device ep # Etherlink III based cards

View File

@ -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>
@ -55,6 +56,10 @@
#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"
@ -74,6 +79,7 @@ static int ed_ioctl __P((struct ifnet *, u_long, caddr_t));
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 *));
@ -1586,6 +1592,7 @@ ed_attach(sc, unit, flags)
{
struct ifnet *ifp = &sc->arpcom.ac_if;
callout_handle_init(&sc->tick_ch);
/*
* Set interface to stopped condition (reset)
*/
@ -1695,6 +1702,8 @@ ed_stop(sc)
{
int n = 5000;
untimeout(ed_tick, sc, sc->tick_ch);
callout_handle_init(&sc->tick_ch);
if (sc->gone)
return;
/*
@ -1729,6 +1738,27 @@ ed_watchdog(ifp)
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.
*/
@ -1870,6 +1900,11 @@ ed_init(xsc)
}
}
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.
*/
@ -1881,6 +1916,8 @@ ed_init(xsc)
*/
ed_start(ifp);
untimeout(ed_tick, sc, sc->tick_ch);
sc->tick_ch = timeout(ed_tick, sc, hz);
(void) splx(s);
}
@ -2492,6 +2529,8 @@ ed_ioctl(ifp, command, data)
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) {
@ -2554,6 +2593,16 @@ ed_ioctl(ifp, command, data)
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;
}
@ -3173,6 +3222,101 @@ ed_hpp_write_mbufs(struct ed_softc *sc, struct mbuf *m, int dst)
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 val;
int failed;
sc = device_get_softc(dev);
if (sc->gone)
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);
return (failed ? 0 : val);
}
void
ed_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;
(*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);
}
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
ed_setrcr(sc)
struct ed_softc *sc;

View File

@ -44,13 +44,20 @@
#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 <dev/pccard/pccarddevs.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"
MODULE_DEPEND(ed, miibus, 1, 1, 1);
/*
* PC-Card (PCMCIA) specific code.
@ -65,6 +72,10 @@ static int ed_pccard_ax88190(device_t dev);
static void ax88190_geteprom(struct ed_softc *);
static int ed_pccard_memwrite(device_t dev, off_t offset, u_char byte);
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);
static int linksys;
/*
@ -659,6 +670,13 @@ ed_pccard_Linksys(device_t dev)
sc->isa16bit = 1;
sc->type = ED_TYPE_NE2000;
sc->type_str = "Linksys";
/* Probe for an MII bus, but continue as normal if there isn't one. */
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 (1);
}
@ -694,12 +712,87 @@ ed_pccard_ax88190(device_t dev)
return (error);
}
/* 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;
}
static device_method_t ed_pccard_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pccard_compat_probe),
DEVMETHOD(device_attach, pccard_compat_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),
/* Card interface */
DEVMETHOD(card_compat_match, ed_pccard_match),
DEVMETHOD(card_compat_probe, ed_pccard_probe),
@ -714,3 +807,4 @@ static driver_t ed_pccard_driver = {
};
DRIVER_MODULE(if_ed, pccard, ed_pccard_driver, ed_devclass, 0, 0);
DRIVER_MODULE(miibus, ed, miibus_driver, miibus_devclass, 0, 0);

View File

@ -21,6 +21,7 @@
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/kernel.h>

View File

@ -1113,3 +1113,32 @@ struct ed_ring {
#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

View File

@ -49,6 +49,10 @@ struct ed_softc {
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 */
@ -205,6 +209,11 @@ void ed_pio_readmem __P((struct ed_softc *, int, unsigned char *,
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;

View File

@ -182,6 +182,7 @@ device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'')
# ISA Ethernet NICs. pccard nics included.
device cs # Crystal Semiconductor CS89x0 NIC
# 'device ed' requires 'device miibus'
device ed # NE[12]000, SMC Ultra, 3c503, DS8390 cards
device ex # Intel EtherExpress Pro/10 and Pro/10+
device ep # Etherlink III based cards

View File

@ -40,7 +40,7 @@ maxusers 32
options MATH_EMULATE #Support for x87 emulation
options INET #InterNETworking
options INET6 #IPv6 communications protocols
#options INET6 #IPv6 communications protocols
options FFS #Berkeley Fast Filesystem
options SOFTUPDATES #Enable FFS soft updates support
options MFS #Memory Filesystem
@ -68,13 +68,18 @@ options KBD_INSTALL_CDEV # install a CDEV entry in /dev
#options SMP # Symmetric MultiProcessor Kernel
#options APIC_IO # Symmetric (APIC) I/O
options IPFIREWALL
options DUMMYNET
options IPFIREWALL_DEFAULT_TO_ACCEPT
options IPDIVERT
device isa
device eisa
device pci
device pccard
device pmtimer
device cardbus
options COMPAT_OLDISA # compatability shims for lnc, le
#options COMPAT_OLDISA # compatability shims for lnc, le
# Floppy drives
device fdc
@ -158,7 +163,7 @@ device pcm
# Pcmcia and cardbus bridge support
device pcic # pcmcia bridge
#device pcic # pcmcia bridge
device pccbb # cardbus (yenta) bridge
# Serial (COM) ports
@ -196,6 +201,7 @@ device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'')
# ISA Ethernet NICs. pccard nics included.
device cs # Crystal Semiconductor CS89x0 NIC
# 'device ed' requires 'device miibus'
device ed # NE[12]000, SMC Ultra, 3c503, DS8390 cards
device ex # Intel EtherExpress Pro/10 and Pro/10+
device ep # Etherlink III based cards
@ -204,8 +210,8 @@ device sn # SMC's 9000 series of ethernet chips
device xe # Xircom pccard ethernet
# The probe order of these is presently determined by i386/isa/isa_compat.c.
device ie
device le
#device ie
#device le
#device lnc
# Wireless NIC cards
@ -223,8 +229,8 @@ device ppp 1 # Kernel PPP
device tun # Packet tunnel.
device pty # Pseudo-ttys (telnet etc)
device md # Memory "disks"
device gif 4 # IPv6 and IPv4 tunneling
device faith 1 # IPv6-to-IPv4 relaying (translation)
#device gif 4 # IPv6 and IPv4 tunneling
#device faith 1 # IPv6-to-IPv4 relaying (translation)
# The `bpf' device enables the Berkeley Packet Filter.
# Be aware of the administrative consequences of enabling this!
@ -248,5 +254,8 @@ device aue # ADMtek USB ethernet
device cue # CATC USB ethernet
device kue # Kawasaki LSI USB ethernet
# This is an experimental kernel, so include DDB
options DDB
# This is an experimental kernel, so include DDB, INVARIANTS and WITNESS
options DDB
options INVARIANTS
options INVARIANT_SUPPORT
options WITNESS

View File

@ -12,6 +12,6 @@ CFLAGS+= -DPC98
SRCS+= if_ed_isa.c
.endif
SRCS+= opt_bdg.h bus_if.h card_if.h device_if.h isa_if.h pci_if.h
SRCS+= opt_bdg.h bus_if.h card_if.h device_if.h isa_if.h pci_if.h miibus_if.h
.include <bsd.kmod.mk>