diff options
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 127 |
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 | ||
1240 | struct mwl8k_txq_info { | 1240 | static 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 | |||
1249 | static 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 | |||
1284 | static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | 1279 | static 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) \ |