wl1251: add U-APSD support
[deliverable/linux.git] / drivers / net / wireless / mwl8k.c
index 6598efcda5cc2700c0a75cf244b4b132f2b3b444..13b0e32b051af0c0f8b23a89581e4f39e96b8225 100644 (file)
@@ -202,8 +202,11 @@ struct mwl8k_priv {
         */
        struct work_struct finalize_join_worker;
 
-       /* Tasklet to reclaim TX descriptors and buffers after tx */
-       struct tasklet_struct tx_reclaim_task;
+       /* Tasklet to perform TX reclaim.  */
+       struct tasklet_struct poll_tx_task;
+
+       /* Tasklet to perform RX.  */
+       struct tasklet_struct poll_rx_task;
 };
 
 /* Per interface specific private data */
@@ -2963,19 +2966,22 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
        u32 status;
 
        status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
-       iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
-
        if (!status)
                return IRQ_NONE;
 
-       if (status & MWL8K_A2H_INT_TX_DONE)
-               tasklet_schedule(&priv->tx_reclaim_task);
+       if (status & MWL8K_A2H_INT_TX_DONE) {
+               status &= ~MWL8K_A2H_INT_TX_DONE;
+               tasklet_schedule(&priv->poll_tx_task);
+       }
 
        if (status & MWL8K_A2H_INT_RX_READY) {
-               while (rxq_process(hw, 0, 1))
-                       rxq_refill(hw, 0, 1);
+               status &= ~MWL8K_A2H_INT_RX_READY;
+               tasklet_schedule(&priv->poll_rx_task);
        }
 
+       if (status)
+               iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+
        if (status & MWL8K_A2H_INT_OPC_DONE) {
                if (priv->hostcmd_wait != NULL)
                        complete(priv->hostcmd_wait);
@@ -2990,6 +2996,53 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static void mwl8k_tx_poll(unsigned long data)
+{
+       struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+       struct mwl8k_priv *priv = hw->priv;
+       int limit;
+       int i;
+
+       limit = 32;
+
+       spin_lock_bh(&priv->tx_lock);
+
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               limit -= mwl8k_txq_reclaim(hw, i, limit, 0);
+
+       if (!priv->pending_tx_pkts && priv->tx_wait != NULL) {
+               complete(priv->tx_wait);
+               priv->tx_wait = NULL;
+       }
+
+       spin_unlock_bh(&priv->tx_lock);
+
+       if (limit) {
+               writel(~MWL8K_A2H_INT_TX_DONE,
+                      priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+       } else {
+               tasklet_schedule(&priv->poll_tx_task);
+       }
+}
+
+static void mwl8k_rx_poll(unsigned long data)
+{
+       struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+       struct mwl8k_priv *priv = hw->priv;
+       int limit;
+
+       limit = 32;
+       limit -= rxq_process(hw, 0, limit);
+       limit -= rxq_refill(hw, 0, limit);
+
+       if (limit) {
+               writel(~MWL8K_A2H_INT_RX_READY,
+                      priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+       } else {
+               tasklet_schedule(&priv->poll_rx_task);
+       }
+}
+
 
 /*
  * Core driver operations.
@@ -3025,8 +3078,9 @@ static int mwl8k_start(struct ieee80211_hw *hw)
                return -EIO;
        }
 
-       /* Enable tx reclaim tasklet */
-       tasklet_enable(&priv->tx_reclaim_task);
+       /* Enable TX reclaim and RX tasklets.  */
+       tasklet_enable(&priv->poll_tx_task);
+       tasklet_enable(&priv->poll_rx_task);
 
        /* Enable interrupts */
        iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
@@ -3059,7 +3113,8 @@ static int mwl8k_start(struct ieee80211_hw *hw)
        if (rc) {
                iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
                free_irq(priv->pdev->irq, hw);
-               tasklet_disable(&priv->tx_reclaim_task);
+               tasklet_disable(&priv->poll_tx_task);
+               tasklet_disable(&priv->poll_rx_task);
        }
 
        return rc;
@@ -3083,8 +3138,9 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
        if (priv->beacon_skb != NULL)
                dev_kfree_skb(priv->beacon_skb);
 
-       /* Stop tx reclaim tasklet */
-       tasklet_disable(&priv->tx_reclaim_task);
+       /* Stop TX reclaim and RX tasklets.  */
+       tasklet_disable(&priv->poll_tx_task);
+       tasklet_disable(&priv->poll_rx_task);
 
        /* Return all skbs to mac80211 */
        for (i = 0; i < MWL8K_TX_QUEUES; i++)
@@ -3643,23 +3699,6 @@ static const struct ieee80211_ops mwl8k_ops = {
        .ampdu_action           = mwl8k_ampdu_action,
 };
 
-static void mwl8k_tx_reclaim_handler(unsigned long data)
-{
-       int i;
-       struct ieee80211_hw *hw = (struct ieee80211_hw *) data;
-       struct mwl8k_priv *priv = hw->priv;
-
-       spin_lock_bh(&priv->tx_lock);
-       for (i = 0; i < MWL8K_TX_QUEUES; i++)
-               mwl8k_txq_reclaim(hw, i, INT_MAX, 0);
-
-       if (priv->tx_wait != NULL && !priv->pending_tx_pkts) {
-               complete(priv->tx_wait);
-               priv->tx_wait = NULL;
-       }
-       spin_unlock_bh(&priv->tx_lock);
-}
-
 static void mwl8k_finalize_join_worker(struct work_struct *work)
 {
        struct mwl8k_priv *priv =
@@ -3858,10 +3897,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
        /* Finalize join worker */
        INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
 
-       /* TX reclaim tasklet */
-       tasklet_init(&priv->tx_reclaim_task,
-                       mwl8k_tx_reclaim_handler, (unsigned long)hw);
-       tasklet_disable(&priv->tx_reclaim_task);
+       /* TX reclaim and RX tasklets.  */
+       tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
+       tasklet_disable(&priv->poll_tx_task);
+       tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw);
+       tasklet_disable(&priv->poll_rx_task);
 
        /* Power management cookie */
        priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
@@ -3890,7 +3930,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
        iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
        iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
-       iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
+       iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY,
+                 priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
        iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
 
        rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
@@ -4017,8 +4058,9 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
 
        ieee80211_unregister_hw(hw);
 
-       /* Remove tx reclaim tasklet */
-       tasklet_kill(&priv->tx_reclaim_task);
+       /* Remove TX reclaim and RX tasklets.  */
+       tasklet_kill(&priv->poll_tx_task);
+       tasklet_kill(&priv->poll_rx_task);
 
        /* Stop hardware */
        mwl8k_hw_reset(priv);
This page took 0.028911 seconds and 5 git commands to generate.