Skip to contentSkip to conversation

integrate dma_ops

PATCH New Glauber Costa 1 participant 29 messages Apr 8, 2008

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover integrate dma_ops

Hi,

This is the final integration of dma_ops between x86_64 and i386. The final code is closer to x86_64 than to i386, which is obviously expected.

At the end, pci-dma_{32,64}.c are gone, pci-nommu_64.c is gone, and the temporary pci-base_32.c is gone too.

This patchset received the same level of scrutiny as the others from my side:
compiled tested in at least 6 different random configs, boot tested in my hardware.

The final diffstat says:

 Documentation/feature-removal-schedule.txt |    7 
 arch/x86/kernel/Makefile                   |    9 
 arch/x86/kernel/pci-base_32.c              |   72 ---
 arch/x86/kernel/pci-dma.c                  |  524 +++++++++++++++++++++++++++++
 arch/x86/kernel/pci-dma_32.c               |  503 +++++++--------------------
 arch/x86/kernel/pci-dma_64.c               |  443 +-----------------------
 arch/x86/kernel/pci-nommu.c                |  100 +++++
 arch/x86/kernel/pci-nommu_64.c             |  140 -------
 arch/x86/mm/init_64.c                      |    4 
 include/asm-x86/dma-mapping.h              |   14 
 include/asm-x86/scatterlist.h              |    3 
 11 files changed, 832 insertions(+), 987 deletions(-)
#1 lore raw

PATCH 1/28 x86: introduce pci-dma.c

This patch introduces pci-dma.c, a common file for pci dma between i386 and x86_64. As a start, dma_set_mask() is the same between architectures, and is placed there.

---
 arch/x86/kernel/Makefile     |    2 +-
 arch/x86/kernel/pci-dma.c    |   14 ++++++++++++++
 arch/x86/kernel/pci-dma_32.c |   12 ------------
 arch/x86/kernel/pci-dma_64.c |    9 ---------
 4 files changed, 15 insertions(+), 22 deletions(-)
 create mode 100644 arch/x86/kernel/pci-dma.c
arch/x86/kernel/Makefile +1 -1
index 53c8fa4..befe901 100644
@@ -24,7 +24,7 @@ obj-$(CONFIG_X86_32)	+= sys_i386_32.o i386_ksyms_32.o
 obj-$(CONFIG_X86_64)	+= sys_x86_64.o x8664_ksyms_64.o
 obj-$(CONFIG_X86_64)	+= syscall_64.o vsyscall_64.o setup64.o
 obj-y			+= pci-dma_$(BITS).o  bootflag.o e820_$(BITS).o
-obj-y			+= quirks.o i8237.o topology.o kdebugfs.o
+obj-y			+= pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
 obj-y			+= alternative.o i8253.o
 obj-$(CONFIG_X86_64)	+= pci-nommu_64.o bugs_64.o
 obj-$(CONFIG_X86_32)	+= pci-base_32.o
