aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k
diff options
context:
space:
mode:
authorBob Copeland <me@bobcopeland.com>2009-01-10 14:42:54 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:00:22 -0500
commitb6ea03562f04382776ad825624daefe27f5d3f9c (patch)
tree1fa0d8df1c011ae6ab693bcd4db6bc14a936a68a /drivers/net/wireless/ath5k
parent138ab2e44e99a9544aad60cf137b8ac1f54131c5 (diff)
ath5k: fix bf->skb==NULL panic in ath5k_tasklet_rx
Under memory pressure, we may not be able to allocate a new skb for new packets. If the allocation fails, ath5k_tasklet_rx will exit but will leave a buffer in the list with a NULL skb, eventually triggering a BUG_ON. Extract the skb allocation from ath5k_rxbuf_setup() and change the tasklet to allocate the next skb before accepting a packet. Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bob Copeland <me@bobcopeland.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath5k')
-rw-r--r--drivers/net/wireless/ath5k/base.c85
1 files changed, 53 insertions, 32 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index fdf7733e76e1..d3178731adc6 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1096,6 +1096,42 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
1096* Buffers setup * 1096* Buffers setup *
1097\***************/ 1097\***************/
1098 1098
1099static
1100struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
1101{
1102 struct sk_buff *skb;
1103 unsigned int off;
1104
1105 /*
1106 * Allocate buffer with headroom_needed space for the
1107 * fake physical layer header at the start.
1108 */
1109 skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
1110
1111 if (!skb) {
1112 ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
1113 sc->rxbufsize + sc->cachelsz - 1);
1114 return NULL;
1115 }
1116 /*
1117 * Cache-line-align. This is important (for the
1118 * 5210 at least) as not doing so causes bogus data
1119 * in rx'd frames.
1120 */
1121 off = ((unsigned long)skb->data) % sc->cachelsz;
1122 if (off != 0)
1123 skb_reserve(skb, sc->cachelsz - off);
1124
1125 *skb_addr = pci_map_single(sc->pdev,
1126 skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
1127 if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) {
1128 ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
1129 dev_kfree_skb(skb);
1130 return NULL;
1131 }
1132 return skb;
1133}
1134
1099static int 1135static int
1100ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) 1136ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
1101{ 1137{
@@ -1103,37 +1139,11 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
1103 struct sk_buff *skb = bf->skb; 1139 struct sk_buff *skb = bf->skb;
1104 struct ath5k_desc *ds; 1140 struct ath5k_desc *ds;
1105 1141
1106 if (likely(skb == NULL)) { 1142 if (!skb) {
1107 unsigned int off; 1143 skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr);
1108 1144 if (!skb)
1109 /*
1110 * Allocate buffer with headroom_needed space for the
1111 * fake physical layer header at the start.
1112 */
1113 skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
1114 if (unlikely(skb == NULL)) {
1115 ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
1116 sc->rxbufsize + sc->cachelsz - 1);
1117 return -ENOMEM; 1145 return -ENOMEM;
1118 }
1119 /*
1120 * Cache-line-align. This is important (for the
1121 * 5210 at least) as not doing so causes bogus data
1122 * in rx'd frames.
1123 */
1124 off = ((unsigned long)skb->data) % sc->cachelsz;
1125 if (off != 0)
1126 skb_reserve(skb, sc->cachelsz - off);
1127
1128 bf->skb = skb; 1146 bf->skb = skb;
1129 bf->skbaddr = pci_map_single(sc->pdev,
1130 skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
1131 if (unlikely(pci_dma_mapping_error(sc->pdev, bf->skbaddr))) {
1132 ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
1133 dev_kfree_skb(skb);
1134 bf->skb = NULL;
1135 return -ENOMEM;
1136 }
1137 } 1147 }
1138 1148
1139 /* 1149 /*
@@ -1662,7 +1672,8 @@ ath5k_tasklet_rx(unsigned long data)
1662{ 1672{
1663 struct ieee80211_rx_status rxs = {}; 1673 struct ieee80211_rx_status rxs = {};
1664 struct ath5k_rx_status rs = {}; 1674 struct ath5k_rx_status rs = {};
1665 struct sk_buff *skb; 1675 struct sk_buff *skb, *next_skb;
1676 dma_addr_t next_skb_addr;
1666 struct ath5k_softc *sc = (void *)data; 1677 struct ath5k_softc *sc = (void *)data;
1667 struct ath5k_buf *bf, *bf_last; 1678 struct ath5k_buf *bf, *bf_last;
1668 struct ath5k_desc *ds; 1679 struct ath5k_desc *ds;
@@ -1747,10 +1758,17 @@ ath5k_tasklet_rx(unsigned long data)
1747 goto next; 1758 goto next;
1748 } 1759 }
1749accept: 1760accept:
1761 next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr);
1762
1763 /*
1764 * If we can't replace bf->skb with a new skb under memory
1765 * pressure, just skip this packet
1766 */
1767 if (!next_skb)
1768 goto next;
1769
1750 pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, 1770 pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
1751 PCI_DMA_FROMDEVICE); 1771 PCI_DMA_FROMDEVICE);
1752 bf->skb = NULL;
1753
1754 skb_put(skb, rs.rs_datalen); 1772 skb_put(skb, rs.rs_datalen);
1755 1773
1756 /* The MAC header is padded to have 32-bit boundary if the 1774 /* The MAC header is padded to have 32-bit boundary if the
@@ -1823,6 +1841,9 @@ accept:
1823 ath5k_check_ibss_tsf(sc, skb, &rxs); 1841 ath5k_check_ibss_tsf(sc, skb, &rxs);
1824 1842
1825 __ieee80211_rx(sc->hw, skb, &rxs); 1843 __ieee80211_rx(sc->hw, skb, &rxs);
1844
1845 bf->skb = next_skb;
1846 bf->skbaddr = next_skb_addr;
1826next: 1847next:
1827 list_move_tail(&bf->list, &sc->rxbuf); 1848 list_move_tail(&bf->list, &sc->rxbuf);
1828 } while (ath5k_rxbuf_setup(sc, bf) == 0); 1849 } while (ath5k_rxbuf_setup(sc, bf) == 0);