From d9c543d4f6d55c5f3f595f27c47c8bacf3ffaf9f Mon Sep 17 00:00:00 2001 From: Alexander Egorenkov Date: Tue, 16 Feb 2010 19:57:45 +0100 Subject: [PATCH] A-MPDU Tx support; Increased size of Tx ring to 256 --- rt2870.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++----------- rt2870_softc.h | 4 +- 2 files changed, 101 insertions(+), 23 deletions(-) diff --git a/rt2870.c b/rt2870.c index a885836..c2d9f80 100644 --- a/rt2870.c +++ b/rt2870.c @@ -653,6 +653,7 @@ static int rt2870_attach(device_t dev) ic->ic_htcaps = IEEE80211_HTC_HT | IEEE80211_HTC_AMSDU | /* A-MSDU Tx */ + IEEE80211_HTC_AMPDU | /* A-MPDU Tx */ IEEE80211_HTCAP_MAXAMSDU_3839 | /* max. A-MSDU Rx length */ IEEE80211_HTCAP_CHWIDTH40 | /* HT 40MHz channel width */ IEEE80211_HTCAP_GREENFIELD | /* HT greenfield */ @@ -2478,7 +2479,7 @@ static int rt2870_recv_action(struct ieee80211_node *ni, struct ieee80211com *ic; struct ifnet *ifp; const struct ieee80211_action *ia; - uint16_t associd, baparamset; + uint16_t associd, status, baparamset; uint8_t wcid; int ret, tid, bufsize; uint32_t tmp; @@ -2506,7 +2507,7 @@ static int rt2870_recv_action(struct ieee80211_node *ni, bufsize = RT2870_MS(baparamset, IEEE80211_BAPS_BUFSIZ); RT2870_DPRINTF(sc, RT2870_DEBUG_BA, - "%s: received ADDBA: associd=0x%04x, tid=%d, bufsize=%d\n", + "%s: received ADDBA request: associd=0x%04x, tid=%d, bufsize=%d\n", device_get_nameunit(sc->dev), associd, tid, bufsize); RT2870_SOFTC_LOCK(sc); @@ -2520,13 +2521,36 @@ static int rt2870_recv_action(struct ieee80211_node *ni, RT2870_SOFTC_UNLOCK(sc); break; + /* IEEE80211_ACTION_BA_ADDBA_RESPONSE */ + case IEEE80211_ACTION_BA_ADDBA_RESPONSE: + status = LE_READ_2(frm + 3); + baparamset = LE_READ_2(frm + 4); + tid = RT2870_MS(baparamset, IEEE80211_BAPS_TID); + bufsize = RT2870_MS(baparamset, IEEE80211_BAPS_BUFSIZ); + + RT2870_DPRINTF(sc, RT2870_DEBUG_BA, + "%s: received ADDBA response: associd=0x%04x, status=%d, tid=%d, bufsize=%d\n", + device_get_nameunit(sc->dev), associd, status, tid, bufsize); + + if (status == IEEE80211_STATUS_SUCCESS) + { + sc->tx_ampdu_sessions++; + + RT2870_SOFTC_LOCK(sc); + + rt2870_asic_updateprot(sc); + + RT2870_SOFTC_UNLOCK(sc); + } + break; + /* IEEE80211_ACTION_BA_DELBA */ case IEEE80211_ACTION_BA_DELBA: baparamset = LE_READ_2(frm + 2); tid = RT2870_MS(baparamset, IEEE80211_BAPS_TID); RT2870_DPRINTF(sc, RT2870_DEBUG_BA, - "%s: received DELBA: associd=0x%04x, tid=%d\n", + "%s: received DELBA request: associd=0x%04x, tid=%d\n", device_get_nameunit(sc->dev), associd, tid); RT2870_SOFTC_LOCK(sc); @@ -2577,22 +2601,28 @@ static int rt2870_send_action(struct ieee80211_node *ni, case IEEE80211_ACTION_BA_DELBA: baparamset = RT2870_SM(args[0], IEEE80211_DELBAPS_TID) | args[1]; - if (RT2870_MS(baparamset, IEEE80211_DELBAPS_INIT) == IEEE80211_DELBAPS_INIT) - break; - tid = RT2870_MS(baparamset, IEEE80211_DELBAPS_TID); RT2870_DPRINTF(sc, RT2870_DEBUG_BA, - "%s: sending DELBA: associd=0x%04x, tid=%d\n", + "%s: sending DELBA request: associd=0x%04x, tid=%d\n", device_get_nameunit(sc->dev), associd, tid); RT2870_SOFTC_LOCK(sc); - tmp = rt2870_io_mac_read(sc, RT2870_REG_WCID(wcid) + 4); + if (RT2870_MS(baparamset, IEEE80211_DELBAPS_INIT) != IEEE80211_DELBAPS_INIT) + { + tmp = rt2870_io_mac_read(sc, RT2870_REG_WCID(wcid) + 4); - tmp &= ~(0x10000 << tid); + tmp &= ~(0x10000 << tid); - rt2870_io_mac_write(sc, RT2870_REG_WCID(wcid) + 4, tmp); + rt2870_io_mac_write(sc, RT2870_REG_WCID(wcid) + 4, tmp); + } + else + { + sc->tx_ampdu_sessions--; + + rt2870_asic_updateprot(sc); + } RT2870_SOFTC_UNLOCK(sc); break; @@ -3179,6 +3209,7 @@ static void rt2870_asic_updateprot(struct rt2870_softc *sc) struct ieee80211vap *vap; uint32_t cck_prot, ofdm_prot, mm20_prot, mm40_prot, gf20_prot, gf40_prot; uint8_t htopmode; + enum ieee80211_protmode htprotmode; ifp = sc->ifp; ic = ifp->if_l2com; @@ -3238,12 +3269,26 @@ static void rt2870_asic_updateprot(struct rt2870_softc *sc) else htopmode = ic->ic_curhtprotmode; + htprotmode = ic->ic_htprotmode; + + /* force HT mixed mode and RTS/CTS protection if A-MPDU Tx aggregation is enabled */ + + if (sc->tx_ampdu_sessions > 0) + { + RT2870_DPRINTF(sc, RT2870_DEBUG_PROT, + "%s: updating protection mode: forcing HT mixed mode and RTS/CTS protection\n", + device_get_nameunit(sc->dev)); + + htopmode = IEEE80211_HTINFO_OPMODE_MIXED; + htprotmode = IEEE80211_PROT_RTSCTS; + } + RT2870_DPRINTF(sc, RT2870_DEBUG_PROT, "%s: updating protection mode: HT operation mode=0x%02x, protection mode=%s\n", device_get_nameunit(sc->dev), htopmode & IEEE80211_HTINFO_OPMODE, - (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) ? "RTS/CTS" : - ((ic->ic_htprotmode == IEEE80211_PROT_CTSONLY) ? "CTS-to-self" : "none")); + (htprotmode == IEEE80211_PROT_RTSCTS) ? "RTS/CTS" : + ((htprotmode == IEEE80211_PROT_CTSONLY) ? "CTS-to-self" : "none")); switch (htopmode & IEEE80211_HTINFO_OPMODE) { @@ -3262,9 +3307,9 @@ static void rt2870_asic_updateprot(struct rt2870_softc *sc) (RT2870_REG_PROT_PHYMODE_OFDM << RT2870_REG_PROT_PHYMODE_SHIFT) | (0x84 << RT2870_REG_PROT_MCS_SHIFT); - if (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) + if (htprotmode == IEEE80211_PROT_RTSCTS) mm40_prot |= RT2870_REG_PROT_CTRL_RTS_CTS; - else if (ic->ic_htprotmode == IEEE80211_PROT_CTSONLY) + else if (htprotmode == IEEE80211_PROT_CTSONLY) mm40_prot |= RT2870_REG_PROT_CTRL_CTS; else mm40_prot |= RT2870_REG_PROT_CTRL_NONE; @@ -3285,9 +3330,9 @@ static void rt2870_asic_updateprot(struct rt2870_softc *sc) mm20_prot |= (RT2870_REG_PROT_PHYMODE_OFDM << RT2870_REG_PROT_PHYMODE_SHIFT) | (4 << RT2870_REG_PROT_MCS_SHIFT); - if (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) + if (htprotmode == IEEE80211_PROT_RTSCTS) mm20_prot |= RT2870_REG_PROT_CTRL_RTS_CTS; - else if (ic->ic_htprotmode == IEEE80211_PROT_CTSONLY) + else if (htprotmode == IEEE80211_PROT_CTSONLY) mm20_prot |= RT2870_REG_PROT_CTRL_CTS; else mm20_prot |= RT2870_REG_PROT_CTRL_NONE; @@ -3303,9 +3348,9 @@ static void rt2870_asic_updateprot(struct rt2870_softc *sc) mm40_prot |= (RT2870_REG_PROT_PHYMODE_OFDM << RT2870_REG_PROT_PHYMODE_SHIFT) | (0x84 << RT2870_REG_PROT_MCS_SHIFT); - if (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) + if (htprotmode == IEEE80211_PROT_RTSCTS) mm40_prot |= RT2870_REG_PROT_CTRL_RTS_CTS; - else if (ic->ic_htprotmode == IEEE80211_PROT_CTSONLY) + else if (htprotmode == IEEE80211_PROT_CTSONLY) mm40_prot |= RT2870_REG_PROT_CTRL_CTS; else mm40_prot |= RT2870_REG_PROT_CTRL_NONE; @@ -4137,11 +4182,13 @@ static int rt2870_tx_data(struct rt2870_softc *sc, struct rt2870_txinfo *txinfo; struct rt2870_txwi *txwi; struct ieee80211_frame *wh; + struct ieee80211_tx_ampdu *tx_ampdu; + ieee80211_seq seqno; struct rt2870_softc_tx_radiotap_header *tap; u_int hdrsize, hdrspace; - uint8_t type, rate, bw, stbc, shortgi, mcs, pid, wcid; + uint8_t type, rate, bw, stbc, shortgi, mcs, pid, wcid, mpdu_density, bawin_size; uint16_t qos, len, dmalen, mpdu_len, dur; - int hasqos; + int hasqos, ac, tid, ampdu; KASSERT(qid >= 0 && qid < (sc->usb_endpoints - 1), ("%s: Tx data: invalid qid=%d\n", @@ -4296,6 +4343,35 @@ static int rt2870_tx_data(struct rt2870_softc *sc, *(uint16_t *) wh->i_dur = htole16(dur); } + /* check fo A-MPDU */ + + if (m->m_flags & M_AMPDU_MPDU) + { + ac = M_WME_GETAC(m); + tid = WME_AC_TO_TID(ac); + tx_ampdu = &ni->ni_tx_ampdu[ac]; + + mpdu_density = RT2870_MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY); + bawin_size = 13; //tx_ampdu->txa_wnd; + + txwi->mpdu_density_flags |= + ((mpdu_density & RT2870_TXWI_MPDU_DENSITY_MASK) << RT2870_TXWI_MPDU_DENSITY_SHIFT) | + (RT2870_TXWI_FLAGS_AMPDU << RT2870_TXWI_FLAGS_SHIFT); + + txwi->bawin_size_xflags |= + ((bawin_size & RT2870_TXWI_BAWIN_SIZE_MASK) << RT2870_TXWI_BAWIN_SIZE_SHIFT); + + seqno = ni->ni_txseqs[tid]++; + + *(uint16_t *) &wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + + ampdu = 1; + } + else + { + ampdu = 0; + } + /* ask MAC to insert timestamp into probe responses */ if ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == @@ -4345,10 +4421,10 @@ static int rt2870_tx_data(struct rt2870_softc *sc, RT2870_DPRINTF(sc, RT2870_DEBUG_TX, "%s: sending data: qid=%d, hdrsize=%d, hdrspace=%d, len=%d, " - "bw=%d, stbc=%d, shortgi=%d, mcs=%d, wcid=0x%02x, DMA len=%d\n", + "bw=%d, stbc=%d, shortgi=%d, mcs=%d, wcid=0x%02x, ampdu=%d, DMA len=%d\n", device_get_nameunit(sc->dev), qid, hdrsize, hdrspace, m->m_pkthdr.len, - bw, stbc, shortgi, mcs, wcid, dmalen); + bw, stbc, shortgi, mcs, wcid, ampdu, dmalen); data->len = dmalen; data->m = m; diff --git a/rt2870_softc.h b/rt2870_softc.h index d9f47c5..3399dd8 100644 --- a/rt2870_softc.h +++ b/rt2870_softc.h @@ -84,7 +84,7 @@ #define RT2870_SOFTC_RX_RING_DATA_COUNT 128 -#define RT2870_SOFTC_TX_RING_DATA_COUNT 128 +#define RT2870_SOFTC_TX_RING_DATA_COUNT 256 #define RT2870_SOFTC_CMD_DATA_LEN 256 #define RT2870_SOFTC_CMD_RING_CMD_COUNT 64 @@ -219,6 +219,8 @@ struct rt2870_softc struct ifnet *ifp; int if_flags; + int tx_ampdu_sessions; + int (*recv_action)(struct ieee80211_node *ni, const struct ieee80211_frame *wh, const uint8_t *frm, const uint8_t *efrm); -- 2.11.4.GIT