cregit-Linux how code gets into the kernel

Release 4.7 drivers/net/wireless/ath/ath9k/recv.c

/*
 * Copyright (c) 2008-2011 Atheros Communications Inc.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <linux/dma-mapping.h>
#include "ath9k.h"
#include "ar9003_mac.h"


#define SKB_CB_ATHBUF(__skb)	(*((struct ath_rxbuf **)__skb->cb))


static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) { return sc->ps_enabled && (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP); }

Contributors

PersonTokensPropCommitsCommitProp
vasanthakumar thiagarajanvasanthakumar thiagarajan29100.00%1100.00%
Total29100.00%1100.00%

/* * Setup and link descriptors. * * 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. */
static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf, bool flush) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; struct sk_buff *skb; ds = bf->bf_desc; ds->ds_link = 0; /* link to null */ ds->ds_data = bf->bf_buf_addr; /* virtual addr of the beginning of the buffer. */ skb = bf->bf_mpdu; BUG_ON(skb == NULL); ds->ds_vdata = skb->data; /* * setup rx descriptors. The rx_bufsize here tells the hardware * how much data it can DMA to us and that we are prepared * to process */ ath9k_hw_setuprxdesc(ah, ds, common->rx_bufsize, 0); if (sc->rx.rxlink) *sc->rx.rxlink = bf->bf_daddr; else if (!flush) ath9k_hw_putrxbuf(ah, bf->bf_daddr); sc->rx.rxlink = &ds->ds_link; }

Contributors

PersonTokensPropCommitsCommitProp
luis r. rodriguezluis r. rodriguez12080.00%444.44%
felix fietkaufelix fietkau1912.67%222.22%
sujith manoharansujith manoharan117.33%333.33%
Total150100.00%9100.00%


static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf, bool flush) { if (sc->rx.buf_hold) ath_rx_buf_link(sc, sc->rx.buf_hold, flush); sc->rx.buf_hold = bf; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau48100.00%3100.00%
Total48100.00%3100.00%


static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) { /* XXX block beacon interrupts */ ath9k_hw_setantenna(sc->sc_ah, antenna); sc->rx.defant = antenna; sc->rx.rxotherant = 0; }

Contributors

PersonTokensPropCommitsCommitProp
sujith manoharansujith manoharan40100.00%2100.00%
Total40100.00%2100.00%


static void ath_opmode_init(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); u32 rfilt, mfilt[2]; /* configure rx filter */ rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(ah, rfilt); /* configure bssid mask */ ath_hw_setbssidmask(common); /* configure operational mode */ ath9k_hw_setopmode(ah); /* calculate and install multicast filter */ mfilt[0] = mfilt[1] = ~0; ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); }

Contributors

PersonTokensPropCommitsCommitProp
sujith manoharansujith manoharan8287.23%250.00%
luis r. rodriguezluis r. rodriguez1212.77%250.00%
Total94100.00%4100.00%


static bool ath_rx_edma_buf_link(struct ath_softc *sc, enum ath9k_rx_qtype qtype) { struct ath_hw *ah = sc->sc_ah; struct ath_rx_edma *rx_edma; struct sk_buff *skb; struct ath_rxbuf *bf; rx_edma = &sc->rx.rx_edma[qtype]; if (skb_queue_len(&rx_edma->rx_fifo) >= rx_edma->rx_fifo_hwsize) return false; bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list); list_del_init(&bf->list); skb = bf->bf_mpdu; memset(skb->data, 0, ah->caps.rx_status_len); dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, ah->caps.rx_status_len, DMA_TO_DEVICE); SKB_CB_ATHBUF(skb) = bf; ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype); __skb_queue_tail(&rx_edma->rx_fifo, skb); return true; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau10865.85%228.57%
sujith manoharansujith manoharan3823.17%342.86%
luis r. rodriguezluis r. rodriguez1810.98%228.57%
Total164100.00%7100.00%


static void ath_rx_addbuffer_edma(struct ath_softc *sc, enum ath9k_rx_qtype qtype) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_rxbuf *bf, *tbf; if (list_empty(&sc->rx.rxbuf)) { ath_dbg(common, QUEUE, "No free rx buf available\n"); return; } list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) if (!ath_rx_edma_buf_link(sc, qtype)) break; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau4151.25%220.00%
sujith manoharansujith manoharan1721.25%220.00%
mohammed shafi shajakhanmohammed shafi shajakhan1417.50%110.00%
luis r. rodriguezluis r. rodriguez56.25%220.00%
joe perchesjoe perches22.50%220.00%
senthil balasubramaniansenthil balasubramanian11.25%110.00%
Total80100.00%10100.00%


