aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2009-08-17 21:18:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:38:08 -0400
commit618952a7b19b796fce98364fb26551cbe3e16a75 (patch)
treeea1abbe59b699e423e13c50e970a7195a1ebd304
parent950d5b0191dc3e71017f336017f75f6189f39f08 (diff)
mwl8k: fix firmware command serialisation
The current mwl8k_priv->fw_lock spinlock doesn't actually protect against multiple commands being submitted at once, as it is not kept held over the entire firmware command submission. And since waiting for command completion sleeps, we can't use a spinlock anyway. To fix mwl8k firmware command serialisation properly, we have the following requirements: - Some commands require that the packet transmit path is idle when the command is issued. (For simplicity, we'll just quiesce the transmit path for every command.) - There are certain sequences of commands that need to be issued to the hardware sequentially, with no other intervening commands. This leads to an implementation of a "firmware lock" as a mutex that can be taken recursively, and which is taken by both the low-level command submission function (mwl8k_post_cmd) as well as any users of that function that require issuing of an atomic sequence of commands, and quiesces the transmit path whenever it's taken. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/mwl8k.c154
1 files changed, 89 insertions, 65 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 7bbdca418314..93b92680d070 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -139,13 +139,18 @@ struct mwl8k_priv {
139 139
140 struct pci_dev *pdev; 140 struct pci_dev *pdev;
141 u8 name[16]; 141 u8 name[16];
142 /* firmware access lock */
143 spinlock_t fw_lock;
144 142
145 /* firmware files and meta data */ 143 /* firmware files and meta data */
146 struct mwl8k_firmware fw; 144 struct mwl8k_firmware fw;
147 u32 part_num; 145 u32 part_num;
148 146
147 /* firmware access */
148 struct mutex fw_mutex;
149 struct task_struct *fw_mutex_owner;
150 int fw_mutex_depth;
151 struct completion *tx_wait;
152 struct completion *hostcmd_wait;
153
149 /* lock held over TX and TX reap */ 154 /* lock held over TX and TX reap */
150 spinlock_t tx_lock; 155 spinlock_t tx_lock;
151 156
@@ -179,9 +184,6 @@ struct mwl8k_priv {
179 bool radio_short_preamble; 184 bool radio_short_preamble;
180 bool wmm_enabled; 185 bool wmm_enabled;
181 186
182 /* Set if PHY config is in progress */
183 bool inconfig;
184
185 /* XXX need to convert this to handle multiple interfaces */ 187 /* XXX need to convert this to handle multiple interfaces */
186 bool capture_beacon; 188 bool capture_beacon;
187 u8 capture_bssid[ETH_ALEN]; 189 u8 capture_bssid[ETH_ALEN];
@@ -200,8 +202,6 @@ struct mwl8k_priv {
200 202
201 /* Work thread to serialize configuration requests */ 203 /* Work thread to serialize configuration requests */
202 struct workqueue_struct *config_wq; 204 struct workqueue_struct *config_wq;
203 struct completion *hostcmd_wait;
204 struct completion *tx_wait;
205}; 205};
206 206
207/* Per interface specific private data */ 207/* Per interface specific private data */
@@ -1113,6 +1113,9 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
1113 return ndescs; 1113 return ndescs;
1114} 1114}
1115 1115
1116/*
1117 * Must be called with hw->fw_mutex held and tx queues stopped.
1118 */
1116static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) 1119static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
1117{ 1120{
1118 struct mwl8k_priv *priv = hw->priv; 1121 struct mwl8k_priv *priv = hw->priv;
@@ -1122,9 +1125,6 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
1122 1125
1123 might_sleep(); 1126 might_sleep();
1124 1127
1125 if (priv->tx_wait != NULL)
1126 printk(KERN_ERR "WARNING Previous TXWaitEmpty instance\n");
1127
1128 spin_lock_bh(&priv->tx_lock); 1128 spin_lock_bh(&priv->tx_lock);
1129 count = mwl8k_txq_busy(priv); 1129 count = mwl8k_txq_busy(priv);
1130 if (count) { 1130 if (count) {
@@ -1140,7 +1140,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
1140 int newcount; 1140 int newcount;
1141 1141
1142 timeout = wait_for_completion_timeout(&cmd_wait, 1142 timeout = wait_for_completion_timeout(&cmd_wait,
1143 msecs_to_jiffies(1000)); 1143 msecs_to_jiffies(5000));
1144 if (timeout) 1144 if (timeout)
1145 return 0; 1145 return 0;
1146 1146
@@ -1149,7 +1149,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
1149 newcount = mwl8k_txq_busy(priv); 1149 newcount = mwl8k_txq_busy(priv);
1150 spin_unlock_bh(&priv->tx_lock); 1150 spin_unlock_bh(&priv->tx_lock);
1151 1151
1152 printk(KERN_ERR "%s(%u) TIMEDOUT:1000ms Pend:%u-->%u\n", 1152 printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n",
1153 __func__, __LINE__, count, newcount); 1153 __func__, __LINE__, count, newcount);
1154 1154
1155 mwl8k_scan_tx_ring(priv, txinfo); 1155 mwl8k_scan_tx_ring(priv, txinfo);
@@ -1228,10 +1228,10 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
1228 1228
1229 ieee80211_tx_status_irqsafe(hw, skb); 1229 ieee80211_tx_status_irqsafe(hw, skb);
1230 1230
1231 wake = !priv->inconfig && priv->radio_on; 1231 wake = 1;
1232 } 1232 }
1233 1233
1234 if (wake) 1234 if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
1235 ieee80211_wake_queue(hw, index); 1235 ieee80211_wake_queue(hw, index);
1236} 1236}
1237 1237
@@ -1360,6 +1360,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1360 1360
1361 1361
1362/* 1362/*
1363 * Firmware access.
1364 *
1365 * We have the following requirements for issuing firmware commands:
1366 * - Some commands require that the packet transmit path is idle when
1367 * the command is issued. (For simplicity, we'll just quiesce the
1368 * transmit path for every command.)
1369 * - There are certain sequences of commands that need to be issued to
1370 * the hardware sequentially, with no other intervening commands.
1371 *
1372 * This leads to an implementation of a "firmware lock" as a mutex that
1373 * can be taken recursively, and which is taken by both the low-level
1374 * command submission function (mwl8k_post_cmd) as well as any users of
1375 * that function that require issuing of an atomic sequence of commands,
1376 * and quiesces the transmit path whenever it's taken.
1377 */
1378static int mwl8k_fw_lock(struct ieee80211_hw *hw)
1379{
1380 struct mwl8k_priv *priv = hw->priv;
1381
1382 if (priv->fw_mutex_owner != current) {
1383 int rc;
1384
1385 mutex_lock(&priv->fw_mutex);
1386 ieee80211_stop_queues(hw);
1387
1388 rc = mwl8k_tx_wait_empty(hw);
1389 if (rc) {
1390 ieee80211_wake_queues(hw);
1391 mutex_unlock(&priv->fw_mutex);
1392
1393 return rc;
1394 }
1395
1396 priv->fw_mutex_owner = current;
1397 }
1398
1399 priv->fw_mutex_depth++;
1400
1401 return 0;
1402}
1403
1404static void mwl8k_fw_unlock(struct ieee80211_hw *hw)
1405{
1406 struct mwl8k_priv *priv = hw->priv;
1407
1408 if (!--priv->fw_mutex_depth) {
1409 ieee80211_wake_queues(hw);
1410 priv->fw_mutex_owner = NULL;
1411 mutex_unlock(&priv->fw_mutex);
1412 }
1413}
1414
1415
1416/*
1363 * Command processing. 1417 * Command processing.
1364 */ 1418 */
1365 1419
@@ -1384,28 +1438,28 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
1384 if (pci_dma_mapping_error(priv->pdev, dma_addr)) 1438 if (pci_dma_mapping_error(priv->pdev, dma_addr))
1385 return -ENOMEM; 1439 return -ENOMEM;
1386 1440
1387 if (priv->hostcmd_wait != NULL) 1441 rc = mwl8k_fw_lock(hw);
1388 printk(KERN_ERR "WARNING host command in progress\n"); 1442 if (rc)
1443 return rc;
1389 1444
1390 spin_lock_irq(&priv->fw_lock);
1391 priv->hostcmd_wait = &cmd_wait; 1445 priv->hostcmd_wait = &cmd_wait;
1392 iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); 1446 iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
1393 iowrite32(MWL8K_H2A_INT_DOORBELL, 1447 iowrite32(MWL8K_H2A_INT_DOORBELL,
1394 regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1448 regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
1395 iowrite32(MWL8K_H2A_INT_DUMMY, 1449 iowrite32(MWL8K_H2A_INT_DUMMY,
1396 regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1450 regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
1397 spin_unlock_irq(&priv->fw_lock);
1398 1451
1399 timeout = wait_for_completion_timeout(&cmd_wait, 1452 timeout = wait_for_completion_timeout(&cmd_wait,
1400 msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); 1453 msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS));
1401 1454
1455 priv->hostcmd_wait = NULL;
1456
1457 mwl8k_fw_unlock(hw);
1458
1402 pci_unmap_single(priv->pdev, dma_addr, dma_size, 1459 pci_unmap_single(priv->pdev, dma_addr, dma_size,
1403 PCI_DMA_BIDIRECTIONAL); 1460 PCI_DMA_BIDIRECTIONAL);
1404 1461
1405 if (!timeout) { 1462 if (!timeout) {
1406 spin_lock_irq(&priv->fw_lock);
1407 priv->hostcmd_wait = NULL;
1408 spin_unlock_irq(&priv->fw_lock);
1409 printk(KERN_ERR "%s: Command %s timeout after %u ms\n", 1463 printk(KERN_ERR "%s: Command %s timeout after %u ms\n",
1410 priv->name, 1464 priv->name,
1411 mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), 1465 mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
@@ -2336,17 +2390,14 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
2336 } 2390 }
2337 2391
2338 if (status & MWL8K_A2H_INT_OPC_DONE) { 2392 if (status & MWL8K_A2H_INT_OPC_DONE) {
2339 if (priv->hostcmd_wait != NULL) { 2393 if (priv->hostcmd_wait != NULL)
2340 complete(priv->hostcmd_wait); 2394 complete(priv->hostcmd_wait);
2341 priv->hostcmd_wait = NULL;
2342 }
2343 } 2395 }
2344 2396
2345 if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { 2397 if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
2346 if (!priv->inconfig && 2398 if (!mutex_is_locked(&priv->fw_mutex) &&
2347 priv->radio_on && 2399 priv->radio_on && mwl8k_txq_busy(priv))
2348 mwl8k_txq_busy(priv)) 2400 mwl8k_tx_start(priv);
2349 mwl8k_tx_start(priv);
2350 } 2401 }
2351 2402
2352 return IRQ_HANDLED; 2403 return IRQ_HANDLED;
@@ -2395,41 +2446,13 @@ static void mwl8k_config_thread(struct work_struct *wt)
2395{ 2446{
2396 struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt; 2447 struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt;
2397 struct ieee80211_hw *hw = worker->hw; 2448 struct ieee80211_hw *hw = worker->hw;
2398 struct mwl8k_priv *priv = hw->priv;
2399 int rc = 0; 2449 int rc = 0;
2400 int iter;
2401 2450
2402 spin_lock_irq(&priv->tx_lock); 2451 rc = mwl8k_fw_lock(hw);
2403 priv->inconfig = true; 2452 if (!rc) {
2404 spin_unlock_irq(&priv->tx_lock);
2405
2406 ieee80211_stop_queues(hw);
2407
2408 /*
2409 * Wait for host queues to drain before doing PHY
2410 * reconfiguration. This avoids interrupting any in-flight
2411 * DMA transfers to the hardware.
2412 */
2413 iter = 4;
2414 do {
2415 rc = mwl8k_tx_wait_empty(hw);
2416 if (rc)
2417 printk(KERN_ERR "%s() txwait timeout=1000ms "
2418 "Retry:%u/%u\n", __func__, 4 - iter + 1, 4);
2419 } while (rc && --iter);
2420
2421 rc = iter ? 0 : -ETIMEDOUT;
2422
2423 if (!rc)
2424 rc = worker->wfunc(wt); 2453 rc = worker->wfunc(wt);
2425 2454 mwl8k_fw_unlock(hw);
2426 spin_lock_irq(&priv->tx_lock); 2455 }
2427 priv->inconfig = false;
2428 if (priv->pending_tx_pkts && priv->radio_on)
2429 mwl8k_tx_start(priv);
2430 spin_unlock_irq(&priv->tx_lock);
2431
2432 ieee80211_wake_queues(hw);
2433 2456
2434 worker->rc = rc; 2457 worker->rc = rc;
2435 complete(worker->cmd_wait); 2458 complete(worker->cmd_wait);
@@ -3145,15 +3168,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
3145 priv = hw->priv; 3168 priv = hw->priv;
3146 priv->hw = hw; 3169 priv->hw = hw;
3147 priv->pdev = pdev; 3170 priv->pdev = pdev;
3148 priv->hostcmd_wait = NULL;
3149 priv->tx_wait = NULL;
3150 priv->inconfig = false;
3151 priv->wmm_enabled = false; 3171 priv->wmm_enabled = false;
3152 priv->pending_tx_pkts = 0; 3172 priv->pending_tx_pkts = 0;
3153 strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); 3173 strncpy(priv->name, MWL8K_NAME, sizeof(priv->name));
3154 3174
3155 spin_lock_init(&priv->fw_lock);
3156
3157 SET_IEEE80211_DEV(hw, &pdev->dev); 3175 SET_IEEE80211_DEV(hw, &pdev->dev);
3158 pci_set_drvdata(pdev, hw); 3176 pci_set_drvdata(pdev, hw);
3159 3177
@@ -3219,6 +3237,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
3219 goto err_iounmap; 3237 goto err_iounmap;
3220 rxq_refill(hw, 0, INT_MAX); 3238 rxq_refill(hw, 0, INT_MAX);
3221 3239
3240 mutex_init(&priv->fw_mutex);
3241 priv->fw_mutex_owner = NULL;
3242 priv->fw_mutex_depth = 0;
3243 priv->tx_wait = NULL;
3244 priv->hostcmd_wait = NULL;
3245
3222 spin_lock_init(&priv->tx_lock); 3246 spin_lock_init(&priv->tx_lock);
3223 3247
3224 for (i = 0; i < MWL8K_TX_QUEUES; i++) { 3248 for (i = 0; i < MWL8K_TX_QUEUES; i++) {