]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/wireless/iwlwifi/iwl-agn-tx.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[net-next-2.6.git] / drivers / net / wireless / iwlwifi / iwl-agn-tx.c
index a732f1094e5d3a983a102d7afe3038eddc2eb6a2..f9134ceb69ab9d603ee5e86f58abe5615be745fb 100644 (file)
@@ -469,7 +469,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
        }
 
        /* Set up antennas */
-       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+                                             priv->hw_params.valid_tx_ant);
        rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
 
        /* Set the rate in the TX cmd */
@@ -567,10 +568,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        hdr_len = ieee80211_hdrlen(fc);
 
        /* Find index into station table for destination station */
-       if (!info->control.sta)
-               sta_id = priv->hw_params.bcast_sta_id;
-       else
-               sta_id = iwl_sta_id(info->control.sta);
+       sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -598,11 +596,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        }
 
        txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+
+       /* irqs already disabled/saved above when locking priv->lock */
+       spin_lock(&priv->sta_lock);
+
        if (ieee80211_is_data_qos(fc)) {
                qc = ieee80211_get_qos_ctl(hdr);
                tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-               if (unlikely(tid >= MAX_TID_COUNT))
+               if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
+                       spin_unlock(&priv->sta_lock);
                        goto drop_unlock;
+               }
                seq_number = priv->stations[sta_id].tid[tid].seq_number;
                seq_number &= IEEE80211_SCTL_SEQ;
                hdr->seq_ctrl = hdr->seq_ctrl &
@@ -620,15 +624,22 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        swq_id = txq->swq_id;
        q = &txq->q;
 
-       if (unlikely(iwl_queue_space(q) < q->high_mark))
+       if (unlikely(iwl_queue_space(q) < q->high_mark)) {
+               spin_unlock(&priv->sta_lock);
                goto drop_unlock;
+       }
 
-       if (ieee80211_is_data_qos(fc))
+       if (ieee80211_is_data_qos(fc)) {
                priv->stations[sta_id].tid[tid].tfds_in_queue++;
+               if (!ieee80211_has_morefrags(fc))
+                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
+       }
+
+       spin_unlock(&priv->sta_lock);
 
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
-       txq->txb[q->write_ptr].skb[0] = skb;
+       txq->txb[q->write_ptr].skb = skb;
 
        /* Set up first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[q->write_ptr];
@@ -694,8 +705,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        txcmd_phys = pci_map_single(priv->pci_dev,
                                    &out_cmd->hdr, len,
                                    PCI_DMA_BIDIRECTIONAL);
-       pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
-       pci_unmap_len_set(out_meta, len, len);
+       dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+       dma_unmap_len_set(out_meta, len, len);
        /* Add buffer containing Tx command and MAC(!) header to TFD's
         * first entry */
        priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -703,8 +714,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        if (!ieee80211_has_morefrags(hdr->frame_control)) {
                txq->need_update = 1;
-               if (qc)
-                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
        } else {
                wait_write_ptr = 1;
                txq->need_update = 0;
@@ -1009,6 +1018,8 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
        if (ret)
                return ret;
 
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       tid_data = &priv->stations[sta_id].tid[tid];
        if (tid_data->tfds_in_queue == 0) {
                IWL_DEBUG_HT(priv, "HW queue is empty\n");
                tid_data->agg.state = IWL_AGG_ON;
@@ -1018,6 +1029,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
                             tid_data->tfds_in_queue);
                tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
        }
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
        return ret;
 }
 
@@ -1040,11 +1052,14 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                return -ENXIO;
        }
 
+       spin_lock_irqsave(&priv->sta_lock, flags);
+
        if (priv->stations[sta_id].tid[tid].agg.state ==
                                IWL_EMPTYING_HW_QUEUE_ADDBA) {
                IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
                return 0;
        }
 
@@ -1062,13 +1077,17 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
                priv->stations[sta_id].tid[tid].agg.state =
                                IWL_EMPTYING_HW_QUEUE_DELBA;
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
                return 0;
        }
 
        IWL_DEBUG_HT(priv, "HW queue is empty\n");
        priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       /* do not restore/save irqs */
+       spin_unlock(&priv->sta_lock);
+       spin_lock(&priv->lock);
+
        /*
         * the only reason this call can fail is queue number out of range,
         * which can happen if uCode is reloaded and all the station
@@ -1092,6 +1111,8 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
        u8 *addr = priv->stations[sta_id].sta.sta.addr;
        struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
 
+       WARN_ON(!spin_is_locked(&priv->sta_lock));
+
        switch (priv->stations[sta_id].tid[tid].agg.state) {
        case IWL_EMPTYING_HW_QUEUE_DELBA:
                /* We are reclaiming the last packet of the */
@@ -1116,6 +1137,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
                }
                break;
        }
+
        return 0;
 }
 
@@ -1159,12 +1181,12 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               iwlagn_tx_status(priv, tx_info->skb[0]);
+               iwlagn_tx_status(priv, tx_info->skb);
 
-               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+               hdr = (struct ieee80211_hdr *)tx_info->skb->data;
                if (hdr && ieee80211_is_data_qos(hdr->frame_control))
                        nfreed++;
-               tx_info->skb[0] = NULL;
+               tx_info->skb = NULL;
 
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
                        priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
@@ -1188,7 +1210,7 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
        int i, sh, ack;
        u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
        u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-       u64 bitmap;
+       u64 bitmap, sent_bitmap;
        int successes = 0;
        struct ieee80211_tx_info *info;
 
@@ -1216,24 +1238,26 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
 
        /* check for success or failure according to the
         * transmitted bitmap and block-ack bitmap */
-       bitmap &= agg->bitmap;
+       sent_bitmap = bitmap & agg->bitmap;
 
        /* For each frame attempted in aggregation,
         * update driver's record of tx frame's status. */
-       for (i = 0; i < agg->frame_count ; i++) {
-               ack = bitmap & (1ULL << i);
-               successes += !!ack;
+       i = 0;
+       while (sent_bitmap) {
+               ack = sent_bitmap & 1ULL;
+               successes += ack;
                IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
                        ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
                        agg->start_idx + i);
+               sent_bitmap >>= 1;
+               ++i;
        }
 
-       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
        memset(&info->status, 0, sizeof(info->status));
        info->flags |= IEEE80211_TX_STAT_ACK;
        info->flags |= IEEE80211_TX_STAT_AMPDU;
        info->status.ampdu_ack_len = successes;
-       info->status.ampdu_ack_map = bitmap;
        info->status.ampdu_len = agg->frame_count;
        iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
 
@@ -1281,6 +1305,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        int index;
        int sta_id;
        int tid;
+       unsigned long flags;
 
        /* "flow" corresponds to Tx queue */
        u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
@@ -1303,7 +1328,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        /* Find index just before block-ack window */
        index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
 
-       /* TODO: Need to get this copy more safely - now good for debug */
+       spin_lock_irqsave(&priv->sta_lock, flags);
 
        IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
                           "sta_id = %d\n",
@@ -1339,4 +1364,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
 
                iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
        }
+
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
 }