Port the latest FreeBSD "fxp" driver to NetBSD-current. Changes include:
- Work around a bug in the 82557 that causes the receiver to lock up in certain conditions by kicking the multicast address filter if we haven't heard anything come down the wire for some period of time. - Fix a bug that could cause TxCB descriptor chains to cross page boundaries on the Alpha. - Remove some unneeded register masking. - Fix a bug where too much data was copied from the config template, causing memory corruption. - Fix handing of if_timer (it was be cleared too early in some cases). - Attempt to reduce the chances of receiver overrun by doubling the number of receive DMA segments, and processing receive interrupts before transmit interrupts. - Remove a gratuitous assignment. - Fix a bug where incoming packets were counted twice.
This commit is contained in:
parent
8320ff9bde
commit
cdc616ca77
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: if_fxp.c,v 1.4 1997/08/25 22:39:55 thorpej Exp $ */
|
||||
/* $NetBSD: if_fxp.c,v 1.5 1997/10/20 01:15:53 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995, David Greenman
|
||||
@ -29,7 +29,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Id: if_fxp.c,v 1.38 1997/08/02 14:33:10 bde Exp
|
||||
* Id: if_fxp.c,v 1.44 1997/10/17 06:27:44 davidg Exp
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -47,6 +47,7 @@
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
|
||||
#ifdef INET
|
||||
@ -68,7 +69,6 @@
|
||||
#include <sys/errno.h>
|
||||
#include <sys/device.h>
|
||||
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_ether.h>
|
||||
|
||||
#include <netinet/if_inarp.h>
|
||||
@ -164,8 +164,7 @@ static u_char fxp_cb_config_template[] = {
|
||||
0xf3, /* 18 */
|
||||
0x0, /* 19 */
|
||||
0x3f, /* 20 */
|
||||
0x5, /* 21 */
|
||||
0x0, 0x0
|
||||
0x5 /* 21 */
|
||||
};
|
||||
|
||||
/* Supported media types. */
|
||||
@ -208,9 +207,7 @@ const struct fxp_supported_media fxp_media[] = {
|
||||
|
||||
static int fxp_mediachange __P((struct ifnet *));
|
||||
static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
|
||||
|
||||
void fxp_set_media __P((struct fxp_softc *, int));
|
||||
|
||||
static inline void fxp_scb_wait __P((struct fxp_softc *));
|
||||
static FXP_INTR_TYPE fxp_intr __P((void *));
|
||||
static void fxp_start __P((struct ifnet *));
|
||||
@ -225,8 +222,8 @@ static void fxp_mdi_write __P((struct fxp_softc *, int, int, int));
|
||||
static void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *,
|
||||
int, int));
|
||||
static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *));
|
||||
|
||||
void fxp_stats_update __P((void *));
|
||||
static void fxp_mc_setup __P((struct fxp_softc *));
|
||||
|
||||
/*
|
||||
* Set initial transmit threshold at 64 (512 bytes). This is
|
||||
@ -247,22 +244,19 @@ static int tx_threshold = 64;
|
||||
*/
|
||||
#define FXP_TXCB_MASK (FXP_NTXCB - 1)
|
||||
|
||||
/*
|
||||
* Number of DMA segments in a TxCB. Note that this is carefully
|
||||
* chosen to make the total struct size an even power of two. It's
|
||||
* critical that no TxCB be split across a page boundry since
|
||||
* no attempt is made to allocate physically contiguous memory.
|
||||
*
|
||||
* XXX - don't forget to change the hard-coded constant in the
|
||||
* fxp_cb_tx struct (defined in if_fxpreg.h), too!
|
||||
*/
|
||||
#define FXP_NTXSEG 29
|
||||
|
||||
/*
|
||||
* Number of receive frame area buffers. These are large so chose
|
||||
* wisely.
|
||||
*/
|
||||
#define FXP_NRFABUFS 32
|
||||
#define FXP_NRFABUFS 64
|
||||
|
||||
/*
|
||||
* Maximum number of seconds that the receiver can be idle before we
|
||||
* assume it's dead and attempt to reset it by reprogramming the
|
||||
* multicast filter. This is part of a work-around for a bug in the
|
||||
* NIC. See fxp_stats_update().
|
||||
*/
|
||||
#define FXP_MAX_RX_IDLE 15
|
||||
|
||||
/*
|
||||
* Wait for the previous command to be accepted (but not necessarily
|
||||
@ -274,8 +268,7 @@ fxp_scb_wait(sc)
|
||||
{
|
||||
int i = 10000;
|
||||
|
||||
while ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) & FXP_SCB_COMMAND_MASK)
|
||||
&& --i);
|
||||
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
@ -517,6 +510,7 @@ fxp_attach(config_id, unit)
|
||||
if (sc == NULL)
|
||||
return;
|
||||
bzero(sc, sizeof(struct fxp_softc));
|
||||
callout_handle_init(&sc->stat_ch);
|
||||
|
||||
s = splimp();
|
||||
|
||||
@ -630,6 +624,10 @@ fxp_attach_common(sc, enaddr)
|
||||
goto fail;
|
||||
bzero(sc->fxp_stats, sizeof(struct fxp_stats));
|
||||
|
||||
sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT);
|
||||
if (sc->mcsp == NULL)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Pre-allocate our receive buffers.
|
||||
*/
|
||||
@ -684,6 +682,8 @@ fxp_attach_common(sc, enaddr)
|
||||
free(sc->cbl_base, M_DEVBUF);
|
||||
if (sc->fxp_stats)
|
||||
free(sc->fxp_stats, M_DEVBUF);
|
||||
if (sc->mcsp)
|
||||
free(sc->mcsp, M_DEVBUF);
|
||||
/* frees entire chain */
|
||||
if (sc->rfa_headm)
|
||||
m_freem(sc->rfa_headm);
|
||||
@ -776,9 +776,12 @@ fxp_start(ifp)
|
||||
|
||||
txloop:
|
||||
/*
|
||||
* See if we're all filled up with buffers to transmit.
|
||||
* See if we're all filled up with buffers to transmit, or
|
||||
* if we need to suspend xmit until the multicast filter
|
||||
* has been reprogrammed (which can only be done at the
|
||||
* head of the command chain).
|
||||
*/
|
||||
if (sc->tx_queued >= FXP_NTXCB)
|
||||
if (sc->tx_queued >= FXP_NTXCB || sc->need_mcsetup)
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -920,31 +923,6 @@ fxp_intr(arg)
|
||||
*/
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
|
||||
|
||||
/*
|
||||
* Free any finished transmit mbuf chains.
|
||||
*/
|
||||
if (statack & FXP_SCB_STATACK_CNA) {
|
||||
struct fxp_cb_tx *txp;
|
||||
|
||||
for (txp = sc->cbl_first;
|
||||
(txp->cb_status & FXP_CB_STATUS_C) != 0;
|
||||
txp = txp->next) {
|
||||
if (txp->mb_head != NULL) {
|
||||
m_freem(txp->mb_head);
|
||||
txp->mb_head = NULL;
|
||||
sc->tx_queued--;
|
||||
}
|
||||
if (txp == sc->cbl_last)
|
||||
break;
|
||||
}
|
||||
sc->cbl_first = txp;
|
||||
ifp->if_timer = 0;
|
||||
/*
|
||||
* Try to start more packets transmitting.
|
||||
*/
|
||||
if (ifp->if_snd.ifq_head != NULL)
|
||||
fxp_start(ifp);
|
||||
}
|
||||
/*
|
||||
* Process receiver interrupts. If a no-resource (RNR)
|
||||
* condition exists, get whatever packets we can and
|
||||
@ -1021,6 +999,33 @@ rcvloop:
|
||||
FXP_SCB_COMMAND_RU_START);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Free any finished transmit mbuf chains.
|
||||
*/
|
||||
if (statack & FXP_SCB_STATACK_CNA) {
|
||||
struct fxp_cb_tx *txp;
|
||||
|
||||
for (txp = sc->cbl_first; sc->tx_queued &&
|
||||
(txp->cb_status & FXP_CB_STATUS_C) != 0;
|
||||
txp = txp->next) {
|
||||
if (txp->mb_head != NULL) {
|
||||
m_freem(txp->mb_head);
|
||||
txp->mb_head = NULL;
|
||||
}
|
||||
sc->tx_queued--;
|
||||
}
|
||||
sc->cbl_first = txp;
|
||||
if (sc->tx_queued == 0) {
|
||||
ifp->if_timer = 0;
|
||||
if (sc->need_mcsetup)
|
||||
fxp_mc_setup(sc);
|
||||
}
|
||||
/*
|
||||
* Try to start more packets transmitting.
|
||||
*/
|
||||
if (ifp->if_snd.ifq_head != NULL)
|
||||
fxp_start(ifp);
|
||||
}
|
||||
}
|
||||
#if defined(__NetBSD__)
|
||||
return (claimed);
|
||||
@ -1045,10 +1050,16 @@ fxp_stats_update(arg)
|
||||
struct fxp_softc *sc = arg;
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
struct fxp_stats *sp = sc->fxp_stats;
|
||||
int s;
|
||||
|
||||
ifp->if_opackets += sp->tx_good;
|
||||
ifp->if_collisions += sp->tx_total_collisions;
|
||||
ifp->if_ipackets += sp->rx_good;
|
||||
if (sp->rx_good) {
|
||||
ifp->if_ipackets += sp->rx_good;
|
||||
sc->rx_idle_secs = 0;
|
||||
} else {
|
||||
sc->rx_idle_secs++;
|
||||
}
|
||||
ifp->if_ierrors +=
|
||||
sp->rx_crc_errors +
|
||||
sp->rx_alignment_errors +
|
||||
@ -1063,20 +1074,31 @@ fxp_stats_update(arg)
|
||||
if (tx_threshold < 192)
|
||||
tx_threshold += 64;
|
||||
}
|
||||
s = splimp();
|
||||
/*
|
||||
* If we haven't received any packets in FXP_MAC_RX_IDLE seconds,
|
||||
* then assume the receiver has locked up and attempt to clear
|
||||
* the condition by reprogramming the multicast filter. This is
|
||||
* a work-around for a bug in the 82557 where the receiver locks
|
||||
* up if it gets certain types of garbage in the syncronization
|
||||
* bits prior to the packet header. This bug is supposed to only
|
||||
* occur in 10Mbps mode, but has been seen to occur in 100Mbps
|
||||
* mode as well (perhaps due to a 10/100 speed transition).
|
||||
*/
|
||||
if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) {
|
||||
sc->rx_idle_secs = 0;
|
||||
fxp_mc_setup(sc);
|
||||
}
|
||||
/*
|
||||
* If there is no pending command, start another stats
|
||||
* dump. Otherwise punt for now.
|
||||
*/
|
||||
if ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) &
|
||||
FXP_SCB_COMMAND_MASK) == 0) {
|
||||
if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) {
|
||||
/*
|
||||
* Start another stats dump. By waiting for it to be
|
||||
* accepted, we avoid having to do splhigh locking when
|
||||
* writing scb_command in other parts of the driver.
|
||||
* Start another stats dump.
|
||||
*/
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
|
||||
FXP_SCB_COMMAND_CU_DUMPRESET);
|
||||
fxp_scb_wait(sc);
|
||||
} else {
|
||||
/*
|
||||
* A previous command is still waiting to be accepted.
|
||||
@ -1093,10 +1115,11 @@ fxp_stats_update(arg)
|
||||
sp->rx_rnr_errors = 0;
|
||||
sp->rx_overrun_errors = 0;
|
||||
}
|
||||
splx(s);
|
||||
/*
|
||||
* Schedule another timeout one second from now.
|
||||
*/
|
||||
timeout(fxp_stats_update, sc, hz);
|
||||
FXP_TIMEOUT(sc, fxp_stats_update, hz);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1114,7 +1137,7 @@ fxp_stop(sc)
|
||||
/*
|
||||
* Cancel stats updater.
|
||||
*/
|
||||
untimeout(fxp_stats_update, sc);
|
||||
FXP_UNTIMEOUT(sc, fxp_stats_update);
|
||||
|
||||
/*
|
||||
* Issue software reset
|
||||
@ -1166,7 +1189,7 @@ fxp_watchdog(ifp)
|
||||
{
|
||||
struct fxp_softc *sc = ifp->if_softc;
|
||||
|
||||
log(LOG_ERR, FXP_FORMAT ": device timeout\n", FXP_ARGS(sc));
|
||||
printf(FXP_FORMAT ": device timeout\n", FXP_ARGS(sc));
|
||||
ifp->if_oerrors++;
|
||||
|
||||
fxp_init(sc);
|
||||
@ -1181,7 +1204,7 @@ fxp_init(xsc)
|
||||
struct fxp_cb_config *cbp;
|
||||
struct fxp_cb_ias *cb_ias;
|
||||
struct fxp_cb_tx *txp;
|
||||
int i, s, mcast, prm;
|
||||
int i, s, prm;
|
||||
|
||||
s = splimp();
|
||||
/*
|
||||
@ -1191,12 +1214,6 @@ fxp_init(xsc)
|
||||
|
||||
prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
|
||||
sc->promisc_mode = prm;
|
||||
/*
|
||||
* Sleeze out here and enable reception of all multicasts if
|
||||
* multicasts are enabled. Ideally, we'd program the multicast
|
||||
* address filter to only accept specific multicasts.
|
||||
*/
|
||||
mcast = (ifp->if_flags & (IFF_MULTICAST|IFF_ALLMULTI)) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Initialize base of CBL and RFA memory. Loading with zero
|
||||
@ -1227,7 +1244,8 @@ fxp_init(xsc)
|
||||
* zero and must be one bits in this structure and this is the easiest
|
||||
* way to initialize them all to proper values.
|
||||
*/
|
||||
bcopy(fxp_cb_config_template, cbp, sizeof(struct fxp_cb_config));
|
||||
bcopy(fxp_cb_config_template, (void *)&cbp->cb_status,
|
||||
sizeof(fxp_cb_config_template));
|
||||
|
||||
cbp->cb_status = 0;
|
||||
cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
|
||||
@ -1261,13 +1279,13 @@ fxp_init(xsc)
|
||||
cbp->force_fdx = 0; /* (don't) force full duplex */
|
||||
cbp->fdx_pin_en = 1; /* (enable) FDX# pin */
|
||||
cbp->multi_ia = 0; /* (don't) accept multiple IAs */
|
||||
cbp->mc_all = mcast; /* accept all multicasts */
|
||||
cbp->mc_all = sc->all_mcasts;/* accept all multicasts */
|
||||
|
||||
/*
|
||||
* Start the config command/DMA.
|
||||
*/
|
||||
fxp_scb_wait(sc);
|
||||
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(cbp));
|
||||
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||
/* ...and wait for it to complete. */
|
||||
while (!(cbp->cb_status & FXP_CB_STATUS_C));
|
||||
@ -1304,17 +1322,17 @@ fxp_init(xsc)
|
||||
for (i = 0; i < FXP_NTXCB; i++) {
|
||||
txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
|
||||
txp[i].cb_command = FXP_CB_COMMAND_NOP;
|
||||
txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK]);
|
||||
txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status);
|
||||
txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]);
|
||||
txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK];
|
||||
}
|
||||
/*
|
||||
* Set the stop flag on the first TxCB and start the control
|
||||
* Set the suspend flag on the first TxCB and start the control
|
||||
* unit. It will execute the NOP and then suspend.
|
||||
*/
|
||||
txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
|
||||
sc->cbl_first = sc->cbl_last = txp;
|
||||
sc->tx_queued = 0;
|
||||
sc->tx_queued = 1;
|
||||
|
||||
fxp_scb_wait(sc);
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||
@ -1339,7 +1357,7 @@ fxp_init(xsc)
|
||||
/*
|
||||
* Start stats updater.
|
||||
*/
|
||||
timeout(fxp_stats_update, sc, hz);
|
||||
FXP_TIMEOUT(sc, fxp_stats_update, hz);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1593,6 +1611,7 @@ fxp_ioctl(ifp, command, data)
|
||||
break;
|
||||
|
||||
case SIOCSIFFLAGS:
|
||||
sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* If interface is marked up and not running, then start it.
|
||||
@ -1610,10 +1629,8 @@ fxp_ioctl(ifp, command, data)
|
||||
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
|
||||
#if defined(__NetBSD__)
|
||||
{
|
||||
struct ifreq *ifr = (struct ifreq *) data;
|
||||
|
||||
error = (command == SIOCADDMULTI) ?
|
||||
ether_addmulti(ifr, &sc->sc_ethercom) :
|
||||
ether_delmulti(ifr, &sc->sc_ethercom);
|
||||
@ -1623,16 +1640,29 @@ fxp_ioctl(ifp, command, data)
|
||||
* Multicast list has changed; set the hardware
|
||||
* filter accordingly.
|
||||
*/
|
||||
fxp_init(sc);
|
||||
if (!sc->all_mcasts)
|
||||
fxp_mc_setup(sc);
|
||||
/*
|
||||
* fxp_mc_setup() can turn on all_mcasts if we run
|
||||
* out of space, so check it again rather than else {}.
|
||||
*/
|
||||
if (sc->all_mcasts)
|
||||
fxp_init(sc);
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
#else /* __FreeBSD__ */
|
||||
/*
|
||||
* Multicast list has changed; set the hardware filter
|
||||
* accordingly.
|
||||
*/
|
||||
fxp_init(sc);
|
||||
if (!sc->all_mcasts)
|
||||
fxp_mc_setup(sc);
|
||||
/*
|
||||
* fxp_mc_setup() can turn on sc->all_mcasts, so check it
|
||||
* again rather than else {}.
|
||||
*/
|
||||
if (sc->all_mcasts)
|
||||
fxp_init(sc);
|
||||
error = 0;
|
||||
#endif /* __NetBSD__ */
|
||||
break;
|
||||
@ -1648,3 +1678,108 @@ fxp_ioctl(ifp, command, data)
|
||||
(void) splx(s);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Program the multicast filter.
|
||||
*
|
||||
* We have an artificial restriction that the multicast setup command
|
||||
* must be the first command in the chain, so we take steps to ensure
|
||||
* that. By requiring this, it allows us to keep the performance of
|
||||
* the pre-initialized command ring (esp. link pointers) by not actually
|
||||
* inserting the mcsetup command in the ring - i.e. it's link pointer
|
||||
* points to the TxCB ring, but the mcsetup descriptor itself is not part
|
||||
* of it. We then can do 'CU_START' on the mcsetup descriptor and have it
|
||||
* lead into the regular TxCB ring when it completes.
|
||||
*
|
||||
* This function must be called at splimp.
|
||||
*/
|
||||
static void
|
||||
fxp_mc_setup(sc)
|
||||
struct fxp_softc *sc;
|
||||
{
|
||||
struct fxp_cb_mcs *mcsp = sc->mcsp;
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
#if defined(__NetBSD__)
|
||||
struct ethercom *ec = &sc->sc_ethercom;
|
||||
struct ether_multi *enm;
|
||||
struct ether_multistep step;
|
||||
#else
|
||||
struct ifmultiaddr *ifma;
|
||||
#endif /* __NetBSD__ */
|
||||
int nmcasts;
|
||||
|
||||
if (sc->tx_queued) {
|
||||
sc->need_mcsetup = 1;
|
||||
return;
|
||||
}
|
||||
sc->need_mcsetup = 0;
|
||||
|
||||
/*
|
||||
* Initialize multicast setup descriptor.
|
||||
*/
|
||||
mcsp->next = sc->cbl_base;
|
||||
mcsp->mb_head = NULL;
|
||||
mcsp->cb_status = 0;
|
||||
mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S;
|
||||
mcsp->link_addr = vtophys(&sc->cbl_base->cb_status);
|
||||
|
||||
nmcasts = 0;
|
||||
if (!sc->all_mcasts) {
|
||||
#if defined(__NetBSD__)
|
||||
ETHER_FIRST_MULTI(step, ec, enm);
|
||||
while (enm != NULL) {
|
||||
/*
|
||||
* Check for too many multicast addresses or if we're
|
||||
* listening to a range. Either way, we simply have
|
||||
* to accept all multicasts.
|
||||
*/
|
||||
if (nmcasts >= MAXMCADDR ||
|
||||
bcmp(enm->enm_addrlo, enm->enm_addrhi,
|
||||
ETHER_ADDR_LEN) != 0) {
|
||||
sc->all_mcasts = 1;
|
||||
nmcasts = 0;
|
||||
break;
|
||||
}
|
||||
bcopy(enm->enm_addrlo,
|
||||
(void *) &sc->mcsp->mc_addr[nmcasts][0],
|
||||
ETHER_ADDR_LEN);
|
||||
nmcasts++;
|
||||
ETHER_NEXT_MULTI(step, enm);
|
||||
}
|
||||
#else /* __FreeBSD__ */
|
||||
for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
|
||||
ifma = ifma->ifma_link.le_next) {
|
||||
if (ifma->ifma_addr->sa_family != AF_LINK)
|
||||
continue;
|
||||
if (nmcasts >= MAXMCADDR) {
|
||||
sc->all_mcasts = 1;
|
||||
nmcasts = 0;
|
||||
break;
|
||||
}
|
||||
bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
|
||||
(void *) &sc->mcsp->mc_addr[nmcasts][0], 6);
|
||||
nmcasts++;
|
||||
}
|
||||
#endif /* __NetBSD__ */
|
||||
}
|
||||
mcsp->mc_cnt = nmcasts * 6;
|
||||
sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp;
|
||||
sc->tx_queued = 1;
|
||||
|
||||
/*
|
||||
* Wait until command unit is not active. This should never
|
||||
* be the case when nothing is queued, but make sure anyway.
|
||||
*/
|
||||
while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
|
||||
FXP_SCB_CUS_ACTIVE) ;
|
||||
|
||||
/*
|
||||
* Start the multicast setup command.
|
||||
*/
|
||||
fxp_scb_wait(sc);
|
||||
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status));
|
||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||
|
||||
ifp->if_timer = 5;
|
||||
return;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: if_fxpreg.h,v 1.3 1997/08/23 09:28:14 thorpej Exp $ */
|
||||
/* $NetBSD: if_fxpreg.h,v 1.4 1997/10/20 01:15:55 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995, David Greenman
|
||||
@ -26,7 +26,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Id: if_fxpreg.h,v 1.9 1997/06/13 22:34:52 davidg Exp
|
||||
* Id: if_fxpreg.h,v 1.11 1997/09/29 11:27:42 davidg Exp
|
||||
*/
|
||||
|
||||
#define FXP_VENDORID_INTEL 0x8086
|
||||
@ -80,7 +80,6 @@
|
||||
#define FXP_SCB_STATACK_FR 0x40
|
||||
#define FXP_SCB_STATACK_CXTNO 0x80
|
||||
|
||||
#define FXP_SCB_COMMAND_MASK 0xff
|
||||
#define FXP_SCB_COMMAND_CU_NOP 0x00
|
||||
#define FXP_SCB_COMMAND_CU_START 0x10
|
||||
#define FXP_SCB_COMMAND_CU_RESUME 0x20
|
||||
@ -101,11 +100,13 @@
|
||||
* Command block definitions
|
||||
*/
|
||||
struct fxp_cb_nop {
|
||||
void *fill[2];
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
};
|
||||
struct fxp_cb_ias {
|
||||
void *fill[2];
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
@ -113,6 +114,7 @@ struct fxp_cb_ias {
|
||||
};
|
||||
/* I hate bit-fields :-( */
|
||||
struct fxp_cb_config {
|
||||
void *fill[2];
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
@ -170,12 +172,38 @@ struct fxp_cb_config {
|
||||
mc_all:1,
|
||||
:4;
|
||||
};
|
||||
|
||||
#define MAXMCADDR 80
|
||||
struct fxp_cb_mcs {
|
||||
struct fxp_cb_tx *next;
|
||||
struct mbuf *mb_head;
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
volatile u_int16_t mc_cnt;
|
||||
volatile u_int8_t mc_addr[MAXMCADDR][6];
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of DMA segments in a TxCB. Note that this is carefully
|
||||
* chosen to make the total struct size an even power of two. It's
|
||||
* critical that no TxCB be split across a page boundry since
|
||||
* no attempt is made to allocate physically contiguous memory.
|
||||
*
|
||||
*/
|
||||
#ifdef __alpha__ /* XXX - should be conditional on pointer size */
|
||||
#define FXP_NTXSEG 28
|
||||
#else
|
||||
#define FXP_NTXSEG 29
|
||||
#endif
|
||||
|
||||
struct fxp_tbd {
|
||||
volatile u_int32_t tb_addr;
|
||||
volatile u_int32_t tb_size;
|
||||
};
|
||||
|
||||
struct fxp_cb_tx {
|
||||
struct fxp_cb_tx *next;
|
||||
struct mbuf *mb_head;
|
||||
volatile u_int16_t cb_status;
|
||||
volatile u_int16_t cb_command;
|
||||
volatile u_int32_t link_addr;
|
||||
@ -186,9 +214,7 @@ struct fxp_cb_tx {
|
||||
/*
|
||||
* The following isn't actually part of the TxCB.
|
||||
*/
|
||||
volatile struct fxp_tbd tbd[29];
|
||||
struct mbuf *mb_head;
|
||||
struct fxp_cb_tx *next;
|
||||
volatile struct fxp_tbd tbd[FXP_NTXSEG];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -202,7 +228,7 @@ struct fxp_cb_tx {
|
||||
#define FXP_CB_COMMAND_NOP 0x0
|
||||
#define FXP_CB_COMMAND_IAS 0x1
|
||||
#define FXP_CB_COMMAND_CONFIG 0x2
|
||||
#define FXP_CB_COMMAND_MAS 0x3
|
||||
#define FXP_CB_COMMAND_MCAS 0x3
|
||||
#define FXP_CB_COMMAND_XMIT 0x4
|
||||
#define FXP_CB_COMMAND_RESRV 0x5
|
||||
#define FXP_CB_COMMAND_DUMP 0x6
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: if_fxpvar.h,v 1.2 1997/08/25 22:39:57 thorpej Exp $ */
|
||||
/* $NetBSD: if_fxpvar.h,v 1.3 1997/10/20 01:15:56 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995, David Greenman
|
||||
@ -29,7 +29,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Id: if_fxp.c,v 1.34 1997/04/23 01:44:30 davidg Exp
|
||||
* Id: if_fxpvar.h,v 1.3 1997/09/29 11:27:43 davidg Exp
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -46,7 +46,8 @@ struct fxp_softc {
|
||||
struct ethercom sc_ethercom; /* ethernet common part */
|
||||
#else
|
||||
struct arpcom arpcom; /* per-interface network data */
|
||||
struct caddr_t csr; /* control/status registers */
|
||||
caddr_t csr; /* control/status registers */
|
||||
struct callout_handle stat_ch; /* Handle for canceling our stat timeout */
|
||||
#endif /* __NetBSD__ */
|
||||
struct ifmedia sc_media; /* media information */
|
||||
struct fxp_cb_tx *cbl_base; /* base of TxCB list */
|
||||
@ -60,6 +61,10 @@ struct fxp_softc {
|
||||
int phy_primary_addr; /* address of primary PHY */
|
||||
int phy_primary_device; /* device type of primary PHY */
|
||||
int phy_10Mbps_only; /* PHY is 10Mbps-only device */
|
||||
int rx_idle_secs; /* # of seconds RX has been idle */
|
||||
int need_mcsetup; /* multicast filter needs programming */
|
||||
int all_mcasts; /* receive all multicasts */
|
||||
struct fxp_cb_mcs *mcsp; /* Pointer to mcast setup descriptor */
|
||||
};
|
||||
|
||||
/* Macros to ease CSR access. */
|
||||
@ -99,6 +104,9 @@ struct fxp_softc {
|
||||
#define FXP_INTR_TYPE int
|
||||
#define FXP_IOCTLCMD_TYPE u_long
|
||||
#define FXP_BPFTAP_ARG(ifp) (ifp)->if_bpf
|
||||
#define FXP_TIMEOUT(sc, func, hz) \
|
||||
timeout((func), (sc), (hz))
|
||||
#define FXP_UNTIMEOUT(sc, func) untimeout((func), (sc))
|
||||
#else /* __FreeBSD__ */
|
||||
#define sc_if arpcom.ac_if
|
||||
#define FXP_FORMAT "fxp%d"
|
||||
@ -106,4 +114,7 @@ struct fxp_softc {
|
||||
#define FXP_INTR_TYPE void
|
||||
#define FXP_IOCTLCMD_TYPE int
|
||||
#define FXP_BPFTAP_ARG(ifp) ifp
|
||||
#define FXP_TIMEOUT(sc, func, hz) \
|
||||
(sc)->stat_ch = timeout((func), (sc), (hz))
|
||||
#define FXP_UNTIMEOUT(sc, func) untimeout((func), (sc), (sc)->stat_ch)
|
||||
#endif /* __NetBSD__ */
|
||||
|
Loading…
Reference in New Issue
Block a user