arch/x86/kernel/pci-dma.c new file +14 -0
new file mode 100644
index 0000000..f1c24d8
@@ -0,0 +1,14 @@
+#include <linux/dma-mapping.h>
+
+int dma_set_mask(struct device *dev, u64 mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, mask))
+		return -EIO;
+
+	*dev->dma_mask = mask;
+
+	return 0;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+
arch/x86/kernel/pci-dma_32.c +0 -12
index be6b1f6..9e82976 100644
@@ -182,18 +182,6 @@ dma_supported(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(dma_supported);
 
-int
-dma_set_mask(struct device *dev, u64 mask)
-{
-	if (!dev->dma_mask || !dma_supported(dev, mask))
-		return -EIO;
-
-	*dev->dma_mask = mask;
-
-	return 0;
-}
-EXPORT_SYMBOL(dma_set_mask);
-
 
 static __devinit void via_no_dac(struct pci_dev *dev)
 {
arch/x86/kernel/pci-dma_64.c +0 -9
index f97a08d..e697b86 100644
@@ -213,15 +213,6 @@ int dma_supported(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(dma_supported);
 
-int dma_set_mask(struct device *dev, u64 mask)
-{
-	if (!dev->dma_mask || !dma_supported(dev, mask))
-		return -EIO;
-	*dev->dma_mask = mask;
-	return 0;
-}
-EXPORT_SYMBOL(dma_set_mask);
-
 /*
  * See <Documentation/x86_64/boot-options.txt> for the iommu kernel parameter
  * documentation.
Signature · 1 line
1.5.0.6
#2 lore raw

PATCH 2/28 x86: delete empty functions from pci-nommu_64.c

In reply to Glauber Costa

This functions are now called conditionally on their existence in the struct. So just delete them, instead of keeping an empty implementation.

---
 arch/x86/kernel/pci-nommu_64.c |   15 ---------------
 1 files changed, 0 insertions(+), 15 deletions(-)
arch/x86/kernel/pci-nommu_64.c +0 -15
index 6e33076..90a7c40 100644
@@ -35,10 +35,6 @@ nommu_map_single(struct device *hwdev, phys_addr_t paddr, size_t size,
 	return bus;
 }
 
-static void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
-			int direction)
-{
-}
 
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scatter-gather version of the
@@ -71,20 +67,9 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
 	return nents;
 }
 
-/* Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-static void nommu_unmap_sg(struct device *dev, struct scatterlist *sg,
-		  int nents, int dir)
-{
-}
-
 const struct dma_mapping_ops nommu_dma_ops = {
 	.map_single = nommu_map_single,
-	.unmap_single = nommu_unmap_single,
 	.map_sg = nommu_map_sg,
-	.unmap_sg = nommu_unmap_sg,
 	.is_phys = 1,
 };
 
Signature · 1 line
1.5.0.6
#3 lore raw

PATCH 3/28 x86: implement mapping_error in pci-nommu_64.c

In reply to Glauber Costa

This patch implements mapping_error for pci-nommu_64.c. It takes care to keep the same compatible behaviour it already had. Although this file is not (yet) used for i386, we introduce the i386 version here. Again, care is taken, even at the expense of an ifdef, to keep the same behaviour inconditionally.

---
 arch/x86/kernel/pci-nommu_64.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/x86/kernel/pci-nommu_64.c +12 -0
index 90a7c40..a4e8ccf 100644
@@ -67,9 +67,21 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
 	return nents;
 }
 
+/* Make sure we keep the same behaviour */
+static int nommu_mapping_error(dma_addr_t dma_addr)
+{
+#ifdef CONFIG_X86_32
+	return 0;
+#else
+	return (dma_addr == bad_dma_address);
+#endif
+}
+
+
 const struct dma_mapping_ops nommu_dma_ops = {
 	.map_single = nommu_map_single,
 	.map_sg = nommu_map_sg,
+	.mapping_error = nommu_mapping_error,
 	.is_phys = 1,
 };
 
Signature · 1 line
1.5.0.6
#4 lore raw

PATCH 4/28 x86: Add flush_write_buffers in nommu functions

In reply to Glauber Costa

This patch adds flush_write_buffers() in some functions of pci-nommu_64.c They are added anywhere i386 would also have it. This is not a problem for x86_64, since flush_rite_buffers() an nop for it.

---
 arch/x86/kernel/pci-nommu_64.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
arch/x86/kernel/pci-nommu_64.c +2 -0
index a4e8ccf..1da9cf9 100644
@@ -32,6 +32,7 @@ nommu_map_single(struct device *hwdev, phys_addr_t paddr, size_t size,
 	dma_addr_t bus = paddr;
 	if (!check_addr("map_single", hwdev, bus, size))
 				return bad_dma_address;
+	flush_write_buffers();
 	return bus;
 }
 
@@ -64,6 +65,7 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
 			return 0;
 		s->dma_length = s->length;
 	}
+	flush_write_buffers();
 	return nents;
 }
 
Signature · 1 line
1.5.0.6
#5 lore raw

PATCH 5/28 x86: use sg_phys in x86_64

In reply to Glauber Costa

To make the code usable in i386, where we have high memory mappings, we drop te virt_to_bus(sg_virt()) construction in favour of sg_phys.

---
 arch/x86/kernel/pci-nommu_64.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kernel/pci-nommu_64.c +1 -1
index 1da9cf9..c6901e7 100644
@@ -60,7 +60,7 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
 
 	for_each_sg(sg, s, nents, i) {
 		BUG_ON(!sg_page(s));
-		s->dma_address = virt_to_bus(sg_virt(s));
+		s->dma_address = sg_phys(s);
 		if (!check_addr("map_sg", hwdev, s->dma_address, s->length))
 			return 0;
 		s->dma_length = s->length;
Signature · 1 line
1.5.0.6
#6 lore raw

PATCH 6/28 x86: use dma_length in i386

In reply to Glauber Costa

This is done to get the code closer to x86_64.

---
 arch/x86/kernel/pci-base_32.c |    1 +
 include/asm-x86/scatterlist.h |    2 --
 2 files changed, 1 insertions(+), 2 deletions(-)
arch/x86/kernel/pci-base_32.c +1 -0
index 7caf5c2..837bbe9 100644
@@ -24,6 +24,7 @@ static int pci32_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 		BUG_ON(!sg_page(sg));
 
 		sg->dma_address = sg_phys(sg);
+		sg->dma_length = sg->length;
 	}
 
 	flush_write_buffers();
include/asm-x86/scatterlist.h +0 -2
index d13c197..c043206 100644
@@ -11,9 +11,7 @@ struct scatterlist {
 	unsigned int	offset;
 	unsigned int	length;
 	dma_addr_t	dma_address;
-#ifdef CONFIG_X86_64
 	unsigned int	dma_length;
-#endif
 };
 
 #define ARCH_HAS_SG_CHAIN
Signature · 1 line
1.5.0.6
#7 lore raw

PATCH 7/28 x86: use WARN_ON in mapping functions

In reply to Glauber Costa

In the very same way i386 do, we use WARN_ON functions in map_simple and map_sg.

---
 arch/x86/kernel/pci-nommu_64.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
arch/x86/kernel/pci-nommu_64.c +3 -0
index c6901e7..8d036ae 100644
@@ -30,6 +30,7 @@ nommu_map_single(struct device *hwdev, phys_addr_t paddr, size_t size,
 	       int direction)
 {
 	dma_addr_t bus = paddr;
+	WARN_ON(size == 0);
 	if (!check_addr("map_single", hwdev, bus, size))
 				return bad_dma_address;
 	flush_write_buffers();
@@ -58,6 +59,8 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
 	struct scatterlist *s;
 	int i;
 
+	WARN_ON(nents == 0 || sg[0].length == 0);
+
 	for_each_sg(sg, s, nents, i) {
 		BUG_ON(!sg_page(s));
 		s->dma_address = sg_phys(s);
Signature · 1 line
1.5.0.6
#8 lore raw

PATCH 8/28 x86: move definition to pci-dma.c

In reply to Glauber Costa

Move dma_ops structure definition to pci-dma.c, where it belongs.

---
 arch/x86/kernel/pci-base_32.c |   11 ++++++++---
 arch/x86/kernel/pci-dma.c     |    3 +++
 arch/x86/mm/init_64.c         |    3 ---
 3 files changed, 11 insertions(+), 6 deletions(-)
arch/x86/kernel/pci-base_32.c +8 -3
index 837bbe9..b44ea51 100644
@@ -37,7 +37,7 @@ static int pci32_map_error(dma_addr_t dma_addr)
 	return 0;
 }
 
-static const struct dma_mapping_ops pci32_dma_ops = {
+const struct dma_mapping_ops pci32_dma_ops = {
 	.map_single = pci32_map_single,
 	.unmap_single = NULL,
 	.map_sg = pci32_dma_map_sg,
@@ -51,5 +51,10 @@ static const struct dma_mapping_ops pci32_dma_ops = {
 	.mapping_error = pci32_map_error,
 };
 
-const struct dma_mapping_ops *dma_ops = &pci32_dma_ops;
-EXPORT_SYMBOL(dma_ops);
+/* this is temporary */
+int __init no_iommu_init(void)
+{
+	dma_ops = &pci32_dma_ops;
+	return 0;
+}
+fs_initcall(no_iommu_init);
arch/x86/kernel/pci-dma.c +3 -0
index f1c24d8..1323cd8 100644
@@ -1,5 +1,8 @@
 #include <linux/dma-mapping.h>
 
+const struct dma_mapping_ops *dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
 int dma_set_mask(struct device *dev, u64 mask)
 {
 	if (!dev->dma_mask || !dma_supported(dev, mask))
arch/x86/mm/init_64.c +0 -3
index 8c989b8..f06a51e 100644
@@ -47,9 +47,6 @@
 #include <asm/numa.h>
 #include <asm/cacheflush.h>
 
-const struct dma_mapping_ops *dma_ops;
-EXPORT_SYMBOL(dma_ops);
-
 static unsigned long dma_reserve __initdata;
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
Signature · 1 line
1.5.0.6
#9 lore raw

PATCH 9/28 x86: move initialization functions to pci-dma.c

In reply to Glauber Costa

initcalls that triggers the various possibiities for dma subsys are moved to pci-dma.c.

---
 arch/x86/kernel/pci-dma.c    |   25 +++++++++++++++++++++++++
 arch/x86/kernel/pci-dma_64.c |   23 -----------------------
 2 files changed, 25 insertions(+), 23 deletions(-)
arch/x86/kernel/pci-dma.c +25 -0
index 1323cd8..d30634b 100644
@@ -1,4 +1,8 @@
 #include <linux/dma-mapping.h>
+#include <linux/dmar.h>
+
+#include <asm/gart.h>
+#include <asm/calgary.h>
 
 const struct dma_mapping_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
@@ -14,4 +18,25 @@ int dma_set_mask(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(dma_set_mask);
 
+static int __init pci_iommu_init(void)
+{
+#ifdef CONFIG_CALGARY_IOMMU
+	calgary_iommu_init();
+#endif
+
+	intel_iommu_init();
 
+#ifdef CONFIG_GART_IOMMU
+	gart_iommu_init();
+#endif
+
+	no_iommu_init();
+	return 0;
+}
+
+void pci_iommu_shutdown(void)
+{
+	gart_iommu_shutdown();
+}
+/* Must execute after PCI subsystem */
+fs_initcall(pci_iommu_init);
arch/x86/kernel/pci-dma_64.c +0 -23
index e697b86..e95f671 100644
@@ -347,27 +347,6 @@ void __init pci_iommu_alloc(void)
 #endif
 }
 
-static int __init pci_iommu_init(void)
-{
-#ifdef CONFIG_CALGARY_IOMMU
-	calgary_iommu_init();
-#endif
-
-	intel_iommu_init();
-
-#ifdef CONFIG_GART_IOMMU
-	gart_iommu_init();
-#endif
-
-	no_iommu_init();
-	return 0;
-}
-
-void pci_iommu_shutdown(void)
-{
-	gart_iommu_shutdown();
-}
-
 #ifdef CONFIG_PCI
 /* Many VIA bridges seem to corrupt data for DAC. Disable it here */
 
@@ -380,5 +359,3 @@ static __devinit void via_no_dac(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
 #endif
-/* Must execute after PCI subsystem */
-fs_initcall(pci_iommu_init);
Signature · 1 line
1.5.0.6
#10 lore raw

PATCH 10/28 x86: unify pci-nommu

In reply to Glauber Costa

merge pci-base_32.c and pci-nommu_64.c into pci-nommu.c Their code were made the same, so now they can be merged.

---
 arch/x86/kernel/Makefile       |    5 +-
 arch/x86/kernel/pci-base_32.c  |   60 ------------------------
 arch/x86/kernel/pci-dma.c      |    8 +++
 arch/x86/kernel/pci-dma_64.c   |    8 ---
 arch/x86/kernel/pci-nommu.c    |  100 ++++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/pci-nommu_64.c |  100 ----------------------------------------
 6 files changed, 110 insertions(+), 171 deletions(-)
 delete mode 100644 arch/x86/kernel/pci-base_32.c
 create mode 100644 arch/x86/kernel/pci-nommu.c
 delete mode 100644 arch/x86/kernel/pci-nommu_64.c
arch/x86/kernel/Makefile +2 -3
index befe901..b2a1358 100644
@@ -25,9 +25,8 @@ obj-$(CONFIG_X86_64)	+= sys_x86_64.o x8664_ksyms_64.o
 obj-$(CONFIG_X86_64)	+= syscall_64.o vsyscall_64.o setup64.o
 obj-y			+= pci-dma_$(BITS).o  bootflag.o e820_$(BITS).o
 obj-y			+= pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
-obj-y			+= alternative.o i8253.o
-obj-$(CONFIG_X86_64)	+= pci-nommu_64.o bugs_64.o
-obj-$(CONFIG_X86_32)	+= pci-base_32.o
+obj-y			+= alternative.o i8253.o pci-nommu.o
+obj-$(CONFIG_X86_64)	+= bugs_64.o
 obj-y			+= tsc_$(BITS).o io_delay.o rtc.o
 
 obj-y				+= process.o
arch/x86/kernel/pci-base_32.c deleted +0 -60

60 lines not on this page · raw message

arch/x86/kernel/pci-dma.c +8 -0
index d30634b..6b77fd8 100644
@@ -7,6 +7,14 @@
 const struct dma_mapping_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
+#ifdef CONFIG_IOMMU_DEBUG
+int panic_on_overflow __read_mostly = 1;
+int force_iommu __read_mostly = 1;
+#else
+int panic_on_overflow __read_mostly = 0;
+int force_iommu __read_mostly = 0;
+#endif
+
 int dma_set_mask(struct device *dev, u64 mask)
 {
 	if (!dev->dma_mask || !dma_supported(dev, mask))
arch/x86/kernel/pci-dma_64.c +0 -8
index e95f671..4202130 100644
@@ -27,14 +27,6 @@ EXPORT_SYMBOL(iommu_bio_merge);
 static int iommu_sac_force __read_mostly = 0;
 
 int no_iommu __read_mostly;
-#ifdef CONFIG_IOMMU_DEBUG
-int panic_on_overflow __read_mostly = 1;
-int force_iommu __read_mostly = 1;
-#else
-int panic_on_overflow __read_mostly = 0;
-int force_iommu __read_mostly= 0;
-#endif
-
 /* Set this to 1 if there is a HW IOMMU in the system */
 int iommu_detected __read_mostly = 0;
 
arch/x86/kernel/pci-nommu.c new file +100 -0

100 lines not on this page · raw message

arch/x86/kernel/pci-nommu_64.c deleted +0 -100

100 lines not on this page · raw message

Signature · 1 line
1.5.0.6
#11 lore raw

PATCH 11/28 x86: move pci fixup to pci-dma.c

In reply to Glauber Costa

via_no_dac provides a fixup that is the same for both architectures. Move it to pci-dma.c.

---
 arch/x86/kernel/pci-dma.c     |   18 ++++++++++++++++++
 arch/x86/kernel/pci-dma_32.c  |   13 -------------
 arch/x86/kernel/pci-dma_64.c  |   15 ---------------
 include/asm-x86/dma-mapping.h |    2 +-
 4 files changed, 19 insertions(+), 29 deletions(-)
arch/x86/kernel/pci-dma.c +18 -0
index 6b77fd8..e81e16f 100644
@@ -1,9 +1,13 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmar.h>
+#include <linux/pci.h>
 
 #include <asm/gart.h>
 #include <asm/calgary.h>
 
+int forbid_dac __read_mostly;
+EXPORT_SYMBOL(forbid_dac);
+
 const struct dma_mapping_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
@@ -48,3 +52,17 @@ void pci_iommu_shutdown(void)
 }
 /* Must execute after PCI subsystem */
 fs_initcall(pci_iommu_init);
+
+#ifdef CONFIG_PCI
+/* Many VIA bridges seem to corrupt data for DAC. Disable it here */
+
+static __devinit void via_no_dac(struct pci_dev *dev)
+{
+	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
+		printk(KERN_INFO "PCI: VIA PCI bridge detected."
+				 "Disabling DAC.\n");
+		forbid_dac = 1;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
+#endif
arch/x86/kernel/pci-dma_32.c +0 -13
index 9e82976..6543bb3 100644
@@ -157,9 +157,6 @@ EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
 #ifdef CONFIG_PCI
 /* Many VIA bridges seem to corrupt data for DAC. Disable it here */
 
-int forbid_dac;
-EXPORT_SYMBOL(forbid_dac);
-
 int
 dma_supported(struct device *dev, u64 mask)
 {
@@ -182,16 +179,6 @@ dma_supported(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(dma_supported);
 
-
-static __devinit void via_no_dac(struct pci_dev *dev)
-{
-	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
-		printk(KERN_INFO "PCI: VIA PCI bridge detected. Disabling DAC.\n");
-		forbid_dac = 1;
-	}
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
-
 static int check_iommu(char *s)
 {
 	if (!strcmp(s, "usedac")) {
arch/x86/kernel/pci-dma_64.c +0 -15
index 4202130..e194460 100644
@@ -161,8 +161,6 @@ void dma_free_coherent(struct device *dev, size_t size,
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
-static int forbid_dac __read_mostly;
-
 int dma_supported(struct device *dev, u64 mask)
 {
 #ifdef CONFIG_PCI
@@ -338,16 +336,3 @@ void __init pci_iommu_alloc(void)
 	pci_swiotlb_init();
 #endif
 }
-
-#ifdef CONFIG_PCI
-/* Many VIA bridges seem to corrupt data for DAC. Disable it here */
-
-static __devinit void via_no_dac(struct pci_dev *dev)
-{
-	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
-		printk(KERN_INFO "PCI: VIA PCI bridge detected. Disabling DAC.\n");
-		forbid_dac = 1;
-	}
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
-#endif
include/asm-x86/dma-mapping.h +1 -1
index 914846d..d82517d 100644
@@ -14,6 +14,7 @@ extern dma_addr_t bad_dma_address;
 extern int iommu_merge;
 extern struct device fallback_dev;
 extern int panic_on_overflow;
+extern int forbid_dac;
 
 struct dma_mapping_ops {
 	int             (*mapping_error)(dma_addr_t dma_addr);
@@ -223,6 +224,5 @@ dma_release_declared_memory(struct device *dev);
 extern void *
 dma_mark_declared_memory_occupied(struct device *dev,
 				  dma_addr_t device_addr, size_t size);
-extern int forbid_dac;
 #endif /* CONFIG_X86_32 */
 #endif
Signature · 1 line
1.5.0.6
#12 lore raw

PATCH 12/28 x86: move x86_64-specific to common code.

In reply to Glauber Costa

This patch moves the bootmem functions, that are largely x86_64-specific into pci-dma.c. The code goes inside an ifdef.

---
 arch/x86/kernel/pci-dma.c    |   73 ++++++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/pci-dma_64.c |   68 ---------------------------------------
 2 files changed, 73 insertions(+), 68 deletions(-)
arch/x86/kernel/pci-dma.c +73 -0
index e81e16f..f6d6a92 100644
@@ -1,7 +1,10 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmar.h>
 #include <linux/pci.h>
+#include <linux/bootmem.h>
 
+#include <asm/proto.h>
+#include <asm/dma.h>
 #include <asm/gart.h>
 #include <asm/calgary.h>
 
@@ -66,3 +69,73 @@ static __devinit void via_no_dac(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
 #endif
+
+#ifdef CONFIG_X86_64
+static __initdata void *dma32_bootmem_ptr;
+static unsigned long dma32_bootmem_size __initdata = (128ULL<<20);
+
+static int __init parse_dma32_size_opt(char *p)
+{
+	if (!p)
+		return -EINVAL;
+	dma32_bootmem_size = memparse(p, &p);
+	return 0;
+}
+early_param("dma32_size", parse_dma32_size_opt);
+
+void __init dma32_reserve_bootmem(void)
+{
+	unsigned long size, align;
+	if (end_pfn <= MAX_DMA32_PFN)
+		return;
+
+	align = 64ULL<<20;
+	size = round_up(dma32_bootmem_size, align);
+	dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align,
+				 __pa(MAX_DMA_ADDRESS));
+	if (dma32_bootmem_ptr)
+		dma32_bootmem_size = size;
+	else
+		dma32_bootmem_size = 0;
+}
+static void __init dma32_free_bootmem(void)
+{
+	int node;
+
+	if (end_pfn <= MAX_DMA32_PFN)
+		return;
+
+	if (!dma32_bootmem_ptr)
+		return;
+
+	for_each_online_node(node)
+		free_bootmem_node(NODE_DATA(node), __pa(dma32_bootmem_ptr),
+				  dma32_bootmem_size);
+
+	dma32_bootmem_ptr = NULL;
+	dma32_bootmem_size = 0;
+}
+
+void __init pci_iommu_alloc(void)
+{
+	/* free the range so iommu could get some range less than 4G */
+	dma32_free_bootmem();
+	/*
+	 * The order of these functions is important for
+	 * fall-back/fail-over reasons
+	 */
+#ifdef CONFIG_GART_IOMMU
+	gart_iommu_hole_init();
+#endif
+
+#ifdef CONFIG_CALGARY_IOMMU
+	detect_calgary();
+#endif
+
+	detect_intel_iommu();
+
+#ifdef CONFIG_SWIOTLB
+	pci_swiotlb_init();
+#endif
+}
+#endif
arch/x86/kernel/pci-dma_64.c +0 -68

71 lines not on this page · raw message

Signature · 1 line
1.5.0.6
#13 lore raw

PATCH 13/28 x86: merge dma_supported

In reply to Glauber Costa

The code for both arches are very similar, so this patch merge them.

---
 arch/x86/kernel/pci-dma.c    |   44 ++++++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/pci-dma_32.c |   24 ----------------------
 arch/x86/kernel/pci-dma_64.c |   44 +-----------------------------------------
 3 files changed, 45 insertions(+), 67 deletions(-)
arch/x86/kernel/pci-dma.c +44 -0
index f6d6a92..4289a9b 100644
@@ -14,6 +14,8 @@ EXPORT_SYMBOL(forbid_dac);
 const struct dma_mapping_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
+int iommu_sac_force __read_mostly = 0;
+
 #ifdef CONFIG_IOMMU_DEBUG
 int panic_on_overflow __read_mostly = 1;
 int force_iommu __read_mostly = 1;
@@ -33,6 +35,48 @@ int dma_set_mask(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(dma_set_mask);
 
+int dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PCI
+	if (mask > 0xffffffff && forbid_dac > 0) {
+		printk(KERN_INFO "PCI: Disallowing DAC for device %s\n",
+				 dev->bus_id);
+		return 0;
+	}
+#endif
+
+	if (dma_ops->dma_supported)
+		return dma_ops->dma_supported(dev, mask);
+
+	/* Copied from i386. Doesn't make much sense, because it will
+	   only work for pci_alloc_coherent.
+	   The caller just has to use GFP_DMA in this case. */
+	if (mask < DMA_24BIT_MASK)
+		return 0;
+
+	/* Tell the device to use SAC when IOMMU force is on.  This
+	   allows the driver to use cheaper accesses in some cases.
+
+	   Problem with this is that if we overflow the IOMMU area and
+	   return DAC as fallback address the device may not handle it
+	   correctly.
+
+	   As a special case some controllers have a 39bit address
+	   mode that is as efficient as 32bit (aic79xx). Don't force
+	   SAC for these.  Assume all masks <= 40 bits are of this
+	   type. Normally this doesn't make any difference, but gives
+	   more gentle handling of IOMMU overflow. */
+	if (iommu_sac_force && (mask >= DMA_40BIT_MASK)) {
+		printk(KERN_INFO "%s: Force SAC with mask %Lx\n",
+				 dev->bus_id, mask);
+		return 0;
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL(dma_supported);
+
+
 static int __init pci_iommu_init(void)
 {
 #ifdef CONFIG_CALGARY_IOMMU
arch/x86/kernel/pci-dma_32.c +0 -24
index 6543bb3..1d4091a 100644
@@ -155,30 +155,6 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
 EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
 
 #ifdef CONFIG_PCI
-/* Many VIA bridges seem to corrupt data for DAC. Disable it here */
-
-int
-dma_supported(struct device *dev, u64 mask)
-{
-	/*
-	 * we fall back to GFP_DMA when the mask isn't all 1s,
-	 * so we can't guarantee allocations that must be
-	 * within a tighter range than GFP_DMA..
-	 */
-	if (mask < 0x00ffffff)
-		return 0;
-
-	/* Work around chipset bugs */
-	if (forbid_dac > 0 && mask > 0xffffffffULL)
-		return 0;
-
-	if (dma_ops->dma_supported)
-		return dma_ops->dma_supported(dev, mask);
-
-	return 1;
-}
-EXPORT_SYMBOL(dma_supported);
-
 static int check_iommu(char *s)
 {
 	if (!strcmp(s, "usedac")) {
arch/x86/kernel/pci-dma_64.c +1 -43

56 lines not on this page · raw message

Signature · 1 line
1.5.0.6
#14 lore raw

PATCH 14/28 x86: merge iommu initialization parameters

In reply to Glauber Costa

we merge the iommu initialization parameters in pci-dma.c Nice thing, that both architectures at least recognize the same parameters.

usedac i386 parameter is marked for deprecation

---
 Documentation/feature-removal-schedule.txt |    7 +++
 arch/x86/kernel/pci-dma.c                  |   81 ++++++++++++++++++++++++++++
 arch/x86/kernel/pci-dma_32.c               |   12 ----
 arch/x86/kernel/pci-dma_64.c               |   79 ---------------------------
 include/asm-x86/dma-mapping.h              |    1 +
 5 files changed, 89 insertions(+), 91 deletions(-)
Documentation/feature-removal-schedule.txt +7 -0
index 1092b2e..537c88b 100644
@@ -306,3 +306,10 @@ Why:	Not used in-tree. The current out-of-tree users used it to
 	code / infrastructure should be in the kernel and not in some
 	out-of-tree driver.
 Who:	Thomas Gleixner <[email protected]>
+
+----------------------------
+
+What:	usedac i386 kernel parameter
+When:	2.6.27
+Why:	replaced by allowdac and no dac combination
+Who:	Glauber Costa <[email protected]>
arch/x86/kernel/pci-dma.c +81 -0

90 lines not on this page · raw message

arch/x86/kernel/pci-dma_32.c +0 -12
index 1d4091a..eea52df 100644
@@ -153,15 +153,3 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
 	return mem->virt_base + (pos << PAGE_SHIFT);
 }
 EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
-
-#ifdef CONFIG_PCI
-static int check_iommu(char *s)
-{
-	if (!strcmp(s, "usedac")) {
-		forbid_dac = -1;
-		return 1;
-	}
-	return 0;
-}
-__setup("iommu=", check_iommu);
-#endif
arch/x86/kernel/pci-dma_64.c +0 -79

91 lines not on this page · raw message

include/asm-x86/dma-mapping.h +1 -0
index d82517d..7580736 100644
@@ -15,6 +15,7 @@ extern int iommu_merge;
 extern struct device fallback_dev;
 extern int panic_on_overflow;
 extern int forbid_dac;
+extern int force_iommu;
 
 struct dma_mapping_ops {
 	int             (*mapping_error)(dma_addr_t dma_addr);
Signature · 1 line
1.5.0.6
#15 lore raw

PATCH 15/28 x86: move dma_coherent functions to pci-dma.c

In reply to Glauber Costa

They are placed in an ifdef, since they are i386 specific the structure definition goes to dma-mapping.h.

---
 arch/x86/kernel/pci-dma.c     |   81 +++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/pci-dma_32.c  |   85 -----------------------------------------
 include/asm-x86/dma-mapping.h |    8 ++++
 3 files changed, 89 insertions(+), 85 deletions(-)
arch/x86/kernel/pci-dma.c +81 -0
index e04f42c..d06d8df 100644
@@ -47,6 +47,87 @@ int dma_set_mask(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(dma_set_mask);
 
+#ifdef CONFIG_X86_32
+int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+				dma_addr_t device_addr, size_t size, int flags)
+{
+	void __iomem *mem_base = NULL;
+	int pages = size >> PAGE_SHIFT;
+	int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
+
+	if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
+		goto out;
+	if (!size)
+		goto out;
+	if (dev->dma_mem)
+		goto out;
+
+	/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
+
+	mem_base = ioremap(bus_addr, size);
+	if (!mem_base)
+		goto out;
+
+	dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
+	if (!dev->dma_mem)
+		goto out;
+	dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!dev->dma_mem->bitmap)
+		goto free1_out;
+
+	dev->dma_mem->virt_base = mem_base;
+	dev->dma_mem->device_base = device_addr;
+	dev->dma_mem->size = pages;
+	dev->dma_mem->flags = flags;
+
+	if (flags & DMA_MEMORY_MAP)
+		return DMA_MEMORY_MAP;
+
+	return DMA_MEMORY_IO;
+
+ free1_out:
+	kfree(dev->dma_mem);
+ out:
+	if (mem_base)
+		iounmap(mem_base);
+	return 0;
+}
+EXPORT_SYMBOL(dma_declare_coherent_memory);
+
+void dma_release_declared_memory(struct device *dev)
+{
+	struct dma_coherent_mem *mem = dev->dma_mem;
+
+	if (!mem)
+		return;
+	dev->dma_mem = NULL;
+	iounmap(mem->virt_base);
+	kfree(mem->bitmap);
+	kfree(mem);
+}
+EXPORT_SYMBOL(dma_release_declared_memory);
+
+void *dma_mark_declared_memory_occupied(struct device *dev,
+					dma_addr_t device_addr, size_t size)
+{
+	struct dma_coherent_mem *mem = dev->dma_mem;
+	int pos, err;
+	int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1);
+
+	pages >>= PAGE_SHIFT;
+
+	if (!mem)
+		return ERR_PTR(-EINVAL);
+
+	pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
+	err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
+	if (err != 0)
+		return ERR_PTR(err);
+	return mem->virt_base + (pos << PAGE_SHIFT);
+}
+EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
+#endif /* CONFIG_X86_32 */
+
 int dma_supported(struct device *dev, u64 mask)
 {
 #ifdef CONFIG_PCI
arch/x86/kernel/pci-dma_32.c +0 -85

94 lines not on this page · raw message

include/asm-x86/dma-mapping.h +8 -0
index 7580736..a1a4dc7 100644
@@ -215,6 +215,14 @@ static inline int dma_get_cache_alignment(void)
 
 #ifdef CONFIG_X86_32
 #  define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
+struct dma_coherent_mem {
+	void		*virt_base;
+	u32		device_base;
+	int		size;
+	int		flags;
+	unsigned long	*bitmap;
+};
+
 extern int
 dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
 			    dma_addr_t device_addr, size_t size, int flags);
Signature · 1 line
1.5.0.6
#16 lore raw

PATCH 16/28 x86: isolate coherent mapping functions

In reply to Glauber Costa

i386 implements the declare coherent memory API, and x86_64 does not it is reflected in pieces of dma_alloc_coherent and dma_free_coherent. Those pieces are isolated in separate functions, that are declared as empty macros in x86_64. This way we can make the code the same.

---
 arch/x86/kernel/pci-dma_32.c |   51 ++++++++++++++++++++++++++++-------------
 arch/x86/kernel/pci-dma_64.c |   11 ++++++++-
 2 files changed, 45 insertions(+), 17 deletions(-)
arch/x86/kernel/pci-dma_32.c +35 -16
index 818d95e..78c7640 100644
@@ -18,27 +18,50 @@
 dma_addr_t bad_dma_address __read_mostly = 0x0;
 EXPORT_SYMBOL(bad_dma_address);
 
-void *dma_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t gfp)
+static int dma_alloc_from_coherent_mem(struct device *dev, ssize_t size,
+				       dma_addr_t *dma_handle, void **ret)
 {
-	void *ret;
 	struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
 	int order = get_order(size);
-	/* ignore region specifiers */
-	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
 
 	if (mem) {
 		int page = bitmap_find_free_region(mem->bitmap, mem->size,
 						     order);
 		if (page >= 0) {
 			*dma_handle = mem->device_base + (page << PAGE_SHIFT);
-			ret = mem->virt_base + (page << PAGE_SHIFT);
-			memset(ret, 0, size);
-			return ret;
+			*ret = mem->virt_base + (page << PAGE_SHIFT);
+			memset(*ret, 0, size);
 		}
 		if (mem->flags & DMA_MEMORY_EXCLUSIVE)
-			return NULL;
+			*ret = NULL;
+	}
+	return (mem != NULL);
+}
+
+static int dma_release_coherent(struct device *dev, int order, void *vaddr)
+{
+	struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+
+	if (mem && vaddr >= mem->virt_base && vaddr <
+		   (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+		int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+
+		bitmap_release_region(mem->bitmap, page, order);
+		return 1;
 	}
+	return 0;
+}
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+			   dma_addr_t *dma_handle, gfp_t gfp)
+{
+	void *ret = NULL;
+	int order = get_order(size);
+	/* ignore region specifiers */
+	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+	if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &ret))
+		return ret;
 
 	if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
 		gfp |= GFP_DMA;
@@ -56,15 +79,11 @@ EXPORT_SYMBOL(dma_alloc_coherent);
 void dma_free_coherent(struct device *dev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
-	struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
 	int order = get_order(size);
 
 	WARN_ON(irqs_disabled());	/* for portability */
-	if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
-		int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
-
-		bitmap_release_region(mem->bitmap, page, order);
-	} else
-		free_pages((unsigned long)vaddr, order);
+	if (dma_release_coherent(dev, order, vaddr))
+		return;
+	free_pages((unsigned long)vaddr, order);
 }
 EXPORT_SYMBOL(dma_free_coherent);
arch/x86/kernel/pci-dma_64.c +10 -1
index e7d45cf..6eacd58 100644
@@ -39,6 +39,8 @@ dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order)
 	return page ? page_address(page) : NULL;
 }
 
+#define dma_alloc_from_coherent_mem(dev, size, handle, ret) (0)
+#define dma_release_coherent(dev, order, vaddr) (0)
 /*
  * Allocate memory for a coherent mapping.
  */
@@ -50,6 +52,10 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
 	unsigned long dma_mask = 0;
 	u64 bus;
 
+
+	if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &memory))
+		return memory;
+
 	if (!dev)
 		dev = &fallback_dev;
 	dma_mask = dev->coherent_dma_mask;
@@ -141,9 +147,12 @@ EXPORT_SYMBOL(dma_alloc_coherent);
 void dma_free_coherent(struct device *dev, size_t size,
 			 void *vaddr, dma_addr_t bus)
 {
+	int order = get_order(size);
 	WARN_ON(irqs_disabled());	/* for portability */
+	if (dma_release_coherent(dev, order, vaddr))
+		return;
 	if (dma_ops->unmap_single)
 		dma_ops->unmap_single(dev, bus, size, 0);
-	free_pages((unsigned long)vaddr, get_order(size));
+	free_pages((unsigned long)vaddr, order);
 }
 EXPORT_SYMBOL(dma_free_coherent);
Signature · 1 line
1.5.0.6
#17 lore raw

PATCH 17/28 x86: adjust dma_free_coherent for i386

In reply to Glauber Costa

We call unmap_single, if available.

---
 arch/x86/kernel/pci-dma_32.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
arch/x86/kernel/pci-dma_32.c +2 -0
index 78c7640..49166a4 100644
@@ -84,6 +84,8 @@ void dma_free_coherent(struct device *dev, size_t size,
 	WARN_ON(irqs_disabled());	/* for portability */
 	if (dma_release_coherent(dev, order, vaddr))
 		return;
+	if (dma_ops->unmap_single)
+		dma_ops->unmap_single(dev, dma_handle, size, 0);
 	free_pages((unsigned long)vaddr, order);
 }
 EXPORT_SYMBOL(dma_free_coherent);
Signature · 1 line
1.5.0.6
#18 lore raw

PATCH 18/28 x86: move bad_dma_address

In reply to Glauber Costa

It goes to pci-dma.c, and is removed from the arch-specific files.

---
 arch/x86/kernel/pci-dma.c    |    2 ++
 arch/x86/kernel/pci-dma_32.c |    4 ----
 arch/x86/kernel/pci-dma_64.c |    2 --
 3 files changed, 2 insertions(+), 6 deletions(-)
arch/x86/kernel/pci-dma.c +2 -0
index d06d8df..d6734ed 100644
@@ -35,6 +35,8 @@ int iommu_detected __read_mostly = 0;
 int iommu_bio_merge __read_mostly = 0;
 EXPORT_SYMBOL(iommu_bio_merge);
 
+dma_addr_t bad_dma_address __read_mostly = 0;
+EXPORT_SYMBOL(bad_dma_address);
 
 int dma_set_mask(struct device *dev, u64 mask)
 {
arch/x86/kernel/pci-dma_32.c +0 -4
index 49166a4..5ae3470 100644
@@ -14,10 +14,6 @@
 #include <linux/module.h>
 #include <asm/io.h>
 
-/* For i386, we make it point to the NULL address */
-dma_addr_t bad_dma_address __read_mostly = 0x0;
-EXPORT_SYMBOL(bad_dma_address);
-
 static int dma_alloc_from_coherent_mem(struct device *dev, ssize_t size,
 				       dma_addr_t *dma_handle, void **ret)
 {
arch/x86/kernel/pci-dma_64.c +0 -2
index 6eacd58..5f03e41 100644
@@ -14,8 +14,6 @@
 #include <asm/gart.h>
 #include <asm/calgary.h>
 
-dma_addr_t bad_dma_address __read_mostly;
-EXPORT_SYMBOL(bad_dma_address);
 
 /* Dummy device used for NULL arguments (normally ISA). Better would
    be probably a smaller DMA mask, but this is bug-to-bug compatible
Signature · 1 line
1.5.0.6
#19 lore raw

PATCH 19/28 x86: remove virt_to_bus in pci-dma_64.c

In reply to Glauber Costa

virt_to_bus() is deprecated according to the docs, and moreover, won't return the right thing in i386 if we're dealing with high memory mappings. So we make our allocation function return a page, and then use page_address() (for virtual addr) and page_to_phys() (for physical addr) instead.

---
 arch/x86/kernel/pci-dma_64.c |   14 +++++++-------
 1 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/kernel/pci-dma_64.c +7 -7
index 5f03e41..13a31a4 100644
@@ -28,13 +28,11 @@ struct device fallback_dev = {
 noinline static void *
 dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order)
 {
-	struct page *page;
 	int node;
 
 	node = dev_to_node(dev);
 
-	page = alloc_pages_node(node, gfp, order);
-	return page ? page_address(page) : NULL;
+	return alloc_pages_node(node, gfp, order);
 }
 
 #define dma_alloc_from_coherent_mem(dev, size, handle, ret) (0)
@@ -47,6 +45,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
 		   gfp_t gfp)
 {
 	void *memory;
+	struct page *page;
 	unsigned long dma_mask = 0;
 	u64 bus;
 
@@ -79,13 +78,14 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
 		gfp |= GFP_DMA32;
 
  again:
-	memory = dma_alloc_pages(dev, gfp, get_order(size));
-	if (memory == NULL)
+	page = dma_alloc_pages(dev, gfp, get_order(size));
+	if (page == NULL)
 		return NULL;
 
 	{
 		int high, mmu;
-		bus = virt_to_bus(memory);
+		bus = page_to_phys(page);
+		memory = page_address(page);
 	        high = (bus + size) >= dma_mask;
 		mmu = high;
 		if (force_iommu && !(gfp & GFP_DMA))
@@ -112,7 +112,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
 
 		memset(memory, 0, size);
 		if (!mmu) {
-			*dma_handle = virt_to_bus(memory);
+			*dma_handle = bus;
 			return memory;
 		}
 	}
Signature · 1 line
1.5.0.6
#20 lore raw

PATCH 20/28 x86: use numa allocation function in i386

In reply to Glauber Costa

We can do it here to, in the same way x86_64 does.

---
 arch/x86/kernel/pci-dma_32.c |   27 ++++++++++++++++++++++-----
 1 files changed, 22 insertions(+), 5 deletions(-)
arch/x86/kernel/pci-dma_32.c +22 -5
index 5ae3470..0d630ae 100644
@@ -48,10 +48,23 @@ static int dma_release_coherent(struct device *dev, int order, void *vaddr)
 	return 0;
 }
 
+/* Allocate DMA memory on node near device */
+noinline struct page *
+dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order)
+{
+	int node;
+
+	node = dev_to_node(dev);
+
+	return alloc_pages_node(node, gfp, order);
+}
+
 void *dma_alloc_coherent(struct device *dev, size_t size,
 			   dma_addr_t *dma_handle, gfp_t gfp)
 {
 	void *ret = NULL;
+	struct page *page;
+	dma_addr_t bus;
 	int order = get_order(size);
 	/* ignore region specifiers */
 	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
@@ -62,12 +75,16 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 	if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
 		gfp |= GFP_DMA;
 
-	ret = (void *)__get_free_pages(gfp, order);
+	page = dma_alloc_pages(dev, gfp, order);
+	if (page == NULL)
+		return NULL;
+
+	ret = page_address(page);
+	bus = page_to_phys(page);
+
+	memset(ret, 0, size);
+	*dma_handle = bus;
 
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_phys(ret);
-	}
 	return ret;
 }
 EXPORT_SYMBOL(dma_alloc_coherent);
Signature · 1 line
1.5.0.6
#21 lore raw

PATCH 21/28 x86: retry allocation if failed

In reply to Glauber Costa

This patch puts in the code to retry allocation in case it fails. By its own, it does not make much sense but making the code look like x86_64. But later patches in this series will make we try to allocate from zones other than DMA first, which will possibly fail.

---
 arch/x86/kernel/pci-dma_32.c |   34 +++++++++++++++++++++++++++++-----
 1 files changed, 29 insertions(+), 5 deletions(-)
arch/x86/kernel/pci-dma_32.c +29 -5
index 0d630ae..f6cf434 100644
@@ -66,6 +66,8 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 	struct page *page;
 	dma_addr_t bus;
 	int order = get_order(size);
+	unsigned long dma_mask = 0;
+
 	/* ignore region specifiers */
 	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
 
@@ -75,15 +77,37 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 	if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
 		gfp |= GFP_DMA;
 
+	dma_mask = dev->coherent_dma_mask;
+	if (dma_mask == 0)
+		dma_mask = DMA_32BIT_MASK;
+
+ again:
 	page = dma_alloc_pages(dev, gfp, order);
 	if (page == NULL)
 		return NULL;
 
-	ret = page_address(page);
-	bus = page_to_phys(page);
-
-	memset(ret, 0, size);
-	*dma_handle = bus;
+	{
+		int high, mmu;
+		bus = page_to_phys(page);
+		ret = page_address(page);
+		high = (bus + size) >= dma_mask;
+		mmu = high;
+		if (force_iommu && !(gfp & GFP_DMA))
+			mmu = 1;
+		else if (high) {
+			free_pages((unsigned long)ret,
+				   get_order(size));
+
+			/* Don't use the 16MB ZONE_DMA unless absolutely
+			   needed. It's better to use remapping first. */
+			if (dma_mask < DMA_32BIT_MASK && !(gfp & GFP_DMA)) {
+				gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
+				goto again;
+			}
+		}
+		memset(ret, 0, size);
+		*dma_handle = bus;
+	}
 
 	return ret;
 }
Signature · 1 line
1.5.0.6
#22 lore raw

PATCH 22/28 x86: use a fallback dev for i386

In reply to Glauber Costa

We can use a fallback dev for cases of a NULL device being passed (mostly ISA) This comes from x86_64 implementation.

---
 arch/x86/kernel/pci-dma_32.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)
arch/x86/kernel/pci-dma_32.c +13 -0
index f6cf434..0e9ec11 100644
@@ -14,6 +14,16 @@
 #include <linux/module.h>
 #include <asm/io.h>
 
+/* Dummy device used for NULL arguments (normally ISA). Better would
+   be probably a smaller DMA mask, but this is bug-to-bug compatible
+   to i386. */
+struct device fallback_dev = {
+	.bus_id = "fallback device",
+	.coherent_dma_mask = DMA_32BIT_MASK,
+	.dma_mask = &fallback_dev.coherent_dma_mask,
+};
+
+
 static int dma_alloc_from_coherent_mem(struct device *dev, ssize_t size,
 				       dma_addr_t *dma_handle, void **ret)
 {
@@ -77,6 +87,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 	if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
 		gfp |= GFP_DMA;
 
+	if (!dev)
+		dev = &fallback_dev;
+
 	dma_mask = dev->coherent_dma_mask;
 	if (dma_mask == 0)
 		dma_mask = DMA_32BIT_MASK;
Signature · 1 line
1.5.0.6
#23 lore raw

PATCH 23/28 x86: don't try to allocate from DMA zone at first

In reply to Glauber Costa

If we fail, we'll loop into the allocation again,
and then allocate in the DMA zone.

---
 arch/x86/kernel/pci-dma_32.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)
arch/x86/kernel/pci-dma_32.c +0 -3
index 0e9ec11..11f100a 100644
@@ -84,9 +84,6 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 	if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &ret))
 		return ret;
 
-	if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-		gfp |= GFP_DMA;
-
 	if (!dev)
 		dev = &fallback_dev;
 
Signature · 1 line
1.5.0.6
#24 lore raw

PATCH 24/28 x86: unify gfp masks

In reply to Glauber Costa

Use the same gfp masks for x86_64 and i386.
It involves using HIGHMEM or DMA32 where necessary, for the sake of code compatibility, (no real effect), and using the NORETRY mask for i386.

---
 arch/x86/kernel/pci-dma_32.c |    6 ++++--
 arch/x86/kernel/pci-dma_64.c |    2 ++
 2 files changed, 6 insertions(+), 2 deletions(-)
arch/x86/kernel/pci-dma_32.c +4 -2
index 11f100a..5450bd1 100644
@@ -79,7 +79,7 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 	unsigned long dma_mask = 0;
 
 	/* ignore region specifiers */
-	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
 
 	if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &ret))
 		return ret;
@@ -91,7 +91,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 	if (dma_mask == 0)
 		dma_mask = DMA_32BIT_MASK;
 
- again:
+	/* Don't invoke OOM killer */
+	gfp |= __GFP_NORETRY;
+again:
 	page = dma_alloc_pages(dev, gfp, order);
 	if (page == NULL)
 		return NULL;
arch/x86/kernel/pci-dma_64.c +2 -0
index 13a31a4..b956f59 100644
@@ -49,6 +49,8 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
 	unsigned long dma_mask = 0;
 	u64 bus;
 
+	/* ignore region specifiers */
+	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
 
 	if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &memory))
 		return memory;
Signature · 1 line
1.5.0.6
#25 lore raw

PATCH 25/28 x86: remove kludge from x86_64

In reply to Glauber Costa

The claim is that i386 does it. Just it does not.
So remove it.

---
 arch/x86/kernel/pci-dma_64.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)
