ath9k: make ath9k_hw_setbssidmask() and ath9k_hw_write_associd() use ath_hw
[safe/jmp/linux-2.6] / drivers / net / wireless / ath / ath9k / recv.c
index 76abbbe..529cab6 100644 (file)
@@ -100,38 +100,6 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
        return (tsf & ~0x7fff) | rstamp;
 }
 
-static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask)
-{
-       struct sk_buff *skb;
-       u32 off;
-
-       /*
-        * Cache-line-align.  This is important (for the
-        * 5210 at least) as not doing so causes bogus data
-        * in rx'd frames.
-        */
-
-       /* Note: the kernel can allocate a value greater than
-        * what we ask it to give us. We really only need 4 KB as that
-        * is this hardware supports and in fact we need at least 3849
-        * as that is the MAX AMSDU size this hardware supports.
-        * Unfortunately this means we may get 8 KB here from the
-        * kernel... and that is actually what is observed on some
-        * systems :( */
-       skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask);
-       if (skb != NULL) {
-               off = ((unsigned long) skb->data) % sc->cachelsz;
-               if (off != 0)
-                       skb_reserve(skb, sc->cachelsz - off);
-       } else {
-               DPRINTF(sc, ATH_DBG_FATAL,
-                       "skbuff alloc of size %u failed\n", len);
-               return NULL;
-       }
-
-       return skb;
-}
-
 /*
  * 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
@@ -145,6 +113,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 +201,61 @@ 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;
+
+       /* Update Beacon RSSI, this is used by ANI. */
+       if (ieee80211_is_beacon(fc))
+               sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi;
+
        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% */
@@ -264,7 +280,7 @@ static void ath_opmode_init(struct ath_softc *sc)
 
        /* configure bssid mask */
        if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
-               ath9k_hw_setbssidmask(sc);
+               ath9k_hw_setbssidmask(ah);
 
        /* configure operational mode */
        ath9k_hw_setopmode(ah);
@@ -288,23 +304,23 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
        spin_lock_init(&sc->rx.rxbuflock);
 
        sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
-                                min(sc->cachelsz, (u16)64));
+                                min(sc->common.cachelsz, (u16)64));
 
-       DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
-               sc->cachelsz, sc->rx.bufsize);
+       DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+               sc->common.cachelsz, sc->rx.bufsize);
 
        /* Initialize rx descriptors */
 
        error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
                                  "rx", nbufs, 1);
        if (error != 0) {
-               DPRINTF(sc, ATH_DBG_FATAL,
+               DPRINTF(sc->sc_ah, ATH_DBG_FATAL,
                        "failed to allocate rx descriptors: %d\n", error);
                goto err;
        }
 
        list_for_each_entry(bf, &sc->rx.rxbuf, list) {
-               skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
+               skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL);
                if (skb == NULL) {
                        error = -ENOMEM;
                        goto err;
@@ -318,7 +334,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
                                               bf->bf_buf_addr))) {
                        dev_kfree_skb_any(skb);
                        bf->bf_mpdu = NULL;
-                       DPRINTF(sc, ATH_DBG_FATAL,
+                       DPRINTF(sc->sc_ah, ATH_DBG_FATAL,
                                "dma_mapping_error() on RX init\n");
                        error = -ENOMEM;
                        goto err;
@@ -404,15 +420,18 @@ 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) {
+       if (conf_is_ht(&sc->hw->conf))
+               rfilt |= ATH9K_RX_FILTER_COMP_BAR;
+
+       if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
                /* TODO: only needed if more than one BSSID is in use in
                 * station/adhoc mode */
-               /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM
-                */
+               /* The following may also be needed for other 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;
        }
 
@@ -473,6 +492,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->sc_ah, 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->sc_ah, 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->sc_ah, 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->sc_ah, 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->sc_ah, 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)                                               \
@@ -582,7 +749,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 
                /* Ensure we always have an skb to requeue once we are done
                 * processing the current buffer's skb */
-               requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC);
+               requeue_skb = ath_rxbuf_alloc(&sc->common, sc->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
@@ -597,7 +764,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 +788,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 +797,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 (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)
-                                       __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,
@@ -670,8 +811,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                          bf->bf_buf_addr))) {
                        dev_kfree_skb_any(requeue_skb);
                        bf->bf_mpdu = NULL;
-                       DPRINTF(sc, ATH_DBG_FATAL,
+                       DPRINTF(sc->sc_ah, 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 +829,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);