#include "bpfilter.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <sys/queue.h>
#include <sys/kernel.h>
#include <sys/timeout.h>
#include <net/if.h>
#include <net/if_media.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#if NBPFILTER > 0
#include <net/bpf.h>
#endif
#include <machine/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
#include <dev/ic/elink3reg.h>
#undef EF_DEBUG
struct ef_softc {
struct device sc_dv;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
struct arpcom sc_arpcom;
struct mii_data sc_mii;
struct timeout sc_tick_tmo;
void * sc_ih;
int sc_tx_start_thresh;
int sc_tx_succ_ok;
int sc_busmaster;
};
#define EF_W0_EEPROM_COMMAND 0x200a
#define EF_EEPROM_BUSY (1 << 9)
#define EF_EEPROM_READ (1 << 7)
#define EF_W0_EEPROM_DATA 0x200c
#define EF_W1_TX_PIO_WR_1 0x10
#define EF_W1_RX_PIO_RR_1 0x10
#define EF_W1_RX_ERRORS 0x14
#define EF_W1_RX_STATUS 0x18
#define EF_W1_TX_STATUS 0x1b
#define EF_W1_FREE_TX 0x1c
#define EF_W4_MEDIA 0x0a
#define EF_MEDIA_SQE 0x0008
#define EF_MEDIA_TP 0x00c0
#define EF_MEDIA_LNK 0x0080
#define EF_MEDIA_LNKBEAT 0x0800
#define EF_MII_CLK 0x01
#define EF_MII_DATA 0x02
#define EF_MII_DIR 0x04
int ef_isapnp_match(struct device *, void *, void *);
void ef_isapnp_attach(struct device *, struct device *, void *);
void efstart(struct ifnet *);
int efioctl(struct ifnet *, u_long, caddr_t);
void efwatchdog(struct ifnet *);
void efreset(struct ef_softc *);
void efstop(struct ef_softc *);
void efsetmulti(struct ef_softc *);
int efbusyeeprom(struct ef_softc *);
int efintr(void *);
void efinit(struct ef_softc *);
void efcompletecmd(struct ef_softc *, u_int, u_int);
void eftxstat(struct ef_softc *);
void efread(struct ef_softc *);
struct mbuf *efget(struct ef_softc *, int totlen);
void ef_miibus_writereg(struct device *, int, int, int);
void ef_miibus_statchg(struct device *);
int ef_miibus_readreg(struct device *, int, int);
void ef_mii_writeb(struct ef_softc *, int);
void ef_mii_sync(struct ef_softc *);
int ef_ifmedia_upd(struct ifnet *);
void ef_ifmedia_sts(struct ifnet *, struct ifmediareq *);
void ef_tick(void *);
struct cfdriver ef_cd = {
NULL, "ef", DV_IFNET
};
const struct cfattach ef_isapnp_ca = {
sizeof(struct ef_softc), ef_isapnp_match, ef_isapnp_attach
};
int
ef_isapnp_match(struct device *parent, void *match, void *aux)
{
return (1);
}
void
ef_isapnp_attach(struct device *parent, struct device *self, void *aux)
{
struct ef_softc *sc = (void *)self;
struct isa_attach_args *ia = aux;
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
bus_space_tag_t iot;
bus_space_handle_t ioh;
int i;
u_int16_t x;
u_int32_t cfg;
sc->sc_iot = iot = ia->ia_iot;
sc->sc_ioh = ioh = ia->ipa_io[0].h;
efcompletecmd(sc, EP_COMMAND, GLOBAL_RESET);
DELAY(1500);
for (i = 0; i < 3; i++) {
if (efbusyeeprom(sc))
return;
bus_space_write_2(iot, ioh, EF_W0_EEPROM_COMMAND,
EF_EEPROM_READ | i);
if (efbusyeeprom(sc))
return;
x = bus_space_read_2(iot, ioh, EF_W0_EEPROM_DATA);
sc->sc_arpcom.ac_enaddr[(i << 1)] = x >> 8;
sc->sc_arpcom.ac_enaddr[(i << 1) + 1] = x;
}
printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
GO_WINDOW(3);
cfg = bus_space_read_4(iot, ioh, EP_W3_INTERNAL_CONFIG);
cfg &= ~(0x00f00000);
cfg |= (0x06 << 20);
bus_space_write_4(iot, ioh, EP_W3_INTERNAL_CONFIG, cfg);
sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
IPL_NET, efintr, sc, sc->sc_dv.dv_xname);
if (ia->ia_drq != DRQUNK)
isadma_cascade(ia->ia_drq);
timeout_set(&sc->sc_tick_tmo, ef_tick, sc);
bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
ifp->if_softc = sc;
ifp->if_start = efstart;
ifp->if_ioctl = efioctl;
ifp->if_watchdog = efwatchdog;
ifp->if_flags =
IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
sc->sc_mii.mii_ifp = ifp;
sc->sc_mii.mii_readreg = ef_miibus_readreg;
sc->sc_mii.mii_writereg = ef_miibus_writereg;
sc->sc_mii.mii_statchg = ef_miibus_statchg;
ifmedia_init(&sc->sc_mii.mii_media, 0, ef_ifmedia_upd, ef_ifmedia_sts);
mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
0);
if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
} else
ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
if_attach(ifp);
ether_ifattach(ifp);
sc->sc_tx_start_thresh = 20;
efcompletecmd(sc, EP_COMMAND, RX_RESET);
efcompletecmd(sc, EP_COMMAND, TX_RESET);
}
void
efstart(struct ifnet *ifp)
{
struct ef_softc *sc = ifp->if_softc;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct mbuf *m, *m0;
int s, len, pad, i;
int fillcnt = 0;
u_int32_t filler = 0;
if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
return;
startagain:
m0 = ifq_deq_begin(&ifp->if_snd);
if (m0 == NULL)
return;
if ((m0->m_flags & M_PKTHDR) == 0)
panic("efstart: no header mbuf");
len = m0->m_pkthdr.len;
pad = (4 - len) & 3;
if (len + pad > ETHER_MAX_LEN) {
ifp->if_oerrors++;
ifq_deq_commit(&ifp->if_snd, m0);
m_freem(m0);
goto startagain;
}
if (bus_space_read_2(iot, ioh, EF_W1_FREE_TX) < len + pad + 4) {
bus_space_write_2(iot, ioh, EP_COMMAND,
SET_TX_AVAIL_THRESH | ((len + pad) >> 2));
ifq_deq_rollback(&ifp->if_snd, m0);
ifq_set_oactive(&ifp->if_snd);
return;
} else {
bus_space_write_2(iot, ioh, EP_COMMAND,
SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
}
bus_space_write_2(iot, ioh, EP_COMMAND, SET_TX_START_THRESH |
((len / 4 + sc->sc_tx_start_thresh)));
#if NBPFILTER
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
#endif
ifq_deq_commit(&ifp->if_snd, m0);
if (m0 == NULL)
return;
s = splhigh();
bus_space_write_4(iot, ioh, EF_W1_TX_PIO_WR_1, len);
for (m = m0; m; ) {
if (fillcnt) {
while (m->m_len && fillcnt < 4) {
fillcnt++;
filler >>= 8;
filler |= m->m_data[0] << 24;
m->m_data++;
m->m_len--;
}
if (fillcnt == 4) {
bus_space_write_4(iot, ioh,
EF_W1_TX_PIO_WR_1, filler);
filler = 0;
fillcnt = 0;
}
}
if (m->m_len & ~3)
bus_space_write_multi_4(iot, ioh,
EF_W1_TX_PIO_WR_1, (u_int32_t *)m->m_data,
m->m_len >> 2);
for (i = 0; i < (m->m_len & 3); i++) {
fillcnt++;
filler >>= 8;
filler |= m->m_data[(m->m_len & ~3) + i] << 24;
}
m0 = m_free(m);
m = m0;
}
if (fillcnt) {
bus_space_write_4(iot, ioh, EF_W1_TX_PIO_WR_1,
filler >> (32 - (8 * fillcnt)));
fillcnt = 0;
filler = 0;
}
splx(s);
goto startagain;
}
int
efioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct ef_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
s = splnet();
switch (cmd) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
efinit(sc);
break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
break;
case SIOCSIFFLAGS:
if ((ifp->if_flags & IFF_UP) == 0 &&
(ifp->if_flags & IFF_RUNNING) != 0) {
efstop(sc);
ifp->if_flags &= ~IFF_RUNNING;
} else if ((ifp->if_flags & IFF_UP) != 0 &&
(ifp->if_flags & IFF_RUNNING) == 0) {
efinit(sc);
}
efsetmulti(sc);
break;
default:
error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
}
if (error == ENETRESET) {
if (ifp->if_flags & IFF_RUNNING) {
efreset(sc);
efsetmulti(sc);
}
error = 0;
}
splx(s);
return (error);
}
void
efinit(struct ef_softc *sc)
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
int i, s;
s = splnet();
efstop(sc);
while (bus_space_read_2(iot, ioh, EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
GO_WINDOW(2);
for (i = 0; i < 6; i++)
bus_space_write_1(iot, ioh, EP_W2_ADDR_0 + i,
sc->sc_arpcom.ac_enaddr[i]);
for (i = 0; i < 3; i += 2)
bus_space_write_2(iot, ioh, EP_W2_RECVMASK_0 + (i * 2), 0);
efcompletecmd(sc, EP_COMMAND, RX_RESET);
efcompletecmd(sc, EP_COMMAND, TX_RESET);
bus_space_write_2(iot, ioh, EP_COMMAND,
SET_TX_AVAIL_THRESH | (ETHER_MAX_DIX_LEN >> 2));
efsetmulti(sc);
bus_space_write_2(iot, ioh, EP_COMMAND, STATUS_ENABLE | 0);
GO_WINDOW(6);
for (i = 0; i < 10; i++)
(void)bus_space_read_1(iot, ioh, i);
(void)bus_space_read_2(iot, ioh, 10);
(void)bus_space_read_2(iot, ioh, 12);
GO_WINDOW(4);
(void)bus_space_read_1(iot, ioh, 12);
bus_space_write_2(iot, ioh, EP_W4_NET_DIAG, 0x0040);
GO_WINDOW(7);
efsetmulti(sc);
bus_space_write_2(iot, ioh, EP_COMMAND, RX_ENABLE);
bus_space_write_2(iot, ioh, EP_COMMAND, TX_ENABLE);
bus_space_write_2(iot, ioh, EP_COMMAND, STATUS_ENABLE |
S_CARD_FAILURE | S_INT_RQD | S_UPD_STATS | S_TX_COMPLETE |
S_TX_AVAIL | S_RX_COMPLETE |
(sc->sc_busmaster ? S_DMA_DONE : 0));
bus_space_write_2(iot, ioh, EP_COMMAND, ACK_INTR |
S_INTR_LATCH | S_TX_AVAIL | S_RX_EARLY | S_INT_RQD);
bus_space_write_2(iot, ioh, EP_COMMAND, SET_INTR_MASK |
S_INTR_LATCH | S_TX_AVAIL | S_RX_COMPLETE | S_UPD_STATS |
(sc->sc_busmaster ? S_DMA_DONE : 0) | S_UP_COMPLETE |
S_DOWN_COMPLETE | S_CARD_FAILURE | S_TX_COMPLETE);
mii_mediachg(&sc->sc_mii);
ifp->if_flags |= IFF_RUNNING;
ifq_clr_oactive(&ifp->if_snd);
splx(s);
timeout_add_sec(&sc->sc_tick_tmo, 1);
efstart(ifp);
}
void
efreset(struct ef_softc *sc)
{
int s;
s = splnet();
efstop(sc);
efinit(sc);
splx(s);
}
void
efstop(struct ef_softc *sc)
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
ifp->if_timer = 0;
ifp->if_flags &= ~IFF_RUNNING;
ifq_clr_oactive(&ifp->if_snd);
timeout_del(&sc->sc_tick_tmo);
bus_space_write_2(iot, ioh, EP_COMMAND, RX_DISABLE);
efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
bus_space_write_2(iot, ioh, EP_COMMAND, TX_DISABLE);
bus_space_write_2(iot, ioh, EP_COMMAND, STOP_TRANSCEIVER);
efcompletecmd(sc, EP_COMMAND, RX_RESET);
efcompletecmd(sc, EP_COMMAND, TX_RESET);
bus_space_write_2(iot, ioh, EP_COMMAND, C_INTR_LATCH);
bus_space_write_2(iot, ioh, EP_COMMAND, SET_RD_0_MASK);
bus_space_write_2(iot, ioh, EP_COMMAND, SET_INTR_MASK);
bus_space_write_2(iot, ioh, EP_COMMAND, SET_RX_FILTER);
}
void
efcompletecmd(struct ef_softc *sc, u_int cmd, u_int arg)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
bus_space_write_2(iot, ioh, cmd, arg);
while (bus_space_read_2(iot, ioh, EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
}
int
efintr(void *vsc)
{
struct ef_softc *sc = vsc;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
u_int16_t status;
int r = 0;
status = bus_space_read_2(iot, ioh, EP_STATUS);
do {
if (status & S_RX_COMPLETE) {
r = 1;
bus_space_write_2(iot, ioh, EP_STATUS, C_RX_COMPLETE);
efread(sc);
}
if (status & S_TX_AVAIL) {
bus_space_write_2(iot, ioh, EP_STATUS, C_TX_AVAIL);
r = 1;
ifq_clr_oactive(&sc->sc_arpcom.ac_if.if_snd);
efstart(&sc->sc_arpcom.ac_if);
}
if (status & S_CARD_FAILURE) {
r = 1;
efreset(sc);
printf("%s: adapter failure (%x)\n",
sc->sc_dv.dv_xname, status);
bus_space_write_2(iot, ioh, EP_COMMAND,
C_CARD_FAILURE);
return (1);
}
if (status & S_TX_COMPLETE) {
r = 1;
eftxstat(sc);
efstart(ifp);
}
bus_space_write_2(iot, ioh, EP_COMMAND,
C_INTR_LATCH | C_INT_RQD);
} while ((status = bus_space_read_2(iot, ioh, EP_STATUS)) &
(S_INT_RQD | S_RX_COMPLETE));
return (r);
}
void
eftxstat(struct ef_softc *sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
int i;
while ((i = bus_space_read_1(iot, ioh, EF_W1_TX_STATUS)) &
TXS_COMPLETE) {
bus_space_write_1(iot, ioh, EF_W1_TX_STATUS, 0);
if (i & TXS_JABBER) {
sc->sc_arpcom.ac_if.if_oerrors++;
#ifdef EF_DEBUG
if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
printf("%s: jabber (%x)\n",
sc->sc_dv.dv_xname, i);
#endif
efreset(sc);
}
else if (i & TXS_UNDERRUN) {
sc->sc_arpcom.ac_if.if_oerrors++;
#ifdef EF_DEBUG
if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
printf("%s: fifo underrun (%x) @%d\n",
sc->sc_dv.dv_xname, i,
sc->sc_tx_start_thresh);
#endif
if (sc->sc_tx_succ_ok < 100)
sc->sc_tx_start_thresh = min(ETHER_MAX_LEN,
sc->sc_tx_start_thresh + 20);
sc->sc_tx_succ_ok = 0;
efreset(sc);
}
else if (i & TXS_MAX_COLLISION) {
sc->sc_arpcom.ac_if.if_collisions++;
bus_space_write_2(iot, ioh, EP_COMMAND, TX_ENABLE);
ifq_clr_oactive(&sc->sc_arpcom.ac_if.if_snd);
}
else
sc->sc_tx_succ_ok = (sc->sc_tx_succ_ok + 1) & 127;
}
}
int
efbusyeeprom(struct ef_softc *sc)
{
int i = 100, j;
while (i--) {
j = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
EF_W0_EEPROM_COMMAND);
if (j & EF_EEPROM_BUSY)
delay(100);
else
break;
}
if (i == 0) {
printf("%s: eeprom failed to come ready\n",
sc->sc_dv.dv_xname);
return (1);
}
return (0);
}
void
efwatchdog(struct ifnet *ifp)
{
struct ef_softc *sc = ifp->if_softc;
printf("%s: device timeout\n", sc->sc_dv.dv_xname);
sc->sc_arpcom.ac_if.if_oerrors++;
efreset(sc);
}
void
efsetmulti(struct ef_softc *sc)
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct arpcom *ac = &sc->sc_arpcom;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct ether_multi *enm;
struct ether_multistep step;
u_int16_t cmd = SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST;
int mcnt = 0;
ETHER_FIRST_MULTI(step, ac, enm);
while (enm != NULL) {
mcnt++;
ETHER_NEXT_MULTI(step, enm);
}
if (mcnt || ifp->if_flags & IFF_ALLMULTI)
cmd |= FIL_MULTICAST;
if (ifp->if_flags & IFF_PROMISC)
cmd |= FIL_PROMISC;
bus_space_write_2(iot, ioh, EP_COMMAND, cmd);
}
void
efread(struct ef_softc *sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct mbuf_list ml = MBUF_LIST_INITIALIZER();
struct mbuf *m;
int len;
len = bus_space_read_2(iot, ioh, EF_W1_RX_STATUS);
#ifdef EF_DEBUG
if (ifp->if_flags & IFF_DEBUG) {
int err = len & ERR_MASK;
char *s = NULL;
if (len & ERR_INCOMPLETE)
s = "incomplete packet";
else if (err == ERR_OVERRUN)
s = "packet overrun";
else if (err == ERR_RUNT)
s = "runt packet";
else if (err == ERR_ALIGNMENT)
s = "bad alignment";
else if (err == ERR_CRC)
s = "bad crc";
else if (err == ERR_OVERSIZE)
s = "oversized packet";
else if (err == ERR_DRIBBLE)
s = "dribble bits";
if (s)
printf("%s: %s\n", sc->sc_dv.dv_xname, s);
}
#endif
if (len & ERR_INCOMPLETE)
return;
if (len & ERR_RX) {
ifp->if_ierrors++;
efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
return;
}
len &= RX_BYTES_MASK;
m = efget(sc, len);
if (m == NULL) {
ifp->if_ierrors++;
efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
return;
}
ml_enqueue(&ml, m);
if_input(ifp, &ml);
}
struct mbuf *
efget(struct ef_softc *sc, int totlen)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct mbuf *top, **mp, *m;
int len, pad, s;
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
return (NULL);
m->m_pkthdr.len = totlen;
pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
m->m_data += pad;
len = MHLEN -pad;
top = 0;
mp = ⊤
s = splhigh();
while (totlen > 0) {
if (top) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
m_freem(top);
splx(s);
return (NULL);
}
len = MLEN;
}
if (top && totlen >= MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
if (m->m_flags & M_EXT)
len = MCLBYTES;
}
len = min(totlen, len);
if (len > 1) {
len &= ~1;
bus_space_read_raw_multi_2(iot, ioh,
EF_W1_RX_PIO_RR_1, mtod(m, u_int8_t *),
len);
} else
*(mtod(m, u_int8_t *)) =
bus_space_read_1(iot, ioh, EF_W1_RX_PIO_RR_1);
m->m_len = len;
totlen -= len;
*mp = m;
mp = &m->m_next;
}
efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
splx(s);
return (top);
}
#define MII_SET(sc, x) \
bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS, \
bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS) \
| (x))
#define MII_CLR(sc, x) \
bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS, \
bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS) \
& (~(x)))
void
ef_mii_writeb(struct ef_softc *sc, int b)
{
MII_CLR(sc, EF_MII_CLK);
if (b)
MII_SET(sc, EF_MII_DATA);
else
MII_CLR(sc, EF_MII_DATA);
MII_CLR(sc, EF_MII_CLK);
DELAY(1);
MII_SET(sc, EF_MII_CLK);
DELAY(1);
}
void
ef_mii_sync(struct ef_softc *sc)
{
int i;
for (i = 0; i < 32; i++)
ef_mii_writeb(sc, 1);
}
int
ef_miibus_readreg(struct device *dev, int phy, int reg)
{
struct ef_softc *sc = (struct ef_softc *)dev;
int i, ack, s, val = 0;
s = splnet();
GO_WINDOW(4);
bus_space_write_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS, 0);
MII_SET(sc, EF_MII_DIR);
MII_CLR(sc, EF_MII_CLK);
ef_mii_sync(sc);
ef_mii_writeb(sc, 0);
ef_mii_writeb(sc, 1);
ef_mii_writeb(sc, 1);
ef_mii_writeb(sc, 0);
for (i = 0x10; i; i >>= 1)
ef_mii_writeb(sc, (phy & i) ? 1 : 0);
for (i = 0x10; i; i >>= 1)
ef_mii_writeb(sc, (reg & i) ? 1 : 0);
MII_CLR(sc, EF_MII_CLK | EF_MII_DATA);
DELAY(1);
MII_SET(sc, EF_MII_CLK);
DELAY(1);
MII_CLR(sc, EF_MII_DIR);
MII_CLR(sc, EF_MII_CLK);
DELAY(1);
MII_SET(sc, EF_MII_CLK);
DELAY(1);
ack = bus_space_read_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS) &
EF_MII_DATA;
for (i = 0x8000; i; i >>= 1) {
MII_CLR(sc, EF_MII_CLK);
DELAY(1);
if (bus_space_read_2(sc->sc_iot, sc->sc_ioh,
EP_W4_CTRLR_STATUS) & EF_MII_DATA)
val |= i;
MII_SET(sc, EF_MII_CLK);
DELAY(1);
}
MII_CLR(sc, EF_MII_CLK);
DELAY(1);
MII_SET(sc, EF_MII_CLK);
DELAY(1);
splx(s);
return (val);
}
void
ef_miibus_writereg(struct device *dev, int phy, int reg, int val)
{
struct ef_softc *sc = (struct ef_softc *)dev;
int s, i;
s = splnet();
GO_WINDOW(4);
bus_space_write_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS, 0);
MII_SET(sc, EF_MII_DIR);
ef_mii_sync(sc);
ef_mii_writeb(sc, 0);
ef_mii_writeb(sc, 1);
ef_mii_writeb(sc, 0);
ef_mii_writeb(sc, 1);
for (i = 0x10; i; i >>= 1)
ef_mii_writeb(sc, (phy & i) ? 1 : 0);
for (i = 0x10; i; i >>= 1)
ef_mii_writeb(sc, (reg & i) ? 1 : 0);
ef_mii_writeb(sc, 1);
ef_mii_writeb(sc, 0);
for (i = 0x8000; i; i >>= 1)
ef_mii_writeb(sc, (val & i) ? 1 : 0);
splx(s);
}
int
ef_ifmedia_upd(struct ifnet *ifp)
{
struct ef_softc *sc = ifp->if_softc;
mii_mediachg(&sc->sc_mii);
return (0);
}
void
ef_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
{
struct ef_softc *sc = ifp->if_softc;
mii_pollstat(&sc->sc_mii);
ifmr->ifm_status = sc->sc_mii.mii_media_status;
ifmr->ifm_active = sc->sc_mii.mii_media_active;
}
void
ef_miibus_statchg(struct device *self)
{
struct ef_softc *sc = (struct ef_softc *)self;
int s;
s = splnet();
GO_WINDOW(3);
if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
bus_space_write_1(sc->sc_iot, sc->sc_ioh,
EP_W3_MAC_CONTROL, 0x20);
else
bus_space_write_1(sc->sc_iot, sc->sc_ioh,
EP_W3_MAC_CONTROL, 0x00);
GO_WINDOW(7);
splx(s);
}
void
ef_tick(void *v)
{
struct ef_softc *sc = v;
int s;
s = splnet();
mii_tick(&sc->sc_mii);
splx(s);
timeout_add_sec(&sc->sc_tick_tmo, 1);
}