arch/x86/kernel/pci-dma_64.c +0 -4
index b956f59..596c8c8 100644
@@ -68,10 +68,6 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
 	/* Don't invoke OOM killer */
 	gfp |= __GFP_NORETRY;
 
-	/* Kludge to make it bug-to-bug compatible with i386. i386
-	   uses the normal dma_mask for alloc_coherent. */
-	dma_mask &= *dev->dma_mask;
-
 	/* Why <=? Even when the mask is smaller than 4GB it is often
 	   larger than 16MB and in this case we have a chance of
 	   finding fitting memory in the next higher zone first. If
Signature · 1 line
1.5.0.6
#26 lore raw

PATCH 26/28 x86: return conditional to mmu

In reply to Glauber Costa

Just return our allocation if we don't have an mmu. For i386, where this patch is being applied, we never have. So our goal is just to have the code to look like x86_64's.

---
 arch/x86/kernel/pci-dma_32.c |   34 ++++++++++++++++++++++++++++++++--
 1 files changed, 32 insertions(+), 2 deletions(-)
arch/x86/kernel/pci-dma_32.c +32 -2
index 5450bd1..f134de3 100644
@@ -116,12 +116,42 @@ again:
 				gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
 				goto again;
 			}
+
+			/* Let low level make its own zone decisions */
+			gfp &= ~(GFP_DMA32|GFP_DMA);
+
+			if (dma_ops->alloc_coherent)
+				return dma_ops->alloc_coherent(dev, size,
+							   dma_handle, gfp);
+			return NULL;
+
 		}
 		memset(ret, 0, size);
