mwl8k: Handle watchdog event with highest prioriry
authorYogesh Ashok Powar <yogeshp@marvell.com>
Thu, 3 Jan 2013 07:54:19 +0000 (13:24 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 7 Jan 2013 20:18:27 +0000 (15:18 -0500)
Currently, command path waits till all the tx host queues
are empty. Whenever watchdog event is raised, firmware
expects driver to destroy ampdu queues immediately.

This requires corresponding commands i.e.
mwl8k_cmd_get_watchdog_bitmap and mwl8k_destroy_ba to be
sent without waiting for the tx queues to be completely
empty.

Use "watchdog_event_pending" to ensure the above mentioned
two commands are sent down immediately.

Signed-off-by: Nishant Sarmukadam <nishants@marvell.com>
Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwl8k.c

index 19afd2c..3b046cc 100644 (file)
@@ -213,6 +213,8 @@ struct mwl8k_priv {
        int fw_mutex_depth;
        struct completion *hostcmd_wait;
 
+       atomic_t watchdog_event_pending;
+
        /* lock held over TX and TX reap */
        spinlock_t tx_lock;
 
@@ -1527,6 +1529,9 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
                        return -EBUSY;
        }
 
+       if (atomic_read(&priv->watchdog_event_pending))
+               return 0;
+
        /*
         * The TX queues are stopped at this point, so this test
         * doesn't need to take ->tx_lock.
@@ -1548,6 +1553,14 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
                spin_unlock_bh(&priv->tx_lock);
                timeout = wait_for_completion_timeout(&tx_wait,
                            msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS));
+
+               if (atomic_read(&priv->watchdog_event_pending)) {
+                       spin_lock_bh(&priv->tx_lock);
+                       priv->tx_wait = NULL;
+                       spin_unlock_bh(&priv->tx_lock);
+                       return 0;
+               }
+
                spin_lock_bh(&priv->tx_lock);
 
                if (timeout) {
@@ -3645,6 +3658,7 @@ static void mwl8k_watchdog_ba_events(struct work_struct *work)
 
        spin_unlock(&priv->stream_lock);
 done:
+       atomic_dec(&priv->watchdog_event_pending);
        status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
        iowrite32((status | MWL8K_A2H_INT_BA_WATCHDOG),
                  priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
@@ -4346,6 +4360,10 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
        }
 
        if (status & MWL8K_A2H_INT_BA_WATCHDOG) {
+               iowrite32(~MWL8K_A2H_INT_BA_WATCHDOG,
+                         priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+
+               atomic_inc(&priv->watchdog_event_pending);
                status &= ~MWL8K_A2H_INT_BA_WATCHDOG;
                ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
        }
@@ -5520,6 +5538,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
        priv->sniffer_enabled = false;
        priv->wmm_enabled = false;
        priv->pending_tx_pkts = 0;
+       atomic_set(&priv->watchdog_event_pending, 0);
 
        rc = mwl8k_rxq_init(hw, 0);
        if (rc)