summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ath/ath_hal/ah.c2
-rw-r--r--sys/dev/ath/ath_hal/ah.h1
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_attach.c2
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_recv.c9
-rw-r--r--sys/dev/ath/if_ath.c21
-rw-r--r--sys/dev/ath/if_athvar.h5
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)))
OpenPOWER on IntegriCloud