static void ath_rx_remove_buffer(struct ath_softc *sc, enum ath9k_rx_qtype qtype) { struct ath_rxbuf *bf; struct ath_rx_edma *rx_edma; struct sk_buff *skb; rx_edma = &sc->rx.rx_edma[qtype]; while ((skb = __skb_dequeue(&rx_edma->rx_fifo)) != NULL) { bf = SKB_CB_ATHBUF(skb); BUG_ON(!bf); list_add_tail(&bf->list, &sc->rx.rxbuf); } }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau6068.18%225.00%
luis r. rodriguezluis r. rodriguez1820.45%225.00%
sujith manoharansujith manoharan910.23%337.50%
gabor juhosgabor juhos11.14%112.50%
Total88100.00%8100.00%


static void ath_rx_edma_cleanup(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_rxbuf *bf; ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); list_for_each_entry(bf, &sc->rx.rxbuf, list) { if (bf->bf_mpdu) { dma_unmap_single(sc->dev, bf->bf_buf_addr, common->rx_bufsize, DMA_BIDIRECTIONAL); dev_kfree_skb_any(bf->bf_mpdu); bf->bf_buf_addr = 0; bf->bf_mpdu = NULL; } } }

Contributors

PersonTokensPropCommitsCommitProp
mohammed shafi shajakhanmohammed shafi shajakhan5048.54%114.29%
felix fietkaufelix fietkau2120.39%228.57%
luis r. rodriguezluis r. rodriguez1918.45%228.57%
sujith manoharansujith manoharan1312.62%228.57%
Total103100.00%7100.00%


static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size) { __skb_queue_head_init(&rx_edma->rx_fifo); rx_edma->rx_fifo_hwsize = size; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau1967.86%133.33%
luis r. rodriguezluis r. rodriguez828.57%133.33%
sujith manoharansujith manoharan13.57%133.33%
Total28100.00%3100.00%


static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; struct sk_buff *skb; struct ath_rxbuf *bf; int error = 0, i; u32 size; ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize - ah->caps.rx_status_len); ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_LP], ah->caps.rx_lp_qdepth); ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_HP], ah->caps.rx_hp_qdepth); size = sizeof(struct ath_rxbuf) * nbufs; bf = devm_kzalloc(sc->dev, size, GFP_KERNEL); if (!bf) return -ENOMEM; INIT_LIST_HEAD(&sc->rx.rxbuf); for (i = 0; i < nbufs; i++, bf++) { skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL); if (!skb) { error = -ENOMEM; goto rx_init_fail; } memset(skb->data, 0, common->rx_bufsize); bf->bf_mpdu = skb; bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, common->rx_bufsize, DMA_BIDIRECTIONAL); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; bf->bf_buf_addr = 0; ath_err(common, "dma_mapping_error() on RX init\n"); error = -ENOMEM; goto rx_init_fail; } list_add_tail(&bf->list, &sc->rx.rxbuf); } return 0; rx_init_fail: ath_rx_edma_cleanup(sc); return error; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau30797.77%360.00%
ben greearben greear61.91%120.00%
joe perchesjoe perches10.32%120.00%
Total314100.00%5100.00%


static void ath_edma_start_recv(struct ath_softc *sc) { ath9k_hw_rxena(sc->sc_ah); ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP); ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP); ath_opmode_init(sc); ath9k_hw_startpcureceive(sc->sc_ah, sc->cur_chan->offchannel); }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau4692.00%250.00%
luis r. rodriguezluis r. rodriguez36.00%125.00%
sujith manoharansujith manoharan12.00%125.00%
Total50100.00%4100.00%


static void ath_edma_stop_recv(struct ath_softc *sc) { ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau25100.00%1100.00%
Total25100.00%1100.00%


int ath_rx_init(struct ath_softc *sc, int nbufs) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct sk_buff *skb; struct ath_rxbuf *bf; int error = 0; spin_lock_init(&sc->sc_pcu_lock); common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + sc->sc_ah->caps.rx_status_len; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) return ath_rx_edma_init(sc, nbufs); ath_dbg(common, CONFIG, "cachelsz %u rxbufsize %u\n", common->cachelsz, common->rx_bufsize); /* Initialize rx descriptors */ error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, "rx", nbufs, 1, 0); if (error != 0) { ath_err(common, "failed to allocate rx descriptors: %d\n", error); goto err; } list_for_each_entry(bf, &sc->rx.rxbuf, list) { skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL); if (skb == NULL) { error = -ENOMEM; goto err; } bf->bf_mpdu = skb; bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, common->rx_bufsize, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; bf->bf_buf_addr = 0; ath_err(common, "dma_mapping_error() on RX init\n"); error = -ENOMEM; goto err; } } sc->rx.rxlink = NULL; err: if (error) ath_rx_cleanup(sc); return error; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau27695.50%333.33%
ben greearben greear62.08%111.11%
joe perchesjoe perches41.38%333.33%
vasanthakumar thiagarajanvasanthakumar thiagarajan20.69%111.11%
luis r. rodriguezluis r. rodriguez10.35%111.11%
Total289100.00%9100.00%


