diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2009-10-22 14:19:37 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-11-04 18:44:43 -0500 |
commit | 88de754ad59025eba797e7a8375807755577f450 (patch) | |
tree | 630531ea3a88e8b80ba8c564654af93d7ae0e2b6 /drivers/net/wireless/mwl8k.c | |
parent | c2c357ce309221b85fd36e50aade66d01a556cde (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.c | 37 |
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 | ||
1067 | static inline int mwl8k_txq_busy(struct mwl8k_priv *priv) | ||
1068 | { | ||
1069 | return priv->pending_tx_pkts; | ||
1070 | } | ||
1071 | |||
1072 | struct mwl8k_txq_info { | 1069 | struct 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 | */ |
1118 | static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | 1113 | static 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) |