Spruce up the Sundance ST201 driver:

- Convert to using TX descritor polling similar to the xl driver (the
  ST201 is a clone of the 3c90xB chipset and offers the same transmit
  polling scheme). This should reduce TX overhad a little.

- Make sure to reset PHY when switching mode, as in the starfire driver.

- Fix instances of free() that should be contigfree().

- Remove dead code.
This commit is contained in:
Bill Paul 1999-12-07 20:14:42 +00:00
parent 87db5eaa0d
commit a2c195896a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=54268
2 changed files with 126 additions and 139 deletions

View File

@ -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);

View File

@ -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;