summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/pci/if_xl.c363
-rw-r--r--sys/pci/if_xlreg.h19
2 files changed, 309 insertions, 73 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;
diff --git a/sys/pci/if_xlreg.h b/sys/pci/if_xlreg.h
index 9497e39..c504ccc 100644
--- a/sys/pci/if_xlreg.h
+++ b/sys/pci/if_xlreg.h
@@ -92,9 +92,11 @@
#define XL_TX_FREE 0x1C
#define XL_DMACTL 0x20
#define XL_DOWNLIST_PTR 0x24
+#define XL_DOWN_POLL 0x2D /* 3c90xB only */
#define XL_TX_FREETHRESH 0x2F
#define XL_UPLIST_PTR 0x38
#define XL_UPLIST_STATUS 0x30
+#define XL_UP_POLL 0x3D /* 3c90xB only */
#define XL_PKTSTAT_UP_STALLED 0x00002000
#define XL_PKTSTAT_UP_ERROR 0x00004000
@@ -440,6 +442,8 @@ struct xl_list_onefrag {
#define XL_RX_LIST_CNT 128
#define XL_TX_LIST_CNT 256
#define XL_MIN_FRAMELEN 60
+#define ETHER_ALIGN 2
+#define XL_INC(x, y) (x) = (x + 1) % y
struct xl_list_data {
struct xl_list_onefrag xl_rx_list[XL_RX_LIST_CNT];
@@ -451,6 +455,8 @@ struct xl_chain {
struct xl_list *xl_ptr;
struct mbuf *xl_mbuf;
struct xl_chain *xl_next;
+ struct xl_chain *xl_prev;
+ u_int32_t xl_phys;
};
struct xl_chain_onefrag {
@@ -465,9 +471,15 @@ struct xl_chain_data {
struct xl_chain_onefrag *xl_rx_head;
+ /* 3c90x "boomerang" queuing stuff */
struct xl_chain *xl_tx_head;
struct xl_chain *xl_tx_tail;
struct xl_chain *xl_tx_free;
+
+ /* 3c90xB "cyclone/hurricane/tornado" stuff */
+ int xl_tx_prod;
+ int xl_tx_cons;
+ int xl_tx_cnt;
};
#define XL_RXSTAT_LENMASK 0x00001FFF
@@ -495,11 +507,12 @@ struct xl_chain_data {
#define XL_TXSTAT_IPCKSUM 0x02000000 /* 3c905B only */
#define XL_TXSTAT_TCPCKSUM 0x04000000 /* 3c905B only */
#define XL_TXSTAT_UDPCKSUM 0x08000000 /* 3c905B only */
+#define XL_TXSTAT_RND_DEFEAT 0x10000000 /* 3c905B only */
+#define XL_TXSTAT_EMPTY 0x20000000 /* 3c905B only */
#define XL_TXSTAT_DL_INTR 0x80000000
#define XL_CAPABILITY_BM 0x20
-
struct xl_type {
u_int16_t xl_vid;
u_int16_t xl_did;
@@ -528,6 +541,9 @@ struct xl_mii_frame {
* take advantage of, namely the multicast hash filter. With older
* chips, you only have the option of turning on reception of all
* multicast frames, which is kind of lame.
+ *
+ * We also use this to decide on a transmit strategy. For the 3c90xB
+ * cards, we can use polled descriptor mode, which reduces CPU overhead.
*/
#define XL_TYPE_905B 1
#define XL_TYPE_90X 2
@@ -549,7 +565,6 @@ struct xl_softc {
u_int16_t xl_caps;
u_int8_t xl_stats_no_timeout;
u_int16_t xl_tx_thresh;
- caddr_t xl_ldata_ptr;
struct xl_list_data *xl_ldata;
struct xl_chain_data xl_cdata;
struct callout_handle xl_stat_ch;
OpenPOWER on IntegriCloud