-		*dma_handle = bus;
+		if (!mmu) {
+			*dma_handle = bus;
+			return ret;
+		}
+	}
+
+	if (dma_ops->alloc_coherent) {
+		free_pages((unsigned long)ret, get_order(size));
+		gfp &= ~(GFP_DMA|GFP_DMA32);
+		return dma_ops->alloc_coherent(dev, size, dma_handle, gfp);
+	}
+
+	if (dma_ops->map_simple) {
+		*dma_handle = dma_ops->map_simple(dev, virt_to_phys(ret),
+					      size,
+					      PCI_DMA_BIDIRECTIONAL);
+		if (*dma_handle != bad_dma_address)
+			return ret;
 	}
 
-	return ret;
+	if (panic_on_overflow)
+		panic("dma_alloc_coherent: IOMMU overflow by %lu bytes\n",
+		      (unsigned long)size);
+	free_pages((unsigned long)ret, get_order(size));
+	return NULL;
 }
 EXPORT_SYMBOL(dma_alloc_coherent);
 
Signature · 1 line
1.5.0.6
#27 lore raw

PATCH 27/28 x86: don't do dma if mask is NULL.

In reply to Glauber Costa

if the device hasn't provided a mask, abort allocation. Note that we're using a fallback device now, so it does not cover the case of a NULL device: just drivers passing NULL masks around.

