iwlwifi: dynamic allocate tx queue structure
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / iwl-tx.c
index a7422e52d8836f8333137b79c631f7f0d0467db9..625da63d01ee99e294da86f2594744a2dff66d2e 100644 (file)
@@ -197,6 +197,12 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
                pci_free_consistent(dev, priv->hw_params.tfd_size *
                                    txq->q.n_bd, txq->tfds, txq->q.dma_addr);
 
+       /* deallocate arrays */
+       kfree(txq->cmd);
+       kfree(txq->meta);
+       txq->cmd = NULL;
+       txq->meta = NULL;
+
        /* 0-fill queue descriptor structure */
        memset(txq, 0, sizeof(*txq));
 }
@@ -399,15 +405,19 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
        int txq_id;
 
        /* Tx queues */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-               if (txq_id == IWL_CMD_QUEUE_NUM)
-                       iwl_cmd_queue_free(priv);
-               else
-                       iwl_tx_queue_free(priv, txq_id);
-
+       if (priv->txq)
+               for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
+                    txq_id++)
+                       if (txq_id == IWL_CMD_QUEUE_NUM)
+                               iwl_cmd_queue_free(priv);
+                       else
+                               iwl_tx_queue_free(priv, txq_id);
        iwl_free_dma_ptr(priv, &priv->kw);
 
        iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
+
+       /* free tx queue structure */
+       iwl_free_txq_mem(priv);
 }
 EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
 
@@ -439,6 +449,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
                IWL_ERR(priv, "Keep Warm allocation failed\n");
                goto error_kw;
        }
+
+       /* allocate tx queue structure */
+       ret = iwl_alloc_txq_mem(priv);
+       if (ret)
+               goto error;
+
        spin_lock_irqsave(&priv->lock, flags);
 
        /* Turn off all Tx DMA fifos */
@@ -703,7 +719,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        dma_addr_t phys_addr;
        dma_addr_t txcmd_phys;
        dma_addr_t scratch_phys;
-       u16 len, len_org;
+       u16 len, len_org, firstlen, secondlen;
        u16 seq_number = 0;
        __le16 fc;
        u8 hdr_len;
@@ -836,7 +852,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                sizeof(struct iwl_cmd_header) + hdr_len;
 
        len_org = len;
-       len = (len + 3) & ~3;
+       firstlen = len = (len + 3) & ~3;
 
        if (len_org != len)
                len_org = 1;
@@ -870,7 +886,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        /* Set up TFD's 2nd entry to point directly to remainder of skb,
         * if any (802.11 null frames have no payload). */
-       len = skb->len - hdr_len;
+       secondlen = len = skb->len - hdr_len;
        if (len) {
                phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
                                           len, PCI_DMA_TODEVICE);
@@ -904,6 +920,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
                                       len, PCI_DMA_BIDIRECTIONAL);
 
+       trace_iwlwifi_dev_tx(priv,
+                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
+                            sizeof(struct iwl_tfd),
+                            &out_cmd->hdr, firstlen,
+                            skb->data + hdr_len, secondlen);
+
        /* Tell device the write index *just past* this latest filled TFD */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
        ret = iwl_txq_update_write_ptr(priv, txq);
@@ -963,13 +985,19 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
               !(cmd->flags & CMD_SIZE_HUGE));
 
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
+       if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
+               IWL_DEBUG_INFO(priv, "Not sending command - RF/CT KILL\n");
                return -EIO;
        }
 
        if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
                IWL_ERR(priv, "No space for Tx\n");
+               if (iwl_within_ct_kill_margin(priv))
+                       iwl_tt_enter_ct_kill(priv);
+               else {
+                       IWL_ERR(priv, "Restarting adapter due to queue full\n");
+                       queue_work(priv->workqueue, &priv->restart);
+               }
                return -ENOSPC;
        }
 
@@ -1032,6 +1060,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        pci_unmap_addr_set(out_meta, mapping, phys_addr);
        pci_unmap_len_set(out_meta, len, fix_size);
 
+       trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
+
        priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
                                                   phys_addr, fix_size, 1,
                                                   U32_PAD(cmd->len));
@@ -1394,7 +1424,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
 
        info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
        memset(&info->status, 0, sizeof(info->status));
-       info->flags = IEEE80211_TX_STAT_ACK;
+       info->flags |= IEEE80211_TX_STAT_ACK;
        info->flags |= IEEE80211_TX_STAT_AMPDU;
        info->status.ampdu_ack_map = successes;
        info->status.ampdu_ack_len = agg->frame_count;
This page took 0.02963 seconds and 5 git commands to generate.