diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 77 |
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 | ||
2996 | static 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 | ||
3646 | static 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 | |||
3663 | static void mwl8k_finalize_join_worker(struct work_struct *work) | 3678 | static 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); |