void ath_rx_cleanup(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; struct ath_rxbuf *bf; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { ath_rx_edma_cleanup(sc); return; } list_for_each_entry(bf, &sc->rx.rxbuf, list) { skb = bf->bf_mpdu; if (skb) { dma_unmap_single(sc->dev, bf->bf_buf_addr, common->rx_bufsize, DMA_FROM_DEVICE); dev_kfree_skb(skb); bf->bf_buf_addr = 0; bf->bf_mpdu = NULL; } } }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau10389.57%266.67%
ben greearben greear1210.43%133.33%
Total115100.00%3100.00%

/* * Calculate the receive filter according to the * operating mode and state: * * o always accept unicast, broadcast, and multicast traffic * o maintain current state of phy error reception (the hal * may enable phy error frames for noise immunity work) * o probe request frames are accepted only when operating in * hostap, adhoc, or monitor modes * o enable promiscuous mode according to the interface state * o accept beacons: * - when operating in adhoc mode so the 802.11 layer creates * node table entries for peers, * - when operating in station mode for collecting rssi data when * the station is otherwise quiet, or * - when operating as a repeater so we see repeater-sta beacons * - when scanning */
u32 ath_calcrxfilter(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); u32 rfilt; if (config_enabled(CONFIG_ATH9K_TX99)) return 0; rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ATH9K_RX_FILTER_MCAST; /* if operating on a DFS channel, enable radar pulse detection */ if (sc->hw->conf.radar_enabled) rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR; spin_lock_bh(&sc->chan_lock); if (sc->cur_chan->rxfilter & FIF_PROBE_REQ) rfilt |= ATH9K_RX_FILTER_PROBEREQ; if (sc->sc_ah->is_monitoring) rfilt |= ATH9K_RX_FILTER_PROM; if ((sc->cur_chan->rxfilter & FIF_CONTROL) || sc->sc_ah->dynack.enabled) rfilt |= ATH9K_RX_FILTER_CONTROL; if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && (sc->cur_chan->nvifs <= 1) && !(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC)) rfilt |= ATH9K_RX_FILTER_MYBEACON; else if (sc->sc_ah->opmode != NL80211_IFTYPE_OCB) rfilt |= ATH9K_RX_FILTER_BEACON; if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || (sc->cur_chan->rxfilter & FIF_PSPOLL)) rfilt |= ATH9K_RX_FILTER_PSPOLL; if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT) rfilt |= ATH9K_RX_FILTER_COMP_BAR; if (sc->cur_chan->nvifs > 1 || (sc->cur_chan->rxfilter & FIF_OTHER_BSS)) { /* This is needed for older chips */ if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160) rfilt |= ATH9K_RX_FILTER_PROM; rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; } if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah) || AR_SREV_9561(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_4ADDRESS; if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_CONTROL_WRAPPER; if (ath9k_is_chanctx_enabled() && test_bit(ATH_OP_SCANNING, &common->op_flags)) rfilt |= ATH9K_RX_FILTER_BEACON; spin_unlock_bh(&sc->chan_lock); return rfilt; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau17252.12%314.29%
sujith manoharansujith manoharan4613.94%628.57%
miaoqing panmiaoqing pan278.18%29.52%
zefir kurtisizefir kurtisi175.15%14.76%
ben greearben greear154.55%14.76%
gabor juhosgabor juhos133.94%14.76%
luis r. rodriguezluis r. rodriguez133.94%29.52%
jan kaisrlikjan kaisrlik113.33%14.76%
lorenzo bianconilorenzo bianconi103.03%14.76%
jouni malinenjouni malinen30.91%14.76%
thomas wagnerthomas wagner20.61%14.76%
rajkumar manoharanrajkumar manoharan10.30%14.76%
Total330100.00%21100.00%


void ath_startrecv(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_rxbuf *bf, *tbf; if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { ath_edma_start_recv(sc); return; } if (list_empty(&sc->rx.rxbuf)) goto start_recv; sc->rx.buf_hold = NULL; sc->rx.rxlink = NULL; list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { ath_rx_buf_link(sc, bf, false); } /* We could have deleted elements so the list may be empty now */ if (list_empty(&sc->rx.rxbuf)) goto start_recv; bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list); ath9k_hw_putrxbuf(ah, bf->bf_daddr); ath9k_hw_rxena(ah); start_recv: ath_opmode_init(sc); ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel); }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau15696.30%562.50%
luis r. rodriguezluis r. rodriguez31.85%112.50%
sujith manoharansujith manoharan31.85%225.00%
Total162100.00%8100.00%


