aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-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++) {