aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/mwl8k.c127
1 files changed, 67 insertions, 60 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 793a83e10e16..a16255810d15 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1237,99 +1237,106 @@ static inline void mwl8k_tx_start(struct mwl8k_priv *priv)
1237 ioread32(priv->regs + MWL8K_HIU_INT_CODE); 1237 ioread32(priv->regs + MWL8K_HIU_INT_CODE);
1238} 1238}
1239 1239
1240struct mwl8k_txq_info { 1240static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw)
1241 u32 fw_owned;
1242 u32 drv_owned;
1243 u32 unused;
1244 u32 len;
1245 u32 head;
1246 u32 tail;
1247};
1248
1249static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
1250 struct mwl8k_txq_info *txinfo)
1251{ 1241{
1252 int count, desc, status; 1242 struct mwl8k_priv *priv = hw->priv;
1253 struct mwl8k_tx_queue *txq; 1243 int i;
1254 struct mwl8k_tx_desc *tx_desc;
1255 int ndescs = 0;
1256 1244
1257 memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info)); 1245 for (i = 0; i < MWL8K_TX_QUEUES; i++) {
1246 struct mwl8k_tx_queue *txq = priv->txq + i;
1247 int fw_owned = 0;
1248 int drv_owned = 0;
1249 int unused = 0;
1250 int desc;
1258 1251
1259 for (count = 0; count < MWL8K_TX_QUEUES; count++) {
1260 txq = priv->txq + count;
1261 txinfo[count].len = txq->stats.len;
1262 txinfo[count].head = txq->head;
1263 txinfo[count].tail = txq->tail;
1264 for (desc = 0; desc < MWL8K_TX_DESCS; desc++) { 1252 for (desc = 0; desc < MWL8K_TX_DESCS; desc++) {
1265 tx_desc = txq->txd + desc; 1253 struct mwl8k_tx_desc *tx_desc = txq->txd + desc;
1266 status = le32_to_cpu(tx_desc->status); 1254 u32 status;
1267 1255
1256 status = le32_to_cpu(tx_desc->status);
1268 if (status & MWL8K_TXD_STATUS_FW_OWNED) 1257 if (status & MWL8K_TXD_STATUS_FW_OWNED)
1269 txinfo[count].fw_owned++; 1258 fw_owned++;
1270 else 1259 else
1271 txinfo[count].drv_owned++; 1260 drv_owned++;
1272 1261
1273 if (tx_desc->pkt_len == 0) 1262 if (tx_desc->pkt_len == 0)
1274 txinfo[count].unused++; 1263 unused++;
1275 } 1264 }
1276 }
1277 1265
1278 return ndescs; 1266 printk(KERN_ERR "%s: txq[%d] len=%d head=%d tail=%d "
1267 "fw_owned=%d drv_owned=%d unused=%d\n",
1268 wiphy_name(hw->wiphy), i,
1269 txq->stats.len, txq->head, txq->tail,
1270 fw_owned, drv_owned, unused);
1271 }
1279} 1272}
1280 1273
1281/* 1274/*
1282 * Must be called with priv->fw_mutex held and tx queues stopped. 1275 * Must be called with priv->fw_mutex held and tx queues stopped.
1283 */ 1276 */
1277#define MWL8K_TX_WAIT_TIMEOUT_MS 1000
1278
1284static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) 1279static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
1285{ 1280{
1286 struct mwl8k_priv *priv = hw->priv; 1281 struct mwl8k_priv *priv = hw->priv;
1287 DECLARE_COMPLETION_ONSTACK(tx_wait); 1282 DECLARE_COMPLETION_ONSTACK(tx_wait);
1288 u32 count; 1283 int retry;
1289 unsigned long timeout; 1284 int rc;
1290 1285
1291 might_sleep(); 1286 might_sleep();
1292 1287
1288 /*
1289 * The TX queues are stopped at this point, so this test
1290 * doesn't need to take ->tx_lock.
1291 */
1292 if (!priv->pending_tx_pkts)
1293 return 0;
1294
1295 retry = 0;
1296 rc = 0;
1297
1293 spin_lock_bh(&priv->tx_lock); 1298 spin_lock_bh(&priv->tx_lock);
1294 count = priv->pending_tx_pkts; 1299 priv->tx_wait = &tx_wait;
1295 if (count) 1300 while (!rc) {
1296 priv->tx_wait = &tx_wait; 1301 int oldcount;
1297 spin_unlock_bh(&priv->tx_lock); 1302 unsigned long timeout;
1298 1303
1299 if (count) { 1304 oldcount = priv->pending_tx_pkts;
1300 struct mwl8k_txq_info txinfo[MWL8K_TX_QUEUES];
1301 int index;
1302 int newcount;
1303 1305
1306 spin_unlock_bh(&priv->tx_lock);
1304 timeout = wait_for_completion_timeout(&tx_wait, 1307 timeout = wait_for_completion_timeout(&tx_wait,
1305 msecs_to_jiffies(5000)); 1308 msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS));
1306 if (timeout)
1307 return 0;
1308
1309 spin_lock_bh(&priv->tx_lock); 1309 spin_lock_bh(&priv->tx_lock);
1310 priv->tx_wait = NULL;
1311 newcount = priv->pending_tx_pkts;
1312 mwl8k_scan_tx_ring(priv, txinfo);
1313 spin_unlock_bh(&priv->tx_lock);
1314 1310
1315 printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n", 1311 if (timeout) {
1316 __func__, __LINE__, count, newcount); 1312 WARN_ON(priv->pending_tx_pkts);
1313 if (retry) {
1314 printk(KERN_NOTICE "%s: tx rings drained\n",
1315 wiphy_name(hw->wiphy));
1316 }
1317 break;
1318 }
1317 1319
1318 for (index = 0; index < MWL8K_TX_QUEUES; index++) 1320 if (priv->pending_tx_pkts < oldcount) {
1319 printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u " 1321 printk(KERN_NOTICE "%s: timeout waiting for tx "
1320 "DRV:%u U:%u\n", 1322 "rings to drain (%d -> %d pkts), retrying\n",
1321 index, 1323 wiphy_name(hw->wiphy), oldcount,
1322 txinfo[index].len, 1324 priv->pending_tx_pkts);
1323 txinfo[index].head, 1325 retry = 1;
1324 txinfo[index].tail, 1326 continue;
1325 txinfo[index].fw_owned, 1327 }
1326 txinfo[index].drv_owned, 1328
1327 txinfo[index].unused); 1329 priv->tx_wait = NULL;
1330
1331 printk(KERN_ERR "%s: tx rings stuck for %d ms\n",
1332 wiphy_name(hw->wiphy), MWL8K_TX_WAIT_TIMEOUT_MS);
1333 mwl8k_dump_tx_rings(hw);
1328 1334
1329 return -ETIMEDOUT; 1335 rc = -ETIMEDOUT;
1330 } 1336 }
1337 spin_unlock_bh(&priv->tx_lock);
1331 1338
1332 return 0; 1339 return rc;
1333} 1340}
1334 1341
1335#define MWL8K_TXD_SUCCESS(status) \ 1342#define MWL8K_TXD_SUCCESS(status) \