|
@@ -985,17 +985,31 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
|
|
|
|
|
|
if (iwl_queue_space(&txq->q) > txq->q.low_mark)
|
|
|
iwl_wake_queue(trans, txq);
|
|
|
+
|
|
|
+ if (q->read_ptr == q->write_ptr) {
|
|
|
+ IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id);
|
|
|
+ iwl_trans_pcie_unref(trans);
|
|
|
+ }
|
|
|
+
|
|
|
out:
|
|
|
spin_unlock_bh(&txq->lock);
|
|
|
}
|
|
|
|
|
|
-static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans)
|
|
|
+static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
|
|
|
+ const struct iwl_host_cmd *cmd)
|
|
|
{
|
|
|
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
|
int ret;
|
|
|
|
|
|
lockdep_assert_held(&trans_pcie->reg_lock);
|
|
|
|
|
|
+ if (!(cmd->flags & CMD_SEND_IN_IDLE) &&
|
|
|
+ !trans_pcie->ref_cmd_in_flight) {
|
|
|
+ trans_pcie->ref_cmd_in_flight = true;
|
|
|
+ IWL_DEBUG_RPM(trans, "set ref_cmd_in_flight - ref\n");
|
|
|
+ iwl_trans_pcie_ref(trans);
|
|
|
+ }
|
|
|
+
|
|
|
if (trans_pcie->cmd_in_flight)
|
|
|
return 0;
|
|
|
|
|
@@ -1036,6 +1050,12 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
|
|
|
|
|
|
lockdep_assert_held(&trans_pcie->reg_lock);
|
|
|
|
|
|
+ if (trans_pcie->ref_cmd_in_flight) {
|
|
|
+ trans_pcie->ref_cmd_in_flight = false;
|
|
|
+ IWL_DEBUG_RPM(trans, "clear ref_cmd_in_flight - unref\n");
|
|
|
+ iwl_trans_pcie_unref(trans);
|
|
|
+ }
|
|
|
+
|
|
|
if (WARN_ON(!trans_pcie->cmd_in_flight))
|
|
|
return 0;
|
|
|
|
|
@@ -1473,7 +1493,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|
|
mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
|
|
|
|
|
|
spin_lock_irqsave(&trans_pcie->reg_lock, flags);
|
|
|
- ret = iwl_pcie_set_cmd_in_flight(trans);
|
|
|
+ ret = iwl_pcie_set_cmd_in_flight(trans, cmd);
|
|
|
if (ret < 0) {
|
|
|
idx = ret;
|
|
|
spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
|
|
@@ -1819,9 +1839,13 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|
|
wait_write_ptr = ieee80211_has_morefrags(fc);
|
|
|
|
|
|
/* start timer if queue currently empty */
|
|
|
- if (txq->need_update && q->read_ptr == q->write_ptr &&
|
|
|
- trans_pcie->wd_timeout)
|
|
|
- mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
|
|
|
+ if (q->read_ptr == q->write_ptr) {
|
|
|
+ if (txq->need_update && trans_pcie->wd_timeout)
|
|
|
+ mod_timer(&txq->stuck_timer,
|
|
|
+ jiffies + trans_pcie->wd_timeout);
|
|
|
+ IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
|
|
|
+ iwl_trans_pcie_ref(trans);
|
|
|
+ }
|
|
|
|
|
|
/* Tell device the write index *just past* this latest filled TFD */
|
|
|
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr);
|