aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwl8k.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r--drivers/net/wireless/mwl8k.c77
1 files changed, 46 insertions, 31 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 6598efcda5cc..3f55aa0c8db3 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -202,8 +202,8 @@ struct mwl8k_priv {
202 */ 202 */
203 struct work_struct finalize_join_worker; 203 struct work_struct finalize_join_worker;
204 204
205 /* Tasklet to reclaim TX descriptors and buffers after tx */ 205 /* Tasklet to perform TX reclaim. */
206 struct tasklet_struct tx_reclaim_task; 206 struct tasklet_struct poll_tx_task;
207}; 207};
208 208
209/* Per interface specific private data */ 209/* Per interface specific private data */
@@ -2963,13 +2963,16 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
2963 u32 status; 2963 u32 status;
2964 2964
2965 status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 2965 status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
2966 iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
2967
2968 if (!status) 2966 if (!status)
2969 return IRQ_NONE; 2967 return IRQ_NONE;
2970 2968
2971 if (status & MWL8K_A2H_INT_TX_DONE) 2969 if (status & MWL8K_A2H_INT_TX_DONE) {
2972 tasklet_schedule(&priv->tx_reclaim_task); 2970 status &= ~MWL8K_A2H_INT_TX_DONE;
2971 tasklet_schedule(&priv->poll_tx_task);
2972 }
2973
2974 if (status)
2975 iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
2973 2976
2974 if (status & MWL8K_A2H_INT_RX_READY) { 2977 if (status & MWL8K_A2H_INT_RX_READY) {
2975 while (rxq_process(hw, 0, 1)) 2978 while (rxq_process(hw, 0, 1))
@@ -2990,6 +2993,35 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
2990 return IRQ_HANDLED; 2993 return IRQ_HANDLED;
2991} 2994}
2992 2995
2996static void mwl8k_tx_poll(unsigned long data)
2997{
2998 struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
2999 struct mwl8k_priv *priv = hw->priv;
3000 int limit;
3001 int i;
3002
3003 limit = 32;
3004
3005 spin_lock_bh(&priv->tx_lock);
3006
3007 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3008 limit -= mwl8k_txq_reclaim(hw, i, limit, 0);
3009
3010 if (!priv->pending_tx_pkts && priv->tx_wait != NULL) {
3011 complete(priv->tx_wait);
3012 priv->tx_wait = NULL;
3013 }
3014
3015 spin_unlock_bh(&priv->tx_lock);
3016
3017 if (limit) {
3018 writel(~MWL8K_A2H_INT_TX_DONE,
3019 priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
3020 } else {
3021 tasklet_schedule(&priv->poll_tx_task);
3022 }
3023}
3024
2993 3025
2994/* 3026/*
2995 * Core driver operations. 3027 * Core driver operations.
@@ -3026,7 +3058,7 @@ static int mwl8k_start(struct ieee80211_hw *hw)
3026 } 3058 }
3027 3059
3028 /* Enable tx reclaim tasklet */ 3060 /* Enable tx reclaim tasklet */
3029 tasklet_enable(&priv->tx_reclaim_task); 3061 tasklet_enable(&priv->poll_tx_task);
3030 3062
3031 /* Enable interrupts */ 3063 /* Enable interrupts */
3032 iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 3064 iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
@@ -3059,7 +3091,7 @@ static int mwl8k_start(struct ieee80211_hw *hw)
3059 if (rc) { 3091 if (rc) {
3060 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 3092 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
3061 free_irq(priv->pdev->irq, hw); 3093 free_irq(priv->pdev->irq, hw);
3062 tasklet_disable(&priv->tx_reclaim_task); 3094 tasklet_disable(&priv->poll_tx_task);
3063 } 3095 }
3064 3096
3065 return rc; 3097 return rc;
@@ -3084,7 +3116,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
3084 dev_kfree_skb(priv->beacon_skb); 3116 dev_kfree_skb(priv->beacon_skb);
3085 3117
3086 /* Stop tx reclaim tasklet */ 3118 /* Stop tx reclaim tasklet */
3087 tasklet_disable(&priv->tx_reclaim_task); 3119 tasklet_disable(&priv->poll_tx_task);
3088 3120
3089 /* Return all skbs to mac80211 */ 3121 /* Return all skbs to mac80211 */
3090 for (i = 0; i < MWL8K_TX_QUEUES; i++) 3122 for (i = 0; i < MWL8K_TX_QUEUES; i++)
@@ -3643,23 +3675,6 @@ static const struct ieee80211_ops mwl8k_ops = {
3643 .ampdu_action = mwl8k_ampdu_action, 3675 .ampdu_action = mwl8k_ampdu_action,
3644}; 3676};
3645 3677
3646static void mwl8k_tx_reclaim_handler(unsigned long data)
3647{
3648 int i;
3649 struct ieee80211_hw *hw = (struct ieee80211_hw *) data;
3650 struct mwl8k_priv *priv = hw->priv;
3651
3652 spin_lock_bh(&priv->tx_lock);
3653 for (i = 0; i < MWL8K_TX_QUEUES; i++)
3654 mwl8k_txq_reclaim(hw, i, INT_MAX, 0);
3655
3656 if (priv->tx_wait != NULL && !priv->pending_tx_pkts) {
3657 complete(priv->tx_wait);
3658 priv->tx_wait = NULL;
3659 }
3660 spin_unlock_bh(&priv->tx_lock);
3661}
3662
3663static void mwl8k_finalize_join_worker(struct work_struct *work) 3678static void mwl8k_finalize_join_worker(struct work_struct *work)
3664{ 3679{
3665 struct mwl8k_priv *priv = 3680 struct mwl8k_priv *priv =
@@ -3859,9 +3874,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
3859 INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); 3874 INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
3860 3875
3861 /* TX reclaim tasklet */ 3876 /* TX reclaim tasklet */
3862 tasklet_init(&priv->tx_reclaim_task, 3877 tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
3863 mwl8k_tx_reclaim_handler, (unsigned long)hw); 3878 tasklet_disable(&priv->poll_tx_task);
3864 tasklet_disable(&priv->tx_reclaim_task);
3865 3879
3866 /* Power management cookie */ 3880 /* Power management cookie */
3867 priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); 3881 priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
@@ -3890,7 +3904,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
3890 3904
3891 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 3905 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
3892 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 3906 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
3893 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); 3907 iowrite32(MWL8K_A2H_INT_TX_DONE,
3908 priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
3894 iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 3909 iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
3895 3910
3896 rc = request_irq(priv->pdev->irq, mwl8k_interrupt, 3911 rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
@@ -4018,7 +4033,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
4018 ieee80211_unregister_hw(hw); 4033 ieee80211_unregister_hw(hw);
4019 4034
4020 /* Remove tx reclaim tasklet */ 4035 /* Remove tx reclaim tasklet */
4021 tasklet_kill(&priv->tx_reclaim_task); 4036 tasklet_kill(&priv->poll_tx_task);
4022 4037
4023 /* Stop hardware */ 4038 /* Stop hardware */
4024 mwl8k_hw_reset(priv); 4039 mwl8k_hw_reset(priv);