From: Will Dyson <[EMAIL PROTECTED]>
When DMA mapping for RX fails because of the limitation, retry the allocation
in ZONE_DMA. When the network stack passes us TX buffers that cannot be mapped
because of the limitation, allocate a bounce buffer in ZONE_DMA and copy the
packet there.
Signed-off-by: Will Dyson <[EMAIL PROTECTED]>
---
.../net/wireless/mac80211/bcm43xx/bcm43xx_dma.c | 73 ++++++++++++++++++-
1 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c
b/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c
index 1dc95a7..faefdc4 100644
--- a/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c
@@ -525,8 +525,24 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring
*ring,
return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data,
ring->rx_buffersize, 0);
- if (dma_mapping_error(dmaaddr))
+ if (dma_mapping_error(dmaaddr)) {
+ /* ugh. try to realloc in zone_dma */
+ gfp_flags &= ~GFP_KERNEL;
+ gfp_flags |= GFP_DMA;
+
+ dev_kfree_skb_any(skb);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data,
+ ring->rx_buffersize, 0);
+ }
+
+ if (dma_mapping_error(dmaaddr)) {
+ dev_kfree_skb_any(skb);
return -EIO;
+ }
meta->skb = skb;
meta->dmaaddr = dmaaddr;
@@ -731,6 +747,7 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct
bcm43xx_wldev *dev,
struct bcm43xx_dmaring *ring;
int err;
int nr_slots;
+ dma_addr_t dma_test;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
@@ -750,6 +767,32 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct
bcm43xx_wldev *dev,
GFP_KERNEL);
if (!ring->txhdr_cache)
goto err_kfree_meta;
+
+ /* test for ability to dma to txhdr_cache */
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache, sizeof(struct
bcm43xx_txhdr_fw4),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test)) {
+ /* ugh realloc */
+ kfree(ring->txhdr_cache);
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct
bcm43xx_txhdr_fw4),
+ GFP_DMA);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache, sizeof(struct
bcm43xx_txhdr_fw4),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test))
+ goto err_kfree_txhdr_cache;
+ }
+
+ dma_unmap_single(dev->dev->dev,
+ dma_test, sizeof(struct bcm43xx_txhdr_fw4),
+ DMA_TO_DEVICE);
}
ring->dev = dev;
@@ -1030,9 +1073,11 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
const struct bcm43xx_dma_ops *ops = ring->ops;
u8 *header;
int slot;
+ int err;
struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta;
struct bcm43xx_dmadesc_meta *meta_hdr;
+ struct sk_buff *bounce_skb;
#define SLOTS_PER_PACKET 2
assert(skb_shinfo(skb)->nr_frags == 0);
@@ -1062,9 +1107,27 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
meta->skb = skb;
meta->is_last_fragment = 1;
+
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
- if(dma_mapping_error(meta->dmaaddr))
- goto out_unmap_hdr;
+
+ /* create a bounce buffer in zone_dma on mapping failure. */
+ if (dma_mapping_error(meta->dmaaddr)) {
+ bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
+ if (!bounce_skb) {
+ err = -ENOMEM;
+ goto out_unmap_hdr;
+ }
+
+ memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+ skb = bounce_skb;
+ meta->skb = skb;
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ if (dma_mapping_error(meta->dmaaddr)) {
+ err = -EIO;
+ goto out_free_bounce;
+ }
+ }
ops->fill_descriptor(ring, desc, meta->dmaaddr,
skb->len, 0, 1, 1);
@@ -1074,10 +1137,12 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
ops->poke_tx(ring, next_slot(ring, slot));
return 0;
+out_free_bounce:
+ dev_kfree_skb_any(skb);
out_unmap_hdr:
unmap_descbuffer(ring, meta_hdr->dmaaddr,
sizeof(struct bcm43xx_txhdr_fw4), 1);
- return -EIO;
+ return err;
}
int bcm43xx_dma_tx(struct bcm43xx_wldev *dev,
--
1.5.0.3
_______________________________________________
Bcm43xx-dev mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/bcm43xx-dev