diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/recv.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 92 |
1 files changed, 64 insertions, 28 deletions
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index cece1c4c6bda..61edfab20ffc 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -145,6 +145,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, u8 ratecode; __le16 fc; struct ieee80211_hw *hw; + struct ieee80211_sta *sta; + struct ath_node *an; + int last_rssi = ATH_RSSI_DUMMY_MARKER; + hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; @@ -229,17 +233,57 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } } + rcu_read_lock(); + sta = ieee80211_find_sta(sc->hw, hdr->addr2); + if (sta) { + an = (struct ath_node *) sta->drv_priv; + if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && + !ds->ds_rxstat.rs_moreaggr) + ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi); + last_rssi = an->last_rssi; + } + rcu_read_unlock(); + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi, + ATH_RSSI_EP_MULTIPLIER); + if (ds->ds_rxstat.rs_rssi < 0) + ds->ds_rxstat.rs_rssi = 0; + else if (ds->ds_rxstat.rs_rssi > 127) + ds->ds_rxstat.rs_rssi = 127; + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; rx_status->noise = sc->ani.noise_floor; - rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; + rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi; rx_status->antenna = ds->ds_rxstat.rs_antenna; - /* at 45 you will be able to use MCS 15 reliably. A more elaborate - * scheme can be used here but it requires tables of SNR/throughput for - * each possible mode used. */ - rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + /* + * Theory for reporting quality: + * + * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. + * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. + * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. + * + * MCS 7 is the highets MCS index usable by a 1-stream device. + * MCS 15 is the highest MCS index usable by a 2-stream device. + * + * All ath9k devices are either 1-stream or 2-stream. + * + * How many bars you see is derived from the qual reporting. + * + * A more elaborate scheme can be used here but it requires tables + * of SNR/throughput for each possible mode used. For the MCS table + * you can refer to the wireless wiki: + * + * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n + * + */ + if (conf_is_ht(&hw->conf)) + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + else + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35; /* rssi can be more than 45 though, anything above that * should be considered at 100% */ @@ -505,11 +549,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) return false; } -static void ath_rx_ps_back_to_sleep(struct ath_softc *sc) -{ - sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); -} - static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) { struct ieee80211_mgmt *mgmt; @@ -521,6 +560,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) return; /* not from our current AP */ + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + if (sc->sc_flags & SC_OP_BEACON_SYNC) { sc->sc_flags &= ~SC_OP_BEACON_SYNC; DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on " @@ -528,14 +569,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) ath_beacon_config(sc, NULL); } - if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) { - /* We are not in PS mode anymore; remain awake */ - DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain " - "awake\n"); - sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); - return; - } - if (ath_beacon_dtim_pending_cab(skb)) { /* * Remain awake waiting for buffered broadcast/multicast @@ -556,11 +589,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * fails to send a frame indicating that all CAB frames have * been delivered. */ + sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); } - - /* No more broadcast/multicast frames to be received at this point. */ - ath_rx_ps_back_to_sleep(sc); } static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) @@ -578,13 +609,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) ieee80211_is_action(hdr->frame_control)) && is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_moredata(hdr->frame_control)) { - DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " - "sleep\n"); /* * No more broadcast/multicast frames to be received at this * point. */ - ath_rx_ps_back_to_sleep(sc); + sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; + DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " + "sleep\n"); } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { @@ -619,13 +650,18 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, if (aphy == NULL) continue; nskb = skb_copy(skb, GFP_ATOMIC); - if (nskb) - __ieee80211_rx(aphy->hw, nskb, rx_status); + if (nskb) { + memcpy(IEEE80211_SKB_RXCB(nskb), rx_status, + sizeof(*rx_status)); + ieee80211_rx(aphy->hw, nskb); + } } - __ieee80211_rx(sc->hw, skb, rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); + ieee80211_rx(sc->hw, skb); } else { /* Deliver unicast frames based on receiver address */ - __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); + ieee80211_rx(ath_get_virt_hw(sc, hdr), skb); } } |