ath9k: Cleanup TX power calculation for 4K chips
[safe/jmp/linux-2.6] / drivers / net / wireless / ath / ath9k / recv.c
index b46badd..f6a8b1c 100644 (file)
@@ -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% */
@@ -404,8 +448,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
        else
                rfilt |= ATH9K_RX_FILTER_BEACON;
 
-       /* If in HOSTAP mode, want to enable reception of PSPOLL frames */
-       if (sc->sc_ah->opmode == NL80211_IFTYPE_AP)
+       if (sc->rx.rxfilter & FIF_PSPOLL)
                rfilt |= ATH9K_RX_FILTER_PSPOLL;
 
        if (sc->sec_wiphy) {
@@ -473,6 +516,154 @@ void ath_flushrecv(struct ath_softc *sc)
        spin_unlock_bh(&sc->rx.rxflushlock);
 }
 
+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;
+}
+
+static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
+{
+       struct ieee80211_mgmt *mgmt;
+
+       if (skb->len < 24 + 8 + 2 + 2)
+               return;
+
+       mgmt = (struct ieee80211_mgmt *)skb->data;
+       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 "
+                       "timestamp from the AP\n");
+               ath_beacon_config(sc, NULL);
+       }
+
+       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.
+                */
+               DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating "
+                       "buffered broadcast/multicast frame(s)\n");
+               sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON;
+               return;
+       }
+
+       if (sc->sc_flags & SC_OP_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->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+               DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
+       }
+}
+
+static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+
+       /* Process Beacon and CAB receive in PS state */
+       if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) &&
+           ieee80211_is_beacon(hdr->frame_control))
+               ath_rx_ps_beacon(sc, skb);
+       else if ((sc->sc_flags & SC_OP_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->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)) {
+               sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA;
+               DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
+                       "received PS-Poll data (0x%x)\n",
+                       sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+                                       SC_OP_WAIT_FOR_CAB |
+                                       SC_OP_WAIT_FOR_PSPOLL_DATA |
+                                       SC_OP_WAIT_FOR_TX_ACK));
+       }
+}
+
+static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
+                                   struct ieee80211_rx_status *rx_status)
+{
+       struct ieee80211_hdr *hdr;
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+
+       /* Send the frame to mac80211 */
+       if (is_multicast_ether_addr(hdr->addr1)) {
+               int i;
+               /*
+                * Deliver broadcast/multicast frames to all suitable
+                * virtual wiphys.
+                */
+               /* TODO: filter based on channel configuration */
+               for (i = 0; i < sc->num_sec_wiphy; i++) {
+                       struct ath_wiphy *aphy = sc->sec_wiphy[i];
+                       struct sk_buff *nskb;
+                       if (aphy == NULL)
+                               continue;
+                       nskb = skb_copy(skb, GFP_ATOMIC);
+                       if (nskb) {
+                               memcpy(IEEE80211_SKB_RXCB(nskb), rx_status,
+                                       sizeof(*rx_status));
+                               ieee80211_rx(aphy->hw, nskb);
+                       }
+               }
+               memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+               ieee80211_rx(sc->hw, skb);
+       } else {
+               /* Deliver unicast frames based on receiver address */
+               memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+               ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
+       }
+}
+
 int ath_rx_tasklet(struct ath_softc *sc, int flush)
 {
 #define PA2DESC(_sc, _pa)                                               \
@@ -597,7 +788,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                                 DMA_FROM_DEVICE);
 
                skb_put(skb, ds->ds_rxstat.rs_datalen);
-               skb->protocol = cpu_to_be16(ETH_P_CONTROL);
 
                /* see if any padding is done by the hw and remove it */
                hdr = (struct ieee80211_hdr *)skb->data;
@@ -622,7 +812,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 
                if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
                        rx_status.flag |= RX_FLAG_DECRYPTED;
-               } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
+               } else if (ieee80211_has_protected(fc)
                           && !decrypt_error && skb->len >= hdrlen + 4) {
                        keyix = skb->data[hdrlen + 3] >> 6;
 
@@ -631,36 +821,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                }
                if (ah->sw_mgmt_crypto &&
                    (rx_status.flag & RX_FLAG_DECRYPTED) &&
-                   ieee80211_is_mgmt(hdr->frame_control)) {
+                   ieee80211_is_mgmt(fc)) {
                        /* Use software decrypt for management frames. */
                        rx_status.flag &= ~RX_FLAG_DECRYPTED;
                }
 
-               /* Send the frame to mac80211 */
-               if (hdr->addr1[5] & 0x01) {
-                       int i;
-                       /*
-                        * Deliver broadcast/multicast frames to all suitable
-                        * virtual wiphys.
-                        */
-                       /* TODO: filter based on channel configuration */
-                       for (i = 0; i < sc->num_sec_wiphy; i++) {
-                               struct ath_wiphy *aphy = sc->sec_wiphy[i];
-                               struct sk_buff *nskb;
-                               if (aphy == NULL)
-                                       continue;
-                               nskb = skb_copy(skb, GFP_ATOMIC);
-                               if (nskb)
-                                       __ieee80211_rx(aphy->hw, nskb,
-                                                      &rx_status);
-                       }
-                       __ieee80211_rx(sc->hw, skb, &rx_status);
-               } else {
-                       /* Deliver unicast frames based on receiver address */
-                       __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb,
-                                      &rx_status);
-               }
-
                /* We will now give hardware our shiny new allocated skb */
                bf->bf_mpdu = requeue_skb;
                bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
@@ -672,6 +837,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                        bf->bf_mpdu = NULL;
                        DPRINTF(sc, ATH_DBG_FATAL,
                                "dma_mapping_error() on RX\n");
+                       ath_rx_send_to_mac80211(sc, skb, &rx_status);
                        break;
                }
                bf->bf_dmacontext = bf->bf_buf_addr;
@@ -687,11 +853,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                        sc->rx.rxotherant = 0;
                }
 
-               if (ieee80211_is_beacon(fc) &&
-                               (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) {
-                       sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
-                       ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
-               }
+               if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+                                            SC_OP_WAIT_FOR_CAB |
+                                            SC_OP_WAIT_FOR_PSPOLL_DATA)))
+                       ath_rx_ps(sc, skb);
+
+               ath_rx_send_to_mac80211(sc, skb, &rx_status);
+
 requeue:
                list_move_tail(&bf->list, &sc->rx.rxbuf);
                ath_rx_buf_link(sc, bf);