ath9k: Check for pci_map_single() errors
authorLuis R. Rodriguez <lrodriguez@atheros.com>
Wed, 3 Dec 2008 11:35:29 +0000 (03:35 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 5 Dec 2008 14:35:59 +0000 (09:35 -0500)
pci_map_single() can fail so detect those errors with
pci_dma_mapping_error() and deal with them accordingly.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath9k/beacon.c
drivers/net/wireless/ath9k/recv.c
drivers/net/wireless/ath9k/xmit.c

index fe6929d..507299b 100644 (file)
@@ -190,6 +190,13 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
                pci_map_single(sc->pdev, skb->data,
                               skb->len,
                               PCI_DMA_TODEVICE);
+       if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) {
+               dev_kfree_skb_any(skb);
+               bf->bf_mpdu = NULL;
+               DPRINTF(sc, ATH_DBG_CONFIG,
+                       "pci_dma_mapping_error() on beaconing\n");
+               return NULL;
+       }
 
        skb = ieee80211_get_buffered_bc(sc->hw, vif);
 
@@ -392,11 +399,18 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
                memcpy(&hdr[1], &val, sizeof(val));
        }
 
+       bf->bf_mpdu = skb;
        bf->bf_buf_addr = bf->bf_dmacontext =
                pci_map_single(sc->pdev, skb->data,
                               skb->len,
                               PCI_DMA_TODEVICE);
-       bf->bf_mpdu = skb;
+       if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) {
+               dev_kfree_skb_any(skb);
+               bf->bf_mpdu = NULL;
+               DPRINTF(sc, ATH_DBG_CONFIG,
+                       "pci_dma_mapping_error() on beacon alloc\n");
+               return -ENOMEM;
+       }
 
        return 0;
 }
index 51e0587..7a45546 100644 (file)
@@ -304,6 +304,15 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
                        bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data,
                                         sc->sc_rxbufsize,
                                         PCI_DMA_FROMDEVICE);
+                       if (unlikely(pci_dma_mapping_error(sc->pdev,
+                                 bf->bf_buf_addr))) {
+                               dev_kfree_skb_any(skb);
+                               bf->bf_mpdu = NULL;
+                               DPRINTF(sc, ATH_DBG_CONFIG,
+                                       "pci_dma_mapping_error() on RX init\n");
+                               error = -ENOMEM;
+                               break;
+                       }
                        bf->bf_dmacontext = bf->bf_buf_addr;
                }
                sc->sc_rxlink = NULL;
@@ -589,6 +598,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data,
                                         sc->sc_rxbufsize,
                                         PCI_DMA_FROMDEVICE);
+               if (unlikely(pci_dma_mapping_error(sc->pdev,
+                         bf->bf_buf_addr))) {
+                       dev_kfree_skb_any(requeue_skb);
+                       bf->bf_mpdu = NULL;
+                       DPRINTF(sc, ATH_DBG_CONFIG,
+                               "pci_dma_mapping_error() on RX\n");
+                       break;
+               }
                bf->bf_dmacontext = bf->bf_buf_addr;
 
                /*
index 5cf8311..17fd05e 100644 (file)
@@ -1642,7 +1642,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
        }
 }
 
-static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
+static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
                                struct sk_buff *skb,
                                struct ath_tx_control *txctl)
 {
@@ -1701,9 +1701,18 @@ static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
        /* DMA setup */
 
        bf->bf_mpdu = skb;
+
        bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data,
                                           skb->len, PCI_DMA_TODEVICE);
+       if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_dmacontext))) {
+               bf->bf_mpdu = NULL;
+               DPRINTF(sc, ATH_DBG_CONFIG,
+                       "pci_dma_mapping_error() on TX\n");
+               return -ENOMEM;
+       }
+
        bf->bf_buf_addr = bf->bf_dmacontext;
+       return 0;
 }
 
 /* FIXME: tx power */
@@ -1775,10 +1784,12 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
        spin_unlock_bh(&txctl->txq->axq_lock);
 }
 
+/* Upon failure caller should free skb */
 int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
                 struct ath_tx_control *txctl)
 {
        struct ath_buf *bf;
+       int r;
 
        /* Check if a tx buffer is available */
 
@@ -1788,7 +1799,15 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
                return -1;
        }
 
-       ath_tx_setup_buffer(sc, bf, skb, txctl);
+       r = ath_tx_setup_buffer(sc, bf, skb, txctl);
+       if (unlikely(r)) {
+               spin_lock_bh(&sc->sc_txbuflock);
+               DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n");
+               list_add_tail(&bf->list, &sc->sc_txbuf);
+               spin_unlock_bh(&sc->sc_txbuflock);
+               return r;
+       }
+
        ath_tx_start_dma(sc, bf, txctl);
 
        return 0;