summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_xl.c
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1999-09-20 00:24:11 +0000
committerwpaul <wpaul@FreeBSD.org>1999-09-20 00:24:11 +0000
commitb895b5437522f0b73e31c715714e989f86b9a039 (patch)
tree1c3feef061d8874ad8ddf9c8cec67e20fed5b0b2 /sys/pci/if_xl.c
parentacbf246f5fb72c851b709d310e3def4bae13f8b9 (diff)
downloadFreeBSD-src-b895b5437522f0b73e31c715714e989f86b9a039.zip
FreeBSD-src-b895b5437522f0b73e31c715714e989f86b9a039.tar.gz
Add an alternate transmit strategy for 3c90xB adapters based on the transmit
strategy used in the 3Com Linux driver. The new strategy is to use transmit descriptor polling -- that is, the NIC polls the descriptors to see when new packets are available for transmission. The advantage to the new scheme is that no register accesses are needed in the transmit routine. The old scheme requires several register accesses to stall the TX engine, update the TX DMA list pointer register, then unstall the TX engine. Hopefully the new scheme will provide improved transmit performance with less CPU overhead. This only affects the 3c90xB or 3c90xC cards, not the 3c90x cards. This means the original 3c900 and 3c905 cards are unaffected. Newer cards include the 3c900B series, the 3c905B, 3c980, 3c980B, 3c905C and 3c905C, and the 3cSOHO100-TX OfficeConnect.
Diffstat (limited to 'sys/pci/if_xl.c')
-rw-r--r--sys/pci/if_xl.c363
1 files changed, 292 insertions, 71 deletions
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c
index a5f50a2..36ff5a2 100644
--- a/sys/pci/if_xl.c
+++ b/sys/pci/if_xl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 1998
+ * Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -202,12 +202,16 @@ static int xl_newbuf __P((struct xl_softc *,
static void xl_stats_update __P((void *));
static int xl_encap __P((struct xl_softc *, struct xl_chain *,
struct mbuf * ));
+static int xl_encap_90xB __P((struct xl_softc *, struct xl_chain *,
+ struct mbuf * ));
static void xl_rxeof __P((struct xl_softc *));
static void xl_txeof __P((struct xl_softc *));
+static void xl_txeof_90xB __P((struct xl_softc *));
static void xl_txeoc __P((struct xl_softc *));
static void xl_intr __P((void *));
static void xl_start __P((struct ifnet *));
+static void xl_start_90xB __P((struct ifnet *));
static int xl_ioctl __P((struct ifnet *, u_long, caddr_t));
static void xl_init __P((void *));
static void xl_stop __P((struct xl_softc *));
@@ -232,6 +236,7 @@ static void xl_setmulti_hash __P((struct xl_softc *));
static void xl_reset __P((struct xl_softc *));
static int xl_list_rx_init __P((struct xl_softc *));
static int xl_list_tx_init __P((struct xl_softc *));
+static int xl_list_tx_init_90xB __P((struct xl_softc *));
static void xl_wait __P((struct xl_softc *));
static void xl_mediacheck __P((struct xl_softc *));
#ifdef notdef
@@ -1147,14 +1152,12 @@ static void xl_mediacheck(sc)
static int xl_attach(dev)
device_t dev;
{
- int s, i;
+ int s;
u_char eaddr[ETHER_ADDR_LEN];
u_int32_t command;
struct xl_softc *sc;
struct ifnet *ifp;
int media = IFM_ETHER|IFM_100_TX|IFM_FDX;
- unsigned int round;
- caddr_t roundptr;
int unit, error = 0, rid;
s = splimp();
@@ -1285,9 +1288,10 @@ static int xl_attach(dev)
callout_handle_init(&sc->xl_stat_ch);
bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
- sc->xl_ldata_ptr = malloc(sizeof(struct xl_list_data) + 8,
- M_DEVBUF, M_NOWAIT);
- if (sc->xl_ldata_ptr == NULL) {
+ sc->xl_ldata = contigmalloc(sizeof(struct xl_list_data), M_DEVBUF,
+ M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0);
+
+ if (sc->xl_ldata == NULL) {
printf("xl%d: no memory for list buffers!\n", unit);
bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
@@ -1296,19 +1300,19 @@ static int xl_attach(dev)
goto fail;
}
- sc->xl_ldata = (struct xl_list_data *)sc->xl_ldata_ptr;
- round = (uintptr_t)sc->xl_ldata_ptr & 0xF;
- roundptr = sc->xl_ldata_ptr;
- for (i = 0; i < 8; i++) {
- if (round % 8) {
- round++;
- roundptr++;
- } else
- break;
- }
- sc->xl_ldata = (struct xl_list_data *)roundptr;
bzero(sc->xl_ldata, sizeof(struct xl_list_data));
+ /*
+ * Figure out the card type. 3c905B adapters have the
+ * 'supportsNoTxLength' bit set in the capabilities
+ * word in the EEPROM.
+ */
+ xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0);
+ if (sc->xl_caps & XL_CAPS_NO_TXLENGTH)
+ sc->xl_type = XL_TYPE_905B;
+ else
+ sc->xl_type = XL_TYPE_90X;
+
ifp = &sc->arpcom.ac_if;
ifp->if_softc = sc;
ifp->if_unit = unit;
@@ -1317,24 +1321,16 @@ static int xl_attach(dev)
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = xl_ioctl;
ifp->if_output = ether_output;
- ifp->if_start = xl_start;
+ if (sc->xl_type == XL_TYPE_905B)
+ ifp->if_start = xl_start_90xB;
+ else
+ ifp->if_start = xl_start;
ifp->if_watchdog = xl_watchdog;
ifp->if_init = xl_init;
ifp->if_baudrate = 10000000;
ifp->if_snd.ifq_maxlen = XL_TX_LIST_CNT - 1;
/*
- * Figure out the card type. 3c905B adapters have the
- * 'supportsNoTxLength' bit set in the capabilities
- * word in the EEPROM.
- */
- xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0);
- if (sc->xl_caps & XL_CAPS_NO_TXLENGTH)
- sc->xl_type = XL_TYPE_905B;
- else
- sc->xl_type = XL_TYPE_90X;
-
- /*
* Now we have to see what sort of media we have.
* This includes probing for an MII interace and a
* possible PHY.
@@ -1362,7 +1358,8 @@ static int xl_attach(dev)
bus_teardown_intr(dev, sc->xl_irq, sc->xl_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->xl_irq);
bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
- free(sc->xl_ldata_ptr, M_DEVBUF);
+ contigfree(sc->xl_ldata,
+ sizeof(struct xl_list_data), M_DEVBUF);
error = ENXIO;
goto fail;
}
@@ -1491,6 +1488,7 @@ static int xl_detach(dev)
sc = device_get_softc(dev);
ifp = &sc->arpcom.ac_if;
+ xl_reset(sc);
xl_stop(sc);
if_detach(ifp);
@@ -1505,7 +1503,7 @@ static int xl_detach(dev)
bus_release_resource(dev, XL_RES, XL_RID, sc->xl_res);
ifmedia_removeall(&sc->ifmedia);
- free(sc->xl_ldata_ptr, M_DEVBUF);
+ contigfree(sc->xl_ldata, sizeof(struct xl_list_data), M_DEVBUF);
splx(s);
@@ -1539,6 +1537,44 @@ static int xl_list_tx_init(sc)
}
/*
+ * Initialize the transmit descriptors.
+ */
+static int xl_list_tx_init_90xB(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain_data *cd;
+ struct xl_list_data *ld;
+ int i;
+
+ cd = &sc->xl_cdata;
+ ld = sc->xl_ldata;
+ for (i = 0; i < XL_TX_LIST_CNT; i++) {
+ cd->xl_tx_chain[i].xl_ptr = &ld->xl_tx_list[i];
+ cd->xl_tx_chain[i].xl_phys = vtophys(&ld->xl_tx_list[i]);
+ if (i == (XL_TX_LIST_CNT - 1))
+ cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[0];
+ else
+ cd->xl_tx_chain[i].xl_next = &cd->xl_tx_chain[i + 1];
+ if (i == 0)
+ cd->xl_tx_chain[i].xl_prev =
+ &cd->xl_tx_chain[XL_TX_LIST_CNT - 1];
+ else
+ cd->xl_tx_chain[i].xl_prev =
+ &cd->xl_tx_chain[i - 1];
+ }
+
+ bzero((char *)ld->xl_tx_list,
+ sizeof(struct xl_list) * XL_TX_LIST_CNT);
+ ld->xl_tx_list[0].xl_status = XL_TXSTAT_EMPTY;
+
+ cd->xl_tx_prod = 1;
+ cd->xl_tx_cons = 1;
+ cd->xl_tx_cnt = 0;
+
+ return(0);
+}
+
+/*
* Initialize the RX descriptors and allocate mbufs for them. Note that
* we arrange the descriptors in a closed ring, so that the last descriptor
* points back to the first.
@@ -1561,11 +1597,11 @@ static int xl_list_rx_init(sc)
if (i == (XL_RX_LIST_CNT - 1)) {
cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[0];
ld->xl_rx_list[i].xl_next =
- vtophys(&ld->xl_rx_list[0]);
+ vtophys(&ld->xl_rx_list[0]);
} else {
cd->xl_rx_chain[i].xl_next = &cd->xl_rx_chain[i + 1];
ld->xl_rx_list[i].xl_next =
- vtophys(&ld->xl_rx_list[i + 1]);
+ vtophys(&ld->xl_rx_list[i + 1]);
}
}
@@ -1585,26 +1621,28 @@ static int xl_newbuf(sc, c)
MGETHDR(m_new, M_DONTWAIT, MT_DATA);
if (m_new == NULL) {
- printf("xl%d: no memory for rx list -- packet dropped!\n",
- sc->xl_unit);
+ printf("xl%d: no memory for rx list -- "
+ "packet dropped!\n", sc->xl_unit);
return(ENOBUFS);
}
MCLGET(m_new, M_DONTWAIT);
if (!(m_new->m_flags & M_EXT)) {
- printf("xl%d: no memory for rx list -- packet dropped!\n",
- sc->xl_unit);
+ printf("xl%d: no memory for rx list -- "
+ "packet dropped!\n", sc->xl_unit);
m_freem(m_new);
return(ENOBUFS);
}
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+
/* Force longword alignment for packet payload. */
- m_new->m_data += 2;
+ m_adj(m_new, ETHER_ALIGN);
c->xl_mbuf = m_new;
- c->xl_ptr->xl_status = 0;
c->xl_ptr->xl_frag.xl_addr = vtophys(mtod(m_new, caddr_t));
c->xl_ptr->xl_frag.xl_len = MCLBYTES | XL_LAST_FRAG;
+ c->xl_ptr->xl_status = 0;
return(0);
}
@@ -1649,8 +1687,8 @@ again:
* If not, something truly strange has happened.
*/
if (!(rxstat & XL_RXSTAT_UP_CMPLT)) {
- printf("xl%d: bad receive status -- packet dropped",
- sc->xl_unit);
+ printf("xl%d: bad receive status -- "
+ "packet dropped", sc->xl_unit);
ifp->if_ierrors++;
cur_rx->xl_ptr->xl_status = 0;
continue;
@@ -1771,11 +1809,10 @@ static void xl_txeof(sc)
*/
while(sc->xl_cdata.xl_tx_head != NULL) {
cur_tx = sc->xl_cdata.xl_tx_head;
- if ((sc->xl_type == XL_TYPE_905B &&
- !(cur_tx->xl_ptr->xl_status & XL_TXSTAT_DL_COMPLETE)) ||
- CSR_READ_4(sc, XL_DOWNLIST_PTR)) {
+
+ if (CSR_READ_4(sc, XL_DOWNLIST_PTR))
break;
- }
+
sc->xl_cdata.xl_tx_head = cur_tx->xl_next;
m_freem(cur_tx->xl_mbuf);
cur_tx->xl_mbuf = NULL;
@@ -1800,6 +1837,43 @@ static void xl_txeof(sc)
return;
}
+static void xl_txeof_90xB(sc)
+ struct xl_softc *sc;
+{
+ struct xl_chain *cur_tx = NULL;
+ struct ifnet *ifp;
+ int idx;
+
+ ifp = &sc->arpcom.ac_if;
+
+ idx = sc->xl_cdata.xl_tx_cons;
+ while(idx != sc->xl_cdata.xl_tx_prod) {
+
+ cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ if (!(cur_tx->xl_ptr->xl_status & XL_TXSTAT_DL_COMPLETE))
+ break;
+
+ if (cur_tx->xl_mbuf != NULL) {
+ m_freem(cur_tx->xl_mbuf);
+ cur_tx->xl_mbuf = NULL;
+ }
+
+ ifp->if_opackets++;
+
+ sc->xl_cdata.xl_tx_cnt--;
+ XL_INC(idx, XL_TX_LIST_CNT);
+ ifp->if_timer = 0;
+ }
+
+ sc->xl_cdata.xl_tx_cons = idx;
+
+ if (cur_tx != NULL)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return;
+}
+
/*
* TX 'end of channel' interrupt handler. Actually, we should
* only get a 'TX complete' interrupt if there's a transmit error,
@@ -1818,9 +1892,21 @@ static void xl_txeoc(sc)
sc->xl_unit, txstat);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
xl_wait(sc);
- if (sc->xl_cdata.xl_tx_head != NULL)
- CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ if (sc->xl_type == XL_TYPE_905B) {
+ if (sc->xl_cdata.xl_tx_cnt) {
+ int i;
+ struct xl_chain *c;
+ i = sc->xl_cdata.xl_tx_cons;
+ c = &sc->xl_cdata.xl_tx_chain[i];
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ c->xl_phys);
+ CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ }
+ } else {
+ if (sc->xl_cdata.xl_tx_head != NULL)
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
vtophys(sc->xl_cdata.xl_tx_head->xl_ptr));
+ }
/*
* Remember to set this for the
* first generation 3c90X chips.
@@ -1865,14 +1951,7 @@ static void xl_intr(arg)
sc = arg;
ifp = &sc->arpcom.ac_if;
- /* Disable interrupts. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB);
-
- for (;;) {
- status = CSR_READ_2(sc, XL_STATUS);
-
- if ((status & XL_INTRS) == 0)
- break;
+ while((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS) {
CSR_WRITE_2(sc, XL_COMMAND,
XL_CMD_INTR_ACK|(status & XL_INTRS));
@@ -1880,8 +1959,12 @@ static void xl_intr(arg)
if (status & XL_STAT_UP_COMPLETE)
xl_rxeof(sc);
- if (status & XL_STAT_DOWN_COMPLETE)
- xl_txeof(sc);
+ if (status & XL_STAT_DOWN_COMPLETE) {
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_txeof_90xB(sc);
+ else
+ xl_txeof(sc);
+ }
if (status & XL_STAT_TX_COMPLETE) {
ifp->if_oerrors++;
@@ -1900,13 +1983,8 @@ static void xl_intr(arg)
}
}
- /* Re-enable interrupts. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
-
- XL_SEL_WIN(7);
-
if (ifp->if_snd.ifq_head != NULL)
- xl_start(ifp);
+ (*ifp->if_start)(ifp);
return;
}
@@ -2166,6 +2244,120 @@ static void xl_start(ifp)
return;
}
+static int xl_encap_90xB(sc, c, m_head)
+ struct xl_softc *sc;
+ struct xl_chain *c;
+ struct mbuf *m_head;
+{
+ int frag = 0;
+ struct xl_frag *f = NULL;
+ struct mbuf *m;
+ struct xl_list *d;
+
+ /*
+ * Start packing the mbufs in this chain into
+ * the fragment pointers. Stop when we run out
+ * of fragments or hit the end of the mbuf chain.
+ */
+ d = c->xl_ptr;
+ d->xl_status = 0;
+ d->xl_next = 0;
+
+ for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
+ if (m->m_len != 0) {
+ if (frag == XL_MAXFRAGS)
+ break;
+ f = &d->xl_frag[frag];
+ f->xl_addr = vtophys(mtod(m, vm_offset_t));
+ f->xl_len = m->m_len;
+ frag++;
+ }
+ }
+
+ c->xl_mbuf = m_head;
+ c->xl_ptr->xl_frag[frag - 1].xl_len |= XL_LAST_FRAG;
+ c->xl_ptr->xl_status = XL_TXSTAT_RND_DEFEAT;
+
+ return(0);
+}
+
+static void xl_start_90xB(ifp)
+ struct ifnet *ifp;
+{
+ struct xl_softc *sc;
+ struct mbuf *m_head = NULL;
+ struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
+ int idx;
+
+ sc = ifp->if_softc;
+
+ if (ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ idx = sc->xl_cdata.xl_tx_prod;
+ start_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ while (sc->xl_cdata.xl_tx_chain[idx].xl_mbuf == NULL) {
+
+ if ((XL_TX_LIST_CNT - sc->xl_cdata.xl_tx_cnt) < 3) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ cur_tx = &sc->xl_cdata.xl_tx_chain[idx];
+
+ /* Pack the data into the descriptor. */
+ xl_encap_90xB(sc, cur_tx, m_head);
+
+ /* Chain it together. */
+ if (prev != NULL)
+ prev->xl_ptr->xl_next = cur_tx->xl_phys;
+ prev = cur_tx;
+
+#if NBPF > 0
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, cur_tx->xl_mbuf);
+#endif
+
+ XL_INC(idx, XL_TX_LIST_CNT);
+ sc->xl_cdata.xl_tx_cnt++;
+ }
+
+ /*
+ * If there are no packets queued, bail.
+ */
+ if (cur_tx == NULL)
+ return;
+
+ /*
+ * Place the request for the upload interrupt
+ * in the last descriptor in the chain. This way, if
+ * we're chaining several packets at once, we'll only
+ * get an interupt once for the whole chain rather than
+ * once for each packet.
+ */
+ cur_tx->xl_ptr->xl_status |= XL_TXSTAT_DL_INTR;
+
+ /* Start transmission */
+ sc->xl_cdata.xl_tx_prod = idx;
+ start_tx->xl_prev->xl_ptr->xl_next = start_tx->xl_phys;
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+
+ return;
+}
+
static void xl_init(xsc)
void *xsc;
{
@@ -2197,7 +2389,6 @@ static void xl_init(xsc)
/* Clear the station mask. */
for (i = 0; i < 3; i++)
CSR_WRITE_2(sc, XL_W2_STATION_MASK_LO + (i * 2), 0);
-
#ifdef notdef
/* Reset TX and RX. */
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
@@ -2205,7 +2396,6 @@ static void xl_init(xsc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
xl_wait(sc);
#endif
-
/* Init circular RX list. */
if (xl_list_rx_init(sc) == ENOBUFS) {
printf("xl%d: initialization failed: no "
@@ -2215,7 +2405,10 @@ static void xl_init(xsc)
}
/* Init TX descriptors. */
- xl_list_tx_init(sc);
+ if (sc->xl_type == XL_TYPE_905B)
+ xl_list_tx_init_90xB(sc);
+ else
+ xl_list_tx_init(sc);
/*
* Set the TX freethresh value.
@@ -2240,7 +2433,7 @@ static void xl_init(xsc)
*/
if (sc->xl_type == XL_TYPE_905B) {
CSR_WRITE_2(sc, XL_COMMAND,
- XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
+ XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4));
}
/* Set RX filter bits. */
@@ -2292,6 +2485,20 @@ static void xl_init(xsc)
xl_wait(sc);
CSR_WRITE_4(sc, XL_UPLIST_PTR, vtophys(&sc->xl_ldata->xl_rx_list[0]));
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
+ xl_wait(sc);
+
+
+ if (sc->xl_type == XL_TYPE_905B) {
+ /* Set polling interval */
+ CSR_WRITE_1(sc, XL_DOWN_POLL, 64);
+ /* Load the address of the TX list */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_DOWNLIST_PTR,
+ vtophys(&sc->xl_ldata->xl_tx_list[0]));
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);
+ xl_wait(sc);
+ }
/*
* If the coax transceiver is on, make sure to enable
@@ -2324,12 +2531,21 @@ static void xl_init(xsc)
CSR_WRITE_2(sc, XL_DMACTL, XL_DMACTL_UP_RX_EARLY);
/* Enable receiver and transmitter. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);
+ xl_wait(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE);
+ xl_wait(sc);
if (mii != NULL)
mii_mediachg(mii);
+ XL_SEL_WIN(7);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_STALL);
+ xl_wait(sc);
+ CSR_WRITE_4(sc, XL_UPLIST_PTR, vtophys(&sc->xl_ldata->xl_rx_list[0]));
+ CSR_WRITE_1(sc, XL_UP_POLL, 8);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_UP_UNSTALL);
+ xl_wait(sc);
/* Select window 7 for normal operations. */
XL_SEL_WIN(7);
@@ -2530,7 +2746,7 @@ static void xl_watchdog(ifp)
xl_init(sc);
if (ifp->if_snd.ifq_head != NULL)
- xl_start(ifp);
+ (*ifp->if_start)(ifp);
return;
}
@@ -2556,13 +2772,17 @@ static void xl_stop(sc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_DISABLE);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP);
DELAY(800);
-#ifdef notdef
+
+#ifdef foo
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET);
xl_wait(sc);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET);
xl_wait(sc);
#endif
+
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|XL_STAT_INTLATCH);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|0);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
/* Stop the stats updater. */
untimeout(xl_stats_update, sc, sc->xl_stat_ch);
@@ -2606,6 +2826,7 @@ static void xl_shutdown(dev)
sc = device_get_softc(dev);
+ xl_reset(sc);
xl_stop(sc);
return;
OpenPOWER on IntegriCloud