static void ath_flushrecv(struct ath_softc *sc) { if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_rx_tasklet(sc, 1, true); ath_rx_tasklet(sc, 1, false); }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau3687.80%266.67%
luis r. rodriguezluis r. rodriguez512.20%133.33%
Total41100.00%3100.00%


bool ath_stoprecv(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; bool stopped, reset = false; ath9k_hw_abortpcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah, &reset); ath_flushrecv(sc); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_edma_stop_recv(sc); else sc->rx.rxlink = NULL; if (!(ah->ah_flags & AH_UNPLUGGED) && unlikely(!stopped)) { ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, "Failed to stop Rx DMA\n"); RESET_STAT_INC(sc, RESET_RX_DMA_ERROR); } return stopped && !reset; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau9273.60%660.00%
ben greearben greear1713.60%110.00%
rajkumar manoharanrajkumar manoharan97.20%110.00%
luis r. rodriguezluis r. rodriguez75.60%220.00%
Total125100.00%10100.00%


static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) { /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ struct ieee80211_mgmt *mgmt; u8 *pos, *end, id, elen; struct ieee80211_tim_ie *tim; mgmt = (struct ieee80211_mgmt *)skb->data; pos = mgmt->u.beacon.variable; end = skb->data + skb->len; while (pos + 2 < end) { id = *pos++; elen = *pos++; if (pos + elen > end) break; if (id == WLAN_EID_TIM) { if (elen < sizeof(*tim)) break; tim = (struct ieee80211_tim_ie *) pos; if (tim->dtim_count != 0) break; return tim->bitmap_ctrl & 0x01; } pos += elen; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau11679.45%112.50%
sujith manoharansujith manoharan138.90%337.50%
luis r. rodriguezluis r. rodriguez74.79%112.50%
jouni malinenjouni malinen42.74%112.50%
senthil balasubramaniansenthil balasubramanian42.74%112.50%
javier cardonajavier cardona21.37%112.50%
Total146100.00%8100.00%


static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); bool skip_beacon = false; if (skb->len < 24 + 8 + 2 + 2) return; sc->ps_flags &= ~PS_WAIT_FOR_BEACON; if (sc->ps_flags & PS_BEACON_SYNC) { sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT if (ath9k_is_chanctx_enabled()) { if (sc->cur_chan == &sc->offchannel.chan) skip_beacon = true; } #endif if (!skip_beacon && !(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) ath9k_set_beacon(sc); ath9k_p2p_beacon_sync(sc); } if (ath_beacon_dtim_pending_cab(skb)) { /* * Remain awake waiting for buffered broadcast/multicast * frames. If the last broadcast/multicast frame is not * received properly, the next beacon frame will work as * a backup trigger for returning into NETWORK SLEEP state, * so we are waiting for it as well. */ ath_dbg(common, PS, "Received DTIM beacon indicating buffered broadcast/multicast frame(s)\n"); sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON; return; } if (sc->ps_flags & PS_WAIT_FOR_CAB) { /* * This can happen if a broadcast frame is dropped or the AP * fails to send a frame indicating that all CAB frames have * been delivered. */ sc->ps_flags &= ~PS_WAIT_FOR_CAB; ath_dbg(common, PS, "PS wait for CAB frames timed out\n"); } }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau8040.82%214.29%
sujith manoharansujith manoharan5025.51%750.00%
luis r. rodriguezluis r. rodriguez4120.92%17.14%
ben greearben greear157.65%17.14%
joe perchesjoe perches73.57%214.29%
rajkumar manoharanrajkumar manoharan31.53%17.14%
Total196100.00%14100.00%


static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon) { struct ieee80211_hdr *hdr; struct ath_common *common = ath9k_hw_common(sc->sc_ah); hdr = (struct ieee80211_hdr *)skb->data; /* Process Beacon and CAB receive in PS state */ if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc)) && mybeacon) { ath_rx_ps_beacon(sc, skb); } else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && (ieee80211_is_data(hdr->frame_control) || ieee80211_is_action(hdr->frame_control)) && is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_moredata(hdr->frame_control)) { /* * No more broadcast/multicast frames to be received at this * point. */ sc->ps_flags &= ~(PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON); ath_dbg(common, PS, "All PS CAB frames received, back to sleep\n"); } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA; ath_dbg(common, PS, "Going back to sleep after having received PS-Poll data (0x%lx)\n", sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | PS_WAIT_FOR_TX_ACK)); } }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau13668.00%111.11%
luis r. rodriguezluis r. rodriguez3618.00%111.11%
sujith manoharansujith manoharan84.00%222.22%
vasanthakumar thiagarajanvasanthakumar thiagarajan73.50%111.11%
joe perchesjoe perches52.50%222.22%
senthil balasubramaniansenthil balasubramanian42.00%111.11%
rajkumar manoharanrajkumar manoharan42.00%111.11%
Total200100.00%9100.00%


