File: [local] / sys / dev / isa / if_ef_isapnp.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:11:20 2008 UTC (16 years, 3 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: if_ef_isapnp.c,v 1.21 2006/03/25 22:41:44 djm Exp $ */
/*
* Copyright (c) 1999 Jason L. Wright (jason@thought.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#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/selinfo.h>
#include <sys/device.h>
#include <sys/queue.h>
#include <sys/kernel.h>
#include <sys/timeout.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#endif
#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 /* sqe error for aui */
#define EF_MEDIA_TP 0x00c0 /* link/jabber, 10baseT */
#define EF_MEDIA_LNK 0x0080 /* linkbeat, 100baseTX/FX */
#define EF_MEDIA_LNKBEAT 0x0800
/* Window 4: EP_W4_CTRLR_STATUS: mii manipulation */
#define EF_MII_CLK 0x01 /* clock bit */
#define EF_MII_DATA 0x02 /* data bit */
#define EF_MII_DIR 0x04 /* direction */
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
};
struct cfattach ef_isapnp_ca = {
sizeof(struct ef_softc), ef_isapnp_match, ef_isapnp_attach
};
int
ef_isapnp_match(parent, match, aux)
struct device *parent;
void *match, *aux;
{
return (1);
}
void
ef_isapnp_attach(parent, self, aux)
struct device *parent, *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_NOTRAILERS | IFF_MULTICAST;
IFQ_SET_READY(&ifp->if_snd);
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(ifp)
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 | IFF_OACTIVE)) != IFF_RUNNING)
return;
startagain:
IFQ_POLL(&ifp->if_snd, m0);
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_DEQUEUE(&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));
ifp->if_flags |= IFF_OACTIVE;
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_DEQUEUE(&ifp->if_snd, m0);
if (m0 == NULL) /* XXX not needed */
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;
}
MFREE(m, m0);
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);
ifp->if_opackets++;
goto startagain;
}
int
efioctl(ifp, cmd, data)
struct ifnet *ifp;
u_long cmd;
caddr_t data;
{
struct ef_softc *sc = ifp->if_softc;
struct ifaddr *ifa = (struct ifaddr *)data;
struct ifreq *ifr = (struct ifreq *)data;
int s, error = 0;
s = splnet();
if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
splx(s);
return (error);
}
switch (cmd) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
efinit(sc);
arp_ifinit(&sc->sc_arpcom, ifa);
break;
#endif
default:
efinit(sc);
break;
}
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;
case SIOCADDMULTI:
case SIOCDELMULTI:
error = (cmd == SIOCADDMULTI) ?
ether_addmulti(ifr, &sc->sc_arpcom) :
ether_delmulti(ifr, &sc->sc_arpcom);
if (error == ENETRESET) {
if (ifp->if_flags & IFF_RUNNING)
efreset(sc);
error = 0;
}
efsetmulti(sc);
break;
default:
error = EINVAL;
break;
}
splx(s);
return (error);
}
void
efinit(sc)
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;
ifp->if_flags &= ~IFF_OACTIVE;
splx(s);
timeout_add(&sc->sc_tick_tmo, hz);
efstart(ifp);
}
void
efreset(sc)
struct ef_softc *sc;
{
int s;
s = splnet();
efstop(sc);
efinit(sc);
splx(s);
}
void
efstop(sc)
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 | IFF_OACTIVE);
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(sc, cmd, arg)
struct ef_softc *sc;
u_int cmd, 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(vsc)
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;
sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
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(sc)
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);
sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
}
else
sc->sc_tx_succ_ok = (sc->sc_tx_succ_ok + 1) & 127;
}
}
int
efbusyeeprom(sc)
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(ifp)
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(sc)
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(sc)
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 *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;
}
ifp->if_ipackets++;
#if NBPFILTER > 0
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
#endif
ether_input_mbuf(ifp, m);
}
struct mbuf *
efget(sc, totlen)
struct ef_softc *sc;
int totlen;
{
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 *top, **mp, *m;
int len, pad, s;
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
return (NULL);
m->m_pkthdr.rcvif = ifp;
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(sc, b)
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(sc)
struct ef_softc *sc;
{
int i;
for (i = 0; i < 32; i++)
ef_mii_writeb(sc, 1);
}
int
ef_miibus_readreg(dev, phy, reg)
struct device *dev;
int phy, 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);
/* Turn on xmit */
MII_SET(sc, EF_MII_DIR);
MII_CLR(sc, EF_MII_CLK);
ef_mii_sync(sc);
/* Transmit start sequence */
ef_mii_writeb(sc, 0);
ef_mii_writeb(sc, 1);
/* Transmit read sequence */
ef_mii_writeb(sc, 1);
ef_mii_writeb(sc, 0);
/* Transmit phy addr */
for (i = 0x10; i; i >>= 1)
ef_mii_writeb(sc, (phy & i) ? 1 : 0);
/* Transmit reg addr */
for (i = 0x10; i; i >>= 1)
ef_mii_writeb(sc, (reg & i) ? 1 : 0);
/* First cycle of turnaround */
MII_CLR(sc, EF_MII_CLK | EF_MII_DATA);
DELAY(1);
MII_SET(sc, EF_MII_CLK);
DELAY(1);
/* Turn off xmit */
MII_CLR(sc, EF_MII_DIR);
/* Second cycle of turnaround */
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;
/* Read 16bit 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(dev, phy, reg, val)
struct device *dev;
int phy, reg, 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);
/* Turn on xmit */
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(ifp)
struct ifnet *ifp;
{
struct ef_softc *sc = ifp->if_softc;
mii_mediachg(&sc->sc_mii);
return (0);
}
void
ef_ifmedia_sts(ifp, ifmr)
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(self)
struct device *self;
{
struct ef_softc *sc = (struct ef_softc *)self;
int s;
s = splnet();
GO_WINDOW(3);
/* Set duplex bit appropriately */
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(v)
void *v;
{
struct ef_softc *sc = v;
int s;
s = splnet();
mii_tick(&sc->sc_mii);
splx(s);
timeout_add(&sc->sc_tick_tmo, hz);
}