---
 arch/x86/kernel/pci-dma_32.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
arch/x86/kernel/pci-dma_32.c +3 -0
index f134de3..d2f7074 100644
@@ -91,6 +91,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 	if (dma_mask == 0)
 		dma_mask = DMA_32BIT_MASK;
 
+	if (dev->dma_mask == NULL)
+		return NULL;
+
 	/* Don't invoke OOM killer */
 	gfp |= __GFP_NORETRY;
 again:
Signature · 1 line
1.5.0.6
#28 lore raw

PATCH 28/28 x86: integrate pci-dma.c

In reply to Glauber Costa

The code in pci-dma_{32,64}.c are now sufficiently close to each other. We merge them in pci-dma.c.

---
 arch/x86/kernel/Makefile     |    2 +-
 arch/x86/kernel/pci-dma.c    |  175 ++++++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/pci-dma_32.c |  173 -----------------------------------------
 arch/x86/kernel/pci-dma_64.c |  154 -------------------------------------
 4 files changed, 176 insertions(+), 328 deletions(-)
 delete mode 100644 arch/x86/kernel/pci-dma_32.c
 delete mode 100644 arch/x86/kernel/pci-dma_64.c
arch/x86/kernel/Makefile +1 -1
index b2a1358..423e1c4 100644
@@ -23,7 +23,7 @@ obj-y			+= setup_$(BITS).o i8259_$(BITS).o setup.o
 obj-$(CONFIG_X86_32)	+= sys_i386_32.o i386_ksyms_32.o
 obj-$(CONFIG_X86_64)	+= sys_x86_64.o x8664_ksyms_64.o
 obj-$(CONFIG_X86_64)	+= syscall_64.o vsyscall_64.o setup64.o
-obj-y			+= pci-dma_$(BITS).o  bootflag.o e820_$(BITS).o
+obj-y			+= bootflag.o e820_$(BITS).o
 obj-y			+= pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
 obj-y			+= alternative.o i8253.o pci-nommu.o
 obj-$(CONFIG_X86_64)	+= bugs_64.o
arch/x86/kernel/pci-dma.c +175 -0

193 lines not on this page · raw message

arch/x86/kernel/pci-dma_32.c deleted +0 -173

173 lines not on this page · raw message

arch/x86/kernel/pci-dma_64.c deleted +0 -154

154 lines not on this page · raw message

Signature · 1 line
1.5.0.6