summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorthorpej <thorpej@NetBSD.org>1999-08-03 22:43:28 +0000
committerthorpej <thorpej@NetBSD.org>1999-08-03 22:43:28 +0000
commit3012cf91af31cc40be8a42b3b03e4f936561a80f (patch)
tree97bd841884195212265c865c4983f37fdcd555a9 /sys/dev
parente0c8203cb342c46f96aa0135ca81fbfe3cf32b2f (diff)
Completely rewrite the transmit logic, making it look more like the
EPIC/100 driver's. Also, fix the "all multicast" logic. Also do some general cleanup.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/i82557.c761
-rw-r--r--sys/dev/ic/i82557reg.h93
-rw-r--r--sys/dev/ic/i82557var.h121
3 files changed, 539 insertions, 436 deletions
diff --git a/sys/dev/ic/i82557.c b/sys/dev/ic/i82557.c
index 3aaa0c33189..b55b6e5a335 100644
--- a/sys/dev/ic/i82557.c
+++ b/sys/dev/ic/i82557.c
@@ -1,4 +1,4 @@
-/* $NetBSD: i82557.c,v 1.1 1999/06/20 16:33:28 thorpej Exp $ */
+/* $NetBSD: i82557.c,v 1.2 1999/08/03 22:43:28 thorpej Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
@@ -173,7 +173,7 @@ inline void fxp_scb_wait __P((struct fxp_softc *));
void fxp_start __P((struct ifnet *));
int fxp_ioctl __P((struct ifnet *, u_long, caddr_t));
-void fxp_init __P((void *));
+void fxp_init __P((struct fxp_softc *));
void fxp_stop __P((struct fxp_softc *));
void fxp_watchdog __P((struct ifnet *));
int fxp_add_rfabuf __P((struct fxp_softc *, struct fxp_rxdesc *));
@@ -183,7 +183,7 @@ void fxp_mdi_write __P((struct device *, int, int, int));
void fxp_read_eeprom __P((struct fxp_softc *, u_int16_t *, int, int));
void fxp_get_info __P((struct fxp_softc *, u_int8_t *));
void fxp_tick __P((void *));
-void fxp_mc_setup __P((struct fxp_softc *));
+void fxp_mc_setup __P((struct fxp_softc *, int));
void fxp_shutdown __P((void *));
@@ -213,7 +213,7 @@ fxp_scb_wait(sc)
int i = 10000;
while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i)
- DELAY(1);
+ delay(2);
if (i == 0)
printf("%s: WARNING: SCB timed out!\n", sc->sc_dev.dv_xname);
}
@@ -244,13 +244,13 @@ fxp_attach(sc)
}
if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
- sizeof(struct fxp_control_data), (caddr_t *)&sc->control_data,
+ sizeof(struct fxp_control_data), (caddr_t *)&sc->sc_control_data,
BUS_DMA_COHERENT)) != 0) {
printf("%s: unable to map control data, error = %d\n",
sc->sc_dev.dv_xname, error);
goto fail_1;
}
- bzero(sc->control_data, sizeof(struct fxp_control_data));
+ bzero(sc->sc_control_data, sizeof(struct fxp_control_data));
if ((error = bus_dmamap_create(sc->sc_dmat,
sizeof(struct fxp_control_data), 1,
@@ -261,7 +261,7 @@ fxp_attach(sc)
}
if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
- sc->control_data, sizeof(struct fxp_control_data), NULL,
+ sc->sc_control_data, sizeof(struct fxp_control_data), NULL,
0)) != 0) {
printf("%s: can't load control data DMA map, error = %d\n",
sc->sc_dev.dv_xname, error);
@@ -274,7 +274,7 @@ fxp_attach(sc)
for (i = 0; i < FXP_NTXCB; i++) {
if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
FXP_NTXSEG, MCLBYTES, 0, 0,
- &sc->sc_tx_dmamaps[i])) != 0) {
+ &FXP_DSTX(sc, i)->txs_dmamap)) != 0) {
printf("%s: unable to create tx DMA map %d, "
"error = %d\n", sc->sc_dev.dv_xname, i, error);
goto fail_4;
@@ -339,12 +339,6 @@ fxp_attach(sc)
bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,
sizeof(struct ether_header));
#endif
-
- /*
- * Let the system queue as many packets as we have TX descriptors.
- */
- ifp->if_snd.ifq_maxlen = FXP_NTXCB;
-
#if NRND > 0
rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
RND_TYPE_NET, 0);
@@ -381,15 +375,15 @@ fxp_attach(sc)
}
fail_4:
for (i = 0; i < FXP_NTXCB; i++) {
- if (sc->sc_tx_dmamaps[i] != NULL)
+ if (FXP_DSTX(sc, i)->txs_dmamap != NULL)
bus_dmamap_destroy(sc->sc_dmat,
- sc->sc_tx_dmamaps[i]);
+ FXP_DSTX(sc, i)->txs_dmamap);
}
bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
fail_3:
bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
fail_2:
- bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->control_data,
+ bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_control_data,
sizeof(struct fxp_control_data));
fail_1:
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
@@ -441,11 +435,12 @@ fxp_80c24_initmedia(sc)
* kernel memory doesn't get clobbered during warmboot.
*/
void
-fxp_shutdown(sc)
- void *sc;
+fxp_shutdown(arg)
+ void *arg;
{
+ struct fxp_softc *sc = arg;
- fxp_stop((struct fxp_softc *) sc);
+ fxp_stop(sc);
}
/*
@@ -558,161 +553,172 @@ fxp_start(ifp)
struct ifnet *ifp;
{
struct fxp_softc *sc = ifp->if_softc;
- struct fxp_cb_tx *txp;
+ struct mbuf *m0, *m;
+ struct fxp_cb_tx *txd;
+ struct fxp_txsoft *txs;
+ struct fxp_tbdlist *tbd;
bus_dmamap_t dmamap;
- int old_queued;
+ int error, lasttx, nexttx, opending, seg;
/*
- * See 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 we need multicast setup, bail out now.
*/
- if (sc->need_mcsetup || (old_queued = sc->tx_queued) >= FXP_NTXCB) {
+ if (sc->sc_flags & (FXPF_NEEDMCSETUP|FXPF_DOINGMCSETUP)) {
ifp->if_flags |= IFF_OACTIVE;
return;
}
/*
- * We're finished if there is nothing more to add to the list or if
- * we're all filled up with buffers to transmit.
+ * Remember the previous txpending and the current lasttx.
*/
- while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB) {
- struct mbuf *mb_head;
- int segment, error;
+ opending = sc->sc_txpending;
+ lasttx = sc->sc_txlast;
+ /*
+ * Loop through the send queue, setting up transmit descriptors
+ * until we drain the queue, or use up all available transmit
+ * descriptors.
+ */
+ while (sc->sc_txpending < FXP_NTXCB) {
/*
- * Grab a packet to transmit.
+ * Grab a packet off the queue.
*/
- IF_DEQUEUE(&ifp->if_snd, mb_head);
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
/*
- * Get pointer to next available tx desc.
+ * Get the next available transmit descriptor.
*/
- txp = sc->cbl_last->cb_soft.next;
- dmamap = txp->cb_soft.dmamap;
+ nexttx = FXP_NEXTTX(sc->sc_txlast);
+ txd = FXP_CDTX(sc, nexttx);
+ tbd = FXP_CDTBD(sc, nexttx);
+ txs = FXP_DSTX(sc, nexttx);
+ dmamap = txs->txs_dmamap;
/*
- * Go through each of the mbufs in the chain and initialize
- * the transmit buffer descriptors with the physical address
- * and size of the mbuf.
+ * Load the DMA map. If this fails, the packet either
+ * didn't fit in the allotted number of frags, or we were
+ * short on resources. In this case, we'll copy and try
+ * again.
*/
- tbdinit:
- error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap,
- mb_head, BUS_DMA_NOWAIT);
- switch (error) {
- case 0:
- /* Success. */
- break;
-
- case EFBIG:
- {
- struct mbuf *mn;
-
- /*
- * We ran out of segments. We have to recopy this
- * mbuf chain first. Bail out if we can't get the
- * new buffers.
- */
- printf("%s: too many segments, ", sc->sc_dev.dv_xname);
-
- MGETHDR(mn, M_DONTWAIT, MT_DATA);
- if (mn == NULL) {
- m_freem(mb_head);
- printf("aborting\n");
- goto out;
+ if (bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
+ BUS_DMA_NOWAIT) != 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ printf("%s: unable to allocate Tx mbuf\n",
+ sc->sc_dev.dv_xname);
+ IF_PREPEND(&ifp->if_snd, m0);
+ break;
}
- if (mb_head->m_pkthdr.len > MHLEN) {
- MCLGET(mn, M_DONTWAIT);
- if ((mn->m_flags & M_EXT) == 0) {
- m_freem(mn);
- m_freem(mb_head);
- printf("aborting\n");
- goto out;
+ if (m0->m_pkthdr.len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ printf("%s: unable to allocate Tx "
+ "cluster\n", sc->sc_dev.dv_xname);
+ m_freem(m);
+ IF_PREPEND(&ifp->if_snd, m0);
+ break;
}
}
- m_copydata(mb_head, 0, mb_head->m_pkthdr.len,
- mtod(mn, caddr_t));
- mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len;
- m_freem(mb_head);
- mb_head = mn;
- printf("retrying\n");
- goto tbdinit;
- }
-
- default:
- /*
- * Some other problem; report it.
- */
- printf("%s: can't load mbuf chain, error = %d\n",
- sc->sc_dev.dv_xname, error);
- m_freem(mb_head);
- goto out;
+ m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
+ m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
+ m_freem(m0);
+ m0 = m;
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap,
+ m0, BUS_DMA_NOWAIT);
+ if (error) {
+ printf("%s: unable to load Tx buffer, "
+ "error = %d\n", sc->sc_dev.dv_xname, error);
+ IF_PREPEND(&ifp->if_snd, m0);
+ break;
+ }
}
- for (segment = 0; segment < dmamap->dm_nsegs; segment++) {
- txp->tbd[segment].tb_addr =
- dmamap->dm_segs[segment].ds_addr;
- txp->tbd[segment].tb_size =
- dmamap->dm_segs[segment].ds_len;
+ /* Initialize the fraglist. */
+ for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
+ tbd->tbd_d[seg].tb_addr =
+ dmamap->dm_segs[seg].ds_addr;
+ tbd->tbd_d[seg].tb_size =
+ dmamap->dm_segs[seg].ds_len;
}
+ FXP_CDTBDSYNC(sc, nexttx, BUS_DMASYNC_PREWRITE);
+
+ /* Sync the DMA map. */
bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
BUS_DMASYNC_PREWRITE);
- txp->tbd_number = dmamap->dm_nsegs;
- txp->cb_soft.mb_head = mb_head;
- txp->cb_status = 0;
- txp->cb_command =
- FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S;
- txp->tx_threshold = tx_threshold;
- bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
- FXP_TXDESCOFF(sc, txp), FXP_TXDESCSIZE,
- BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-
/*
- * Advance the end of list forward.
+ * Store a pointer to the packet so we can free it later.
*/
- bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
- FXP_TXDESCOFF(sc, sc->cbl_last), FXP_TXDESCSIZE,
- BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;
- sc->cbl_last = txp;
- bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
- FXP_TXDESCOFF(sc, sc->cbl_last), FXP_TXDESCSIZE,
- BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ txs->txs_mbuf = m0;
/*
- * Advance the beginning of the list forward if there are
- * no other packets queued (when nothing is queued, cbl_first
- * sits on the last TxCB that was sent out).
+ * Initialize the transmit descriptor.
*/
- if (sc->tx_queued == 0)
- sc->cbl_first = txp;
+ txd->cb_status = 0;
+ txd->cb_command =
+ FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF;
+ txd->tx_threshold = tx_threshold;
+ txd->tbd_number = dmamap->dm_nsegs;
- sc->tx_queued++;
+ FXP_CDTXSYNC(sc, nexttx,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /* Advance the tx pointer. */
+ sc->sc_txpending++;
+ sc->sc_txlast = nexttx;
#if NBPFILTER > 0
/*
* Pass packet to bpf if there is a listener.
*/
if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, mb_head);
+ bpf_mtap(ifp->if_bpf, m0);
#endif
}
- out:
- /*
- * We're finished. If we added to the list, issue a RESUME to get DMA
- * going again if suspended.
- */
- if (old_queued != sc->tx_queued) {
- fxp_scb_wait(sc);
- CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
+ if (sc->sc_txpending == FXP_NTXCB) {
+ /* No more slots; notify upper layer. */
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+
+ if (sc->sc_txpending != opending) {
+ /*
+ * We enqueued packets. If the transmitter was idle,
+ * reset the txdirty pointer.
+ */
+ if (opending == 0)
+ sc->sc_txdirty = FXP_NEXTTX(lasttx);
+
+ /*
+ * Cause the chip to interrupt and suspend command
+ * processing once the last packet we've enqueued
+ * has been transmitted.
+ */
+ FXP_CDTX(sc, sc->sc_txlast)->cb_command |=
+ FXP_CB_COMMAND_I | FXP_CB_COMMAND_S;
+ FXP_CDTXSYNC(sc, sc->sc_txlast,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
/*
- * Set a 5 second timer just in case we don't hear from the
- * card again.
+ * The entire packet chain is set up. Clear the suspend bit
+ * on the command prior to the first packet we set up.
*/
+ FXP_CDTXSYNC(sc, lasttx,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ FXP_CDTX(sc, lasttx)->cb_command &= ~FXP_CB_COMMAND_S;
+ FXP_CDTXSYNC(sc, lasttx,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Issue a Resume command in case the chip was suspended.
+ */
+ fxp_scb_wait(sc);
+ CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
+
+ /* Set a watchdog timer in case the chip flakes out. */
ifp->if_timer = 5;
}
}
@@ -725,9 +731,12 @@ fxp_intr(arg)
void *arg;
{
struct fxp_softc *sc = arg;
- struct ifnet *ifp = &sc->sc_if;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ struct fxp_cb_mcs *mcsp;
+ struct fxp_cb_tx *txd;
+ struct fxp_txsoft *txs;
+ int i, oflags, claimed = 0;
u_int8_t statack;
- int claimed = 0;
while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
claimed = 1;
@@ -821,40 +830,82 @@ fxp_intr(arg)
* Free any finished transmit mbuf chains.
*/
if (statack & FXP_SCB_STATACK_CNA) {
- struct fxp_cb_tx *txp;
- bus_dmamap_t txmap;
-
- for (txp = sc->cbl_first; sc->tx_queued;
- txp = txp->cb_soft.next) {
- bus_dmamap_sync(sc->sc_dmat,
- sc->sc_dmamap, FXP_TXDESCOFF(sc, txp),
- FXP_TXDESCSIZE,
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * Check for multicast setup completion.
+ */
+ if (sc->sc_flags & FXPF_DOINGMCSETUP) {
+#ifdef DIAGNOSTIC
+ if (sc->sc_txpending)
+ panic("fxp_intr: doing mcsetup and "
+ "txpending");
+#endif
+ mcsp = &sc->sc_control_data->fcd_mcscb;
+ if ((mcsp->cb_status & FXP_CB_STATUS_C) == 0) {
+ printf("%s: mcsetup interrupt but not "
+ "complete\n", sc->sc_dev.dv_xname);
+ fxp_init(sc);
+ return (claimed);
+ }
+ sc->sc_flags &= ~FXPF_DOINGMCSETUP;
+ }
+
+ for (i = sc->sc_txdirty; sc->sc_txpending != 0;
+ i = FXP_NEXTTX(i), sc->sc_txpending--) {
+ txd = FXP_CDTX(sc, i);
+ txs = FXP_DSTX(sc, i);
+
+ FXP_CDTXSYNC(sc, i,
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- if ((txp->cb_status & FXP_CB_STATUS_C) == 0)
+
+ if ((txd->cb_status & FXP_CB_STATUS_C) == 0)
break;
- if (txp->cb_soft.mb_head != NULL) {
- txmap = txp->cb_soft.dmamap;
- bus_dmamap_sync(sc->sc_dmat, txmap,
- 0, txmap->dm_mapsize,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->sc_dmat, txmap);
- m_freem(txp->cb_soft.mb_head);
- txp->cb_soft.mb_head = NULL;
- }
- sc->tx_queued--;
+
+ FXP_CDTBDSYNC(sc, i, BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_sync(sc->sc_dmat, txs->txs_dmamap,
+ 0, txs->txs_dmamap->dm_mapsize,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap);
+ m_freem(txs->txs_mbuf);
+ txs->txs_mbuf = NULL;
}
- sc->cbl_first = txp;
- ifp->if_flags &= ~IFF_OACTIVE;
- if (sc->tx_queued == 0) {
+
+ /* Update the dirty transmit buffer pointer. */
+ sc->sc_txdirty = i;
+
+ /*
+ * Cancel the watchdog timer if there are no pending
+ * transmissions.
+ */
+ if (sc->sc_txpending == 0) {
ifp->if_timer = 0;
- if (sc->need_mcsetup)
- fxp_mc_setup(sc);
+
+ /*
+ * If we need a multicast filter setup,
+ * do that now.
+ */
+ if (sc->sc_flags & FXPF_NEEDMCSETUP) {
+ oflags = ifp->if_flags;
+ fxp_mc_setup(sc, 0);
+
+ /*
+ * If IFF_ALLMULTI state changed,
+ * we need to reinitialize the chip,
+ * because this is handled by the
+ * config block.
+ */
+ if (((ifp->if_flags ^ oflags) &
+ IFF_ALLMULTI) != 0)
+ fxp_init(sc);
+ }
}
+
/*
- * Try to start more packets transmitting.
+ * Try to get more packets going.
*/
- if (ifp->if_snd.ifq_head != NULL)
- fxp_start(ifp);
+ fxp_start(ifp);
}
}
@@ -881,9 +932,13 @@ fxp_tick(arg)
void *arg;
{
struct fxp_softc *sc = arg;
- struct ifnet *ifp = &sc->sc_if;
- struct fxp_stats *sp = &sc->control_data->fcd_stats;
- int s = splnet();
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ struct fxp_stats *sp = &sc->sc_control_data->fcd_stats;
+ int oflags, s;
+
+ s = splnet();
+
+ oflags = ifp->if_flags;
ifp->if_opackets += sp->tx_good;
ifp->if_collisions += sp->tx_total_collisions;
@@ -920,7 +975,7 @@ fxp_tick(arg)
*/
if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) {
sc->rx_idle_secs = 0;
- fxp_mc_setup(sc);
+ fxp_mc_setup(sc, 0);
}
/*
* If there is no pending command, start another stats
@@ -951,6 +1006,20 @@ fxp_tick(arg)
/* Tick the MII clock. */
mii_tick(&sc->sc_mii);
+
+ /*
+ * If IFF_ALLMULTI state changed, we need to reinitialize the chip,
+ * because this is handled by the config block.
+ *
+ * NOTE: This shouldn't ever really happen here.
+ */
+ if (((ifp->if_flags ^ oflags) & IFF_ALLMULTI) != 0) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: fxp_tick: allmulti state changed\n",
+ sc->sc_dev.dv_xname);
+ fxp_init(sc);
+ }
+
splx(s);
/*
@@ -967,9 +1036,9 @@ void
fxp_stop(sc)
struct fxp_softc *sc;
{
- struct ifnet *ifp = &sc->sc_if;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
struct fxp_rxdesc *rxd;
- struct fxp_cb_tx *txp;
+ struct fxp_txsoft *txs;
int i;
/*
@@ -986,14 +1055,15 @@ fxp_stop(sc)
/*
* Release any xmit buffers.
*/
- for (txp = sc->control_data->fcd_txcbs, i = 0; i < FXP_NTXCB; i++) {
- if (txp[i].cb_soft.mb_head != NULL) {
- bus_dmamap_unload(sc->sc_dmat, txp[i].cb_soft.dmamap);
- m_freem(txp[i].cb_soft.mb_head);
- txp[i].cb_soft.mb_head = NULL;
+ for (i = 0; i < FXP_NTXCB; i++) {
+ txs = FXP_DSTX(sc, i);
+ if (txs->txs_mbuf != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap);
+ m_freem(txs->txs_mbuf);
+ txs->txs_mbuf = NULL;
}
}
- sc->tx_queued = 0;
+ sc->sc_txpending = 0;
/*
* Free all the receive buffers then reallocate/reinitialize
@@ -1033,36 +1103,41 @@ fxp_watchdog(ifp)
{
struct fxp_softc *sc = ifp->if_softc;
- printf("%s: device timeout\n", sc->sc_dev.dv_xname);
- ifp->if_oerrors++;
+ if (sc->sc_flags & FXPF_DOINGMCSETUP)
+ printf("%s: mcsetup timed out\n", sc->sc_dev.dv_xname);
+ else {
+ printf("%s: device timeout\n", sc->sc_dev.dv_xname);
+ ifp->if_oerrors++;
+ }
fxp_init(sc);
}
+/*
+ * Initialize the interface. Must be called at splnet().
+ */
void
-fxp_init(xsc)
- void *xsc;
+fxp_init(sc)
+ struct fxp_softc *sc;
{
- struct fxp_softc *sc = xsc;
- struct ifnet *ifp = &sc->sc_if;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
struct fxp_cb_config *cbp;
struct fxp_cb_ias *cb_ias;
- struct fxp_cb_tx *txp;
- int i, s, prm, error;
+ struct fxp_cb_tx *txd;
+ int i, prm, allm;
- s = splnet();
/*
* Cancel any pending I/O
*/
fxp_stop(sc);
- prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
- sc->promisc_mode = prm;
+ sc->sc_flags = 0;
/*
* Initialize base of CBL and RFA memory. Loading with zero
* sets it up for regular linear addressing.
*/
+ fxp_scb_wait(sc);
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
@@ -1070,27 +1145,31 @@ fxp_init(xsc)
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
/*
+ * Initialize the multicast filter. Do this now, since we might
+ * have to setup the config block differently.
+ */
+ fxp_mc_setup(sc, 1);
+
+ prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
+ allm = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
+
+ /*
* Initialize base of dump-stats buffer.
*/
fxp_scb_wait(sc);
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
- sc->sc_cddma + FXP_CDOFF(fcd_stats));
+ sc->sc_cddma + FXP_CDSTATSOFF);
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR);
- /*
- * We temporarily use memory that contains the TxCB list to
- * construct the config CB. The TxCB list memory is rebuilt
- * later.
- */
- cbp = (struct fxp_cb_config *) sc->control_data->fcd_txcbs;
+ cbp = &sc->sc_control_data->fcd_configcb;
+ memset(cbp, 0, sizeof(struct fxp_cb_config));
/*
- * This bcopy is kind of disgusting, but there are a bunch of must be
+ * This copy is kind of disgusting, but there are a bunch of must be
* 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, (void *)&cbp->cb_status,
- sizeof(fxp_cb_config_template));
+ memcpy(cbp, fxp_cb_config_template, sizeof(fxp_cb_config_template));
cbp->cb_status = 0;
cbp->cb_command = FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
@@ -1124,110 +1203,70 @@ 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 = sc->all_mcasts;/* accept all multicasts */
+ cbp->mc_all = allm; /* accept all multicasts */
- /* Load the DMA map */
- error = bus_dmamap_load(sc->sc_dmat, sc->sc_tx_dmamaps[0], cbp,
- sizeof(struct fxp_cb_config), NULL, BUS_DMA_NOWAIT);
- if (error) {
- printf("%s: can't load config buffer, error = %d\n",
- sc->sc_dev.dv_xname, error);
- return;
- }
- bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dmamaps[0],
- 0, sizeof(struct fxp_cb_config),
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ FXP_CDCONFIGSYNC(sc, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
/*
* Start the config command/DMA.
*/
fxp_scb_wait(sc);
- CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
- sc->sc_cddma + FXP_CDOFF(fcd_txcbs[0].cb_status));
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->sc_cddma + FXP_CDCONFIGOFF);
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/* ...and wait for it to complete. */
- bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dmamaps[0],
- 0, sizeof(struct fxp_cb_config),
- BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- while (!(cbp->cb_status & FXP_CB_STATUS_C))
- bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dmamaps[0],
- 0, sizeof(struct fxp_cb_config),
- BUS_DMASYNC_POSTREAD);
-
- /* Unload the DMA map */
- bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_dmamaps[0]);
+ do {
+ FXP_CDCONFIGSYNC(sc,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ } while ((cbp->cb_status & FXP_CB_STATUS_C) == 0);
/*
- * Now initialize the station address. Temporarily use the TxCB
- * memory area like we did above for the config CB.
+ * Initialize the station address.
*/
- cb_ias = (struct fxp_cb_ias *) sc->control_data->fcd_txcbs;
+ cb_ias = &sc->sc_control_data->fcd_iascb;
cb_ias->cb_status = 0;
cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
cb_ias->link_addr = -1;
- bcopy(LLADDR(ifp->if_sadl), (void *)cb_ias->macaddr, 6);
-
- /* Load the DMA map */
- error = bus_dmamap_load(sc->sc_dmat, sc->sc_tx_dmamaps[0], cbp,
- sizeof(struct fxp_cb_ias), NULL, BUS_DMA_NOWAIT);
- if (error) {
- printf("%s: can't load address buffer, error = %d\n",
- sc->sc_dev .dv_xname, error);
- return;
- }
- bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dmamaps[0],
- 0, sizeof(struct fxp_cb_ias),
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ memcpy((void *)cb_ias->macaddr, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
+
+ FXP_CDIASSYNC(sc, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
/*
* Start the IAS (Individual Address Setup) command/DMA.
*/
fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->sc_cddma + FXP_CDIASOFF);
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/* ...and wait for it to complete. */
- bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dmamaps[0],
- 0, sizeof(struct fxp_cb_ias),
- BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- while (!(cb_ias->cb_status & FXP_CB_STATUS_C))
- bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_dmamaps[0],
- 0, sizeof(struct fxp_cb_ias),
- BUS_DMASYNC_POSTREAD);
-
- /* Unload the DMA map */
- bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_dmamaps[0]);
+ do {
+ FXP_CDIASSYNC(sc,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ } while ((cb_ias->cb_status & FXP_CB_STATUS_C) == 0);
/*
- * Initialize transmit control block (TxCB) list.
+ * Initialize the transmit descriptor ring. txlast is initialized
+ * to the end of the list so that it will wrap around to the first
+ * descriptor when the first packet is transmitted.
*/
-
- txp = sc->control_data->fcd_txcbs;
- bzero(txp, sizeof(sc->control_data->fcd_txcbs));
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 = sc->sc_cddma +
- FXP_CDOFF(fcd_txcbs[(i + 1) & FXP_TXCB_MASK].cb_status);
- txp[i].tbd_array_addr = sc->sc_cddma +
- FXP_CDOFF(fcd_txcbs[i].tbd[0]);
- txp[i].cb_soft.dmamap = sc->sc_tx_dmamaps[i];
- txp[i].cb_soft.next = &txp[(i + 1) & FXP_TXCB_MASK];
- bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
- FXP_TXDESCOFF(sc, &txp[i]), FXP_TXDESCSIZE,
- BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ txd = FXP_CDTX(sc, i);
+ memset(txd, 0, sizeof(struct fxp_cb_tx));
+ txd->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
+ txd->tbd_array_addr = FXP_CDTBDADDR(sc, i);
+ txd->link_addr = FXP_CDTXADDR(sc, FXP_NEXTTX(i));
+ FXP_CDTXSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
}
+ sc->sc_txpending = 0;
+ sc->sc_txdirty = 0;
+ sc->sc_txlast = FXP_NTXCB - 1;
+
/*
- * Set the suspend flag on the first TxCB and start the control
- * unit. It will execute the NOP and then suspend.
+ * Give the transmit ring to the chip. We do this by pointing
+ * the chip at the last descriptor (which is a NOP|SUSPEND), and
+ * issuing a start command. It will execute the NOP and then
+ * suspend, pointing at the first descriptor.
*/
- txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
- bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
- FXP_TXDESCOFF(sc, txp), FXP_TXDESCSIZE,
- BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-
- sc->cbl_first = sc->cbl_last = txp;
- sc->tx_queued = 1;
-
fxp_scb_wait(sc);
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, FXP_CDTXADDR(sc, sc->sc_txlast));
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/*
@@ -1243,14 +1282,21 @@ fxp_init(xsc)
*/
mii_mediachg(&sc->sc_mii);
+ /*
+ * ...all done!
+ */
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
- splx(s);
/*
* Start stats updater.
*/
timeout(fxp_tick, sc, hz);
+
+ /*
+ * Attempt to start output on the interface.
+ */
+ fxp_start(ifp);
}
/*
@@ -1478,7 +1524,7 @@ fxp_ioctl(ifp, command, data)
struct fxp_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
struct ifaddr *ifa = (struct ifaddr *)data;
- int s, error = 0;
+ int s, oflags, error = 0;
s = splnet();
@@ -1492,11 +1538,11 @@ fxp_ioctl(ifp, command, data)
fxp_init(sc);
arp_ifinit(ifp, ifa);
break;
-#endif
+#endif /* INET */
#ifdef NS
case AF_NS:
{
- register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+ struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
if (ns_nullhost(*ina))
ina->x_host = *(union ns_host *)
@@ -1508,7 +1554,7 @@ fxp_ioctl(ifp, command, data)
fxp_init(sc);
break;
}
-#endif
+#endif /* NS */
default:
fxp_init(sc);
break;
@@ -1523,25 +1569,31 @@ 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.
- * If it is marked down and running, stop it.
- * XXX If it's up then re-initialize it. This is so flags
- * such as IFF_PROMISC are handled.
- */
- if (ifp->if_flags & IFF_UP) {
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running, then
+ * stop it.
+ */
+ fxp_stop(sc);
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it.
+ */
+ fxp_init(sc);
+ } else if ((ifp->if_flags & IFF_UP) != 0) {
+ /*
+ * Reset the interface to pick up change in any other
+ * flags that affect the hardware state.
+ */
fxp_init(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- fxp_stop(sc);
}
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
- sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
error = (command == SIOCADDMULTI) ?
ether_addmulti(ifr, &sc->sc_ethercom) :
ether_delmulti(ifr, &sc->sc_ethercom);
@@ -1551,13 +1603,15 @@ fxp_ioctl(ifp, command, data)
* Multicast list has changed; set the hardware
* filter accordingly.
*/
- if (!sc->all_mcasts)
- fxp_mc_setup(sc);
+ oflags = ifp->if_flags;
+ fxp_mc_setup(sc, 0);
+
/*
- * fxp_mc_setup() can turn on all_mcasts if we run
- * out of space, so check it again rather than else {}.
+ * If IFF_ALLMULTI state changed, we need to
+ * reinitialize the chip, because this is
+ * handled by the config block.
*/
- if (sc->all_mcasts)
+ if (((ifp->if_flags ^ oflags) & IFF_ALLMULTI) != 0)
fxp_init(sc);
error = 0;
}
@@ -1570,99 +1624,116 @@ fxp_ioctl(ifp, command, data)
default:
error = EINVAL;
+ break;
}
- (void) splx(s);
+
+ 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 splnet.
+ * This function must be called at splnet().
*/
void
-fxp_mc_setup(sc)
+fxp_mc_setup(sc, poll)
struct fxp_softc *sc;
+ int poll;
{
- struct fxp_cb_mcs *mcsp = &sc->control_data->fcd_mcscb;
- struct ifnet *ifp = &sc->sc_if;
+ struct fxp_cb_mcs *mcsp = &sc->sc_control_data->fcd_mcscb;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
struct ethercom *ec = &sc->sc_ethercom;
struct ether_multi *enm;
struct ether_multistep step;
int nmcasts;
- if (sc->tx_queued) {
- sc->need_mcsetup = 1;
+ /*
+ * If there are transmissions pending, wait until they're
+ * complete. fxp_intr() will call us when they've drained.
+ */
+ if (sc->sc_txpending) {
+#ifdef DIAGNOSTIC
+ if (poll)
+ panic("fxp_mc_setup: poll and txpending");
+#endif
+ sc->sc_flags |= FXPF_NEEDMCSETUP;
return;
}
- sc->need_mcsetup = 0;
+ sc->sc_flags &= ~FXPF_NEEDMCSETUP;
+
+ ifp->if_flags &= ~IFF_ALLMULTI;
/*
* Initialize multicast setup descriptor.
*/
- mcsp->cb_soft.next = sc->control_data->fcd_txcbs;
- mcsp->cb_soft.mb_head = NULL;
- mcsp->cb_soft.dmamap = NULL;
- mcsp->cb_status = 0;
- mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S;
- mcsp->link_addr = sc->sc_cddma + FXP_CDOFF(fcd_txcbs[0].cb_status);
-
nmcasts = 0;
- if (!sc->all_mcasts) {
- ETHER_FIRST_MULTI(step, ec, enm);
- while (enm != NULL) {
+ 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 ||
+ memcmp(enm->enm_addrlo, enm->enm_addrhi,
+ ETHER_ADDR_LEN) != 0) {
/*
- * Check for too many multicast addresses or if we're
- * listening to a range. Either way, we simply have
- * to accept all multicasts.
+ * Callers of this function must do the
+ * right thing with this. If we're called
+ * from outside fxp_init(), the caller must
+ * detect if the state if IFF_ALLMULTI changes.
+ * If it does, the caller must then call
+ * fxp_init(), since allmulti is handled by
+ * the config block.
*/
- 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->control_data->fcd_mcscb.mc_addr[nmcasts][0],
- ETHER_ADDR_LEN);
- nmcasts++;
- ETHER_NEXT_MULTI(step, enm);
+ ifp->if_flags |= IFF_ALLMULTI;
+ return;
}
+ memcpy((void *)&mcsp->mc_addr[nmcasts][0], enm->enm_addrlo,
+ ETHER_ADDR_LEN);
+ nmcasts++;
+ ETHER_NEXT_MULTI(step, enm);
}
- mcsp->mc_cnt = nmcasts * 6;
- sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp;
- sc->tx_queued = 1;
- bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
- FXP_CDOFF(fcd_mcscb.cb_status), FXP_MCSDESCSIZE,
- BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ mcsp->cb_status = 0;
+ if (poll) {
+ mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_EL;
+ mcsp->link_addr = -1;
+ } else {
+ mcsp->cb_command = FXP_CB_COMMAND_MCAS | FXP_CB_COMMAND_S |
+ FXP_CB_COMMAND_I;
+ mcsp->link_addr = FXP_CDTXADDR(sc, FXP_NEXTTX(sc->sc_txlast));
+ }
+ mcsp->mc_cnt = nmcasts * ETHER_ADDR_LEN;
+
+ FXP_CDMCSSYNC(sc, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
/*
- * Wait until command unit is not active. This should never
- * be the case when nothing is queued, but make sure anyway.
+ * Wait until the command unit is not active. This should never
+ * happen since nothing is queued, but make sure anyway.
*/
while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
- FXP_SCB_CUS_ACTIVE) ;
+ FXP_SCB_CUS_ACTIVE)
+ /* nothing */ ;
/*
- * Start the multicast setup command.
+ * Start the multicast setup command/DMA.
*/
fxp_scb_wait(sc);
- CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
- sc->sc_cddma + FXP_CDOFF(fcd_mcscb.cb_status));
+ CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->sc_cddma + FXP_CDMCSOFF);
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
- ifp->if_timer = 5;
- return;
+ if (poll) {
+ do {
+ FXP_CDMCSSYNC(sc,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ } while ((mcsp->cb_status & FXP_CB_STATUS_C) == 0);
+ } else {
+ sc->sc_flags |= FXPF_DOINGMCSETUP;
+ ifp->if_flags |= IFF_OACTIVE;
+
+ /* Set a watchdog timer in case the chip flakes out. */
+ ifp->if_timer = 5;
+ }
}
diff --git a/sys/dev/ic/i82557reg.h b/sys/dev/ic/i82557reg.h
index ec9ae3b55ea..35ac28e886f 100644
--- a/sys/dev/ic/i82557reg.h
+++ b/sys/dev/ic/i82557reg.h
@@ -1,7 +1,7 @@
-/* $NetBSD: i82557reg.h,v 1.1 1999/06/20 16:33:28 thorpej Exp $ */
+/* $NetBSD: i82557reg.h,v 1.2 1999/08/03 22:43:28 thorpej Exp $ */
/*-
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -134,33 +134,32 @@
#define FXP_SCB_COMMAND_RU_RBDRESUME 7
/*
- * Software-use only part of the command block.
+ * Command block definitions
*/
-struct fxp_cb_soft {
- void *next; /* pointer to next command block */
- struct mbuf *mb_head; /* pointer to data for this command */
- bus_dmamap_t dmamap; /* our DMA map */
-};
/*
- * Command block definitions
+ * NOP command.
*/
struct fxp_cb_nop {
- struct fxp_cb_soft cb_soft;
volatile u_int16_t cb_status;
volatile u_int16_t cb_command;
volatile u_int32_t link_addr;
};
+
+/*
+ * Individual Address command.
+ */
struct fxp_cb_ias {
- struct fxp_cb_soft cb_soft;
volatile u_int16_t cb_status;
volatile u_int16_t cb_command;
volatile u_int32_t link_addr;
volatile u_int8_t macaddr[6];
};
-/* I hate bit-fields :-( */
+
+/*
+ * Configure command.
+ */
struct fxp_cb_config {
- struct fxp_cb_soft cb_soft;
volatile u_int16_t cb_status;
volatile u_int16_t cb_command;
volatile u_int32_t link_addr;
@@ -220,15 +219,10 @@ struct fxp_cb_config {
};
/*
- * Size of the hardware portion of a given transmit descriptor, including
- * the DMA segment array.
+ * Multicast setup command.
*/
-#define FXP_MCSDESCSIZE \
- (sizeof(struct fxp_cb_mcs) - offsetof(struct fxp_cb_mcs, cb_status))
-
#define MAXMCADDR 80
struct fxp_cb_mcs {
- struct fxp_cb_soft cb_soft;
volatile u_int16_t cb_status;
volatile u_int16_t cb_command;
volatile u_int32_t link_addr;
@@ -237,19 +231,9 @@ struct fxp_cb_mcs {
};
/*
- * Number of DMA segments in a TxCB. The TxCB must map to a
- * contiguous region from the DMA engine's perspective. Since
- * we allocate memory conforming to those contraints, we can
- * arbitrarily choose the number of segments.
+ * Transmit command.
*/
-#define FXP_NTXSEG 32
-
-struct fxp_tbd {
- volatile u_int32_t tb_addr;
- volatile u_int32_t tb_size;
-};
struct fxp_cb_tx {
- struct fxp_cb_soft cb_soft;
volatile u_int16_t cb_status;
volatile u_int16_t cb_command;
volatile u_int32_t link_addr;
@@ -257,28 +241,15 @@ struct fxp_cb_tx {
volatile u_int16_t byte_count;
volatile u_int8_t tx_threshold;
volatile u_int8_t tbd_number;
- /*
- * The following isn't actually part of the TxCB, but we
- * allocate it here for convenience.
- */
- volatile struct fxp_tbd tbd[FXP_NTXSEG];
};
/*
- * Offset of the hardware portion of a given transmit descriptor from the
- * base of the control data DMA mapping.
- */
-#define FXP_TXDESCOFF(sc, txd) \
- (FXP_CDOFF(fcd_txcbs[0]) + \
- (((u_long)(txd)) - ((u_long)&(sc)->control_data->fcd_txcbs[0])) + \
- offsetof(struct fxp_cb_tx, cb_status))
-
-/*
- * Size of the hardware portion of a given transmit descriptor, including
- * the DMA segment array.
+ * Transmit buffer descriptors.
*/
-#define FXP_TXDESCSIZE \
- (sizeof(struct fxp_cb_tx) - offsetof(struct fxp_cb_tx, cb_status))
+struct fxp_tbd {
+ volatile u_int32_t tb_addr;
+ volatile u_int32_t tb_size;
+};
/*
* Control Block (CB) definitions
@@ -287,6 +258,7 @@ struct fxp_cb_tx {
/* status */
#define FXP_CB_STATUS_OK 0x2000
#define FXP_CB_STATUS_C 0x8000
+
/* commands */
#define FXP_CB_COMMAND_NOP 0x0
#define FXP_CB_COMMAND_IAS 0x1
@@ -296,6 +268,7 @@ struct fxp_cb_tx {
#define FXP_CB_COMMAND_RESRV 0x5
#define FXP_CB_COMMAND_DUMP 0x6
#define FXP_CB_COMMAND_DIAG 0x7
+
/* command flags */
#define FXP_CB_COMMAND_SF 0x0008 /* simple/flexible mode */
#define FXP_CB_COMMAND_I 0x2000 /* generate interrupt on completion */
@@ -303,13 +276,13 @@ struct fxp_cb_tx {
#define FXP_CB_COMMAND_EL 0x8000 /* end of list */
/*
- * RFA definitions
+ * Receive Frame Area.
+ *
* NOTE! The RFA will NOT be aligned on a 4-byte boundary in the DMA
* area! To prevent EGCS from optimizing the copy of link_addr and
* rbd_addr (which would cause an unaligned access fault on RISC systems),
* we must make them an array of bytes!
*/
-
struct fxp_rfa {
volatile u_int16_t rfa_status;
volatile u_int16_t rfa_control;
@@ -318,6 +291,7 @@ struct fxp_rfa {
volatile u_int16_t actual_size;
volatile u_int16_t size;
};
+
#define FXP_RFA_STATUS_RCOL 0x0001 /* receive collision */
#define FXP_RFA_STATUS_IAMATCH 0x0002 /* 0 = matches station address */
#define FXP_RFA_STATUS_S4 0x0010 /* receive error from PHY */
@@ -329,8 +303,9 @@ struct fxp_rfa {
#define FXP_RFA_STATUS_CRC 0x0800 /* CRC error */
#define FXP_RFA_STATUS_OK 0x2000 /* packet received okay */
#define FXP_RFA_STATUS_C 0x8000 /* packet reception complete */
-#define FXP_RFA_CONTROL_SF 0x08 /* simple/flexible memory mode */
-#define FXP_RFA_CONTROL_H 0x10 /* header RFD */
+
+#define FXP_RFA_CONTROL_SF 0x0008 /* simple/flexible memory mode */
+#define FXP_RFA_CONTROL_H 0x0010 /* header RFD */
#define FXP_RFA_CONTROL_S 0x4000 /* suspend after reception */
#define FXP_RFA_CONTROL_EL 0x8000 /* end of list */
@@ -362,14 +337,10 @@ struct fxp_stats {
/*
* Serial EEPROM control register bits
*/
-/* shift clock */
-#define FXP_EEPROM_EESK 0x01
-/* chip select */
-#define FXP_EEPROM_EECS 0x02
-/* data in */
-#define FXP_EEPROM_EEDI 0x04
-/* data out */
-#define FXP_EEPROM_EEDO 0x08
+#define FXP_EEPROM_EESK 0x01 /* shift clock */
+#define FXP_EEPROM_EECS 0x02 /* chip select */
+#define FXP_EEPROM_EEDI 0x04 /* data in */
+#define FXP_EEPROM_EEDO 0x08 /* data out */
/*
* Serial EEPROM opcodes, including start bit
@@ -385,7 +356,7 @@ struct fxp_stats {
#define FXP_MDI_READ 0x2
/*
- * PHY device types
+ * PHY device types (from EEPROM)
*/
#define FXP_PHY_NONE 0
#define FXP_PHY_82553A 1
diff --git a/sys/dev/ic/i82557var.h b/sys/dev/ic/i82557var.h
index 2ee714ebb23..6a80eb5516d 100644
--- a/sys/dev/ic/i82557var.h
+++ b/sys/dev/ic/i82557var.h
@@ -1,7 +1,7 @@
-/* $NetBSD: i82557var.h,v 1.1 1999/06/20 16:33:29 thorpej Exp $ */
+/* $NetBSD: i82557var.h,v 1.2 1999/08/03 22:43:28 thorpej Exp $ */
/*-
- * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -72,22 +72,18 @@
*/
/*
- * Number of transmit control blocks. This determines the number
- * of transmit buffers that can be chained in the CB list. This
- * must be a power of two.
+ * Transmit descriptor list size.
*/
-#define FXP_NTXCB 128
-
-/*
- * TxCB list index mask. This is used to do list wrap-around.
- */
-#define FXP_TXCB_MASK (FXP_NTXCB - 1)
+#define FXP_NTXCB 128
+#define FXP_NTXCB_MASK (FXP_NTXCB - 1)
+#define FXP_NEXTTX(x) ((x + 1) & FXP_NTXCB_MASK)
+#define FXP_NTXSEG 16
/*
* Number of receive frame area buffers. These are large, so
* choose wisely.
*/
-#define FXP_NRFABUFS 64
+#define FXP_NRFABUFS 64
/*
* Maximum number of seconds that the reciever can be idle before we
@@ -110,6 +106,23 @@ struct fxp_control_data {
struct fxp_cb_tx fcd_txcbs[FXP_NTXCB];
/*
+ * The transmit buffer descriptors.
+ */
+ struct fxp_tbdlist {
+ struct fxp_tbd tbd_d[FXP_NTXSEG];
+ } fcd_tbdl[FXP_NTXCB];
+
+ /*
+ * The configuration CB.
+ */
+ struct fxp_cb_config fcd_configcb;
+
+ /*
+ * The Individual Address CB.
+ */
+ struct fxp_cb_ias fcd_iascb;
+
+ /*
* The multicast setup CB.
*/
struct fxp_cb_mcs fcd_mcscb;
@@ -121,10 +134,23 @@ struct fxp_control_data {
};
#define FXP_CDOFF(x) offsetof(struct fxp_control_data, x)
+#define FXP_CDTXOFF(x) FXP_CDOFF(fcd_txcbs[(x)])
+#define FXP_CDTBDOFF(x) FXP_CDOFF(fcd_tbdl[(x)])
+#define FXP_CDCONFIGOFF FXP_CDOFF(fcd_configcb)
+#define FXP_CDIASOFF FXP_CDOFF(fcd_iascb)
+#define FXP_CDMCSOFF FXP_CDOFF(fcd_mcscb)
+#define FXP_CDSTATSOFF FXP_CDOFF(fcd_stats)
/*
- * Receive buffer descriptor (software only). This is the analog of
- * the software portion of the fxp_cb_tx.
+ * Software state for transmit descriptors.
+ */
+struct fxp_txsoft {
+ struct mbuf *txs_mbuf; /* head of mbuf chain */
+ bus_dmamap_t txs_dmamap; /* our DMA map */
+};
+
+/*
+ * Software state for receive descriptors.
*/
struct fxp_rxdesc {
struct fxp_rxdesc *fr_next; /* next in the chain */
@@ -132,15 +158,19 @@ struct fxp_rxdesc {
bus_dmamap_t fr_dmamap; /* our DMA map */
};
+/*
+ * Software state per device.
+ */
struct fxp_softc {
struct device sc_dev; /* generic device structures */
- void *sc_ih; /* interrupt handler cookie */
- void *sc_sdhook; /* shutdown hook */
bus_space_tag_t sc_st; /* bus space tag */
bus_space_handle_t sc_sh; /* bus space handle */
bus_dma_tag_t sc_dmat; /* bus dma tag */
struct ethercom sc_ethercom; /* ethernet common part */
-#define sc_if sc_ethercom.ec_if
+ void *sc_sdhook; /* shutdown hook */
+ void *sc_ih; /* interrupt handler cookie */
+
+ struct mii_data sc_mii; /* MII/media information */
/*
* We create a single DMA map that maps all data structure
@@ -151,28 +181,31 @@ struct fxp_softc {
#define sc_cddma sc_dmamap->dm_segs[0].ds_addr
/*
- * These DMA maps map transmit and recieve buffers.
+ * Software state for transmit and receive descriptors.
*/
- bus_dmamap_t sc_tx_dmamaps[FXP_NTXCB];
+ struct fxp_txsoft sc_txsoft[FXP_NTXCB];
+
bus_dmamap_t sc_rx_dmamaps[FXP_NRFABUFS];
+ struct fxp_rxdesc sc_rxdescs[FXP_NRFABUFS];
/*
- * Control data - TxCBs, stats, etc.
+ * Control data structures.
*/
- struct fxp_control_data *control_data;
+ struct fxp_control_data *sc_control_data;
+
+ int sc_flags; /* misc. flags */
+
+#define FXPF_NEEDMCSETUP 0x01 /* multicast setup needed */
+#define FXPF_DOINGMCSETUP 0x02 /* multicast setup in-progress */
+
+ int sc_txpending; /* number of TX requests pending */
+ int sc_txdirty; /* first dirty TX descriptor */
+ int sc_txlast; /* last used TX descriptor */
- /* receive buffer descriptors */
- struct fxp_rxdesc sc_rxdescs[FXP_NRFABUFS];
- struct mii_data sc_mii; /* MII media information */
- struct fxp_cb_tx *cbl_first; /* first active TxCB in list */
- struct fxp_cb_tx *cbl_last; /* last active TxCB in list */
- int tx_queued; /* # of active TxCB's */
- int need_mcsetup; /* multicast filter needs programming */
struct fxp_rxdesc *rfa_head; /* first mbuf in receive frame area */
struct fxp_rxdesc *rfa_tail; /* last mbuf in receive frame area */
int rx_idle_secs; /* # of seconds RX has been idle */
- int all_mcasts; /* receive all multicasts */
- int promisc_mode; /* promiscuous mode enabled */
+
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 */
@@ -181,6 +214,34 @@ struct fxp_softc {
#endif
};
+#define FXP_CDTXADDR(sc, x) ((sc)->sc_cddma + FXP_CDTXOFF((x)))
+#define FXP_CDTBDADDR(sc, x) ((sc)->sc_cddma + FXP_CDTBDOFF((x)))
+
+#define FXP_CDTX(sc, x) (&(sc)->sc_control_data->fcd_txcbs[(x)])
+#define FXP_CDTBD(sc, x) (&(sc)->sc_control_data->fcd_tbdl[(x)])
+
+#define FXP_DSTX(sc, x) (&(sc)->sc_txsoft[(x)])
+
+#define FXP_CDTXSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
+ FXP_CDTXOFF((x)), sizeof(struct fxp_cb_tx), (ops))
+
+#define FXP_CDTBDSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
+ FXP_CDTBDOFF((x)), sizeof(struct fxp_tbdlist), (ops))
+
+#define FXP_CDCONFIGSYNC(sc, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
+ FXP_CDCONFIGOFF, sizeof(struct fxp_cb_config), (ops))
+
+#define FXP_CDIASSYNC(sc, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
+ FXP_CDIASOFF, sizeof(struct fxp_cb_ias), (ops))
+
+#define FXP_CDMCSSYNC(sc, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_dmamap, \
+ FXP_CDMCSOFF, sizeof(struct fxp_cb_mcs), (ops))
+
/* Macros to ease CSR access. */
#define CSR_READ_1(sc, reg) \
bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg))