Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 71d2c5c..1239207 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3861,10 +3861,7 @@
 			return;
 		}
 
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(ri, mapping),
-				 skb_headlen(skb),
-				 PCI_DMA_TODEVICE);
+		skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
 
 		ri->skb = NULL;
 
@@ -3874,12 +3871,6 @@
 			ri = &tp->tx_buffers[sw_idx];
 			if (unlikely(ri->skb != NULL || sw_idx == hw_idx))
 				tx_bug = 1;
-
-			pci_unmap_page(tp->pdev,
-				       pci_unmap_addr(ri, mapping),
-				       skb_shinfo(skb)->frags[i].size,
-				       PCI_DMA_TODEVICE);
-
 			sw_idx = NEXT_TX(sw_idx);
 		}
 
@@ -4633,12 +4624,16 @@
 	} else {
 		/* New SKB is guaranteed to be linear. */
 		entry = *start;
-		new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
-					  PCI_DMA_TODEVICE);
+		ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE);
+		new_addr = skb_shinfo(new_skb)->dma_maps[0];
+
 		/* Make sure new skb does not cross any 4G boundaries.
 		 * Drop the packet if it does.
 		 */
-		if (tg3_4g_overflow_test(new_addr, new_skb->len)) {
+		if (ret || tg3_4g_overflow_test(new_addr, new_skb->len)) {
+			if (!ret)
+				skb_dma_unmap(&tp->pdev->dev, new_skb,
+					      DMA_TO_DEVICE);
 			ret = -1;
 			dev_kfree_skb(new_skb);
 			new_skb = NULL;
@@ -4652,18 +4647,8 @@
 	/* Now clean up the sw ring entries. */
 	i = 0;
 	while (entry != last_plus_one) {
-		int len;
-
-		if (i == 0)
-			len = skb_headlen(skb);
-		else
-			len = skb_shinfo(skb)->frags[i-1].size;
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(&tp->tx_buffers[entry], mapping),
-				 len, PCI_DMA_TODEVICE);
 		if (i == 0) {
 			tp->tx_buffers[entry].skb = new_skb;
-			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr);
 		} else {
 			tp->tx_buffers[entry].skb = NULL;
 		}
@@ -4671,6 +4656,7 @@
 		i++;
 	}
 
+	skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
 	dev_kfree_skb(skb);
 
 	return ret;
@@ -4705,8 +4691,9 @@
 static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tg3 *tp = netdev_priv(dev);
-	dma_addr_t mapping;
 	u32 len, entry, base_flags, mss;
+	struct skb_shared_info *sp;
+	dma_addr_t mapping;
 
 	len = skb_headlen(skb);
 
@@ -4765,11 +4752,16 @@
 			       (vlan_tx_tag_get(skb) << 16));
 #endif
 
-	/* Queue skb data, a.k.a. the main skb fragment. */
-	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) {
+		dev_kfree_skb(skb);
+		goto out_unlock;
+	}
+
+	sp = skb_shinfo(skb);
+
+	mapping = sp->dma_maps[0];
 
 	tp->tx_buffers[entry].skb = skb;
-	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
 		    (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
@@ -4785,13 +4777,8 @@
 			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
 			len = frag->size;
-			mapping = pci_map_page(tp->pdev,
-					       frag->page,
-					       frag->page_offset,
-					       len, PCI_DMA_TODEVICE);
-
+			mapping = sp->dma_maps[i + 1];
 			tp->tx_buffers[entry].skb = NULL;
-			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			tg3_set_txd(tp, entry, mapping, len,
 				    base_flags, (i == last) | (mss << 1));
@@ -4859,9 +4846,10 @@
 static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tg3 *tp = netdev_priv(dev);
-	dma_addr_t mapping;
 	u32 len, entry, base_flags, mss;
+	struct skb_shared_info *sp;
 	int would_hit_hwbug;
+	dma_addr_t mapping;
 
 	len = skb_headlen(skb);
 
@@ -4942,11 +4930,16 @@
 			       (vlan_tx_tag_get(skb) << 16));
 #endif
 
-	/* Queue skb data, a.k.a. the main skb fragment. */
-	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) {
+		dev_kfree_skb(skb);
+		goto out_unlock;
+	}
+
+	sp = skb_shinfo(skb);
+
+	mapping = sp->dma_maps[0];
 
 	tp->tx_buffers[entry].skb = skb;
-	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 	would_hit_hwbug = 0;
 
@@ -4969,13 +4962,9 @@
 			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
 			len = frag->size;
-			mapping = pci_map_page(tp->pdev,
-					       frag->page,
-					       frag->page_offset,
-					       len, PCI_DMA_TODEVICE);
+			mapping = sp->dma_maps[i + 1];
 
 			tp->tx_buffers[entry].skb = NULL;
-			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			if (tg3_4g_overflow_test(mapping, len))
 				would_hit_hwbug = 1;
@@ -5128,7 +5117,6 @@
 	for (i = 0; i < TG3_TX_RING_SIZE; ) {
 		struct tx_ring_info *txp;
 		struct sk_buff *skb;
-		int j;
 
 		txp = &tp->tx_buffers[i];
 		skb = txp->skb;
@@ -5138,22 +5126,11 @@
 			continue;
 		}
 
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(txp, mapping),
-				 skb_headlen(skb),
-				 PCI_DMA_TODEVICE);
+		skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE);
+
 		txp->skb = NULL;
 
-		i++;
-
-		for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) {
-			txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
-			pci_unmap_page(tp->pdev,
-				       pci_unmap_addr(txp, mapping),
-				       skb_shinfo(skb)->frags[j].size,
-				       PCI_DMA_TODEVICE);
-			i++;
-		}
+		i += skb_shinfo(skb)->nr_frags + 1;
 
 		dev_kfree_skb_any(skb);
 	}
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index f5b8cab..6c7b5e3 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2197,7 +2197,6 @@
 
 struct tx_ring_info {
 	struct sk_buff			*skb;
-	DECLARE_PCI_UNMAP_ADDR(mapping)
 	u32				prev_vlan_tag;
 };
 
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9099237..aa80ad9 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -146,8 +146,14 @@
 	unsigned short	gso_segs;
 	unsigned short  gso_type;
 	__be32          ip6_frag_id;
+#ifdef CONFIG_HAS_DMA
+	unsigned int	num_dma_maps;
+#endif
 	struct sk_buff	*frag_list;
 	skb_frag_t	frags[MAX_SKB_FRAGS];
+#ifdef CONFIG_HAS_DMA
+	dma_addr_t	dma_maps[MAX_SKB_FRAGS + 1];
+#endif
 };
 
 /* We divide dataref into two halves.  The higher 16 bits hold references
@@ -353,6 +359,14 @@
 
 #include <asm/system.h>
 
+#ifdef CONFIG_HAS_DMA
+#include <linux/dma-mapping.h>
+extern int skb_dma_map(struct device *dev, struct sk_buff *skb,
+		       enum dma_data_direction dir);
+extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
+			  enum dma_data_direction dir);
+#endif
+
 extern void kfree_skb(struct sk_buff *skb);
 extern void	       __kfree_skb(struct sk_buff *skb);
 extern struct sk_buff *__alloc_skb(unsigned int size,
diff --git a/net/core/Makefile b/net/core/Makefile
index b1332f6..26a37cb 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -6,6 +6,7 @@
 	 gen_stats.o gen_estimator.o net_namespace.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
+obj-$(CONFIG_HAS_DMA) += skb_dma_map.o
 
 obj-y		     += dev.o ethtool.o dev_mcast.o dst.o netevent.o \
 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o
diff --git a/net/core/skb_dma_map.c b/net/core/skb_dma_map.c
new file mode 100644
index 0000000..1f49afc
--- /dev/null
+++ b/net/core/skb_dma_map.c
@@ -0,0 +1,66 @@
+/* skb_dma_map.c: DMA mapping helpers for socket buffers.
+ *
+ * Copyright (C) David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/skbuff.h>
+
+int skb_dma_map(struct device *dev, struct sk_buff *skb,
+		enum dma_data_direction dir)
+{
+	struct skb_shared_info *sp = skb_shinfo(skb);
+	dma_addr_t map;
+	int i;
+
+	map = dma_map_single(dev, skb->data,
+			     skb_headlen(skb), dir);
+	if (dma_mapping_error(dev, map))
+		goto out_err;
+
+	sp->dma_maps[0] = map;
+	for (i = 0; i < sp->nr_frags; i++) {
+		skb_frag_t *fp = &sp->frags[i];
+
+		map = dma_map_page(dev, fp->page, fp->page_offset,
+				   fp->size, dir);
+		if (dma_mapping_error(dev, map))
+			goto unwind;
+		sp->dma_maps[i + 1] = map;
+	}
+	sp->num_dma_maps = i + 1;
+
+	return 0;
+
+unwind:
+	while (i-- >= 0) {
+		skb_frag_t *fp = &sp->frags[i];
+
+		dma_unmap_page(dev, sp->dma_maps[i + 1],
+			       fp->size, dir);
+	}
+	dma_unmap_single(dev, sp->dma_maps[0],
+			 skb_headlen(skb), dir);
+out_err:
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(skb_dma_map);
+
+void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
+		   enum dma_data_direction dir)
+{
+	struct skb_shared_info *sp = skb_shinfo(skb);
+	int i;
+
+	dma_unmap_single(dev, sp->dma_maps[0],
+			 skb_headlen(skb), dir);
+	for (i = 0; i < sp->nr_frags; i++) {
+		skb_frag_t *fp = &sp->frags[i];
+
+		dma_unmap_page(dev, sp->dma_maps[i + 1],
+			       fp->size, dir);
+	}
+}
+EXPORT_SYMBOL(skb_dma_unmap);