Merge branch 'master' of git://github.com/chunkeey/carl9170fw
[carl9170fw.git] / carlfw / src / wlan.c
index 94ed62250d806ed262cdc86c316d2df4370fa35c..b8d4ec436fca3f54ed5708c80407c4b9fc75e4cb 100644 (file)
@@ -345,6 +345,16 @@ static bool wlan_tx_status(struct dma_queue *queue,
        /* update hangcheck */
        fw.wlan.last_super_num[qidx] = 0;
 
+       /*
+        * Note:
+        * There could be a corner case when the TXFAIL is set
+        * even though the frame was properly ACKed by the peer:
+        *   a BlockAckReq with the immediate policy will cause
+        *   the receiving peer to produce a BlockACK unfortunately
+        *   the MAC in this chip seems to be expecting a legacy
+        *   ACK and marks the BAR as failed!
+        */
+
        if (!!(desc->ctrl & AR9170_CTRL_FAIL)) {
                txfail = !!(desc->ctrl & AR9170_CTRL_TXFAIL);
 
@@ -447,6 +457,18 @@ static bool wlan_tx_status(struct dma_queue *queue,
                fw.wlan.cab_queue_len[super->s.vif_id]--;
 #endif /* CONFIG_CARL9170FW_CAB_QUEUE */
 
+       if (unlikely(ieee80211_is_back_req(super->f.data.i3e.frame_control))) {
+               /*
+                * As explained above, the hardware seems to be
+                * incapable of matching BA to BARs. This is a
+                * problem especially with mac80211, because it
+                * does resent failed BARs which of course cause
+                * some mayhem in the receiver buffer at the HT
+                * peer on the other end.
+                */
+               success = true;
+       }
+
        wlan_tx_complete(super, success);
 
        /* recycle freed descriptors */
@@ -546,16 +568,15 @@ static void wlan_send_buffered_ba(void)
        baf->s.queue = AR9170_TXQ_VO;
        baf->f.hdr.length = sizeof(struct ieee80211_ba) + FCS_LEN;
 
-       /* HW Duration / Backoff */
-       baf->f.hdr.mac.backoff = 1;
-       baf->f.hdr.mac.hw_duration = 1;
+       baf->f.hdr.mac.no_ack = 1;
 
-       /* take the TX rate from the RX'd BAR */
-       baf->f.hdr.phy.set = ctx->phy;
-       baf->f.hdr.phy.tx_power = 29; /* 14.5 dBm */
+       baf->f.hdr.phy.modulation = 1; /* OFDM */
+       baf->f.hdr.phy.tx_power = 34; /* 17 dBm */
+       baf->f.hdr.phy.chains = 1;
+       baf->f.hdr.phy.mcs = AR9170_TXRX_PHY_RATE_OFDM_6M;
 
        /* format outgoing BA */
-       ba->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_NULLFUNC);
+       ba->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK);
        ba->duration = cpu_to_le16(0);
        memcpy(ba->ta, ctx->ta, 6);
        memcpy(ba->ra, ctx->ra, 6);
@@ -567,11 +588,7 @@ static void wlan_send_buffered_ba(void)
         */
        memset(ba->bitmap, 0x0, sizeof(ba->bitmap));
 
-       /*
-        * NB:
-        * not entirely sure if this is 100% correct?!
-        */
-       ba->control = ctx->control | cpu_to_le16(1);
+       ba->control = ctx->control;
        ba->start_seq_num = ctx->start_seq_num;
        wlan_tx_fw(&baf->s, NULL);
 }
@@ -589,7 +606,7 @@ static struct carl9170_bar_ctx *wlan_get_bar_cache_buffer(void)
        return tmp;
 }
 
-static void handle_bar(struct dma_desc *desc, struct ieee80211_hdr *hdr,
+static void handle_bar(struct dma_desc *desc __unused, struct ieee80211_hdr *hdr,
                       unsigned int len, unsigned int mac_err)
 {
        struct ieee80211_bar *bar;
@@ -626,19 +643,8 @@ static void handle_bar(struct dma_desc *desc, struct ieee80211_hdr *hdr,
        /* Brilliant! The BAR provides all necessary MACs! */
        memcpy(ctx->ra, bar->ta, 6);
        memcpy(ctx->ta, bar->ra, 6);
-
-       /*
-        * NB:
-        * not entirely sure if this is 100% correct to force the
-        * imm ack bit or not...
-        */
-       ctx->control = bar->control | cpu_to_le16(1);
+       ctx->control = bar->control;
        ctx->start_seq_num = bar->start_seq_num;
-       ctx->phy = ar9170_rx_to_phy(desc);
-       if (unlikely(!ctx->phy)) {
-               /* provide a backup, in case ar9170_rx_to_phy fails */
-               ctx->phy = cpu_to_le32(0x2cc301);
-       }
 }
 
 static void wlan_check_rx_overrun(void)