aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/dma.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2009-11-19 16:24:29 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-23 17:05:28 -0500
commit07681e211d736ba2394ab7f29f77e93adecd22c5 (patch)
treed97c679446e738275894636f02d50190bf986599 /drivers/net/wireless/b43/dma.c
parent8c35024aa65c079f800df7778869a8dbda074182 (diff)
b43: Rewrite DMA Tx status handling sanity checks
This rewrites the error handling policies in the TX status handler. It tries to be error-tolerant as in "try hard to not crash the machine". It won't recover from errors (that are bugs in the firmware or driver), because that's impossible. However, it will return a more or less useful error message and bail out. It also tries hard to use rate-limited messages to not flood the syslog in case of a failure. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/dma.c')
-rw-r--r--drivers/net/wireless/b43/dma.c67
1 files changed, 54 insertions, 13 deletions
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 18b97c02b8a..027be275e03 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -874,7 +874,7 @@ static void free_all_descbuffers(struct b43_dmaring *ring)
874 for (i = 0; i < ring->nr_slots; i++) { 874 for (i = 0; i < ring->nr_slots; i++) {
875 desc = ring->ops->idx2desc(ring, i, &meta); 875 desc = ring->ops->idx2desc(ring, i, &meta);
876 876
877 if (!meta->skb) { 877 if (!meta->skb || b43_dma_ptr_is_poisoned(meta->skb)) {
878 B43_WARN_ON(!ring->tx); 878 B43_WARN_ON(!ring->tx);
879 continue; 879 continue;
880 } 880 }
@@ -926,7 +926,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
926 enum b43_dmatype type) 926 enum b43_dmatype type)
927{ 927{
928 struct b43_dmaring *ring; 928 struct b43_dmaring *ring;
929 int err; 929 int i, err;
930 dma_addr_t dma_test; 930 dma_addr_t dma_test;
931 931
932 ring = kzalloc(sizeof(*ring), GFP_KERNEL); 932 ring = kzalloc(sizeof(*ring), GFP_KERNEL);
@@ -941,6 +941,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
941 GFP_KERNEL); 941 GFP_KERNEL);
942 if (!ring->meta) 942 if (!ring->meta)
943 goto err_kfree_ring; 943 goto err_kfree_ring;
944 for (i = 0; i < ring->nr_slots; i++)
945 ring->meta->skb = B43_DMA_PTR_POISON;
944 946
945 ring->type = type; 947 ring->type = type;
946 ring->dev = dev; 948 ring->dev = dev;
@@ -1251,11 +1253,13 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
1251 case 0x5000: 1253 case 0x5000:
1252 ring = dma->tx_ring_mcast; 1254 ring = dma->tx_ring_mcast;
1253 break; 1255 break;
1254 default:
1255 B43_WARN_ON(1);
1256 } 1256 }
1257 *slot = (cookie & 0x0FFF); 1257 *slot = (cookie & 0x0FFF);
1258 B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots)); 1258 if (unlikely(!ring || *slot < 0 || *slot >= ring->nr_slots)) {
1259 b43dbg(dev->wl, "TX-status contains "
1260 "invalid cookie: 0x%04X\n", cookie);
1261 return NULL;
1262 }
1259 1263
1260 return ring; 1264 return ring;
1261} 1265}
@@ -1494,19 +1498,40 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
1494 struct b43_dmaring *ring; 1498 struct b43_dmaring *ring;
1495 struct b43_dmadesc_generic *desc; 1499 struct b43_dmadesc_generic *desc;
1496 struct b43_dmadesc_meta *meta; 1500 struct b43_dmadesc_meta *meta;
1497 int slot; 1501 int slot, firstused;
1498 bool frame_succeed; 1502 bool frame_succeed;
1499 1503
1500 ring = parse_cookie(dev, status->cookie, &slot); 1504 ring = parse_cookie(dev, status->cookie, &slot);
1501 if (unlikely(!ring)) 1505 if (unlikely(!ring))
1502 return; 1506 return;
1503
1504 B43_WARN_ON(!ring->tx); 1507 B43_WARN_ON(!ring->tx);
1508
1509 /* Sanity check: TX packets are processed in-order on one ring.
1510 * Check if the slot deduced from the cookie really is the first
1511 * used slot. */
1512 firstused = ring->current_slot - ring->used_slots + 1;
1513 if (firstused < 0)
1514 firstused = ring->nr_slots + firstused;
1515 if (unlikely(slot != firstused)) {
1516 /* This possibly is a firmware bug and will result in
1517 * malfunction, memory leaks and/or stall of DMA functionality. */
1518 b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. "
1519 "Expected %d, but got %d\n",
1520 ring->index, firstused, slot);
1521 return;
1522 }
1523
1505 ops = ring->ops; 1524 ops = ring->ops;
1506 while (1) { 1525 while (1) {
1507 B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); 1526 B43_WARN_ON(slot < 0 || slot >= ring->nr_slots);
1508 desc = ops->idx2desc(ring, slot, &meta); 1527 desc = ops->idx2desc(ring, slot, &meta);
1509 1528
1529 if (b43_dma_ptr_is_poisoned(meta->skb)) {
1530 b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) "
1531 "on ring %d\n",
1532 slot, firstused, ring->index);
1533 break;
1534 }
1510 if (meta->skb) { 1535 if (meta->skb) {
1511 struct b43_private_tx_info *priv_info = 1536 struct b43_private_tx_info *priv_info =
1512 b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); 1537 b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
@@ -1522,7 +1547,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
1522 if (meta->is_last_fragment) { 1547 if (meta->is_last_fragment) {
1523 struct ieee80211_tx_info *info; 1548 struct ieee80211_tx_info *info;
1524 1549
1525 BUG_ON(!meta->skb); 1550 if (unlikely(!meta->skb)) {
1551 /* This is a scatter-gather fragment of a frame, so
1552 * the skb pointer must not be NULL. */
1553 b43dbg(dev->wl, "TX status unexpected NULL skb "
1554 "at slot %d (first=%d) on ring %d\n",
1555 slot, firstused, ring->index);
1556 break;
1557 }
1526 1558
1527 info = IEEE80211_SKB_CB(meta->skb); 1559 info = IEEE80211_SKB_CB(meta->skb);
1528 1560
@@ -1540,20 +1572,29 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
1540#endif /* DEBUG */ 1572#endif /* DEBUG */
1541 ieee80211_tx_status(dev->wl->hw, meta->skb); 1573 ieee80211_tx_status(dev->wl->hw, meta->skb);
1542 1574
1543 /* skb is freed by ieee80211_tx_status() */ 1575 /* skb will be freed by ieee80211_tx_status().
1544 meta->skb = NULL; 1576 * Poison our pointer. */
1577 meta->skb = B43_DMA_PTR_POISON;
1545 } else { 1578 } else {
1546 /* No need to call free_descriptor_buffer here, as 1579 /* No need to call free_descriptor_buffer here, as
1547 * this is only the txhdr, which is not allocated. 1580 * this is only the txhdr, which is not allocated.
1548 */ 1581 */
1549 B43_WARN_ON(meta->skb); 1582 if (unlikely(meta->skb)) {
1583 b43dbg(dev->wl, "TX status unexpected non-NULL skb "
1584 "at slot %d (first=%d) on ring %d\n",
1585 slot, firstused, ring->index);
1586 break;
1587 }
1550 } 1588 }
1551 1589
1552 /* Everything unmapped and free'd. So it's not used anymore. */ 1590 /* Everything unmapped and free'd. So it's not used anymore. */
1553 ring->used_slots--; 1591 ring->used_slots--;
1554 1592
1555 if (meta->is_last_fragment) 1593 if (meta->is_last_fragment) {
1594 /* This is the last scatter-gather
1595 * fragment of the frame. We are done. */
1556 break; 1596 break;
1597 }
1557 slot = next_slot(ring, slot); 1598 slot = next_slot(ring, slot);
1558 } 1599 }
1559 if (ring->stopped) { 1600 if (ring->stopped) {