static bool ath_edma_get_buffers(struct ath_softc *sc, enum ath9k_rx_qtype qtype, struct ath_rx_status *rs, struct ath_rxbuf **dest) { struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype]; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; struct ath_rxbuf *bf; int ret; skb = skb_peek(&rx_edma->rx_fifo); if (!skb) return false; bf = SKB_CB_ATHBUF(skb); BUG_ON(!bf); dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, common->rx_bufsize, DMA_FROM_DEVICE); ret = ath9k_hw_process_rxdesc_edma(ah, rs, skb->data); if (ret == -EINPROGRESS) { /*let device gain the buffer again*/ dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, common->rx_bufsize, DMA_FROM_DEVICE); return false; } __skb_unlink(skb, &rx_edma->rx_fifo); if (ret == -EINVAL) { /* corrupt descriptor, skip this one and the following one */ list_add_tail(&bf->list, &sc->rx.rxbuf); ath_rx_edma_buf_link(sc, qtype); skb = skb_peek(&rx_edma->rx_fifo); if (skb) { bf = SKB_CB_ATHBUF(skb); BUG_ON(!bf); __skb_unlink(skb, &rx_edma->rx_fifo); list_add_tail(&bf->list, &sc->rx.rxbuf); ath_rx_edma_buf_link(sc, qtype); } bf = NULL; } *dest = bf; return true; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau18666.67%337.50%
jouni malinenjouni malinen5820.79%225.00%
lei minglei ming217.53%112.50%
luis r. rodriguezluis r. rodriguez93.23%112.50%
gabor juhosgabor juhos51.79%112.50%
Total279100.00%8100.00%


static struct ath_rxbuf *ath_edma_get_next_rx_buf(struct ath_softc *sc, struct ath_rx_status *rs, enum ath9k_rx_qtype qtype) { struct ath_rxbuf *bf = NULL; while (ath_edma_get_buffers(sc, qtype, rs, &bf)) { if (!bf) continue; return bf; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau3663.16%360.00%
jouni malinenjouni malinen2136.84%240.00%
Total57100.00%5100.00%


static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc, struct ath_rx_status *rs) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; struct ath_rxbuf *bf; int ret; if (list_empty(&sc->rx.rxbuf)) { sc->rx.rxlink = NULL; return NULL; } bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list); if (bf == sc->rx.buf_hold) return NULL; ds = bf->bf_desc; /* * Must provide the virtual address of the current * descriptor, the physical address, and the virtual * address of the next descriptor in the h/w chain. * This allows the HAL to look ahead to see if the * hardware is done with a descriptor by checking the * done bit in the following descriptor and the address * of the current descriptor the DMA engine is working * on. All this is necessary because of our use of * a self-linked list to avoid rx overruns. */ ret = ath9k_hw_rxprocdesc(ah, ds, rs); if (ret == -EINPROGRESS) { struct ath_rx_status trs; struct ath_rxbuf *tbf; struct ath_desc *tds; memset(&trs, 0, sizeof(trs)); if (list_is_last(&bf->list, &sc->rx.rxbuf)) { sc->rx.rxlink = NULL; return NULL; } tbf = list_entry(bf->list.next, struct ath_rxbuf, list); /* * On some hardware the descriptor status words could * get corrupted, including the done bit. Because of * this, check if the next descriptor's done bit is * set or not. * * If the next descriptor's done bit is set, the current * descriptor has been corrupted. Force s/w to discard * this descriptor and continue... */ tds = tbf->bf_desc; ret = ath9k_hw_rxprocdesc(ah, tds, &trs); if (ret == -EINPROGRESS) return NULL; /* * Re-check previous descriptor, in case it has been filled * in the mean time. */ ret = ath9k_hw_rxprocdesc(ah, ds, rs); if (ret == -EINPROGRESS) { /* * mark descriptor as zero-length and set the 'more' * flag to ensure that both buffers get discarded */ rs->rs_datalen = 0; rs->rs_more = true; } } list_del(&bf->list); if (!bf->bf_mpdu) return bf; /* * Synchronize the DMA transfer with CPU before * 1. accessing the frame * 2. requeueing the same buffer to h/w */ dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, common->rx_bufsize, DMA_FROM_DEVICE); return bf; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau25181.76%660.00%
jouni malinenjouni malinen5016.29%110.00%
johannes bergjohannes berg30.98%110.00%
luis r. rodriguezluis r. rodriguez20.65%110.00%
lei minglei ming10.33%110.00%
Total307100.00%10100.00%


