diff options
Diffstat (limited to 'drivers/net/wireless/ath9k/recv.c')
-rw-r--r-- | drivers/net/wireless/ath9k/recv.c | 536 |
1 files changed, 0 insertions, 536 deletions
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 828322840a8..2ecb0a010ce 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -64,328 +64,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) ath9k_hw_rxena(ah); } -/* Process received BAR frame */ - -static int ath_bar_rx(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb) -{ - struct ieee80211_bar *bar; - struct ath_arx_tid *rxtid; - struct sk_buff *tskb; - struct ath_recv_status *rx_status; - int tidno, index, cindex; - u16 seqno; - - /* look at BAR contents */ - - bar = (struct ieee80211_bar *)skb->data; - tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M) - >> IEEE80211_BAR_CTL_TID_S; - seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT; - - /* process BAR - indicate all pending RX frames till the BAR seqno */ - - rxtid = &an->an_aggr.rx.tid[tidno]; - - spin_lock_bh(&rxtid->tidlock); - - /* get relative index */ - - index = ATH_BA_INDEX(rxtid->seq_next, seqno); - - /* drop BAR if old sequence (index is too large) */ - - if ((index > rxtid->baw_size) && - (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2)))) - /* discard frame, ieee layer may not treat frame as a dup */ - goto unlock_and_free; - - /* complete receive processing for all pending frames upto BAR seqno */ - - cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - while ((rxtid->baw_head != rxtid->baw_tail) && - (rxtid->baw_head != cindex)) { - tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; - rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; - rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; - - if (tskb != NULL) - ath_rx_subframe(an, tskb, rx_status); - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* ... and indicate rest of the frames in-order */ - - while (rxtid->baw_head != rxtid->baw_tail && - rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) { - tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; - rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; - rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; - - ath_rx_subframe(an, tskb, rx_status); - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - -unlock_and_free: - spin_unlock_bh(&rxtid->tidlock); - /* free bar itself */ - dev_kfree_skb(skb); - return IEEE80211_FTYPE_CTL; -} - -/* Function to handle a subframe of aggregation when HT is enabled */ - -static int ath_ampdu_input(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *rx_status) -{ - struct ieee80211_hdr *hdr; - struct ath_arx_tid *rxtid; - struct ath_rxbuf *rxbuf; - u8 type, subtype; - u16 rxseq; - int tid = 0, index, cindex, rxdiff; - __le16 fc; - u8 *qc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - /* collect stats of frames with non-zero version */ - - if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) { - dev_kfree_skb(skb); - return -1; - } - - type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; - - if (ieee80211_is_back_req(fc)) - return ath_bar_rx(sc, an, skb); - - /* special aggregate processing only for qos unicast data frames */ - - if (!ieee80211_is_data(fc) || - !ieee80211_is_data_qos(fc) || - is_multicast_ether_addr(hdr->addr1)) - return ath_rx_subframe(an, skb, rx_status); - - /* lookup rx tid state */ - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } - - if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { - /* Drop the frame not belonging to me. */ - if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) { - dev_kfree_skb(skb); - return -1; - } - } - - rxtid = &an->an_aggr.rx.tid[tid]; - - spin_lock(&rxtid->tidlock); - - rxdiff = (rxtid->baw_tail - rxtid->baw_head) & - (ATH_TID_MAX_BUFS - 1); - - /* - * If the ADDBA exchange has not been completed by the source, - * process via legacy path (i.e. no reordering buffer is needed) - */ - if (!rxtid->addba_exchangecomplete) { - spin_unlock(&rxtid->tidlock); - return ath_rx_subframe(an, skb, rx_status); - } - - /* extract sequence number from recvd frame */ - - rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT; - - if (rxtid->seq_reset) { - rxtid->seq_reset = 0; - rxtid->seq_next = rxseq; - } - - index = ATH_BA_INDEX(rxtid->seq_next, rxseq); - - /* drop frame if old sequence (index is too large) */ - - if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) { - /* discard frame, ieee layer may not treat frame as a dup */ - spin_unlock(&rxtid->tidlock); - dev_kfree_skb(skb); - return IEEE80211_FTYPE_DATA; - } - - /* sequence number is beyond block-ack window */ - - if (index >= rxtid->baw_size) { - - /* complete receive processing for all pending frames */ - - while (index >= rxtid->baw_size) { - - rxbuf = rxtid->rxbuf + rxtid->baw_head; - - if (rxbuf->rx_wbuf != NULL) { - ath_rx_subframe(an, rxbuf->rx_wbuf, - &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - } - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - - index--; - } - } - - /* add buffer to the recv ba window */ - - cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - rxbuf = rxtid->rxbuf + cindex; - - if (rxbuf->rx_wbuf != NULL) { - spin_unlock(&rxtid->tidlock); - /* duplicate frame */ - dev_kfree_skb(skb); - return IEEE80211_FTYPE_DATA; - } - - rxbuf->rx_wbuf = skb; - rxbuf->rx_time = get_timestamp(); - rxbuf->rx_status = *rx_status; - - /* advance tail if sequence received is newer - * than any received so far */ - - if (index >= rxdiff) { - rxtid->baw_tail = cindex; - INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS); - } - - /* indicate all in-order received frames */ - - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) - break; - - ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* - * start a timer to flush all received frames if there are pending - * receive frames - */ - if (rxtid->baw_head != rxtid->baw_tail) - mod_timer(&rxtid->timer, ATH_RX_TIMEOUT); - else - del_timer_sync(&rxtid->timer); - - spin_unlock(&rxtid->tidlock); - return IEEE80211_FTYPE_DATA; -} - -/* Timer to flush all received sub-frames */ - -static void ath_rx_timer(unsigned long data) -{ - struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data; - struct ath_node *an = rxtid->an; - struct ath_rxbuf *rxbuf; - int nosched; - - spin_lock_bh(&rxtid->tidlock); - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) { - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - continue; - } - - /* - * Stop if the next one is a very recent frame. - * - * Call get_timestamp in every iteration to protect against the - * case in which a new frame is received while we are executing - * this function. Using a timestamp obtained before entering - * the loop could lead to a very large time interval - * (a negative value typecast to unsigned), breaking the - * function's logic. - */ - if ((get_timestamp() - rxbuf->rx_time) < - (ATH_RX_TIMEOUT * HZ / 1000)) - break; - - ath_rx_subframe(an, rxbuf->rx_wbuf, - &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* - * start a timer to flush all received frames if there are pending - * receive frames - */ - if (rxtid->baw_head != rxtid->baw_tail) - nosched = 0; - else - nosched = 1; /* no need to re-arm the timer again */ - - spin_unlock_bh(&rxtid->tidlock); -} - -/* Free all pending sub-frames in the re-ordering buffer */ - -static void ath_rx_flush_tid(struct ath_softc *sc, - struct ath_arx_tid *rxtid, int drop) -{ - struct ath_rxbuf *rxbuf; - unsigned long flag; - - spin_lock_irqsave(&rxtid->tidlock, flag); - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) { - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - continue; - } - - if (drop) - dev_kfree_skb(rxbuf->rx_wbuf); - else - ath_rx_subframe(rxtid->an, - rxbuf->rx_wbuf, - &rxbuf->rx_status); - - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - spin_unlock_irqrestore(&rxtid->tidlock, flag); -} - static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) { @@ -716,23 +394,6 @@ void ath_flushrecv(struct ath_softc *sc) spin_unlock_bh(&sc->sc_rxflushlock); } -/* Process an individual frame */ - -int ath_rx_input(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *rx_status, - enum ATH_RX_TYPE *status) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - *status = ATH_RX_CONSUMED; - return ath_ampdu_input(sc, an, skb, rx_status); - } else { - *status = ATH_RX_NON_CONSUMED; - return -1; - } -} - /* Process receive queue, as well as LED, etc. */ int ath_rx_tasklet(struct ath_softc *sc, int flush) @@ -1091,200 +752,3 @@ rx_next: return 0; #undef PA2DESC } - -/* Process ADDBA request in per-TID data structure */ - -int ath_rx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn) -{ - struct ath_arx_tid *rxtid; - struct ath_node *an; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_supported_band *sband; - u16 buffersize = 0; - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to initialize RX aggregation\n", - __func__); - return -1; - } - - sband = hw->wiphy->bands[hw->conf.channel->band]; - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_cap.ampdu_factor; /* FIXME */ - - rxtid = &an->an_aggr.rx.tid[tid]; - - spin_lock_bh(&rxtid->tidlock); - if (sc->sc_flags & SC_OP_RXAGGR) { - /* Allow aggregation reception - * Adjust rx BA window size. Peer might indicate a - * zero buffer size for a _dont_care_ condition. - */ - if (buffersize) - rxtid->baw_size = min(buffersize, rxtid->baw_size); - - /* set rx sequence number */ - rxtid->seq_next = *ssn; - - /* Allocate the receive buffers for this TID */ - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Allcating rxbuffer for TID %d\n", __func__, tid); - - if (rxtid->rxbuf == NULL) { - /* - * If the rxbuff is not NULL at this point, we *probably* - * already allocated the buffer on a previous ADDBA, - * and this is a subsequent ADDBA that got through. - * Don't allocate, but use the value in the pointer, - * we zero it out when we de-allocate. - */ - rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS * - sizeof(struct ath_rxbuf), GFP_ATOMIC); - } - if (rxtid->rxbuf == NULL) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Unable to allocate RX buffer, " - "refusing ADDBA\n", __func__); - } else { - /* Ensure the memory is zeroed out (all internal - * pointers are null) */ - memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS * - sizeof(struct ath_rxbuf)); - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Allocated @%p\n", __func__, rxtid->rxbuf); - - /* Allow aggregation reception */ - rxtid->addba_exchangecomplete = 1; - } - } - spin_unlock_bh(&rxtid->tidlock); - - return 0; -} - -/* Process DELBA */ - -int ath_rx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid) -{ - struct ath_node *an; - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: RX aggr stop for non-existent node\n", __func__); - return -1; - } - - ath_rx_aggr_teardown(sc, an, tid); - return 0; -} - -/* Rx aggregation tear down */ - -void ath_rx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tid) -{ - struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid]; - - if (!rxtid->addba_exchangecomplete) - return; - - del_timer_sync(&rxtid->timer); - ath_rx_flush_tid(sc, rxtid, 0); - rxtid->addba_exchangecomplete = 0; - - /* De-allocate the receive buffer array allocated when addba started */ - - if (rxtid->rxbuf) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Deallocating TID %d rxbuff @%p\n", - __func__, tid, rxtid->rxbuf); - kfree(rxtid->rxbuf); - - /* Set pointer to null to avoid reuse*/ - rxtid->rxbuf = NULL; - } -} - -/* Initialize per-node receive state */ - -void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - struct ath_arx_tid *rxtid; - int tidno; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - rxtid->an = an; - rxtid->seq_reset = 1; - rxtid->seq_next = 0; - rxtid->baw_size = WME_MAX_BA; - rxtid->baw_head = rxtid->baw_tail = 0; - - /* - * Ensure the buffer pointer is null at this point - * (needs to be allocated when addba is received) - */ - - rxtid->rxbuf = NULL; - setup_timer(&rxtid->timer, ath_rx_timer, - (unsigned long)rxtid); - spin_lock_init(&rxtid->tidlock); - - /* ADDBA state */ - rxtid->addba_exchangecomplete = 0; - } - } -} - -void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - struct ath_arx_tid *rxtid; - int tidno, i; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - - if (!rxtid->addba_exchangecomplete) - continue; - - /* must cancel timer first */ - del_timer_sync(&rxtid->timer); - - /* drop any pending sub-frames */ - ath_rx_flush_tid(sc, rxtid, 1); - - for (i = 0; i < ATH_TID_MAX_BUFS; i++) - ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL); - - rxtid->addba_exchangecomplete = 0; - } - } - -} - -/* Cleanup per-node receive state */ - -void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) -{ - ath_rx_node_cleanup(sc, an); -} |