iwlagn: do nothing when disable agg in wrong state
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / iwl-trans-pcie-tx.c
index 62c00523b3bf9ec42410f0c82249125cb6294e57..fec7065e75e63763d413c3e1a9efe7b27389354a 100644 (file)
@@ -59,13 +59,15 @@ void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
        u8 sta_id = 0;
        u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
        __le16 bc_ent;
+       struct iwl_tx_cmd *tx_cmd =
+               (struct iwl_tx_cmd *) txq->cmd[txq->q.write_ptr]->payload;
 
        scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
 
        WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
 
-       sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
-       sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
+       sta_id = tx_cmd->sta_id;
+       sec_ctl = tx_cmd->sec_ctl;
 
        switch (sec_ctl & TX_CMD_SEC_MSK) {
        case TX_CMD_SEC_CCM:
@@ -353,11 +355,13 @@ static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
        int read_ptr = txq->q.read_ptr;
        u8 sta_id = 0;
        __le16 bc_ent;
+       struct iwl_tx_cmd *tx_cmd =
+               (struct iwl_tx_cmd *) txq->cmd[txq->q.read_ptr]->payload;
 
        WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
 
        if (txq_id != trans->shrd->cmd_queue)
-               sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
+               sta_id = tx_cmd->sta_id;
 
        bc_ent = cpu_to_le16(1 | (sta_id << 12));
        scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
@@ -544,7 +548,7 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_tid_data *tid_data;
        unsigned long flags;
-       u16 txq_id;
+       int txq_id;
 
        txq_id = iwlagn_txq_ctx_activate_free(trans);
        if (txq_id == -1) {
@@ -632,6 +636,8 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans,
        default:
                IWL_WARN(trans, "Stopping AGG while state not ON"
                                "or starting\n");
+               spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
+               return 0;
        }
 
        write_ptr = trans_pcie->txq[txq_id].q.write_ptr;
@@ -762,8 +768,6 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
        if (cmd->flags & CMD_WANT_SKB)
                out_meta->source = cmd;
-       if (cmd->flags & CMD_ASYNC)
-               out_meta->callback = cmd->callback;
 
        /* set up the header */
 
@@ -775,7 +779,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        /* and copy the data that needs to be copied */
 
-       cmd_dest = &out_cmd->cmd.payload[0];
+       cmd_dest = out_cmd->payload;
        for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
                if (!cmd->len[i])
                        continue;
@@ -894,12 +898,15 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
 /**
  * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
  * @rxb: Rx buffer to reclaim
+ * @handler_status: return value of the handler of the command
+ *     (put in setup_rx_handlers)
  *
  * If an Rx buffer has an async callback associated with it the callback
  * will be executed.  The attached skb (if present) will only be freed
  * if the callback returns 1
  */
-void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb)
+void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb,
+                        int handler_status)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -928,21 +935,28 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb)
        cmd = txq->cmd[cmd_index];
        meta = &txq->meta[cmd_index];
 
+       txq->time_stamp = jiffies;
+
        iwlagn_unmap_tfd(trans, meta, &txq->tfds[index],
                         DMA_BIDIRECTIONAL);
 
        /* Input error checking is done when commands are added to queue. */
        if (meta->flags & CMD_WANT_SKB) {
                meta->source->reply_page = (unsigned long)rxb_addr(rxb);
+               meta->source->handler_status = handler_status;
                rxb->page = NULL;
-       } else if (meta->callback)
-               meta->callback(trans->shrd, cmd, pkt);
+       }
 
        spin_lock_irqsave(&trans->hcmd_lock, flags);
 
        iwl_hcmd_queue_reclaim(trans, txq_id, index);
 
        if (!(meta->flags & CMD_ASYNC)) {
+               if (!test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) {
+                       IWL_WARN(trans,
+                                "HCMD_ACTIVE already clear for command %s\n",
+                                get_cmd_string(cmd->hdr.cmd));
+               }
                clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
                IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
                               get_cmd_string(cmd->hdr.cmd));
@@ -956,30 +970,6 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb)
 
 #define HOST_COMPLETE_TIMEOUT (2 * HZ)
 
-static void iwl_generic_cmd_callback(struct iwl_shared *shrd,
-                                    struct iwl_device_cmd *cmd,
-                                    struct iwl_rx_packet *pkt)
-{
-       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERR(shrd->trans, "Bad return from %s (0x%08X)\n",
-                       get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
-               return;
-       }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       switch (cmd->hdr.cmd) {
-       case REPLY_TX_LINK_QUALITY_CMD:
-       case SENSITIVITY_CMD:
-               IWL_DEBUG_HC_DUMP(shrd->trans, "back from %s (0x%08X)\n",
-                               get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
-               break;
-       default:
-               IWL_DEBUG_HC(shrd->trans, "back from %s (0x%08X)\n",
-                               get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
-       }
-#endif
-}
-
 static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 {
        int ret;
@@ -988,9 +978,6 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (WARN_ON(cmd->flags & CMD_WANT_SKB))
                return -EINVAL;
 
-       /* Assign a generic callback if one is not provided */
-       if (!cmd->callback)
-               cmd->callback = iwl_generic_cmd_callback;
 
        if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
                return -EBUSY;
@@ -1012,10 +999,6 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        lockdep_assert_held(&trans->shrd->mutex);
 
-        /* A synchronous command can not have a callback set. */
-       if (WARN_ON(cmd->callback))
-               return -EINVAL;
-
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                        get_cmd_string(cmd->id));
 
@@ -1037,11 +1020,20 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                        HOST_COMPLETE_TIMEOUT);
        if (!ret) {
                if (test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) {
+                       struct iwl_priv *priv = priv(trans);
+                       struct iwl_tx_queue *txq =
+                               &trans_pcie->txq[priv->shrd->cmd_queue];
+                       struct iwl_queue *q = &txq->q;
+
                        IWL_ERR(trans,
                                "Error sending %s: time out after %dms.\n",
                                get_cmd_string(cmd->id),
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
+                       IWL_ERR(trans,
+                               "Current CMD queue read_ptr %d write_ptr %d\n",
+                               q->read_ptr, q->write_ptr);
+
                        clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
                        IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command"
                                 "%s\n", get_cmd_string(cmd->id));
This page took 0.02749 seconds and 5 git commands to generate.