static void ath9k_process_tsf(struct ath_rx_status *rs, struct ieee80211_rx_status *rxs, u64 tsf) { u32 tsf_lower = tsf & 0xffffffff; rxs->mactime = (tsf & ~0xffffffffULL) | rs->rs_tstamp; if (rs->rs_tstamp > tsf_lower && unlikely(rs->rs_tstamp - tsf_lower > 0x10000000)) rxs->mactime -= 0x100000000ULL; if (rs->rs_tstamp < tsf_lower && unlikely(tsf_lower - rs->rs_tstamp > 0x10000000)) rxs->mactime += 0x100000000ULL; }

Contributors

PersonTokensPropCommitsCommitProp
sujith manoharansujith manoharan91100.00%1100.00%
Total91100.00%1100.00%

/* * For Decrypt or Demic errors, we only mark packet status here and always push * up the frame up to let mac80211 handle the actual error case, be it no * decryption key or real decryption error. This let us keep statistics there. */
static int ath9k_rx_skb_preprocess(struct ath_softc *sc, struct sk_buff *skb, struct ath_rx_status *rx_stats, struct ieee80211_rx_status *rx_status, bool *decrypt_error, u64 tsf) { struct ieee80211_hw *hw = sc->hw; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hdr *hdr; bool discard_current = sc->rx.discard_next; /* * Discard corrupt descriptors which are marked in * ath_get_next_rx_buf(). */ if (discard_current) goto corrupt; sc->rx.discard_next = false; /* * Discard zero-length packets. */ if (!rx_stats->rs_datalen) { RX_STAT_INC(rx_len_err); goto corrupt; } /* * rs_status follows rs_datalen so if rs_datalen is too large * we can take a hint that hardware corrupted it, so ignore * those frames. */ if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { RX_STAT_INC(rx_len_err); goto corrupt; } /* Only use status info from the last fragment */ if (rx_stats->rs_more) return 0; /* * Return immediately if the RX descriptor has been marked * as corrupt based on the various error bits. * * This is different from the other corrupt descriptor * condition handled above. */ if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) goto corrupt; hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); ath9k_process_tsf(rx_stats, rx_status, tsf); ath_debug_stat_rx(sc, rx_stats); /* * Process PHY errors and return so that the packet * can be dropped. */ if (rx_stats->rs_status & ATH9K_RXERR_PHY) { ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime); if (ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats, rx_status->mactime)) RX_STAT_INC(rx_spectral); return -EINVAL; } /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. */ spin_lock_bh(&sc->chan_lock); if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->cur_chan->rxfilter)) { spin_unlock_bh(&sc->chan_lock); return -EINVAL; } spin_unlock_bh(&sc->chan_lock); if (ath_is_mybeacon(common, hdr)) { RX_STAT_INC(rx_beacons); rx_stats->is_mybeacon = true; } /* * This shouldn't happen, but have a safety check anyway. */ if (WARN_ON(!ah->curchan)) return -EINVAL; if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) { /* * No valid hardware bitrate found -- we should not get here * because hardware has already validated this frame as OK. */ ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", rx_stats->rs_rate); RX_STAT_INC(rx_rate_err); return -EINVAL; } if (ath9k_is_chanctx_enabled()) { if (rx_stats->is_mybeacon) ath_chanctx_beacon_recv_ev(sc, ATH_CHANCTX_EVENT_BEACON_RECEIVED); } ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); rx_status->band = ah->curchan->chan->band; rx_status->freq = ah->curchan->chan->center_freq; rx_status->antenna = rx_stats->rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_END; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT if (ieee80211_is_data_present(hdr->frame_control) && !ieee80211_is_qos_nullfunc(hdr->frame_control)) sc->rx.num_pkts++; #endif return 0; corrupt: sc->rx.discard_next = rx_stats->rs_more; return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
sujith manoharansujith manoharan37977.19%1257.14%
oleksij rempeloleksij rempel479.57%628.57%
felix fietkaufelix fietkau448.96%29.52%
simon wunderlichsimon wunderlich214.28%14.76%
Total491100.00%21100.00%

/* * Run the LNA combining algorithm only in these cases: * * Standalone WLAN cards with both LNA/Antenna diversity * enabled in the EEPROM. * * WLAN+BT cards which are in the supported card list * in ath_pci_id_table and the user has loaded the * driver with "bt_ant_diversity" set to true. */
static void ath9k_antenna_check(struct ath_softc *sc, struct ath_rx_status *rs) { struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) return; /* * Change the default rx antenna if rx diversity * chooses the other antenna 3 times in a row. */ if (sc->rx.defant != rs->rs_antenna) { if (++sc->rx.rxotherant >= 3) ath_setdefantenna(sc, rs->rs_antenna); } else { sc->rx.rxotherant = 0; } if (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV) { if (common->bt_ant_diversity) ath_ant_comb_scan(sc, rs); } else { ath_ant_comb_scan(sc, rs); } }

