diff --git a/sys/pci/if_ste.c b/sys/pci/if_ste.c index 6be1d8389367..eb56c7b1f05a 100644 --- a/sys/pci/if_ste.c +++ b/sys/pci/if_ste.c @@ -441,6 +441,13 @@ static int ste_ifmedia_upd(ifp) sc = ifp->if_softc; mii = device_get_softc(sc->ste_miibus); + sc->ste_link = 0; + if (mii->mii_instance) { + struct mii_softc *miisc; + for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; + miisc = LIST_NEXT(miisc, mii_list)) + mii_phy_reset(miisc); + } mii_mediachg(mii); return(0); @@ -800,11 +807,10 @@ static void ste_txeoc(sc) ifp->if_oerrors++; printf("ste%d: transmission error: %x\n", sc->ste_unit, txstat); - STE_SETBIT4(sc, STE_ASICCTL, STE_ASICCTL_TX_RESET); - if (sc->ste_cdata.ste_tx_head != NULL) - CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, - vtophys(sc->ste_cdata.ste_tx_head->ste_ptr)); + ste_reset(sc); + ste_init(sc); + if (txstat & STE_TXSTATUS_UNDERRUN && sc->ste_tx_thresh < STE_PACKET_SIZE) { sc->ste_tx_thresh += STE_MIN_FRAMELEN; @@ -826,39 +832,35 @@ static void ste_txeoc(sc) static void ste_txeof(sc) struct ste_softc *sc; { - struct ste_chain *cur_tx; + struct ste_chain *cur_tx = NULL; struct ifnet *ifp; + int idx; ifp = &sc->arpcom.ac_if; - /* Clear the timeout timer. */ - ifp->if_timer = 0; + idx = sc->ste_cdata.ste_tx_cons; + while(idx != sc->ste_cdata.ste_tx_prod) { + cur_tx = &sc->ste_cdata.ste_tx_chain[idx]; - while(sc->ste_cdata.ste_tx_head != NULL) { - cur_tx = sc->ste_cdata.ste_tx_head; if (!(cur_tx->ste_ptr->ste_ctl & STE_TXCTL_DMADONE)) break; - sc->ste_cdata.ste_tx_head = cur_tx->ste_next; - m_freem(cur_tx->ste_mbuf); - cur_tx->ste_mbuf = NULL; + if (cur_tx->ste_mbuf != NULL) { + m_freem(cur_tx->ste_mbuf); + cur_tx->ste_mbuf = NULL; + } + ifp->if_opackets++; - cur_tx->ste_next = sc->ste_cdata.ste_tx_free; - sc->ste_cdata.ste_tx_free = cur_tx; + sc->ste_cdata.ste_tx_cnt--; + STE_INC(idx, STE_TX_LIST_CNT); + ifp->if_timer = 0; } - if (sc->ste_cdata.ste_tx_head == NULL) { + sc->ste_cdata.ste_tx_cons = idx; + + if (cur_tx != NULL) ifp->if_flags &= ~IFF_OACTIVE; - sc->ste_cdata.ste_tx_tail = NULL; - } else { - if (CSR_READ_4(sc, STE_DMACTL) & STE_DMACTL_TXDMA_STOPPED || - !CSR_READ_4(sc, STE_TX_DMALIST_PTR)) { - CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, - vtophys(sc->ste_cdata.ste_tx_head->ste_ptr)); - CSR_WRITE_4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL); - } - } return; } @@ -890,6 +892,14 @@ static void ste_stats_update(xsc) stats.ste_multi_colls + stats.ste_late_colls; mii_tick(mii); + if (!sc->ste_link) { + mii_pollstat(mii); + if (mii->mii_media_status & IFM_ACTIVE && + IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) + sc->ste_link++; + if (ifp->if_snd.ifq_head != NULL) + ste_start(ifp); + } sc->ste_stat_ch = timeout(ste_stats_update, sc, hz); splx(s); @@ -1072,7 +1082,8 @@ static int ste_attach(dev) bus_teardown_intr(dev, sc->ste_irq, sc->ste_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq); bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res); - free(sc->ste_ldata, M_DEVBUF); + contigfree(sc->ste_ldata, + sizeof(struct ste_list_data), M_DEVBUF); error = ENXIO; goto fail; } @@ -1127,7 +1138,7 @@ static int ste_detach(dev) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq); bus_release_resource(dev, STE_RES, STE_RID, sc->ste_res); - free(sc->ste_ldata, M_DEVBUF); + contigfree(sc->ste_ldata, sizeof(struct ste_list_data), M_DEVBUF); splx(s); @@ -1216,15 +1227,28 @@ static void ste_init_tx_list(sc) ld = sc->ste_ldata; for (i = 0; i < STE_TX_LIST_CNT; i++) { cd->ste_tx_chain[i].ste_ptr = &ld->ste_tx_list[i]; + cd->ste_tx_chain[i].ste_phys = vtophys(&ld->ste_tx_list[i]); if (i == (STE_TX_LIST_CNT - 1)) - cd->ste_tx_chain[i].ste_next = NULL; + cd->ste_tx_chain[i].ste_next = + &cd->ste_tx_chain[0]; else cd->ste_tx_chain[i].ste_next = &cd->ste_tx_chain[i + 1]; + if (i == 0) + cd->ste_tx_chain[i].ste_prev = + &cd->ste_tx_chain[STE_TX_LIST_CNT - 1]; + else + cd->ste_tx_chain[i].ste_prev = + &cd->ste_tx_chain[i - 1]; } - cd->ste_tx_free = &cd->ste_tx_chain[0]; - cd->ste_tx_tail = cd->ste_tx_head = NULL; + + bzero((char *)ld->ste_tx_list, + sizeof(struct ste_desc) * STE_TX_LIST_CNT); + + cd->ste_tx_prod = 0; + cd->ste_tx_cons = 0; + cd->ste_tx_cnt = 0; return; } @@ -1266,7 +1290,6 @@ static void ste_init(xsc) CSR_WRITE_1(sc, STE_TX_DMABURST_THRESH, STE_PACKET_SIZE >> 8); /* Set the TX start threshold for best performance. */ - sc->ste_tx_thresh = STE_MIN_FRAMELEN; CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh); /* Set the TX reclaim threshold. */ @@ -1299,6 +1322,18 @@ static void ste_init(xsc) STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL); STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL); + /* Set TX polling interval */ + CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 64); + + /* Load address of the TX list */ + STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL); + ste_wait(sc); + CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, + vtophys(&sc->ste_ldata->ste_tx_list[0])); + STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL); + STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL); + ste_wait(sc); + /* Enable receiver and transmitter */ CSR_WRITE_2(sc, STE_MACCTL0, 0); STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_ENABLE); @@ -1311,7 +1346,7 @@ static void ste_init(xsc) CSR_WRITE_2(sc, STE_ISR, 0xFFFF); CSR_WRITE_2(sc, STE_IMR, STE_INTRS); - mii_mediachg(mii); + ste_ifmedia_upd(ifp); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; @@ -1341,6 +1376,8 @@ static void ste_stop(sc) STE_SETBIT2(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL); ste_wait(sc); + sc->ste_link = 0; + for (i = 0; i < STE_RX_LIST_CNT; i++) { if (sc->ste_cdata.ste_rx_chain[i].ste_mbuf != NULL) { m_freem(sc->ste_cdata.ste_rx_chain[i].ste_mbuf); @@ -1382,30 +1419,6 @@ static void ste_reset(sc) if (i == STE_TIMEOUT) printf("ste%d: global reset never completed\n", sc->ste_unit); -#ifdef foo - STE_SETBIT4(sc, STE_ASICCTL, STE_ASICCTL_RX_RESET); - for (i = 0; i < STE_TIMEOUT; i++) { - if (!(CSR_READ_4(sc, STE_ASICCTL) & STE_ASICCTL_RX_RESET)) - break; - } - - if (i == STE_TIMEOUT) - printf("ste%d: RX reset never completed\n", sc->ste_unit); - - DELAY(100000); - - STE_SETBIT4(sc, STE_ASICCTL, STE_ASICCTL_TX_RESET); - for (i = 0; i < STE_TIMEOUT; i++) { - if (!(CSR_READ_4(sc, STE_ASICCTL) & STE_ASICCTL_TX_RESET)) - break; - } - - if (i == STE_TIMEOUT) - printf("ste%d: TX reset never completed\n", sc->ste_unit); - - DELAY(100000); -#endif - return; } @@ -1432,11 +1445,25 @@ static int ste_ioctl(ifp, command, data) break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { - ste_init(sc); + if (ifp->if_flags & IFF_RUNNING && + ifp->if_flags & IFF_PROMISC && + !(sc->ste_if_flags & IFF_PROMISC)) { + STE_SETBIT1(sc, STE_RX_MODE, + STE_RXMODE_PROMISC); + } else if (ifp->if_flags & IFF_RUNNING && + !(ifp->if_flags & IFF_PROMISC) && + sc->ste_if_flags & IFF_PROMISC) { + STE_CLRBIT1(sc, STE_RX_MODE, + STE_RXMODE_PROMISC); + } else if (!(ifp->if_flags & IFF_RUNNING)) { + sc->ste_tx_thresh = STE_MIN_FRAMELEN; + ste_init(sc); + } } else { if (ifp->if_flags & IFF_RUNNING) ste_stop(sc); } + sc->ste_if_flags = ifp->if_flags; error = 0; break; case SIOCADDMULTI: @@ -1466,11 +1493,13 @@ static int ste_encap(sc, c, m_head) { int frag = 0; struct ste_frag *f = NULL; - int total_len; struct mbuf *m; + struct ste_desc *d; + int total_len = 0; - m = m_head; - total_len = 0; + d = c->ste_ptr; + d->ste_ctl = 0; + d->ste_next = 0; for (m = m_head, frag = 0; m != NULL; m = m->m_next) { if (m->m_len != 0) { @@ -1484,39 +1513,9 @@ static int ste_encap(sc, c, m_head) } } - if (m != NULL) { - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("ste%d: no memory for " - "tx list", sc->ste_unit); - return(1); - } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - printf("ste%d: no memory for " - "tx list", sc->ste_unit); - return(1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - f = &c->ste_ptr->ste_frags[0]; - f->ste_addr = vtophys(mtod(m_new, caddr_t)); - f->ste_len = total_len = m_new->m_len; - frag = 1; - } - c->ste_mbuf = m_head; c->ste_ptr->ste_frags[frag - 1].ste_len |= STE_FRAG_LAST; c->ste_ptr->ste_ctl = total_len; - c->ste_ptr->ste_next = 0; return(0); } @@ -1527,40 +1526,47 @@ static void ste_start(ifp) struct ste_softc *sc; struct mbuf *m_head = NULL; struct ste_chain *prev = NULL, *cur_tx = NULL, *start_tx; + int idx; sc = ifp->if_softc; - if (sc->ste_cdata.ste_tx_free == NULL) { - ifp->if_flags |= IFF_OACTIVE; + if (!sc->ste_link) return; - } - start_tx = sc->ste_cdata.ste_tx_free; + if (ifp->if_flags & IFF_OACTIVE) + return; + + idx = sc->ste_cdata.ste_tx_prod; + start_tx = &sc->ste_cdata.ste_tx_chain[idx]; + + while(sc->ste_cdata.ste_tx_chain[idx].ste_mbuf == NULL) { + + if ((STE_TX_LIST_CNT - sc->ste_cdata.ste_tx_cnt) < 3) { + ifp->if_flags |= IFF_OACTIVE; + break; + } - while(sc->ste_cdata.ste_tx_free != NULL) { IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; - cur_tx = sc->ste_cdata.ste_tx_free; - sc->ste_cdata.ste_tx_free = cur_tx->ste_next; - - cur_tx->ste_next = NULL; + cur_tx = &sc->ste_cdata.ste_tx_chain[idx]; ste_encap(sc, cur_tx, m_head); - if (prev != NULL) { - prev->ste_next = cur_tx; - prev->ste_ptr->ste_next = vtophys(cur_tx->ste_ptr); - } + if (prev != NULL) + prev->ste_ptr->ste_next = cur_tx->ste_phys; prev = cur_tx; /* - * If there's a BPF listener, bounce a copt of this frame + * If there's a BPF listener, bounce a copy of this frame * to him. */ if (ifp->if_bpf) bpf_mtap(ifp, cur_tx->ste_mbuf); + + STE_INC(idx, STE_TX_LIST_CNT); + sc->ste_cdata.ste_tx_cnt++; } if (cur_tx == NULL) @@ -1568,25 +1574,9 @@ static void ste_start(ifp) cur_tx->ste_ptr->ste_ctl |= STE_TXCTL_DMAINTR; - STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL); - ste_wait(sc); - - if (sc->ste_cdata.ste_tx_head != NULL) { - sc->ste_cdata.ste_tx_tail->ste_next = start_tx; - sc->ste_cdata.ste_tx_tail->ste_ptr->ste_next = - vtophys(start_tx->ste_ptr); - sc->ste_cdata.ste_tx_tail->ste_ptr->ste_ctl &= - ~STE_TXCTL_DMAINTR; - sc->ste_cdata.ste_tx_tail = cur_tx; - } else { - sc->ste_cdata.ste_tx_head = start_tx; - sc->ste_cdata.ste_tx_tail = cur_tx; - } - - if (!CSR_READ_4(sc, STE_TX_DMALIST_PTR)) - CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, - vtophys(start_tx->ste_ptr)); - STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL); + /* Start transmission */ + sc->ste_cdata.ste_tx_prod = idx; + start_tx->ste_prev->ste_ptr->ste_next = start_tx->ste_phys; ifp->if_timer = 5; @@ -1603,14 +1593,6 @@ static void ste_watchdog(ifp) ifp->if_oerrors++; printf("ste%d: watchdog timeout\n", sc->ste_unit); -#ifdef foo - if (sc->ste_pinfo != NULL) { - if (!(ste_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) - printf("ste%d: no carrier - transceiver " - "cable problem?\n", sc->ste_unit); - } -#endif - ste_txeoc(sc); ste_txeof(sc); ste_rxeof(sc); diff --git a/sys/pci/if_stereg.h b/sys/pci/if_stereg.h index 8f7d035e73d7..7a0b4876df7f 100644 --- a/sys/pci/if_stereg.h +++ b/sys/pci/if_stereg.h @@ -454,12 +454,13 @@ struct ste_desc_onefrag { #define CSR_READ_1(sc, reg) \ bus_space_read_1(sc->ste_btag, sc->ste_bhandle, reg) -#define STE_TIMEOUT 1000 -#define STE_MIN_FRAMELEN 60 -#define STE_PACKET_SIZE 1536 -#define ETHER_ALIGN 2 -#define STE_RX_LIST_CNT 128 -#define STE_TX_LIST_CNT 256 +#define STE_TIMEOUT 1000 +#define STE_MIN_FRAMELEN 60 +#define STE_PACKET_SIZE 1536 +#define ETHER_ALIGN 2 +#define STE_RX_LIST_CNT 128 +#define STE_TX_LIST_CNT 256 +#define STE_INC(x, y) (x) = (x + 1) % y struct ste_type { u_int16_t ste_vid; @@ -477,6 +478,8 @@ struct ste_chain { struct ste_desc *ste_ptr; struct mbuf *ste_mbuf; struct ste_chain *ste_next; + struct ste_chain *ste_prev; + u_int32_t ste_phys; }; struct ste_chain_onefrag { @@ -490,9 +493,9 @@ struct ste_chain_data { struct ste_chain ste_tx_chain[STE_TX_LIST_CNT]; struct ste_chain_onefrag *ste_rx_head; - struct ste_chain *ste_tx_head; - struct ste_chain *ste_tx_tail; - struct ste_chain *ste_tx_free; + int ste_tx_prod; + int ste_tx_cons; + int ste_tx_cnt; }; struct ste_softc { @@ -506,6 +509,8 @@ struct ste_softc { device_t ste_miibus; int ste_unit; int ste_tx_thresh; + u_int8_t ste_link; + int ste_if_flags; struct ste_list_data *ste_ldata; struct ste_chain_data ste_cdata; struct callout_handle ste_stat_ch;