Work around a bug in the 82557 NIC where the receiver will lock up
if it is in 10Mbps mode and gets certain types of garbage prior to the packet header. The work-around involves reprogramming the multicast filter if nothing is received in some number of seconds (currently set at 15). As a side effect, implemented complete support for multicasting rather than the previous 'receive all multicasts' hack, since we now have the ability to program the filter table. Fixed a serious bug which crept in with the timeout() changes; the cookie was only saved on the first timeout() call in fxp_init() and wasn't updated in the most common place in fxp_stats_update() when the timeout was rescheduled. This bug would have resulted in an eventual panic if fxp_stop() was called (which happens when any interface flags are changed, for example). Fixed a bug in Alpha support that would have caused the TxCB descriptor chain to span a page boundry, causing serious problems if the pages didn't happen to be contiguous. Removed some gratuitous bit masking that was left over from an older implementation. Fixed a bug where too much was copied from the configuration template, spilling over into memory that followed it. Fixed handling of if_timer...it was cleared too early in some cases.
This commit is contained in:
parent
1f38a58f27
commit
397f9dfe26
@ -27,7 +27,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: if_fxp.c,v 1.39 1997/09/05 10:23:54 davidg Exp $
|
* $Id: if_fxp.c,v 1.40 1997/09/21 22:02:08 gibbs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -45,6 +45,7 @@
|
|||||||
#include <sys/syslog.h>
|
#include <sys/syslog.h>
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
#include <net/if_media.h>
|
#include <net/if_media.h>
|
||||||
|
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
@ -162,8 +163,7 @@ static u_char fxp_cb_config_template[] = {
|
|||||||
0xf3, /* 18 */
|
0xf3, /* 18 */
|
||||||
0x0, /* 19 */
|
0x0, /* 19 */
|
||||||
0x3f, /* 20 */
|
0x3f, /* 20 */
|
||||||
0x5, /* 21 */
|
0x5 /* 21 */
|
||||||
0x0, 0x0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Supported media types. */
|
/* Supported media types. */
|
||||||
@ -206,9 +206,7 @@ const struct fxp_supported_media fxp_media[] = {
|
|||||||
|
|
||||||
static int fxp_mediachange __P((struct ifnet *));
|
static int fxp_mediachange __P((struct ifnet *));
|
||||||
static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
|
static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
|
||||||
|
|
||||||
void fxp_set_media __P((struct fxp_softc *, int));
|
void fxp_set_media __P((struct fxp_softc *, int));
|
||||||
|
|
||||||
static inline void fxp_scb_wait __P((struct fxp_softc *));
|
static inline void fxp_scb_wait __P((struct fxp_softc *));
|
||||||
static FXP_INTR_TYPE fxp_intr __P((void *));
|
static FXP_INTR_TYPE fxp_intr __P((void *));
|
||||||
static void fxp_start __P((struct ifnet *));
|
static void fxp_start __P((struct ifnet *));
|
||||||
@ -223,8 +221,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 *,
|
static void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *,
|
||||||
int, int));
|
int, int));
|
||||||
static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *));
|
static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *));
|
||||||
|
|
||||||
void fxp_stats_update __P((void *));
|
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
|
* Set initial transmit threshold at 64 (512 bytes). This is
|
||||||
@ -245,23 +243,20 @@ static int tx_threshold = 64;
|
|||||||
*/
|
*/
|
||||||
#define FXP_TXCB_MASK (FXP_NTXCB - 1)
|
#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
|
* Number of receive frame area buffers. These are large so chose
|
||||||
* wisely.
|
* wisely.
|
||||||
*/
|
*/
|
||||||
#define FXP_NRFABUFS 32
|
#define FXP_NRFABUFS 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* Wait for the previous command to be accepted (but not necessarily
|
||||||
* completed).
|
* completed).
|
||||||
@ -272,8 +267,7 @@ fxp_scb_wait(sc)
|
|||||||
{
|
{
|
||||||
int i = 10000;
|
int i = 10000;
|
||||||
|
|
||||||
while ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) & FXP_SCB_COMMAND_MASK)
|
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
|
||||||
&& --i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
@ -629,6 +623,10 @@ fxp_attach_common(sc, enaddr)
|
|||||||
goto fail;
|
goto fail;
|
||||||
bzero(sc->fxp_stats, sizeof(struct fxp_stats));
|
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.
|
* Pre-allocate our receive buffers.
|
||||||
*/
|
*/
|
||||||
@ -683,6 +681,8 @@ fxp_attach_common(sc, enaddr)
|
|||||||
free(sc->cbl_base, M_DEVBUF);
|
free(sc->cbl_base, M_DEVBUF);
|
||||||
if (sc->fxp_stats)
|
if (sc->fxp_stats)
|
||||||
free(sc->fxp_stats, M_DEVBUF);
|
free(sc->fxp_stats, M_DEVBUF);
|
||||||
|
if (sc->mcsp)
|
||||||
|
free(sc->mcsp, M_DEVBUF);
|
||||||
/* frees entire chain */
|
/* frees entire chain */
|
||||||
if (sc->rfa_headm)
|
if (sc->rfa_headm)
|
||||||
m_freem(sc->rfa_headm);
|
m_freem(sc->rfa_headm);
|
||||||
@ -775,9 +775,12 @@ fxp_start(ifp)
|
|||||||
|
|
||||||
txloop:
|
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;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -925,19 +928,21 @@ fxp_intr(arg)
|
|||||||
if (statack & FXP_SCB_STATACK_CNA) {
|
if (statack & FXP_SCB_STATACK_CNA) {
|
||||||
struct fxp_cb_tx *txp;
|
struct fxp_cb_tx *txp;
|
||||||
|
|
||||||
for (txp = sc->cbl_first;
|
for (txp = sc->cbl_first; sc->tx_queued &&
|
||||||
(txp->cb_status & FXP_CB_STATUS_C) != 0;
|
(txp->cb_status & FXP_CB_STATUS_C) != 0;
|
||||||
txp = txp->next) {
|
txp = txp->next) {
|
||||||
if (txp->mb_head != NULL) {
|
if (txp->mb_head != NULL) {
|
||||||
m_freem(txp->mb_head);
|
m_freem(txp->mb_head);
|
||||||
txp->mb_head = NULL;
|
txp->mb_head = NULL;
|
||||||
sc->tx_queued--;
|
|
||||||
}
|
}
|
||||||
if (txp == sc->cbl_last)
|
sc->tx_queued--;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
sc->cbl_first = txp;
|
sc->cbl_first = txp;
|
||||||
ifp->if_timer = 0;
|
if (sc->tx_queued == 0) {
|
||||||
|
ifp->if_timer = 0;
|
||||||
|
if (sc->need_mcsetup)
|
||||||
|
fxp_mc_setup(sc);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Try to start more packets transmitting.
|
* Try to start more packets transmitting.
|
||||||
*/
|
*/
|
||||||
@ -1044,10 +1049,17 @@ fxp_stats_update(arg)
|
|||||||
struct fxp_softc *sc = arg;
|
struct fxp_softc *sc = arg;
|
||||||
struct ifnet *ifp = &sc->sc_if;
|
struct ifnet *ifp = &sc->sc_if;
|
||||||
struct fxp_stats *sp = sc->fxp_stats;
|
struct fxp_stats *sp = sc->fxp_stats;
|
||||||
|
int s;
|
||||||
|
|
||||||
ifp->if_opackets += sp->tx_good;
|
ifp->if_opackets += sp->tx_good;
|
||||||
ifp->if_collisions += sp->tx_total_collisions;
|
ifp->if_collisions += sp->tx_total_collisions;
|
||||||
ifp->if_ipackets += sp->rx_good;
|
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 +=
|
ifp->if_ierrors +=
|
||||||
sp->rx_crc_errors +
|
sp->rx_crc_errors +
|
||||||
sp->rx_alignment_errors +
|
sp->rx_alignment_errors +
|
||||||
@ -1062,20 +1074,31 @@ fxp_stats_update(arg)
|
|||||||
if (tx_threshold < 192)
|
if (tx_threshold < 192)
|
||||||
tx_threshold += 64;
|
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
|
* If there is no pending command, start another stats
|
||||||
* dump. Otherwise punt for now.
|
* dump. Otherwise punt for now.
|
||||||
*/
|
*/
|
||||||
if ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) &
|
if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) {
|
||||||
FXP_SCB_COMMAND_MASK) == 0) {
|
|
||||||
/*
|
/*
|
||||||
* Start another stats dump. By waiting for it to be
|
* Start another stats dump.
|
||||||
* accepted, we avoid having to do splhigh locking when
|
|
||||||
* writing scb_command in other parts of the driver.
|
|
||||||
*/
|
*/
|
||||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
|
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
|
||||||
FXP_SCB_COMMAND_CU_DUMPRESET);
|
FXP_SCB_COMMAND_CU_DUMPRESET);
|
||||||
fxp_scb_wait(sc);
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* A previous command is still waiting to be accepted.
|
* A previous command is still waiting to be accepted.
|
||||||
@ -1092,10 +1115,11 @@ fxp_stats_update(arg)
|
|||||||
sp->rx_rnr_errors = 0;
|
sp->rx_rnr_errors = 0;
|
||||||
sp->rx_overrun_errors = 0;
|
sp->rx_overrun_errors = 0;
|
||||||
}
|
}
|
||||||
|
splx(s);
|
||||||
/*
|
/*
|
||||||
* Schedule another timeout one second from now.
|
* Schedule another timeout one second from now.
|
||||||
*/
|
*/
|
||||||
timeout(fxp_stats_update, sc, hz);
|
sc->stat_ch = timeout(fxp_stats_update, sc, hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1165,7 +1189,7 @@ fxp_watchdog(ifp)
|
|||||||
{
|
{
|
||||||
struct fxp_softc *sc = ifp->if_softc;
|
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++;
|
ifp->if_oerrors++;
|
||||||
|
|
||||||
fxp_init(sc);
|
fxp_init(sc);
|
||||||
@ -1180,7 +1204,7 @@ fxp_init(xsc)
|
|||||||
struct fxp_cb_config *cbp;
|
struct fxp_cb_config *cbp;
|
||||||
struct fxp_cb_ias *cb_ias;
|
struct fxp_cb_ias *cb_ias;
|
||||||
struct fxp_cb_tx *txp;
|
struct fxp_cb_tx *txp;
|
||||||
int i, s, mcast, prm;
|
int i, s, prm;
|
||||||
|
|
||||||
s = splimp();
|
s = splimp();
|
||||||
/*
|
/*
|
||||||
@ -1190,12 +1214,6 @@ fxp_init(xsc)
|
|||||||
|
|
||||||
prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
|
prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
|
||||||
sc->promisc_mode = prm;
|
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
|
* Initialize base of CBL and RFA memory. Loading with zero
|
||||||
@ -1226,7 +1244,8 @@ fxp_init(xsc)
|
|||||||
* zero and must be one bits in this structure and this is the easiest
|
* zero and must be one bits in this structure and this is the easiest
|
||||||
* way to initialize them all to proper values.
|
* 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_status = 0;
|
||||||
cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
|
cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
|
||||||
@ -1260,13 +1279,13 @@ fxp_init(xsc)
|
|||||||
cbp->force_fdx = 0; /* (don't) force full duplex */
|
cbp->force_fdx = 0; /* (don't) force full duplex */
|
||||||
cbp->fdx_pin_en = 1; /* (enable) FDX# pin */
|
cbp->fdx_pin_en = 1; /* (enable) FDX# pin */
|
||||||
cbp->multi_ia = 0; /* (don't) accept multiple IAs */
|
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.
|
* Start the config command/DMA.
|
||||||
*/
|
*/
|
||||||
fxp_scb_wait(sc);
|
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);
|
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||||
/* ...and wait for it to complete. */
|
/* ...and wait for it to complete. */
|
||||||
while (!(cbp->cb_status & FXP_CB_STATUS_C));
|
while (!(cbp->cb_status & FXP_CB_STATUS_C));
|
||||||
@ -1303,17 +1322,17 @@ fxp_init(xsc)
|
|||||||
for (i = 0; i < FXP_NTXCB; i++) {
|
for (i = 0; i < FXP_NTXCB; i++) {
|
||||||
txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
|
txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
|
||||||
txp[i].cb_command = FXP_CB_COMMAND_NOP;
|
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].tbd_array_addr = vtophys(&txp[i].tbd[0]);
|
||||||
txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK];
|
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.
|
* unit. It will execute the NOP and then suspend.
|
||||||
*/
|
*/
|
||||||
txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
|
txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
|
||||||
sc->cbl_first = sc->cbl_last = txp;
|
sc->cbl_first = sc->cbl_last = txp;
|
||||||
sc->tx_queued = 0;
|
sc->tx_queued = 1;
|
||||||
|
|
||||||
fxp_scb_wait(sc);
|
fxp_scb_wait(sc);
|
||||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||||
@ -1592,6 +1611,7 @@ fxp_ioctl(ifp, command, data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SIOCSIFFLAGS:
|
case SIOCSIFFLAGS:
|
||||||
|
sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If interface is marked up and not running, then start it.
|
* If interface is marked up and not running, then start it.
|
||||||
@ -1609,6 +1629,7 @@ fxp_ioctl(ifp, command, data)
|
|||||||
|
|
||||||
case SIOCADDMULTI:
|
case SIOCADDMULTI:
|
||||||
case SIOCDELMULTI:
|
case SIOCDELMULTI:
|
||||||
|
sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
|
||||||
#if defined(__NetBSD__)
|
#if defined(__NetBSD__)
|
||||||
{
|
{
|
||||||
struct ifreq *ifr = (struct ifreq *) data;
|
struct ifreq *ifr = (struct ifreq *) data;
|
||||||
@ -1622,7 +1643,14 @@ fxp_ioctl(ifp, command, data)
|
|||||||
* Multicast list has changed; set the hardware
|
* Multicast list has changed; set the hardware
|
||||||
* filter accordingly.
|
* 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;
|
error = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1631,7 +1659,14 @@ fxp_ioctl(ifp, command, data)
|
|||||||
* Multicast list has changed; set the hardware filter
|
* Multicast list has changed; set the hardware filter
|
||||||
* accordingly.
|
* 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;
|
error = 0;
|
||||||
#endif /* __NetBSD__ */
|
#endif /* __NetBSD__ */
|
||||||
break;
|
break;
|
||||||
@ -1647,3 +1682,79 @@ fxp_ioctl(ifp, command, data)
|
|||||||
(void) splx(s);
|
(void) splx(s);
|
||||||
return (error);
|
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;
|
||||||
|
struct ifmultiaddr *ifma;
|
||||||
|
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) {
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id: if_fxpreg.h,v 1.10 1997/09/05 10:23:56 davidg Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FXP_VENDORID_INTEL 0x8086
|
#define FXP_VENDORID_INTEL 0x8086
|
||||||
@ -78,7 +78,6 @@
|
|||||||
#define FXP_SCB_STATACK_FR 0x40
|
#define FXP_SCB_STATACK_FR 0x40
|
||||||
#define FXP_SCB_STATACK_CXTNO 0x80
|
#define FXP_SCB_STATACK_CXTNO 0x80
|
||||||
|
|
||||||
#define FXP_SCB_COMMAND_MASK 0xff
|
|
||||||
#define FXP_SCB_COMMAND_CU_NOP 0x00
|
#define FXP_SCB_COMMAND_CU_NOP 0x00
|
||||||
#define FXP_SCB_COMMAND_CU_START 0x10
|
#define FXP_SCB_COMMAND_CU_START 0x10
|
||||||
#define FXP_SCB_COMMAND_CU_RESUME 0x20
|
#define FXP_SCB_COMMAND_CU_RESUME 0x20
|
||||||
@ -99,11 +98,13 @@
|
|||||||
* Command block definitions
|
* Command block definitions
|
||||||
*/
|
*/
|
||||||
struct fxp_cb_nop {
|
struct fxp_cb_nop {
|
||||||
|
void *fill[2];
|
||||||
volatile u_int16_t cb_status;
|
volatile u_int16_t cb_status;
|
||||||
volatile u_int16_t cb_command;
|
volatile u_int16_t cb_command;
|
||||||
volatile u_int32_t link_addr;
|
volatile u_int32_t link_addr;
|
||||||
};
|
};
|
||||||
struct fxp_cb_ias {
|
struct fxp_cb_ias {
|
||||||
|
void *fill[2];
|
||||||
volatile u_int16_t cb_status;
|
volatile u_int16_t cb_status;
|
||||||
volatile u_int16_t cb_command;
|
volatile u_int16_t cb_command;
|
||||||
volatile u_int32_t link_addr;
|
volatile u_int32_t link_addr;
|
||||||
@ -111,6 +112,7 @@ struct fxp_cb_ias {
|
|||||||
};
|
};
|
||||||
/* I hate bit-fields :-( */
|
/* I hate bit-fields :-( */
|
||||||
struct fxp_cb_config {
|
struct fxp_cb_config {
|
||||||
|
void *fill[2];
|
||||||
volatile u_int16_t cb_status;
|
volatile u_int16_t cb_status;
|
||||||
volatile u_int16_t cb_command;
|
volatile u_int16_t cb_command;
|
||||||
volatile u_int32_t link_addr;
|
volatile u_int32_t link_addr;
|
||||||
@ -168,12 +170,38 @@ struct fxp_cb_config {
|
|||||||
mc_all:1,
|
mc_all:1,
|
||||||
:4;
|
: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 {
|
struct fxp_tbd {
|
||||||
volatile u_int32_t tb_addr;
|
volatile u_int32_t tb_addr;
|
||||||
volatile u_int32_t tb_size;
|
volatile u_int32_t tb_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fxp_cb_tx {
|
struct fxp_cb_tx {
|
||||||
|
struct fxp_cb_tx *next;
|
||||||
|
struct mbuf *mb_head;
|
||||||
volatile u_int16_t cb_status;
|
volatile u_int16_t cb_status;
|
||||||
volatile u_int16_t cb_command;
|
volatile u_int16_t cb_command;
|
||||||
volatile u_int32_t link_addr;
|
volatile u_int32_t link_addr;
|
||||||
@ -184,9 +212,7 @@ struct fxp_cb_tx {
|
|||||||
/*
|
/*
|
||||||
* The following isn't actually part of the TxCB.
|
* The following isn't actually part of the TxCB.
|
||||||
*/
|
*/
|
||||||
volatile struct fxp_tbd tbd[29];
|
volatile struct fxp_tbd tbd[FXP_NTXSEG];
|
||||||
struct mbuf *mb_head;
|
|
||||||
struct fxp_cb_tx *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -200,7 +226,7 @@ struct fxp_cb_tx {
|
|||||||
#define FXP_CB_COMMAND_NOP 0x0
|
#define FXP_CB_COMMAND_NOP 0x0
|
||||||
#define FXP_CB_COMMAND_IAS 0x1
|
#define FXP_CB_COMMAND_IAS 0x1
|
||||||
#define FXP_CB_COMMAND_CONFIG 0x2
|
#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_XMIT 0x4
|
||||||
#define FXP_CB_COMMAND_RESRV 0x5
|
#define FXP_CB_COMMAND_RESRV 0x5
|
||||||
#define FXP_CB_COMMAND_DUMP 0x6
|
#define FXP_CB_COMMAND_DUMP 0x6
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: if_fxpvar.h,v 1.1 1997/09/05 10:23:58 davidg Exp $
|
* $Id: if_fxpvar.h,v 1.2 1997/09/21 22:02:09 gibbs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -59,6 +59,10 @@ struct fxp_softc {
|
|||||||
int phy_primary_addr; /* address of primary PHY */
|
int phy_primary_addr; /* address of primary PHY */
|
||||||
int phy_primary_device; /* device type of primary PHY */
|
int phy_primary_device; /* device type of primary PHY */
|
||||||
int phy_10Mbps_only; /* PHY is 10Mbps-only device */
|
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. */
|
/* Macros to ease CSR access. */
|
||||||
|
209
sys/pci/if_fxp.c
209
sys/pci/if_fxp.c
@ -27,7 +27,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: if_fxp.c,v 1.39 1997/09/05 10:23:54 davidg Exp $
|
* $Id: if_fxp.c,v 1.40 1997/09/21 22:02:08 gibbs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -45,6 +45,7 @@
|
|||||||
#include <sys/syslog.h>
|
#include <sys/syslog.h>
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
#include <net/if_media.h>
|
#include <net/if_media.h>
|
||||||
|
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
@ -162,8 +163,7 @@ static u_char fxp_cb_config_template[] = {
|
|||||||
0xf3, /* 18 */
|
0xf3, /* 18 */
|
||||||
0x0, /* 19 */
|
0x0, /* 19 */
|
||||||
0x3f, /* 20 */
|
0x3f, /* 20 */
|
||||||
0x5, /* 21 */
|
0x5 /* 21 */
|
||||||
0x0, 0x0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Supported media types. */
|
/* Supported media types. */
|
||||||
@ -206,9 +206,7 @@ const struct fxp_supported_media fxp_media[] = {
|
|||||||
|
|
||||||
static int fxp_mediachange __P((struct ifnet *));
|
static int fxp_mediachange __P((struct ifnet *));
|
||||||
static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
|
static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
|
||||||
|
|
||||||
void fxp_set_media __P((struct fxp_softc *, int));
|
void fxp_set_media __P((struct fxp_softc *, int));
|
||||||
|
|
||||||
static inline void fxp_scb_wait __P((struct fxp_softc *));
|
static inline void fxp_scb_wait __P((struct fxp_softc *));
|
||||||
static FXP_INTR_TYPE fxp_intr __P((void *));
|
static FXP_INTR_TYPE fxp_intr __P((void *));
|
||||||
static void fxp_start __P((struct ifnet *));
|
static void fxp_start __P((struct ifnet *));
|
||||||
@ -223,8 +221,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 *,
|
static void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *,
|
||||||
int, int));
|
int, int));
|
||||||
static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *));
|
static int fxp_attach_common __P((struct fxp_softc *, u_int8_t *));
|
||||||
|
|
||||||
void fxp_stats_update __P((void *));
|
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
|
* Set initial transmit threshold at 64 (512 bytes). This is
|
||||||
@ -245,23 +243,20 @@ static int tx_threshold = 64;
|
|||||||
*/
|
*/
|
||||||
#define FXP_TXCB_MASK (FXP_NTXCB - 1)
|
#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
|
* Number of receive frame area buffers. These are large so chose
|
||||||
* wisely.
|
* wisely.
|
||||||
*/
|
*/
|
||||||
#define FXP_NRFABUFS 32
|
#define FXP_NRFABUFS 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* Wait for the previous command to be accepted (but not necessarily
|
||||||
* completed).
|
* completed).
|
||||||
@ -272,8 +267,7 @@ fxp_scb_wait(sc)
|
|||||||
{
|
{
|
||||||
int i = 10000;
|
int i = 10000;
|
||||||
|
|
||||||
while ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) & FXP_SCB_COMMAND_MASK)
|
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
|
||||||
&& --i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
@ -629,6 +623,10 @@ fxp_attach_common(sc, enaddr)
|
|||||||
goto fail;
|
goto fail;
|
||||||
bzero(sc->fxp_stats, sizeof(struct fxp_stats));
|
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.
|
* Pre-allocate our receive buffers.
|
||||||
*/
|
*/
|
||||||
@ -683,6 +681,8 @@ fxp_attach_common(sc, enaddr)
|
|||||||
free(sc->cbl_base, M_DEVBUF);
|
free(sc->cbl_base, M_DEVBUF);
|
||||||
if (sc->fxp_stats)
|
if (sc->fxp_stats)
|
||||||
free(sc->fxp_stats, M_DEVBUF);
|
free(sc->fxp_stats, M_DEVBUF);
|
||||||
|
if (sc->mcsp)
|
||||||
|
free(sc->mcsp, M_DEVBUF);
|
||||||
/* frees entire chain */
|
/* frees entire chain */
|
||||||
if (sc->rfa_headm)
|
if (sc->rfa_headm)
|
||||||
m_freem(sc->rfa_headm);
|
m_freem(sc->rfa_headm);
|
||||||
@ -775,9 +775,12 @@ fxp_start(ifp)
|
|||||||
|
|
||||||
txloop:
|
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;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -925,19 +928,21 @@ fxp_intr(arg)
|
|||||||
if (statack & FXP_SCB_STATACK_CNA) {
|
if (statack & FXP_SCB_STATACK_CNA) {
|
||||||
struct fxp_cb_tx *txp;
|
struct fxp_cb_tx *txp;
|
||||||
|
|
||||||
for (txp = sc->cbl_first;
|
for (txp = sc->cbl_first; sc->tx_queued &&
|
||||||
(txp->cb_status & FXP_CB_STATUS_C) != 0;
|
(txp->cb_status & FXP_CB_STATUS_C) != 0;
|
||||||
txp = txp->next) {
|
txp = txp->next) {
|
||||||
if (txp->mb_head != NULL) {
|
if (txp->mb_head != NULL) {
|
||||||
m_freem(txp->mb_head);
|
m_freem(txp->mb_head);
|
||||||
txp->mb_head = NULL;
|
txp->mb_head = NULL;
|
||||||
sc->tx_queued--;
|
|
||||||
}
|
}
|
||||||
if (txp == sc->cbl_last)
|
sc->tx_queued--;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
sc->cbl_first = txp;
|
sc->cbl_first = txp;
|
||||||
ifp->if_timer = 0;
|
if (sc->tx_queued == 0) {
|
||||||
|
ifp->if_timer = 0;
|
||||||
|
if (sc->need_mcsetup)
|
||||||
|
fxp_mc_setup(sc);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Try to start more packets transmitting.
|
* Try to start more packets transmitting.
|
||||||
*/
|
*/
|
||||||
@ -1044,10 +1049,17 @@ fxp_stats_update(arg)
|
|||||||
struct fxp_softc *sc = arg;
|
struct fxp_softc *sc = arg;
|
||||||
struct ifnet *ifp = &sc->sc_if;
|
struct ifnet *ifp = &sc->sc_if;
|
||||||
struct fxp_stats *sp = sc->fxp_stats;
|
struct fxp_stats *sp = sc->fxp_stats;
|
||||||
|
int s;
|
||||||
|
|
||||||
ifp->if_opackets += sp->tx_good;
|
ifp->if_opackets += sp->tx_good;
|
||||||
ifp->if_collisions += sp->tx_total_collisions;
|
ifp->if_collisions += sp->tx_total_collisions;
|
||||||
ifp->if_ipackets += sp->rx_good;
|
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 +=
|
ifp->if_ierrors +=
|
||||||
sp->rx_crc_errors +
|
sp->rx_crc_errors +
|
||||||
sp->rx_alignment_errors +
|
sp->rx_alignment_errors +
|
||||||
@ -1062,20 +1074,31 @@ fxp_stats_update(arg)
|
|||||||
if (tx_threshold < 192)
|
if (tx_threshold < 192)
|
||||||
tx_threshold += 64;
|
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
|
* If there is no pending command, start another stats
|
||||||
* dump. Otherwise punt for now.
|
* dump. Otherwise punt for now.
|
||||||
*/
|
*/
|
||||||
if ((CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) &
|
if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) {
|
||||||
FXP_SCB_COMMAND_MASK) == 0) {
|
|
||||||
/*
|
/*
|
||||||
* Start another stats dump. By waiting for it to be
|
* Start another stats dump.
|
||||||
* accepted, we avoid having to do splhigh locking when
|
|
||||||
* writing scb_command in other parts of the driver.
|
|
||||||
*/
|
*/
|
||||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
|
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND,
|
||||||
FXP_SCB_COMMAND_CU_DUMPRESET);
|
FXP_SCB_COMMAND_CU_DUMPRESET);
|
||||||
fxp_scb_wait(sc);
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* A previous command is still waiting to be accepted.
|
* A previous command is still waiting to be accepted.
|
||||||
@ -1092,10 +1115,11 @@ fxp_stats_update(arg)
|
|||||||
sp->rx_rnr_errors = 0;
|
sp->rx_rnr_errors = 0;
|
||||||
sp->rx_overrun_errors = 0;
|
sp->rx_overrun_errors = 0;
|
||||||
}
|
}
|
||||||
|
splx(s);
|
||||||
/*
|
/*
|
||||||
* Schedule another timeout one second from now.
|
* Schedule another timeout one second from now.
|
||||||
*/
|
*/
|
||||||
timeout(fxp_stats_update, sc, hz);
|
sc->stat_ch = timeout(fxp_stats_update, sc, hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1165,7 +1189,7 @@ fxp_watchdog(ifp)
|
|||||||
{
|
{
|
||||||
struct fxp_softc *sc = ifp->if_softc;
|
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++;
|
ifp->if_oerrors++;
|
||||||
|
|
||||||
fxp_init(sc);
|
fxp_init(sc);
|
||||||
@ -1180,7 +1204,7 @@ fxp_init(xsc)
|
|||||||
struct fxp_cb_config *cbp;
|
struct fxp_cb_config *cbp;
|
||||||
struct fxp_cb_ias *cb_ias;
|
struct fxp_cb_ias *cb_ias;
|
||||||
struct fxp_cb_tx *txp;
|
struct fxp_cb_tx *txp;
|
||||||
int i, s, mcast, prm;
|
int i, s, prm;
|
||||||
|
|
||||||
s = splimp();
|
s = splimp();
|
||||||
/*
|
/*
|
||||||
@ -1190,12 +1214,6 @@ fxp_init(xsc)
|
|||||||
|
|
||||||
prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
|
prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
|
||||||
sc->promisc_mode = prm;
|
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
|
* Initialize base of CBL and RFA memory. Loading with zero
|
||||||
@ -1226,7 +1244,8 @@ fxp_init(xsc)
|
|||||||
* zero and must be one bits in this structure and this is the easiest
|
* zero and must be one bits in this structure and this is the easiest
|
||||||
* way to initialize them all to proper values.
|
* 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_status = 0;
|
||||||
cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
|
cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
|
||||||
@ -1260,13 +1279,13 @@ fxp_init(xsc)
|
|||||||
cbp->force_fdx = 0; /* (don't) force full duplex */
|
cbp->force_fdx = 0; /* (don't) force full duplex */
|
||||||
cbp->fdx_pin_en = 1; /* (enable) FDX# pin */
|
cbp->fdx_pin_en = 1; /* (enable) FDX# pin */
|
||||||
cbp->multi_ia = 0; /* (don't) accept multiple IAs */
|
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.
|
* Start the config command/DMA.
|
||||||
*/
|
*/
|
||||||
fxp_scb_wait(sc);
|
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);
|
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||||
/* ...and wait for it to complete. */
|
/* ...and wait for it to complete. */
|
||||||
while (!(cbp->cb_status & FXP_CB_STATUS_C));
|
while (!(cbp->cb_status & FXP_CB_STATUS_C));
|
||||||
@ -1303,17 +1322,17 @@ fxp_init(xsc)
|
|||||||
for (i = 0; i < FXP_NTXCB; i++) {
|
for (i = 0; i < FXP_NTXCB; i++) {
|
||||||
txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
|
txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
|
||||||
txp[i].cb_command = FXP_CB_COMMAND_NOP;
|
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].tbd_array_addr = vtophys(&txp[i].tbd[0]);
|
||||||
txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK];
|
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.
|
* unit. It will execute the NOP and then suspend.
|
||||||
*/
|
*/
|
||||||
txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
|
txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
|
||||||
sc->cbl_first = sc->cbl_last = txp;
|
sc->cbl_first = sc->cbl_last = txp;
|
||||||
sc->tx_queued = 0;
|
sc->tx_queued = 1;
|
||||||
|
|
||||||
fxp_scb_wait(sc);
|
fxp_scb_wait(sc);
|
||||||
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
|
||||||
@ -1592,6 +1611,7 @@ fxp_ioctl(ifp, command, data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SIOCSIFFLAGS:
|
case SIOCSIFFLAGS:
|
||||||
|
sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If interface is marked up and not running, then start it.
|
* If interface is marked up and not running, then start it.
|
||||||
@ -1609,6 +1629,7 @@ fxp_ioctl(ifp, command, data)
|
|||||||
|
|
||||||
case SIOCADDMULTI:
|
case SIOCADDMULTI:
|
||||||
case SIOCDELMULTI:
|
case SIOCDELMULTI:
|
||||||
|
sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
|
||||||
#if defined(__NetBSD__)
|
#if defined(__NetBSD__)
|
||||||
{
|
{
|
||||||
struct ifreq *ifr = (struct ifreq *) data;
|
struct ifreq *ifr = (struct ifreq *) data;
|
||||||
@ -1622,7 +1643,14 @@ fxp_ioctl(ifp, command, data)
|
|||||||
* Multicast list has changed; set the hardware
|
* Multicast list has changed; set the hardware
|
||||||
* filter accordingly.
|
* 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;
|
error = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1631,7 +1659,14 @@ fxp_ioctl(ifp, command, data)
|
|||||||
* Multicast list has changed; set the hardware filter
|
* Multicast list has changed; set the hardware filter
|
||||||
* accordingly.
|
* 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;
|
error = 0;
|
||||||
#endif /* __NetBSD__ */
|
#endif /* __NetBSD__ */
|
||||||
break;
|
break;
|
||||||
@ -1647,3 +1682,79 @@ fxp_ioctl(ifp, command, data)
|
|||||||
(void) splx(s);
|
(void) splx(s);
|
||||||
return (error);
|
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;
|
||||||
|
struct ifmultiaddr *ifma;
|
||||||
|
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) {
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id: if_fxpreg.h,v 1.10 1997/09/05 10:23:56 davidg Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FXP_VENDORID_INTEL 0x8086
|
#define FXP_VENDORID_INTEL 0x8086
|
||||||
@ -78,7 +78,6 @@
|
|||||||
#define FXP_SCB_STATACK_FR 0x40
|
#define FXP_SCB_STATACK_FR 0x40
|
||||||
#define FXP_SCB_STATACK_CXTNO 0x80
|
#define FXP_SCB_STATACK_CXTNO 0x80
|
||||||
|
|
||||||
#define FXP_SCB_COMMAND_MASK 0xff
|
|
||||||
#define FXP_SCB_COMMAND_CU_NOP 0x00
|
#define FXP_SCB_COMMAND_CU_NOP 0x00
|
||||||
#define FXP_SCB_COMMAND_CU_START 0x10
|
#define FXP_SCB_COMMAND_CU_START 0x10
|
||||||
#define FXP_SCB_COMMAND_CU_RESUME 0x20
|
#define FXP_SCB_COMMAND_CU_RESUME 0x20
|
||||||
@ -99,11 +98,13 @@
|
|||||||
* Command block definitions
|
* Command block definitions
|
||||||
*/
|
*/
|
||||||
struct fxp_cb_nop {
|
struct fxp_cb_nop {
|
||||||
|
void *fill[2];
|
||||||
volatile u_int16_t cb_status;
|
volatile u_int16_t cb_status;
|
||||||
volatile u_int16_t cb_command;
|
volatile u_int16_t cb_command;
|
||||||
volatile u_int32_t link_addr;
|
volatile u_int32_t link_addr;
|
||||||
};
|
};
|
||||||
struct fxp_cb_ias {
|
struct fxp_cb_ias {
|
||||||
|
void *fill[2];
|
||||||
volatile u_int16_t cb_status;
|
volatile u_int16_t cb_status;
|
||||||
volatile u_int16_t cb_command;
|
volatile u_int16_t cb_command;
|
||||||
volatile u_int32_t link_addr;
|
volatile u_int32_t link_addr;
|
||||||
@ -111,6 +112,7 @@ struct fxp_cb_ias {
|
|||||||
};
|
};
|
||||||
/* I hate bit-fields :-( */
|
/* I hate bit-fields :-( */
|
||||||
struct fxp_cb_config {
|
struct fxp_cb_config {
|
||||||
|
void *fill[2];
|
||||||
volatile u_int16_t cb_status;
|
volatile u_int16_t cb_status;
|
||||||
volatile u_int16_t cb_command;
|
volatile u_int16_t cb_command;
|
||||||
volatile u_int32_t link_addr;
|
volatile u_int32_t link_addr;
|
||||||
@ -168,12 +170,38 @@ struct fxp_cb_config {
|
|||||||
mc_all:1,
|
mc_all:1,
|
||||||
:4;
|
: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 {
|
struct fxp_tbd {
|
||||||
volatile u_int32_t tb_addr;
|
volatile u_int32_t tb_addr;
|
||||||
volatile u_int32_t tb_size;
|
volatile u_int32_t tb_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fxp_cb_tx {
|
struct fxp_cb_tx {
|
||||||
|
struct fxp_cb_tx *next;
|
||||||
|
struct mbuf *mb_head;
|
||||||
volatile u_int16_t cb_status;
|
volatile u_int16_t cb_status;
|
||||||
volatile u_int16_t cb_command;
|
volatile u_int16_t cb_command;
|
||||||
volatile u_int32_t link_addr;
|
volatile u_int32_t link_addr;
|
||||||
@ -184,9 +212,7 @@ struct fxp_cb_tx {
|
|||||||
/*
|
/*
|
||||||
* The following isn't actually part of the TxCB.
|
* The following isn't actually part of the TxCB.
|
||||||
*/
|
*/
|
||||||
volatile struct fxp_tbd tbd[29];
|
volatile struct fxp_tbd tbd[FXP_NTXSEG];
|
||||||
struct mbuf *mb_head;
|
|
||||||
struct fxp_cb_tx *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -200,7 +226,7 @@ struct fxp_cb_tx {
|
|||||||
#define FXP_CB_COMMAND_NOP 0x0
|
#define FXP_CB_COMMAND_NOP 0x0
|
||||||
#define FXP_CB_COMMAND_IAS 0x1
|
#define FXP_CB_COMMAND_IAS 0x1
|
||||||
#define FXP_CB_COMMAND_CONFIG 0x2
|
#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_XMIT 0x4
|
||||||
#define FXP_CB_COMMAND_RESRV 0x5
|
#define FXP_CB_COMMAND_RESRV 0x5
|
||||||
#define FXP_CB_COMMAND_DUMP 0x6
|
#define FXP_CB_COMMAND_DUMP 0x6
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: if_fxpvar.h,v 1.1 1997/09/05 10:23:58 davidg Exp $
|
* $Id: if_fxpvar.h,v 1.2 1997/09/21 22:02:09 gibbs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -59,6 +59,10 @@ struct fxp_softc {
|
|||||||
int phy_primary_addr; /* address of primary PHY */
|
int phy_primary_addr; /* address of primary PHY */
|
||||||
int phy_primary_device; /* device type of primary PHY */
|
int phy_primary_device; /* device type of primary PHY */
|
||||||
int phy_10Mbps_only; /* PHY is 10Mbps-only device */
|
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. */
|
/* Macros to ease CSR access. */
|
||||||
|
Loading…
Reference in New Issue
Block a user