Contributors

PersonTokensPropCommitsCommitProp
sujith manoharansujith manoharan138100.00%1100.00%
Total138100.00%1100.00%


static void ath9k_apply_ampdu_details(struct ath_softc *sc, struct ath_rx_status *rs, struct ieee80211_rx_status *rxs) { if (rs->rs_isaggr) { rxs->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN; rxs->ampdu_reference = sc->rx.ampdu_ref; if (!rs->rs_moreaggr) { rxs->flag |= RX_FLAG_AMPDU_IS_LAST; sc->rx.ampdu_ref++; } if (rs->rs_flags & ATH9K_RX_DELIM_CRC_PRE) rxs->flag |= RX_FLAG_AMPDU_DELIM_CRC_ERROR; } }

Contributors

PersonTokensPropCommitsCommitProp
christian lamparterchristian lamparter83100.00%1100.00%
Total83100.00%1100.00%


int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { struct ath_rxbuf *bf; struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb; struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hw *hw = sc->hw; int retval; struct ath_rx_status rs; enum ath9k_rx_qtype qtype; bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int dma_type; u64 tsf = 0; unsigned long flags; dma_addr_t new_buf_addr; unsigned int budget = 512; struct ieee80211_hdr *hdr; if (edma) dma_type = DMA_BIDIRECTIONAL; else dma_type = DMA_FROM_DEVICE; qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; tsf = ath9k_hw_gettsf64(ah); do { bool decrypt_error = false; memset(&rs, 0, sizeof(rs)); if (edma) bf = ath_edma_get_next_rx_buf(sc, &rs, qtype); else bf = ath_get_next_rx_buf(sc, &rs); if (!bf) break; skb = bf->bf_mpdu; if (!skb) continue; /* * Take frame header from the first fragment and RX status from * the last one. */ if (sc->rx.frag) hdr_skb = sc->rx.frag; else hdr_skb = skb; rxs = IEEE80211_SKB_RXCB(hdr_skb); memset(rxs, 0, sizeof(struct ieee80211_rx_status)); retval = ath9k_rx_skb_preprocess(sc, hdr_skb, &rs, rxs, &decrypt_error, tsf); if (retval) goto requeue_drop_frag; /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC); /* If there is no memory we ignore the current RX'd frame, * tell hardware it can give us a new frame using the old * skb and put it at the tail of the sc->rx.rxbuf list for * processing. */ if (!requeue_skb) { RX_STAT_INC(rx_oom_err); goto requeue_drop_frag; } /* We will now give hardware our shiny new allocated skb */ new_buf_addr = dma_map_single(sc->dev, requeue_skb->data, common->rx_bufsize, dma_type); if (unlikely(dma_mapping_error(sc->dev, new_buf_addr))) { dev_kfree_skb_any(requeue_skb); goto requeue_drop_frag; } /* Unmap the frame */ dma_unmap_single(sc->dev, bf->bf_buf_addr, common->rx_bufsize, dma_type); bf->bf_mpdu = requeue_skb; bf->bf_buf_addr = new_buf_addr; skb_put(skb, rs.rs_datalen + ah->caps.rx_status_len); if (ah->caps.rx_status_len) skb_pull(skb, ah->caps.rx_status_len); if (!rs.rs_more) ath9k_cmn_rx_skb_postprocess(common, hdr_skb, &rs, rxs, decrypt_error); if (rs.rs_more) { RX_STAT_INC(rx_frags); /* * rs_more indicates chained descriptors which can be * used to link buffers together for a sort of * scatter-gather operation. */ if (sc->rx.frag) { /* too many fragments - cannot handle frame */ dev_kfree_skb_any(sc->rx.frag); dev_kfree_skb_any(skb); RX_STAT_INC(rx_too_many_frags_err); skb = NULL; } sc->rx.frag = skb; goto requeue; } if (sc->rx.frag) { int space = skb->len - skb_tailroom(hdr_skb); if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { dev_kfree_skb(skb); RX_STAT_INC(rx_oom_err); goto requeue_drop_frag; } sc->rx.frag = NULL; skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len), skb->len); dev_kfree_skb_any(skb); skb = hdr_skb; } if (rxs->flag & RX_FLAG_MMIC_STRIPPED) skb_trim(skb, skb->len - 8); spin_lock_irqsave(&sc->sc_pm_lock, flags); if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA)) || ath9k_check_auto_sleep(sc)) ath_rx_ps(sc, skb, rs.is_mybeacon); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ath9k_antenna_check(sc, &rs); ath9k_apply_ampdu_details(sc, &rs, rxs); ath_debug_rate_stats(sc, &rs, skb); hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_ack(hdr->frame_control)) ath_dynack_sample_ack_ts(sc->sc_ah, skb, rs.rs_tstamp); ieee80211_rx(hw, skb); requeue_drop_frag: if (sc->rx.frag) { dev_kfree_skb_any(sc->rx.frag); sc->rx.frag = NULL; } requeue: list_add_tail(&bf->list, &sc->rx.rxbuf); if (!edma) { ath_rx_buf_relink(sc, bf, flush); if (!flush) ath9k_hw_rxena(ah); } else if (!flush) { ath_rx_edma_buf_link(sc, qtype); } if (!budget--) break; } while (1); if (!(ah->imask & ATH9K_INT_RXEOL)) { ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN); ath9k_hw_set_interrupts(ah); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau34440.23%1323.21%
vasanthakumar thiagarajanvasanthakumar thiagarajan14917.43%35.36%
sujith manoharansujith manoharan9110.64%1017.86%
luis r. rodriguezluis r. rodriguez677.84%814.29%
lorenzo bianconilorenzo bianconi435.03%23.57%
rajkumar manoharanrajkumar manoharan323.74%23.57%
ben greearben greear222.57%11.79%
zefir kurtisizefir kurtisi222.57%11.79%
tim harveytim harvey182.11%23.57%
ashok nagarajanashok nagarajan131.52%11.79%
vivek natarajanvivek natarajan111.29%11.79%
jouni malinenjouni malinen111.29%35.36%
christian lamparterchristian lamparter101.17%11.79%
eric dumazeteric dumazet80.94%11.79%
mohammed shafi shajakhanmohammed shafi shajakhan70.82%23.57%
gabor juhosgabor juhos40.47%35.36%
senthil balasubramaniansenthil balasubramanian20.23%11.79%
oleksij rempeloleksij rempel10.12%11.79%
Total855100.00%56100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
felix fietkaufelix fietkau273053.12%2616.99%
sujith manoharansujith manoharan103620.16%4227.45%
luis r. rodriguezluis r. rodriguez3997.76%2214.38%
vasanthakumar thiagarajanvasanthakumar thiagarajan1873.64%42.61%
jouni malinenjouni malinen1472.86%74.58%
christian lamparterchristian lamparter931.81%10.65%
ben greearben greear931.81%53.27%
mohammed shafi shajakhanmohammed shafi shajakhan711.38%42.61%
lorenzo bianconilorenzo bianconi531.03%31.96%
rajkumar manoharanrajkumar manoharan490.95%53.27%
oleksij rempeloleksij rempel480.93%74.58%
zefir kurtisizefir kurtisi390.76%21.31%
miaoqing panmiaoqing pan270.53%21.31%
gabor juhosgabor juhos230.45%53.27%
lei minglei ming220.43%10.65%
simon wunderlichsimon wunderlich210.41%10.65%
joe perchesjoe perches190.37%31.96%
tim harveytim harvey180.35%21.31%
ashok nagarajanashok nagarajan130.25%10.65%
vivek natarajanvivek natarajan110.21%10.65%
jan kaisrlikjan kaisrlik110.21%10.65%
senthil balasubramaniansenthil balasubramanian110.21%31.96%
eric dumazeteric dumazet80.16%10.65%
alexey dobriyanalexey dobriyan30.06%10.65%
johannes bergjohannes berg30.06%10.65%
javier cardonajavier cardona20.04%10.65%
thomas wagnerthomas wagner20.04%10.65%
Total5139100.00%153100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}