diff options
-rw-r--r-- | sys/dev/ath/ath_hal/ah.c | 2 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ah.h | 1 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5210/ar5210_attach.c | 1 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5211/ar5211_attach.c | 1 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5212/ar5212_attach.c | 1 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5416/ar5416_attach.c | 2 | ||||
-rw-r--r-- | sys/dev/ath/ath_hal/ar5416/ar5416_recv.c | 9 | ||||
-rw-r--r-- | sys/dev/ath/if_ath.c | 21 | ||||
-rw-r--r-- | sys/dev/ath/if_athvar.h | 5 |
9 files changed, 31 insertions, 12 deletions
diff --git a/sys/dev/ath/ath_hal/ah.c b/sys/dev/ath/ath_hal/ah.c index 207629a..b529a7d 100644 --- a/sys/dev/ath/ath_hal/ah.c +++ b/sys/dev/ath/ath_hal/ah.c @@ -616,6 +616,8 @@ ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP; case HAL_CAP_HAS_PSPOLL: /* hardware has ps-poll support */ return pCap->halHasPsPollSupport ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_RXDESC_SELFLINK: /* hardware supports self-linked final RX descriptors correctly */ + return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP; default: return HAL_EINVAL; } diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h index 487e76f..e7b9c9f 100644 --- a/sys/dev/ath/ath_hal/ah.h +++ b/sys/dev/ath/ath_hal/ah.h @@ -114,6 +114,7 @@ typedef enum { HAL_CAP_STREAMS = 39, /* how many 802.11n spatial streams are available */ HAL_CAP_SPLIT_4KB_TRANS = 40, /* hardware supports descriptors straddling a 4k page boundary */ HAL_CAP_HAS_PSPOLL = 41, /* hardware has ps-poll support */ + HAL_CAP_RXDESC_SELFLINK = 42, /* support a self-linked tail RX descriptor */ } HAL_CAPABILITY_TYPE; /* diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c index e1a5067..2068733 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c @@ -378,6 +378,7 @@ ar5210FillCapabilityInfo(struct ath_hal *ah) ; pCap->hal4kbSplitTransSupport = AH_TRUE; + pCap->halHasRxSelfLinkedTail = AH_TRUE; ahpriv->ah_rxornIsFatal = AH_TRUE; return AH_TRUE; diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c index bace648..308ecc9 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c @@ -510,6 +510,7 @@ ar5211FillCapabilityInfo(struct ath_hal *ah) ; pCap->hal4kbSplitTransSupport = AH_TRUE; + pCap->halHasRxSelfLinkedTail = AH_TRUE; /* XXX might be ok w/ some chip revs */ ahpriv->ah_rxornIsFatal = AH_TRUE; diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c index 3aabdcc..4b0fcbe 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c @@ -861,6 +861,7 @@ ar5212FillCapabilityInfo(struct ath_hal *ah) pCap->halIntrMask &= ~HAL_INT_TBTT; pCap->hal4kbSplitTransSupport = AH_TRUE; + pCap->halHasRxSelfLinkedTail = AH_TRUE; return AH_TRUE; #undef IS_COBRA diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c index 4227c54..93c2a19 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c @@ -843,6 +843,8 @@ ar5416FillCapabilityInfo(struct ath_hal *ah) pCap->halBtCoexSupport = AH_FALSE; /* XXX need support */ pCap->halAutoSleepSupport = AH_FALSE; pCap->hal4kbSplitTransSupport = AH_TRUE; + /* Disable this so Block-ACK works correctly */ + pCap->halHasRxSelfLinkedTail = AH_FALSE; #if 0 /* XXX not yet */ pCap->halNumAntCfg2GHz = ar5416GetNumAntConfig(ahp, HAL_FREQ_BAND_2GHZ); pCap->halNumAntCfg5GHz = ar5416GetNumAntConfig(ahp, HAL_FREQ_BAND_5GHZ); diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c b/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c index 251f826..8a7f3ba 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c @@ -99,18 +99,9 @@ ar5416ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds, struct ath_rx_status *rs) { struct ar5416_desc *ads = AR5416DESC(ds); - struct ar5416_desc *ands = AR5416DESC(nds); if ((ads->ds_rxstatus8 & AR_RxDone) == 0) return HAL_EINPROGRESS; - /* - * Given the use of a self-linked tail be very sure that the hw is - * done with this descriptor; the hw may have done this descriptor - * once and picked it up again...make sure the hw has moved on. - */ - if ((ands->ds_rxstatus8 & AR_RxDone) == 0 - && OS_REG_READ(ah, AR_RXDP) == pa) - return HAL_EINPROGRESS; rs->rs_status = 0; rs->rs_flags = 0; diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 26cdebcb..ce7317e 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -595,6 +595,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) sc->sc_hasbmask = ath_hal_hasbssidmask(ah); sc->sc_hasbmatch = ath_hal_hasbssidmatch(ah); sc->sc_hastsfadd = ath_hal_hastsfadjust(ah); + sc->sc_rxslink = ath_hal_self_linked_final_rxdesc(ah); if (ath_hal_hasfastframes(ah)) ic->ic_caps |= IEEE80211_C_FF; wmodes = ath_hal_getwirelessmodes(ah); @@ -3135,8 +3136,17 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) * descriptor list. This insures the hardware always has * someplace to write a new frame. */ + /* + * 11N: we can no longer afford to self link the last descriptor. + * MAC acknowledges BA status as long as it copies frames to host + * buffer (or rx fifo). This can incorrectly acknowledge packets + * to a sender if last desc is self-linked. + */ ds = bf->bf_desc; - ds->ds_link = bf->bf_daddr; /* link to self */ + if (sc->sc_rxslink) + ds->ds_link = bf->bf_daddr; /* link to self */ + else + ds->ds_link = 0; /* terminate the list */ ds->ds_data = bf->bf_segs[0].ds_addr; ath_hal_setuprxdesc(ah, ds , m->m_len /* buffer size */ @@ -3321,9 +3331,16 @@ ath_rx_proc(void *arg, int npending) tsf = ath_hal_gettsf64(ah); do { bf = STAILQ_FIRST(&sc->sc_rxbuf); - if (bf == NULL) { /* NB: shouldn't happen */ + if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */ if_printf(ifp, "%s: no buffer!\n", __func__); break; + } else if (bf == NULL) { + /* + * End of List: + * this can happen for non-self-linked RX chains + */ + sc->sc_stats.ast_rx_hitqueueend++; + break; } m = bf->bf_m; if (m == NULL) { /* NB: shouldn't happen */ diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 4daa2e1..dcb57ef 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -253,7 +253,8 @@ struct ath_softc { sc_resume_up: 1,/* on resume, start all vaps */ sc_tdma : 1,/* TDMA in use */ sc_setcca : 1,/* set/clr CCA with TDMA */ - sc_resetcal : 1;/* reset cal state next trip */ + sc_resetcal : 1,/* reset cal state next trip */ + sc_rxslink : 1;/* do self-linked final descriptor */ uint32_t sc_eerd; /* regdomain from EEPROM */ uint32_t sc_eecc; /* country code from EEPROM */ /* rate tables */ @@ -646,6 +647,8 @@ void ath_intr(void *); (ath_hal_getcapability(_ah, HAL_CAP_TX_CHAINMASK, 0, _ptxchainmask)) #define ath_hal_split4ktrans(_ah) \ (ath_hal_getcapability(_ah, HAP_CAP_SPLIT_4KB_TRANS, 0, NULL) == HAL_OK) +#define ath_hal_self_linked_final_rxdesc(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_RXDESC_SELFLINK, 0, NULL) == HAL_OK) #define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \ ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq))) |