diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2006-01-05 05:36:07 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2006-01-05 05:36:07 +0000 |
commit | 275e5a4c78f35d4b0aa9cfd4d9e5346e8fc0c513 (patch) | |
tree | 527d6cd0c62bd6832bfbcc175c85430b51f5c3de /sys/dev | |
parent | 5b2a424ce2d437402a1b7084e2b02add0c5a4f5e (diff) |
part of rev 1.58 of rtw.c David Young comitted to NetBSD:
Miscellaneous Realtek RTL8180L driver improvements:
3 Revamp handling of transmit descriptor rings.
4 Reliably IFF_OACTIVE when transmit descriptors are available, to
stop the transmit section of the driver from freezing up.
5 Fix beacon transmission in adhoc and hostap modes. XXX There is
a wart in hostap mode, where beacons are transmitted at 1/2 the
correct rate. Load beacon descriptors when the RTW_INTR_BINT
interrupt arrives; schedule RTW_INTR_BINT 1ms ahead of the target
beacon time.
6 Recover more gracefully from tx/rx errors: avoid
transmitter/receiver/chip resets. Try to re-synchronize software
state with hardware state---e.g., load next descriptor pointer
from hardware.
7 Activate the transmit watchdog timer for beacons as well as other
packets.
8 Introduce rtw_idle() that waits for transmit DMA to finish; call
it before resetting the transmitter.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/rtw.c | 416 | ||||
-rw-r--r-- | sys/dev/ic/rtwreg.h | 6 | ||||
-rw-r--r-- | sys/dev/ic/rtwvar.h | 58 |
3 files changed, 331 insertions, 149 deletions
diff --git a/sys/dev/ic/rtw.c b/sys/dev/ic/rtw.c index 8ac6208f753..90736291103 100644 --- a/sys/dev/ic/rtw.c +++ b/sys/dev/ic/rtw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtw.c,v 1.50 2005/11/20 09:49:05 jsg Exp $ */ +/* $OpenBSD: rtw.c,v 1.51 2006/01/05 05:36:05 jsg Exp $ */ /* $NetBSD: rtw.c,v 1.29 2004/12/27 19:49:16 dyoung Exp $ */ /*- @@ -79,6 +79,8 @@ int rtw_rfprog_fallback = 0; int rtw_host_rfio = 0; +int rtw_xmtr_restart = 0; +int rtw_do_chip_reset = 0; int rtw_dwelltime = 200; /* milliseconds per channel */ int rtw_macbangbits_timeout = 100; @@ -90,9 +92,13 @@ int rtw_rxbufs_limit = RTW_RXQLEN; void rtw_start(struct ifnet *); void rtw_txdesc_blk_init_all(struct rtw_txdesc_blk *); void rtw_txsoft_blk_init_all(struct rtw_txsoft_blk *); +void rtw_txdesc_blk_init(struct rtw_txdesc_blk *); void rtw_txdescs_sync(struct rtw_txdesc_blk *, u_int, u_int, int); +u_int rtw_txring_next(struct rtw_regs *, struct rtw_txdesc_blk *); +void rtw_txring_fixup(struct rtw_softc *); void rtw_rxbufs_release(bus_dma_tag_t, struct rtw_rxsoft *); void rtw_rxdesc_init(struct rtw_rxdesc_blk *, struct rtw_rxsoft *, int, int); +void rtw_rxring_fixup(struct rtw_softc *); void rtw_io_enable(struct rtw_regs *, u_int8_t, int); void rtw_intr_rx(struct rtw_softc *, u_int16_t); void rtw_intr_beacon(struct rtw_softc *, u_int16_t); @@ -157,20 +163,21 @@ int rtw_chip_reset1(struct rtw_regs *, const char *); int rtw_chip_reset(struct rtw_regs *, const char *); int rtw_recall_eeprom(struct rtw_regs *, const char *); int rtw_reset(struct rtw_softc *); +void rtw_reset_oactive(struct rtw_softc *); int rtw_txdesc_dmamaps_create(bus_dma_tag_t, struct rtw_txsoft *, u_int); int rtw_rxdesc_dmamaps_create(bus_dma_tag_t, struct rtw_rxsoft *, u_int); void rtw_rxdesc_dmamaps_destroy(bus_dma_tag_t, struct rtw_rxsoft *, u_int); void rtw_txdesc_dmamaps_destroy(bus_dma_tag_t, struct rtw_txsoft *, u_int); void rtw_init_channels(enum rtw_locale, struct ieee80211_channel (*)[], const char*); -void rtw_identify_country(struct rtw_regs *, enum rtw_locale *, const char *); +void rtw_identify_country(struct rtw_regs *, enum rtw_locale *); int rtw_identify_sta(struct rtw_regs *, u_int8_t (*)[], const char *); void rtw_rxdescs_sync(struct rtw_rxdesc_blk *, int, int, int); int rtw_rxsoft_alloc(bus_dma_tag_t, struct rtw_rxsoft *); void rtw_collect_txpkt(struct rtw_softc *, struct rtw_txdesc_blk *, struct rtw_txsoft *, int); void rtw_collect_txring(struct rtw_softc *, struct rtw_txsoft_blk *, - struct rtw_txdesc_blk *); + struct rtw_txdesc_blk *, int); void rtw_suspend_ticks(struct rtw_softc *); void rtw_resume_ticks(struct rtw_softc *); void rtw_enable_interrupts(struct rtw_softc *); @@ -184,12 +191,14 @@ void rtw_rxdesc_init_all(struct rtw_rxdesc_blk *, struct rtw_rxsoft *, int); int rtw_txring_choose(struct rtw_softc *, struct rtw_txsoft_blk **, struct rtw_txdesc_blk **, int); +u_int rtw_txring_next(struct rtw_regs *, struct rtw_txdesc_blk *); struct mbuf *rtw_80211_dequeue(struct rtw_softc *, struct ifqueue *, int, struct rtw_txsoft_blk **, struct rtw_txdesc_blk **, struct ieee80211_node **, short *); uint64_t rtw_tsf_extend(struct rtw_regs *, u_int32_t); void rtw_ibss_merge(struct rtw_softc *, struct ieee80211_node *, u_int32_t); +void rtw_idle(struct rtw_regs *); void rtw_led_attach(struct rtw_led_state *, void *); void rtw_led_init(struct rtw_regs *); void rtw_led_slowblink(void *); @@ -796,8 +805,7 @@ rtw_init_channels(enum rtw_locale locale, } void -rtw_identify_country(struct rtw_regs *regs, enum rtw_locale *locale, - const char *dvname) +rtw_identify_country(struct rtw_regs *regs, enum rtw_locale *locale) { u_int8_t cfg0 = RTW_READ8(regs, RTW_CONFIG0); @@ -862,11 +870,32 @@ void rtw_txdesc_blk_init_all(struct rtw_txdesc_blk *tdb) { int pri; - u_int ndesc[RTW_NTXPRI] = - {RTW_NTXDESCLO, RTW_NTXDESCMD, RTW_NTXDESCHI, RTW_NTXDESCBCN}; + /* nfree: the number of free descriptors in each ring. + * The beacon ring is a special case: I do not let the + * driver use all of the descriptors on the beacon ring. + * The reasons are two-fold: + * + * (1) A BEACON descriptor's OWN bit is (apparently) not + * updated, so the driver cannot easily know if the descriptor + * belongs to it, or if it is racing the NIC. If the NIC + * does not OWN every descriptor, then the driver can safely + * update the descriptors when RTW_TBDA points at tdb_next. + * + * (2) I hope that the NIC will process more than one BEACON + * descriptor in a single beacon interval, since that will + * enable multiple-BSS support. Since the NIC does not + * clear the OWN bit, there is no natural place for it to + * stop processing BEACON desciptors. Maybe it will *not* + * stop processing them! I do not want to chance the NIC + * looping around and around a saturated beacon ring, so + * I will leave one descriptor unOWNed at all times. + */ + u_int nfree[RTW_NTXPRI] = + {RTW_NTXDESCLO, RTW_NTXDESCMD, RTW_NTXDESCHI, + RTW_NTXDESCBCN - 1}; for (pri = 0; pri < RTW_NTXPRI; pri++) { - tdb[pri].tdb_nfree = ndesc[pri]; + tdb[pri].tdb_nfree = nfree[pri]; tdb[pri].tdb_next = 0; } } @@ -884,6 +913,7 @@ rtw_txsoft_blk_init(struct rtw_txsoft_blk *tsb) ts->ts_mbuf = NULL; SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q); } + tsb->tsb_tx_timer = 0; return 0; } @@ -1066,7 +1096,6 @@ rtw_rxdesc_init_all(struct rtw_rxdesc_blk *rdb, struct rtw_rxsoft *ctl, rs = &ctl[i]; rtw_rxdesc_init(rdb, rs, i, kick); } - rdb->rdb_next = 0; } void @@ -1354,6 +1383,7 @@ rtw_txsofts_release(bus_dma_tag_t dmat, struct ieee80211com *ic, SIMPLEQ_REMOVE_HEAD(&tsb->tsb_dirtyq, ts_q); SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q); } + tsb->tsb_tx_timer = 0; } void @@ -1390,10 +1420,30 @@ rtw_collect_txpkt(struct rtw_softc *sc, struct rtw_txdesc_blk *tdb, condstring, rts_retry, data_retry)); } +void +rtw_reset_oactive(struct rtw_softc *sc) +{ + short oflags; + int pri; + struct rtw_txsoft_blk *tsb; + struct rtw_txdesc_blk *tdb; + oflags = sc->sc_if.if_flags; + for (pri = 0; pri < RTW_NTXPRI; pri++) { + tsb = &sc->sc_txsoft_blk[pri]; + tdb = &sc->sc_txdesc_blk[pri]; + if (!SIMPLEQ_EMPTY(&tsb->tsb_freeq) && tdb->tdb_nfree > 0) + sc->sc_if.if_flags &= ~IFF_OACTIVE; + } + if (oflags != sc->sc_if.if_flags) { + DPRINTF(sc, RTW_DEBUG_OACTIVE, + ("%s: reset OACTIVE\n", __func__)); + } +} + /* Collect transmitted packets. */ void rtw_collect_txring(struct rtw_softc *sc, struct rtw_txsoft_blk *tsb, - struct rtw_txdesc_blk *tdb) + struct rtw_txdesc_blk *tdb, int force) { int ndesc; struct rtw_txsoft *ts; @@ -1408,22 +1458,28 @@ rtw_collect_txring(struct rtw_softc *sc, struct rtw_txsoft_blk *tsb, rtw_txdescs_sync(tdb, ts->ts_first, ndesc, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - if ((tdb->tdb_desc[ts->ts_last].td_stat & + if (force) { + int i; + for (i = ts->ts_first; ; i = RTW_NEXT_IDX(tdb, i)) { + tdb->tdb_desc[i].td_stat &= + ~htole32(RTW_TXSTAT_OWN); + if (i == ts->ts_last) + break; + } + rtw_txdescs_sync(tdb, ts->ts_first, ndesc, + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + } else if ((tdb->tdb_desc[ts->ts_last].td_stat & htole32(RTW_TXSTAT_OWN)) != 0) break; - if (&sc->sc_txdesc_blk[RTW_TXPRIBCN] == tdb) { - RTW_DPRINTF(RTW_DEBUG_BEACON, - ("%s: collected beacon\n", __func__)); - } - rtw_collect_txpkt(sc, tdb, ts, ndesc); SIMPLEQ_REMOVE_HEAD(&tsb->tsb_dirtyq, ts_q); SIMPLEQ_INSERT_TAIL(&tsb->tsb_freeq, ts, ts_q); - sc->sc_if.if_flags &= ~IFF_OACTIVE; } + /* no more pending transmissions, cancel watchdog */ if (ts == NULL) tsb->tsb_tx_timer = 0; + rtw_reset_oactive(sc); } void @@ -1437,21 +1493,63 @@ rtw_intr_tx(struct rtw_softc *sc, u_int16_t isr) tsb = &sc->sc_txsoft_blk[pri]; tdb = &sc->sc_txdesc_blk[pri]; - rtw_collect_txring(sc, tsb, tdb); + rtw_collect_txring(sc, tsb, tdb, 0); - if ((isr & RTW_INTR_TX) != 0) - rtw_start(&sc->sc_if); } - /* TBD */ - return; + if ((isr & RTW_INTR_TX) != 0) + rtw_start(&sc->sc_if); } void rtw_intr_beacon(struct rtw_softc *sc, u_int16_t isr) { - /* TBD */ - return; + u_int next; + uint32_t tsfth, tsftl; + struct ieee80211com *ic; + struct rtw_txdesc_blk *tdb = &sc->sc_txdesc_blk[RTW_TXPRIBCN]; + struct rtw_txsoft_blk *tsb = &sc->sc_txsoft_blk[RTW_TXPRIBCN]; + struct mbuf *m; + + tsfth = RTW_READ(&sc->sc_regs, RTW_TSFTRH); + tsftl = RTW_READ(&sc->sc_regs, RTW_TSFTRL); + + if ((isr & (RTW_INTR_TBDOK|RTW_INTR_TBDER)) != 0) { + next = rtw_txring_next(&sc->sc_regs, tdb); + RTW_DPRINTF(RTW_DEBUG_BEACON, + ("%s: beacon ring %sprocessed, isr = %#04hx" + ", next %u expected %u, %llu\n", __func__, + (next == tdb->tdb_next) ? "" : "un", isr, next, + tdb->tdb_next, (uint64_t)tsfth << 32 | tsftl)); + if ((RTW_READ8(&sc->sc_regs, RTW_TPPOLL) & RTW_TPPOLL_BQ) == 0){ + rtw_collect_txring(sc, tsb, tdb, 1); + tdb->tdb_next = 0; + } + } + /* Start beacon transmission. */ + + if ((isr & RTW_INTR_BCNINT) != 0 && + sc->sc_ic.ic_state == IEEE80211_S_RUN && + SIMPLEQ_EMPTY(&tsb->tsb_dirtyq)) { + RTW_DPRINTF(RTW_DEBUG_BEACON, + ("%s: beacon prep. time, isr = %#04hx" + ", %16llu\n", __func__, isr, + (uint64_t)tsfth << 32 | tsftl)); + ic = &sc->sc_ic; + if ((m = ieee80211_beacon_alloc(ic, ic->ic_bss)) != NULL) { + RTW_DPRINTF(RTW_DEBUG_BEACON, + ("%s: m %p len %u\n", __func__, m, m->m_len)); + } + + if (m == NULL) { + printf("%s: could not allocate beacon\n", + sc->sc_dev.dv_xname); + return; + } + m->m_pkthdr.rcvif = (void *)ieee80211_ref_node(ic->ic_bss); + IF_ENQUEUE(&sc->sc_beaconq, m); + rtw_start(&sc->sc_if); + } } void @@ -1497,30 +1595,34 @@ rtw_dump_rings(struct rtw_softc *sc) void rtw_hwring_setup(struct rtw_softc *sc) { + int pri; struct rtw_regs *regs = &sc->sc_regs; + struct rtw_txdesc_blk *tdb; + + sc->sc_txdesc_blk[RTW_TXPRILO].tdb_basereg = RTW_TLPDA; + sc->sc_txdesc_blk[RTW_TXPRILO].tdb_base = RTW_RING_BASE(sc, hd_txlo); + sc->sc_txdesc_blk[RTW_TXPRIMD].tdb_basereg = RTW_TNPDA; + sc->sc_txdesc_blk[RTW_TXPRIMD].tdb_base = RTW_RING_BASE(sc, hd_txmd); + sc->sc_txdesc_blk[RTW_TXPRIHI].tdb_basereg = RTW_THPDA; + sc->sc_txdesc_blk[RTW_TXPRIHI].tdb_base = RTW_RING_BASE(sc, hd_txhi); + sc->sc_txdesc_blk[RTW_TXPRIBCN].tdb_basereg = RTW_TBDA; + sc->sc_txdesc_blk[RTW_TXPRIBCN].tdb_base = RTW_RING_BASE(sc, hd_bcn); + + for (pri = 0; pri < RTW_NTXPRI; pri++) { + tdb = &sc->sc_txdesc_blk[pri]; + RTW_WRITE(regs, tdb->tdb_basereg, tdb->tdb_base); + RTW_DPRINTF(RTW_DEBUG_XMIT_DESC, + ("%s: reg[tdb->tdb_basereg] <- %lx\n", __func__, + (u_int *)tdb->tdb_base)); + } + RTW_WRITE(regs, RTW_RDSAR, RTW_RING_BASE(sc, hd_rx)); - RTW_WRITE(regs, RTW_TLPDA, RTW_RING_BASE(sc, hd_txlo)); - RTW_WRITE(regs, RTW_TNPDA, RTW_RING_BASE(sc, hd_txmd)); - RTW_WRITE(regs, RTW_THPDA, RTW_RING_BASE(sc, hd_txhi)); - RTW_WRITE(regs, RTW_TBDA, RTW_RING_BASE(sc, hd_bcn)); - RTW_SYNC(regs, RTW_TLPDA, RTW_RDSAR); -#if 0 - RTW_DPRINTF(RTW_DEBUG_XMIT_DESC, - ("%s: reg[TLPDA] <- %\n", __func__, - (u_int *)RTW_RING_BASE(sc, hd_txlo))); - RTW_DPRINTF(RTW_DEBUG_XMIT_DESC, - ("%s: reg[TNPDA] <- %\n", __func__, - (u_int *)RTW_RING_BASE(sc, hd_txmd))); - RTW_DPRINTF(RTW_DEBUG_XMIT_DESC, - ("%s: reg[THPDA] <- %\n", __func__, - (u_int *)RTW_RING_BASE(sc, hd_txhi))); - RTW_DPRINTF(RTW_DEBUG_XMIT_DESC, - ("%s: reg[TBDA] <- %\n", __func__, - (u_int *)RTW_RING_BASE(sc, hd_bcn))); + RTW_DPRINTF(RTW_DEBUG_RECV_DESC, - ("%s: reg[RDSAR] <- %\n", __func__, + ("%s: reg[RDSAR] <- %lx\n", __func__, (u_int *)RTW_RING_BASE(sc, hd_rx))); -#endif + + RTW_SYNC(regs, RTW_TLPDA, RTW_RDSAR); } int @@ -1547,6 +1649,7 @@ rtw_swring_setup(struct rtw_softc *sc) rtw_rxdescs_sync(rdb, 0, rdb->rdb_ndesc, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); rtw_rxdesc_init_all(rdb, sc->sc_rxsoft, 1); + rdb->rdb_next = 0; tdb = &sc->sc_txdesc_blk[0]; for (pri = 0; pri < RTW_NTXPRI; pri++) { @@ -1557,75 +1660,118 @@ rtw_swring_setup(struct rtw_softc *sc) } void -rtw_txdesc_blk_reset(struct rtw_txdesc_blk *tdb) +rtw_txdesc_blk_init(struct rtw_txdesc_blk *tdb) { int i; bzero(tdb->tdb_desc, sizeof(tdb->tdb_desc[0]) * tdb->tdb_ndesc); for (i = 0; i < tdb->tdb_ndesc; i++) tdb->tdb_desc[i].td_next = htole32(RTW_NEXT_DESC(tdb, i)); - tdb->tdb_nfree = tdb->tdb_ndesc; - tdb->tdb_next = 0; +} + +u_int +rtw_txring_next(struct rtw_regs *regs, struct rtw_txdesc_blk *tdb) +{ + return (letoh32(RTW_READ(regs, tdb->tdb_basereg)) - tdb->tdb_base) / + sizeof(struct rtw_txdesc); } void -rtw_txdescs_reset(struct rtw_softc *sc) +rtw_txring_fixup(struct rtw_softc *sc) { int pri; + u_int next; struct rtw_txdesc_blk *tdb; + struct rtw_regs *regs = &sc->sc_regs; for (pri = 0; pri < RTW_NTXPRI; pri++) { tdb = &sc->sc_txdesc_blk[pri]; - rtw_txsofts_release(sc->sc_dmat, &sc->sc_ic, - &sc->sc_txsoft_blk[pri]); - rtw_txdesc_blk_reset(tdb); - rtw_txdescs_sync(tdb, 0, tdb->tdb_ndesc, - BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); + next = rtw_txring_next(regs, tdb); + if (tdb->tdb_next == next) + continue; + RTW_DPRINTF(RTW_DEBUG_BUGS, + ("%s: tx-ring %d expected next %u, read %u\n", __func__, + pri, tdb->tdb_next, next)); + tdb->tdb_next = next; } } void -rtw_rxdescs_reset(struct rtw_softc *sc) +rtw_rxring_fixup(struct rtw_softc *sc) { - rtw_rxdesc_init_all(&sc->sc_rxdesc_blk, &sc->sc_rxsoft[0], 1); + u_int next; + uint32_t rdsar; + struct rtw_rxdesc_blk *rdb; + + rdsar = letoh32(RTW_READ(&sc->sc_regs, RTW_RDSAR)); + next = (rdsar - RTW_RING_BASE(sc, hd_rx)) / sizeof(struct rtw_rxdesc); + + rdb = &sc->sc_rxdesc_blk; + if (rdb->rdb_next != next) { + RTW_DPRINTF(RTW_DEBUG_BUGS, + ("%s: rx-ring expected next %u, read %u\n", __func__, + rdb->rdb_next, next)); + rdb->rdb_next = next; + } +} + +void +rtw_txdescs_reset(struct rtw_softc *sc) +{ + int pri; + + for (pri = 0; pri < RTW_NTXPRI; pri++) { + rtw_collect_txring(sc, &sc->sc_txsoft_blk[pri], + &sc->sc_txdesc_blk[pri], 1); + } } void rtw_intr_ioerror(struct rtw_softc *sc, u_int16_t isr) { + uint8_t cr = 0; + int xmtr = 0, rcvr = 0; struct rtw_regs *regs = &sc->sc_regs; -#ifdef RTW_DEBUG - if ((isr & RTW_INTR_TXFOVW) != 0) - printf("%s: tx fifo overflow\n", sc->sc_dev.dv_xname); -#endif + if ((isr & RTW_INTR_TXFOVW) != 0) { + RTW_DPRINTF(RTW_DEBUG_BUGS, + ("%s: tx fifo underflow\n", sc->sc_dev.dv_xname)); + xmtr = 1; + cr |= RTW_CR_TE; + } - if ((isr & (RTW_INTR_RDU|RTW_INTR_RXFOVW)) == 0) + if ((isr & (RTW_INTR_RDU|RTW_INTR_RXFOVW)) != 0) { + cr = RTW_CR_RE; + rcvr = 1; return; + } - RTW_DPRINTF(RTW_DEBUG_BUGS, ("%s: restarting xmit/recv, isr %" + RTW_DPRINTF(RTW_DEBUG_BUGS, ("%s: restarting xmit/recv, isr %hx" "\n", sc->sc_dev.dv_xname, isr)); #ifdef RTW_DEBUG rtw_dump_rings(sc); #endif /* RTW_DEBUG */ - rtw_io_enable(regs, RTW_CR_RE | RTW_CR_TE, 0); + rtw_io_enable(regs, cr, 0); - /* Collect rx'd packets. Refresh rx buffers. */ - rtw_intr_rx(sc, 0); - /* Collect tx'd packets. */ - rtw_intr_tx(sc, 0); + /* Collect rx'd packets. Refresh rx buffers. */ + if (rcvr) + rtw_intr_rx(sc, 0); + /* Collect tx'd packets. XXX let's hope this stops the transmit + * timeouts. + */ + if (xmtr) + rtw_txdescs_reset(sc); RTW_WRITE16(regs, RTW_IMR, 0); RTW_SYNC(regs, RTW_IMR, RTW_IMR); - rtw_chip_reset1(regs, sc->sc_dev.dv_xname); - - rtw_rxdescs_reset(sc); - rtw_txdescs_reset(sc); + if (rtw_do_chip_reset) { + rtw_chip_reset1(regs, sc->sc_dev.dv_xname); + } - rtw_hwring_setup(sc); + rtw_rxdesc_init_all(&sc->sc_rxdesc_blk, &sc->sc_rxsoft[0], 1); #ifdef RTW_DEBUG rtw_dump_rings(sc); @@ -1633,8 +1779,11 @@ rtw_intr_ioerror(struct rtw_softc *sc, u_int16_t isr) RTW_WRITE16(regs, RTW_IMR, sc->sc_inten); RTW_SYNC(regs, RTW_IMR, RTW_IMR); - rtw_io_enable(regs, RTW_CR_RE | RTW_CR_TE, 1); - sc->sc_if.if_flags &= ~IFF_OACTIVE; + if (rcvr) + rtw_rxring_fixup(sc); + rtw_io_enable(regs, cr, 1); + if (xmtr) + rtw_txring_fixup(sc); } void @@ -2568,6 +2717,8 @@ rtw_txring_choose(struct rtw_softc *sc, struct rtw_txsoft_blk **tsbp, tdb = &sc->sc_txdesc_blk[pri]; if (SIMPLEQ_EMPTY(&tsb->tsb_freeq) || tdb->tdb_nfree == 0) { + if (tsb->tsb_tx_timer == 0) + tsb->tsb_tx_timer = 5; *tsbp = NULL; *tdbp = NULL; return -1; @@ -2587,7 +2738,10 @@ rtw_80211_dequeue(struct rtw_softc *sc, struct ifqueue *ifq, int pri, if (IF_IS_EMPTY(ifq)) return NULL; if (rtw_txring_choose(sc, tsbp, tdbp, pri) == -1) { + DPRINTF(sc, RTW_DEBUG_XMIT_RSRC, ("%s: no ring %d descriptor\n", + __func__, pri)); *if_flagsp |= IFF_OACTIVE; + sc->sc_if.if_timer = 1; return NULL; } IF_DEQUEUE(ifq, m); @@ -2642,14 +2796,27 @@ rtw_dequeue(struct ifnet *ifp, struct rtw_txsoft_blk **tsbp, return 0; } + if (sc->sc_ic.ic_state != IEEE80211_S_RUN) { + DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: not running\n", __func__)); + return 0; + } + + *mp = NULL; + + IFQ_POLL(&ifp->if_snd, m0); + if (m0 == NULL) { + DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no frame ready\n", + __func__)); + return 0; + } + if (rtw_txring_choose(sc, tsbp, tdbp, RTW_TXPRIMD) == -1) { DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no descriptor\n", __func__)); *if_flagsp |= IFF_OACTIVE; + sc->sc_if.if_timer = 1; return 0; } - *mp = NULL; - IFQ_DEQUEUE(&ifp->if_snd, m0); if (m0 == NULL) { DPRINTF(sc, RTW_DEBUG_XMIT, ("%s: no frame/ring ready\n", @@ -2746,7 +2913,7 @@ rtw_dmamap_load_txbuf(bus_dma_tag_t dmat, bus_dmamap_t dmam, struct mbuf *chain, m_freem(m0); return NULL; } else if (dmam->dm_nsegs > ndescfree) { - *ifflagsp |= IFF_OACTIVE; + printf("%s: too many tx segments\n", dvname); bus_dmamap_unload(dmat, dmam); m_freem(m0); return NULL; @@ -2760,11 +2927,11 @@ rtw_print_txdesc(struct rtw_softc *sc, const char *action, struct rtw_txsoft *ts, struct rtw_txdesc_blk *tdb, int desc) { struct rtw_txdesc *td = &tdb->tdb_desc[desc]; - DPRINTF(sc, RTW_DEBUG_XMIT_DESC, ("%s: %p %s txdesc[%d] ctl0 %#08x " - "ctl1 %#08x buf %#08x len %#08x\n", + DPRINTF(sc, RTW_DEBUG_XMIT_DESC, ("%s: %p %s txdesc[%d] next %#08x " + "buf %#08x ctl0 %#08x ctl1 %#08x len %#08x\n", sc->sc_dev.dv_xname, ts, action, desc, - letoh32(td->td_ctl0), - letoh32(td->td_ctl1), letoh32(td->td_buf), + letoh32(td->td_buf), letoh32(td->td_next), + letoh32(td->td_ctl0), letoh32(td->td_ctl1), letoh32(td->td_len))); } #endif /* RTW_DEBUG */ @@ -2976,12 +3143,10 @@ rtw_start(struct ifnet *ifp) SIMPLEQ_REMOVE_HEAD(&tsb->tsb_freeq, ts_q); SIMPLEQ_INSERT_TAIL(&tsb->tsb_dirtyq, ts, ts_q); - if (tsb != &sc->sc_txsoft_blk[RTW_TXPRIBCN]) { + if (tsb != &sc->sc_txsoft_blk[RTW_TXPRIBCN]) sc->sc_led_state.ls_event |= RTW_LED_S_TX; - tsb->tsb_tx_timer = 5; - ifp->if_timer = 1; - } - + tsb->tsb_tx_timer = 5; + ifp->if_timer = 1; tppoll = RTW_READ8(&sc->sc_regs, RTW_TPPOLL); tppoll &= ~RTW_TPPOLL_SALL; tppoll |= tsb->tsb_poll & RTW_TPPOLL_ALL; @@ -3000,9 +3165,26 @@ post_dequeue_err: } void +rtw_idle(struct rtw_regs *regs) +{ + int active; + + /* request stop DMA; wait for packets to stop transmitting. */ + + RTW_WRITE8(regs, RTW_TPPOLL, RTW_TPPOLL_SALL); + RTW_WBR(regs, RTW_TPPOLL, RTW_TPPOLL); + + for (active = 0; active < 300 && + (RTW_READ8(regs, RTW_TPPOLL) & RTW_TPPOLL_ACTIVE) != 0; active++) + DELAY(10); + RTW_DPRINTF(RTW_DEBUG_BUGS, + ("%s: transmit DMA idle in %dus\n", __func__, active * 10)); +} + +void rtw_watchdog(struct ifnet *ifp) { - int pri; + int pri, tx_timeouts = 0; struct rtw_softc *sc; struct rtw_txsoft_blk *tsb; @@ -3018,30 +3200,32 @@ rtw_watchdog(struct ifnet *ifp) if (tsb->tsb_tx_timer == 0) continue; - - if (--tsb->tsb_tx_timer == 0) { + else if (--tsb->tsb_tx_timer == 0) { if (SIMPLEQ_EMPTY(&tsb->tsb_dirtyq)) continue; - printf("%s: transmit timeout, priority %d\n", - ifp->if_xname, pri); + RTW_DPRINTF(RTW_DEBUG_BUGS, + ("%s: transmit timeout, priority %d\n", + ifp->if_xname, pri)); ifp->if_oerrors++; - /* Stop Tx DMA, disable transmitter, clear - * Tx rings, and restart. - * - * TBD Stop/restart just the broken ring? - */ - RTW_WRITE8(&sc->sc_regs, RTW_TPPOLL, RTW_TPPOLL_SALL); - RTW_SYNC(&sc->sc_regs, RTW_TPPOLL, RTW_TPPOLL); - rtw_io_enable(&sc->sc_regs, RTW_CR_TE, 0); - rtw_txdescs_reset(sc); - rtw_io_enable(&sc->sc_regs, RTW_CR_TE, 1); - sc->sc_if.if_flags &= ~IFF_OACTIVE; - rtw_start(ifp); + tx_timeouts++; } else ifp->if_timer = 1; } + + if (tx_timeouts > 0) { + /* Stop Tx DMA, disable xmtr, flush Tx rings, enable xmtr, + * reset s/w tx-ring pointers, and start transmission. + * + * TBD Stop/restart just the broken rings? + */ + rtw_idle(&sc->sc_regs); + rtw_io_enable(&sc->sc_regs, RTW_CR_TE, 0); + rtw_txdescs_reset(sc); + rtw_io_enable(&sc->sc_regs, RTW_CR_TE, 1); + rtw_txring_fixup(sc); + rtw_start(ifp); + } ieee80211_watchdog(ifp); - return; } void @@ -3062,7 +3246,7 @@ rtw_next_scan(void *arg) void rtw_join_bss(struct rtw_softc *sc, u_int8_t *bssid, u_int16_t intval0) { - uint16_t bcnitv, intval; + uint16_t bcnitv, bintritv, intval; int i; struct rtw_regs *regs = &sc->sc_regs; @@ -3078,10 +3262,13 @@ rtw_join_bss(struct rtw_softc *sc, u_int8_t *bssid, u_int16_t intval0) bcnitv = RTW_READ16(regs, RTW_BCNITV) & ~RTW_BCNITV_BCNITV_MASK; bcnitv |= LSHIFT(intval, RTW_BCNITV_BCNITV_MASK); RTW_WRITE16(regs, RTW_BCNITV, bcnitv); + /* interrupt host 1ms before the TBTT */ + bintritv = RTW_READ16(regs, RTW_BINTRITV) & ~RTW_BINTRITV_BINTRITV; + bintritv |= LSHIFT(1000, RTW_BINTRITV_BINTRITV); + RTW_WRITE16(regs, RTW_BINTRITV, bintritv); /* magic from Linux */ RTW_WRITE16(regs, RTW_ATIMWND, LSHIFT(1, RTW_ATIMWND_ATIMWND)); RTW_WRITE16(regs, RTW_ATIMTRITV, LSHIFT(2, RTW_ATIMTRITV_ATIMTRITV)); - rtw_set_access(regs, RTW_ACCESS_NONE); /* TBD WEP */ @@ -3096,7 +3283,6 @@ rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { struct ifnet *ifp = &ic->ic_if; struct rtw_softc *sc = ifp->if_softc; - struct mbuf *m; enum ieee80211_state ostate; int error; @@ -3134,12 +3320,6 @@ rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) case IEEE80211_M_HOSTAP: case IEEE80211_M_IBSS: rtw_set_nettype(sc, IEEE80211_M_MONITOR); - m = ieee80211_beacon_alloc(ic, ic->ic_bss); - if (m == NULL) { - printf("%s: could not allocate beacon\n", - sc->sc_dev.dv_xname); - } else - IF_ENQUEUE(&sc->sc_beaconq, m); /*FALLTHROUGH*/ case IEEE80211_M_AHDEMO: case IEEE80211_M_STA: @@ -3159,12 +3339,6 @@ rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) if (nstate != IEEE80211_S_SCAN) timeout_del(&sc->sc_scan_to); - /* Start beacon transmission. */ - if (nstate == IEEE80211_S_RUN && - (ic->ic_opmode == IEEE80211_M_HOSTAP || - ic->ic_opmode == IEEE80211_M_IBSS)) - rtw_start(&sc->sc_if); - return (*sc->sc_mtbl.mt_newstate)(ic, nstate, arg); } @@ -3405,7 +3579,8 @@ rtw_txdesc_blk_setup(struct rtw_txdesc_blk *tdb, struct rtw_txdesc *desc, bzero(tdb->tdb_desc, sizeof(tdb->tdb_desc[0]) * tdb->tdb_ndesc); - rtw_txdesc_blk_reset(tdb); + rtw_txdesc_blk_init(tdb); + tdb->tdb_next = 0; } void @@ -3729,8 +3904,7 @@ rtw_attach(struct rtw_softc *sc) ("%s: PHY delay %d\n", sc->sc_dev.dv_xname, sc->sc_phydelay)); if (sc->sc_locale == RTW_LOCALE_UNKNOWN) - rtw_identify_country(&sc->sc_regs, &sc->sc_locale, - sc->sc_dev.dv_xname); + rtw_identify_country(&sc->sc_regs, &sc->sc_locale); rtw_init_channels(sc->sc_locale, &sc->sc_ic.ic_channels, sc->sc_dev.dv_xname); diff --git a/sys/dev/ic/rtwreg.h b/sys/dev/ic/rtwreg.h index bf1b3b9d187..f4efc6b1f1e 100644 --- a/sys/dev/ic/rtwreg.h +++ b/sys/dev/ic/rtwreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rtwreg.h,v 1.11 2005/11/20 09:49:06 jsg Exp $ */ +/* $OpenBSD: rtwreg.h,v 1.12 2006/01/05 05:36:06 jsg Exp $ */ /* $NetBSD: rtwreg.h,v 1.12 2005/01/16 11:50:43 dyoung Exp $ */ /*- * Copyright (c) 2004, 2005 David Young. All rights reserved. @@ -231,7 +231,7 @@ #define RTW_INTR_TX (RTW_INTR_TLPDER|RTW_INTR_TLPDOK|RTW_INTR_THPDER|\ RTW_INTR_THPDOK|RTW_INTR_TNPDER|RTW_INTR_TNPDOK|\ RTW_INTR_TBDER|RTW_INTR_TBDOK) -#define RTW_INTR_BEACON (RTW_INTR_BCNINT) +#define RTW_INTR_BEACON (RTW_INTR_BCNINT|RTW_INTR_TBDER|RTW_INTR_TBDOK) #define RTW_INTR_IOERROR (RTW_INTR_TXFOVW|RTW_INTR_RXFOVW|RTW_INTR_RDU) #define RTW_TCR 0x40 /* Transmit Configuration Register, 32b */ @@ -883,6 +883,8 @@ /* Start all queues. */ #define RTW_TPPOLL_ALL (RTW_TPPOLL_BQ | RTW_TPPOLL_HPQ | \ RTW_TPPOLL_NPQ | RTW_TPPOLL_LPQ) +/* Check all queues' activity. */ +#define RTW_TPPOLL_ACTIVE RTW_TPPOLL_ALL /* Stop all queues. */ #define RTW_TPPOLL_SALL (RTW_TPPOLL_SBQ | RTW_TPPOLL_SHPQ | \ RTW_TPPOLL_SNPQ | RTW_TPPOLL_SLPQ) diff --git a/sys/dev/ic/rtwvar.h b/sys/dev/ic/rtwvar.h index bd7fc3df0fa..f24e95c6439 100644 --- a/sys/dev/ic/rtwvar.h +++ b/sys/dev/ic/rtwvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rtwvar.h,v 1.20 2005/11/04 14:04:33 jsg Exp $ */ +/* $OpenBSD: rtwvar.h,v 1.21 2006/01/05 05:36:06 jsg Exp $ */ /* $NetBSD: rtwvar.h,v 1.10 2004/12/26 22:37:57 mycroft Exp $ */ /*- @@ -40,30 +40,33 @@ #include <sys/timeout.h> #ifdef RTW_DEBUG -#define RTW_DEBUG_TUNE 0x000001 -#define RTW_DEBUG_PKTFILT 0x000002 -#define RTW_DEBUG_XMIT 0x000004 -#define RTW_DEBUG_XMIT_DESC 0x000008 -#define RTW_DEBUG_NODE 0x000010 -#define RTW_DEBUG_PWR 0x000020 -#define RTW_DEBUG_ATTACH 0x000040 -#define RTW_DEBUG_REGDUMP 0x000080 -#define RTW_DEBUG_ACCESS 0x000100 -#define RTW_DEBUG_RESET 0x000200 -#define RTW_DEBUG_INIT 0x000400 -#define RTW_DEBUG_IOSTATE 0x000800 -#define RTW_DEBUG_RECV 0x001000 -#define RTW_DEBUG_RECV_DESC 0x002000 -#define RTW_DEBUG_IO_KICK 0x004000 -#define RTW_DEBUG_INTR 0x008000 -#define RTW_DEBUG_PHY 0x010000 -#define RTW_DEBUG_PHYIO 0x020000 -#define RTW_DEBUG_PHYBITIO 0x040000 -#define RTW_DEBUG_TIMEOUT 0x080000 -#define RTW_DEBUG_BUGS 0x100000 -#define RTW_DEBUG_BEACON 0x200000 -#define RTW_DEBUG_LED 0x400000 -#define RTW_DEBUG_MAX 0x7fffff +#define RTW_DEBUG_TUNE 0x0000001 +#define RTW_DEBUG_PKTFILT 0x0000002 +#define RTW_DEBUG_XMIT 0x0000004 +#define RTW_DEBUG_XMIT_DESC 0x0000008 +#define RTW_DEBUG_NODE 0x0000010 +#define RTW_DEBUG_PWR 0x0000020 +#define RTW_DEBUG_ATTACH 0x0000040 +#define RTW_DEBUG_REGDUMP 0x0000080 +#define RTW_DEBUG_ACCESS 0x0000100 +#define RTW_DEBUG_RESET 0x0000200 +#define RTW_DEBUG_INIT 0x0000400 +#define RTW_DEBUG_IOSTATE 0x0000800 +#define RTW_DEBUG_RECV 0x0001000 +#define RTW_DEBUG_RECV_DESC 0x0002000 +#define RTW_DEBUG_IO_KICK 0x0004000 +#define RTW_DEBUG_INTR 0x0008000 +#define RTW_DEBUG_PHY 0x0010000 +#define RTW_DEBUG_PHYIO 0x0020000 +#define RTW_DEBUG_PHYBITIO 0x0040000 +#define RTW_DEBUG_TIMEOUT 0x0080000 +#define RTW_DEBUG_BUGS 0x0100000 +#define RTW_DEBUG_BEACON 0x0200000 +#define RTW_DEBUG_LED 0x0400000 +#define RTW_DEBUG_KEY 0x0800000 +#define RTW_DEBUG_XMIT_RSRC 0x1000000 +#define RTW_DEBUG_OACTIVE 0x2000000 +#define RTW_DEBUG_MAX 0x3ffffff extern int rtw_debug; #define RTW_DPRINTF(__flags, __x) \ @@ -180,7 +183,7 @@ struct rtw_txsoft { #define RTW_TXQLENLO 64 /* low-priority queue length */ #define RTW_TXQLENMD 64 /* medium-priority */ #define RTW_TXQLENHI 64 /* high-priority */ -#define RTW_TXQLENBCN 1 /* beacon */ +#define RTW_TXQLENBCN 8 /* beacon */ #define RTW_NTXDESCLO RTW_TXQLENLO #define RTW_NTXDESCMD RTW_TXQLENMD @@ -208,6 +211,9 @@ struct rtw_txdesc_blk { bus_dmamap_t tdb_dmamap; bus_addr_t tdb_physbase; bus_addr_t tdb_ofs; + bus_size_t tdb_basereg; + uint32_t tdb_base; + struct rtw_txdesc *tdb_desc; }; |