]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/iwlwifi/iwl-tx.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-nvram
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / iwlwifi / iwl-tx.c
index 7d8b4e2d509473cad53300ecc2bfab3c3f1b3210..b0ee86c6268501754651206d88b87fdcfceb2401 100644 (file)
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -56,6 +56,26 @@ static const u16 default_tid_to_tx_fifo[] = {
        IWL_TX_FIFO_AC3
 };
 
+static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
+                                   struct iwl_dma_ptr *ptr, size_t size)
+{
+       ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma);
+       if (!ptr->addr)
+               return -ENOMEM;
+       ptr->size = size;
+       return 0;
+}
+
+static inline void iwl_free_dma_ptr(struct iwl_priv *priv,
+                                   struct iwl_dma_ptr *ptr)
+{
+       if (unlikely(!ptr->addr))
+               return;
+
+       pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma);
+       memset(ptr, 0, sizeof(*ptr));
+}
+
 static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
 {
        struct iwl_tfd_tb *tb = &tfd->tbs[idx];
@@ -429,11 +449,6 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
        iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
                             txq->q.dma_addr >> 8);
 
-       /* Enable DMA channel, using same id as for TFD queue */
-       iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
-                       FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-                       FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -517,8 +532,9 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
                else
                        iwl_tx_queue_free(priv, txq_id);
 
-       /* Keep-warm buffer */
-       iwl_kw_free(priv);
+       iwl_free_dma_ptr(priv, &priv->kw);
+
+       iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
 }
 EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
 
@@ -535,13 +551,17 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
        int txq_id, slots_num;
        unsigned long flags;
 
-       iwl_kw_free(priv);
-
        /* Free all tx/cmd queues and keep-warm buffer */
        iwl_hw_txq_ctx_free(priv);
 
+       ret = iwl_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
+                               priv->hw_params.scd_bc_tbls_size);
+       if (ret) {
+               IWL_ERROR("Scheduler BC Table allocation failed\n");
+               goto error_bc_tbls;
+       }
        /* Alloc keep-warm buffer */
-       ret = iwl_kw_alloc(priv);
+       ret = iwl_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
        if (ret) {
                IWL_ERROR("Keep Warm allocation failed\n");
                goto error_kw;
@@ -556,17 +576,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
        /* Turn off all Tx DMA fifos */
        priv->cfg->ops->lib->txq_set_sched(priv, 0);
 
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-
-       /* Tell nic where to find the keep-warm buffer */
-       ret = iwl_kw_init(priv);
-       if (ret) {
-               IWL_ERROR("kw_init failed\n");
-               goto error_reset;
-       }
-
        /* Alloc and init all Tx queues, including the command queue (#4) */
        for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
                slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
@@ -584,8 +599,10 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
  error:
        iwl_hw_txq_ctx_free(priv);
  error_reset:
-       iwl_kw_free(priv);
+       iwl_free_dma_ptr(priv, &priv->kw);
  error_kw:
+       iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
+ error_bc_tbls:
        return ret;
 }
 
@@ -594,11 +611,9 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
  */
 void iwl_txq_ctx_stop(struct iwl_priv *priv)
 {
-
-       int txq_id;
+       int ch;
        unsigned long flags;
 
-
        /* Turn off all Tx DMA fifos */
        spin_lock_irqsave(&priv->lock, flags);
        if (iwl_grab_nic_access(priv)) {
@@ -609,12 +624,11 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)
        priv->cfg->ops->lib->txq_set_sched(priv, 0);
 
        /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               iwl_write_direct32(priv,
-                                  FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
+       for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
+               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
                iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
-                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
-                                   (txq_id), 200);
+                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+                                   1000);
        }
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -631,7 +645,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
                                  struct iwl_tx_cmd *tx_cmd,
                                  struct ieee80211_tx_info *info,
                                  struct ieee80211_hdr *hdr,
-                                 int is_unicast, u8 std_id)
+                                 u8 std_id)
 {
        __le16 fc = hdr->frame_control;
        __le32 tx_flags = tx_cmd->tx_flags;
@@ -820,7 +834,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        u16 len, len_org;
        u16 seq_number = 0;
        __le16 fc;
-       u8 hdr_len, unicast;
+       u8 hdr_len;
        u8 sta_id;
        u8 wait_write_ptr = 0;
        u8 tid = 0;
@@ -840,8 +854,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                goto drop_unlock;
        }
 
-       unicast = !is_multicast_ether_addr(hdr->addr1);
-
        fc = hdr->frame_control;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -980,7 +992,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        len = (u16)skb->len;
        tx_cmd->len = cpu_to_le16(len);
        /* TODO need this for burst mode later on */
-       iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id);
+       iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
 
        /* set is_hcca to 0; it probably will never be implemented */
        iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
@@ -1236,8 +1248,13 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
         * command queue then there a command routing bug has been introduced
         * in the queue management code. */
        if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
-                "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd))
+                "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n",
+                 txq_id, sequence,
+                 priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
+                 priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
+               iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32);
                return;
+       }
 
        cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
        cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
@@ -1469,7 +1486,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
                ack = bitmap & (1ULL << i);
                successes += !!ack;
                IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
-                       ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff,
+                       ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
                        agg->start_idx + i);
        }