aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwl8k.c
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2009-10-22 14:19:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-11-04 18:44:43 -0500
commit88de754ad59025eba797e7a8375807755577f450 (patch)
tree630531ea3a88e8b80ba8c564654af93d7ae0e2b6 /drivers/net/wireless/mwl8k.c
parentc2c357ce309221b85fd36e50aade66d01a556cde (diff)
mwl8k: minor transmit quiescing rework
Minor changes to the transmit quiescing logic: - Clarify the locking rules for ->tx_wait: only the holder of fw_mutex can wait for the TX path to become idle, but tx_wait itself is read and cleared by the TX reclaim tasklet under tx_lock. - Inline mwl8k_txq_busy() in its callers. - There's no need to kick the transmitter again in mwl8k_tx_wait_empty(), since it will have been kicked when the packets currently in the TX ring were added to it. - If the TX ring didn't drain in time, run mwl8k_scan_tx_ring() after reading priv->pending_pkts without dropping tx_lock in between. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r--drivers/net/wireless/mwl8k.c37
1 files changed, 15 insertions, 22 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 252ef9c83364..ba7b8efea778 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -142,12 +142,14 @@ struct mwl8k_priv {
142 struct mutex fw_mutex; 142 struct mutex fw_mutex;
143 struct task_struct *fw_mutex_owner; 143 struct task_struct *fw_mutex_owner;
144 int fw_mutex_depth; 144 int fw_mutex_depth;
145 struct completion *tx_wait;
146 struct completion *hostcmd_wait; 145 struct completion *hostcmd_wait;
147 146
148 /* lock held over TX and TX reap */ 147 /* lock held over TX and TX reap */
149 spinlock_t tx_lock; 148 spinlock_t tx_lock;
150 149
150 /* TX quiesce completion, protected by fw_mutex and tx_lock */
151 struct completion *tx_wait;
152
151 struct ieee80211_vif *vif; 153 struct ieee80211_vif *vif;
152 154
153 struct ieee80211_channel *current_channel; 155 struct ieee80211_channel *current_channel;
@@ -1064,11 +1066,6 @@ static inline void mwl8k_tx_start(struct mwl8k_priv *priv)
1064 ioread32(priv->regs + MWL8K_HIU_INT_CODE); 1066 ioread32(priv->regs + MWL8K_HIU_INT_CODE);
1065} 1067}
1066 1068
1067static inline int mwl8k_txq_busy(struct mwl8k_priv *priv)
1068{
1069 return priv->pending_tx_pkts;
1070}
1071
1072struct mwl8k_txq_info { 1069struct mwl8k_txq_info {
1073 u32 fw_owned; 1070 u32 fw_owned;
1074 u32 drv_owned; 1071 u32 drv_owned;
@@ -1088,7 +1085,6 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
1088 1085
1089 memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info)); 1086 memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info));
1090 1087
1091 spin_lock_bh(&priv->tx_lock);
1092 for (count = 0; count < MWL8K_TX_QUEUES; count++) { 1088 for (count = 0; count < MWL8K_TX_QUEUES; count++) {
1093 txq = priv->txq + count; 1089 txq = priv->txq + count;
1094 txinfo[count].len = txq->tx_stats.len; 1090 txinfo[count].len = txq->tx_stats.len;
@@ -1107,30 +1103,26 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
1107 txinfo[count].unused++; 1103 txinfo[count].unused++;
1108 } 1104 }
1109 } 1105 }
1110 spin_unlock_bh(&priv->tx_lock);
1111 1106
1112 return ndescs; 1107 return ndescs;
1113} 1108}
1114 1109
1115/* 1110/*
1116 * Must be called with hw->fw_mutex held and tx queues stopped. 1111 * Must be called with priv->fw_mutex held and tx queues stopped.
1117 */ 1112 */
1118static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) 1113static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
1119{ 1114{
1120 struct mwl8k_priv *priv = hw->priv; 1115 struct mwl8k_priv *priv = hw->priv;
1121 DECLARE_COMPLETION_ONSTACK(cmd_wait); 1116 DECLARE_COMPLETION_ONSTACK(tx_wait);
1122 u32 count; 1117 u32 count;
1123 unsigned long timeout; 1118 unsigned long timeout;
1124 1119
1125 might_sleep(); 1120 might_sleep();
1126 1121
1127 spin_lock_bh(&priv->tx_lock); 1122 spin_lock_bh(&priv->tx_lock);
1128 count = mwl8k_txq_busy(priv); 1123 count = priv->pending_tx_pkts;
1129 if (count) { 1124 if (count)
1130 priv->tx_wait = &cmd_wait; 1125 priv->tx_wait = &tx_wait;
1131 if (priv->radio_on)
1132 mwl8k_tx_start(priv);
1133 }
1134 spin_unlock_bh(&priv->tx_lock); 1126 spin_unlock_bh(&priv->tx_lock);
1135 1127
1136 if (count) { 1128 if (count) {
@@ -1138,20 +1130,20 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
1138 int index; 1130 int index;
1139 int newcount; 1131 int newcount;
1140 1132
1141 timeout = wait_for_completion_timeout(&cmd_wait, 1133 timeout = wait_for_completion_timeout(&tx_wait,
1142 msecs_to_jiffies(5000)); 1134 msecs_to_jiffies(5000));
1143 if (timeout) 1135 if (timeout)
1144 return 0; 1136 return 0;
1145 1137
1146 spin_lock_bh(&priv->tx_lock); 1138 spin_lock_bh(&priv->tx_lock);
1147 priv->tx_wait = NULL; 1139 priv->tx_wait = NULL;
1148 newcount = mwl8k_txq_busy(priv); 1140 newcount = priv->pending_tx_pkts;
1141 mwl8k_scan_tx_ring(priv, txinfo);
1149 spin_unlock_bh(&priv->tx_lock); 1142 spin_unlock_bh(&priv->tx_lock);
1150 1143
1151 printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n", 1144 printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n",
1152 __func__, __LINE__, count, newcount); 1145 __func__, __LINE__, count, newcount);
1153 1146
1154 mwl8k_scan_tx_ring(priv, txinfo);
1155 for (index = 0; index < MWL8K_TX_QUEUES; index++) 1147 for (index = 0; index < MWL8K_TX_QUEUES; index++)
1156 printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u " 1148 printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u "
1157 "DRV:%u U:%u\n", 1149 "DRV:%u U:%u\n",
@@ -2397,7 +2389,7 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
2397 2389
2398 if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { 2390 if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
2399 if (!mutex_is_locked(&priv->fw_mutex) && 2391 if (!mutex_is_locked(&priv->fw_mutex) &&
2400 priv->radio_on && mwl8k_txq_busy(priv)) 2392 priv->radio_on && priv->pending_tx_pkts)
2401 mwl8k_tx_start(priv); 2393 mwl8k_tx_start(priv);
2402 } 2394 }
2403 2395
@@ -2800,7 +2792,7 @@ static void mwl8k_tx_reclaim_handler(unsigned long data)
2800 for (i = 0; i < MWL8K_TX_QUEUES; i++) 2792 for (i = 0; i < MWL8K_TX_QUEUES; i++)
2801 mwl8k_txq_reclaim(hw, i, 0); 2793 mwl8k_txq_reclaim(hw, i, 0);
2802 2794
2803 if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) { 2795 if (priv->tx_wait != NULL && !priv->pending_tx_pkts) {
2804 complete(priv->tx_wait); 2796 complete(priv->tx_wait);
2805 priv->tx_wait = NULL; 2797 priv->tx_wait = NULL;
2806 } 2798 }
@@ -2932,11 +2924,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
2932 mutex_init(&priv->fw_mutex); 2924 mutex_init(&priv->fw_mutex);
2933 priv->fw_mutex_owner = NULL; 2925 priv->fw_mutex_owner = NULL;
2934 priv->fw_mutex_depth = 0; 2926 priv->fw_mutex_depth = 0;
2935 priv->tx_wait = NULL;
2936 priv->hostcmd_wait = NULL; 2927 priv->hostcmd_wait = NULL;
2937 2928
2938 spin_lock_init(&priv->tx_lock); 2929 spin_lock_init(&priv->tx_lock);
2939 2930
2931 priv->tx_wait = NULL;
2932
2940 for (i = 0; i < MWL8K_TX_QUEUES; i++) { 2933 for (i = 0; i < MWL8K_TX_QUEUES; i++) {
2941 rc = mwl8k_txq_init(hw, i); 2934 rc = mwl8k_txq_init(hw, i);
2942 if (rc) 2935 if (rc)