Hello,
Here there is a series of 20 patches that lays the foundations for
using dma_ops in i386 in the very same way x86_64, as well as many other
architectures already do.The functions themselves for i386 are placed in a pci-base_32.c, but just
a few among them are actually implemented. Most were no-ops anyway.Also, as I said, this is by no means a complete coverage of dma_ops.
there are still some call sites to be patches in pci-dma_32.c (although I don't
really plan to change them, but to integrate them in a single pci-dma.c).
I intend to have it done progressively.The granularity is per-operation, meaning each patch moves one specific function
to the common header. This is compiled-tested in both i386 and x86_64 in
~5 randconfigs each, and boot-tested in my hardware with my default configsThe motivation for that is the ongoing work for pci-passthrough in KVM.
So ingo, avi, what do you think it's the best way to handle these patches through?Thanks
--
Thanks; Please also see Stephen Tweedie's tree at
http://git.et.redhat.com/?p=linux-2.6-dom0-pvops.git;a=summary
I guess your work would be overlapped anyway, but just to make sure there's no
double work.
--
I see the headers are unified, but the .c files are duplicated. I
x86.git.
--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.--
presume correctly.
--
looks very nice to me! I've applied it to x86.git, lets see what
happens.Ingo
--
Houston, we've got a problem! :-/
randconfig testing found that this patchset broke sendfile on certain
.config's - DMA started returning all 0xfffffffff data, corrupting
files. (config attached)After some bisection fun it turns out that the conversions from struct
page are wrong:+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ size_t offset, size_t size,
+ int direction)
+{
+ return dma_map_single(dev, page_address(page)+offset, size, direction);because page_address() is not defined for highmem pages in general. (and
even if it's defined, it will corrupt data)changing it to page_to_phys() is not good because it goes via a 32-bit
bottleneck that trims things on PAE:dma_addr_t (*map_single)(struct device *hwdev, void *ptr,
the 'ptr' is 32-bit albeit it's a DMA target.
what i came up is the prototype 32-bit fix below - this works on 32-bit
but breaks 64-bit because we pass in physical addresses instead of
virtual direct addresses.i'll fix the 64-bit side but that means materially touching all the
dma_mapping_ops instantiations materially on the 64-bit side - not
really something we wanted to do :-/Ingo
---------------->
Subject: x86: dma-ops on highmem fix
From: Ingo Molnar <mingo@elte.hu>Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
arch/x86/kernel/pci-base_32.c | 4 ++--
include/asm-x86/dma-mapping.h | 10 ++++++----
2 files changed, 8 insertions(+), 6 deletions(-)Index: linux-x86.q/arch/x86/kernel/pci-base_32.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/pci-base_32.c
+++ linux-x86.q/arch/x86/kernel/pci-base_32.c
@@ -4,12 +4,12 @@
#include <linux/dma-mapping.h>
#include <asm/dma-mapping.h>-static dma_addr_t pci32_map_single(struct device *dev, void *ptr,
+static dma_addr_t pci32_map_single(struct device *de...
the full fix ended up being the one below. It's not that bad - and
gart_64.c looks even a bit cleaner. Still, it needs careful review.Ingo
--------------->
Subject: x86: dma-ops on highmem fix
From: Ingo Molnar <mingo@elte.hu>Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
arch/x86/kernel/pci-base_32.c | 4 ++--
arch/x86/kernel/pci-calgary_64.c | 3 ++-
arch/x86/kernel/pci-dma_64.c | 2 +-
arch/x86/kernel/pci-gart_64.c | 15 +++++++--------
arch/x86/kernel/pci-nommu_64.c | 4 ++--
arch/x86/kernel/pci-swiotlb_64.c | 9 ++++++++-
include/asm-x86/dma-mapping.h | 10 ++++++----
7 files changed, 28 insertions(+), 19 deletions(-)Index: linux-x86.q/arch/x86/kernel/pci-base_32.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/pci-base_32.c
+++ linux-x86.q/arch/x86/kernel/pci-base_32.c
@@ -4,12 +4,12 @@
#include <linux/dma-mapping.h>
#include <asm/dma-mapping.h>-static dma_addr_t pci32_map_single(struct device *dev, void *ptr,
+static dma_addr_t pci32_map_single(struct device *dev, phys_addr_t ptr,
size_t size, int direction)
{
WARN_ON(size == 0);
flush_write_buffers();
- return virt_to_phys(ptr);
+ return ptr;
}static int pci32_dma_map_sg(struct device *dev, struct scatterlist *sglist,
Index: linux-x86.q/arch/x86/kernel/pci-calgary_64.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/pci-calgary_64.c
+++ linux-x86.q/arch/x86/kernel/pci-calgary_64.c
@@ -470,10 +470,11 @@ error:
return 0;
}-static dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
+static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr,
size_t size, int direction)
{
dma_addr_t dma_handle = bad_dma_address;
+ void *vaddr = phys_to_virt(paddr);
unsigned long uaddr;
unsigned int npages;
struct iommu_table *tbl = find_iommu_table(dev);
Index: linux-x...
It looks all good to me.
I'll give a shot in my systems to see if it goes okay.
--
take it off the x86_64 specific header
Signed-off-by: Glauber Costa <gcosta@redhat.com>
---
include/asm-x86/dma-mapping.h | 54 ++++++++++++++++++++++++++++++++++++++
include/asm-x86/dma-mapping_64.h | 49 ----------------------------------
2 files changed, 54 insertions(+), 49 deletions(-)diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h
index 58f790f..aebd178 100644
--- a/include/asm-x86/dma-mapping.h
+++ b/include/asm-x86/dma-mapping.h
@@ -1,5 +1,59 @@
+#ifndef _ASM_DMA_MAPPING_H_
+#define _ASM_DMA_MAPPING_H_
+
+/*
+ * IOMMU interface. See Documentation/DMA-mapping.txt and DMA-API.txt for
+ * documentation.
+ */
+
+#include <linux/scatterlist.h>
+#include <asm/io.h>
+#include <asm/swiotlb.h>
+
+struct dma_mapping_ops {
+ int (*mapping_error)(dma_addr_t dma_addr);
+ void* (*alloc_coherent)(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp);
+ void (*free_coherent)(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+ dma_addr_t (*map_single)(struct device *hwdev, void *ptr,
+ size_t size, int direction);
+ /* like map_single, but doesn't check the device mask */
+ dma_addr_t (*map_simple)(struct device *hwdev, char *ptr,
+ size_t size, int direction);
+ void (*unmap_single)(struct device *dev, dma_addr_t addr,
+ size_t size, int direction);
+ void (*sync_single_for_cpu)(struct device *hwdev,
+ dma_addr_t dma_handle, size_t size,
+ int direction);
+ void (*sync_single_for_device)(struct device *hwdev,
+ dma_addr_t dma_handle, size_t size,
+ int direction);
+ void (*sync_single_range_for_cpu)(struct device *hwdev,
+ dma_addr_t dma_handle, unsigned long offset,
+ size_t size, int direction);
+ void (*sync_single_range_for_device)(struct device *hwdev,
+ dma_addr_t dma_handle, unsigned long offset,
+ size_t size, int direction);
+ voi...
That's already the name of the game for x86_64. For i386,
we add a pci-base_32.c, that will hold the default operations.
The function call itself goes through dma-mapping.h , the common
headerSigned-off-by: Glauber Costa <gcosta@redhat.com>
---
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/pci-base_32.c | 20 ++++++++++++++++++++
include/asm-x86/dma-mapping.h | 10 ++++++++++
include/asm-x86/dma-mapping_32.h | 10 ----------
include/asm-x86/dma-mapping_64.h | 9 ---------
5 files changed, 31 insertions(+), 19 deletions(-)
create mode 100644 arch/x86/kernel/pci-base_32.cdiff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 340221f..95fbf57 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -27,6 +27,7 @@ obj-y += pci-dma_$(BITS).o bootflag.o e820_$(BITS).o
obj-y += 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 += tsc_$(BITS).o io_delay.o rtc.oobj-y += process.o
diff --git a/arch/x86/kernel/pci-base_32.c b/arch/x86/kernel/pci-base_32.c
new file mode 100644
index 0000000..b613d73
--- /dev/null
+++ b/arch/x86/kernel/pci-base_32.c
@@ -0,0 +1,20 @@
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma-mapping.h>
+
+static dma_addr_t pci32_map_single(struct device *dev, void *ptr,
+ size_t size, int direction)
+{
+ WARN_ON(size == 0);
+ flush_write_buffers();
+ return virt_to_phys(ptr);
+}
+
+static const struct dma_mapping_ops pci32_dma_ops = {
+ .map_single = pci32_map_single,
+};
+
+const struct dma_mapping_ops *dma_ops = &pci32_dma_ops;
+EXPORT_SYMBOL(dma_ops);
diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h
index aebd178..d320244 100644
--- a/include/asm-x86/dma-mapping.h
+++ b/include/asm-x86/dma-mapping.h
@...
i386 base does not need it, so it gets an empty function
Signed-off-by: Glauber Costa <gcosta@redhat.com>
---
arch/x86/kernel/pci-base_32.c | 1 +
include/asm-x86/dma-mapping.h | 10 ++++++++++
include/asm-x86/dma-mapping_32.h | 7 -------
include/asm-x86/dma-mapping_64.h | 8 --------
4 files changed, 11 insertions(+), 15 deletions(-)diff --git a/arch/x86/kernel/pci-base_32.c b/arch/x86/kernel/pci-base_32.c
index b613d73..a8a7c7f 100644
--- a/arch/x86/kernel/pci-base_32.c
+++ b/arch/x86/kernel/pci-base_32.c
@@ -14,6 +14,7 @@ static dma_addr_t pci32_map_single(struct device *dev, void *ptr,static const struct dma_mapping_ops pci32_dma_ops = {
.map_single = pci32_map_single,
+ .unmap_single = NULL,
};const struct dma_mapping_ops *dma_ops = &pci32_dma_ops;
diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h
index d320244..bb0378f 100644
--- a/include/asm-x86/dma-mapping.h
+++ b/include/asm-x86/dma-mapping.h
@@ -66,4 +66,14 @@ dma_map_single(struct device *hwdev, void *ptr, size_t size,
return dma_ops->map_single(hwdev, ptr, size, direction);
}+static inline void
+dma_unmap_single(struct device *dev, dma_addr_t addr, size_t size,
+ int direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+ if (dma_ops->unmap_single)
+ dma_ops->unmap_single(dev, addr, size, direction);
+}
+
+
#endif
diff --git a/include/asm-x86/dma-mapping_32.h b/include/asm-x86/dma-mapping_32.h
index b496306..0b27cb0 100644
--- a/include/asm-x86/dma-mapping_32.h
+++ b/include/asm-x86/dma-mapping_32.h
@@ -17,13 +17,6 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
void dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle);-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
- enum dma_data_direction direction)
-{
- BUG_ON(!valid_dma_direction(direction));
-}
-
static inline int
dma_map_sg(struct device *dev, str...
the old i386 implementation is moved to pci-base_32.c
Signed-off-by: Glauber Costa <gcosta@redhat.com>
---
arch/x86/kernel/pci-base_32.c | 19 +++++++++++++++++++
include/asm-x86/dma-mapping.h | 8 +++++++-
include/asm-x86/dma-mapping_32.h | 20 --------------------
include/asm-x86/dma-mapping_64.h | 7 -------
4 files changed, 26 insertions(+), 28 deletions(-)diff --git a/arch/x86/kernel/pci-base_32.c b/arch/x86/kernel/pci-base_32.c
index a8a7c7f..2474152 100644
--- a/arch/x86/kernel/pci-base_32.c
+++ b/arch/x86/kernel/pci-base_32.c
@@ -12,9 +12,28 @@ static dma_addr_t pci32_map_single(struct device *dev, void *ptr,
return virt_to_phys(ptr);
}+static int pci32_dma_map_sg(struct device *dev, struct scatterlist *sglist,
+ int nents, int direction)
+{
+ struct scatterlist *sg;
+ int i;
+
+ WARN_ON(nents == 0 || sglist[0].length == 0);
+
+ for_each_sg(sglist, sg, nents, i) {
+ BUG_ON(!sg_page(sg));
+
+ sg->dma_address = sg_phys(sg);
+ }
+
+ flush_write_buffers();
+ return nents;
+}
+
static const struct dma_mapping_ops pci32_dma_ops = {
.map_single = pci32_map_single,
.unmap_single = NULL,
+ .map_sg = pci32_dma_map_sg,
};const struct dma_mapping_ops *dma_ops = &pci32_dma_ops;
diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h
index bb0378f..0901154 100644
--- a/include/asm-x86/dma-mapping.h
+++ b/include/asm-x86/dma-mapping.h
@@ -75,5 +75,11 @@ dma_unmap_single(struct device *dev, dma_addr_t addr, size_t size,
dma_ops->unmap_single(dev, addr, size, direction);
}-
+static inline int
+dma_map_sg(struct device *hwdev, struct scatterlist *sg,
+ int nents, int direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+ return dma_ops->map_sg(hwdev, sg, nents, direction);
+}
#endif
diff --git a/include/asm-x86/dma-mapping_32.h b/include/asm-x86/dma-mapping_32.h
index 0b27cb0..cdcdeff 100644
--- a/include/asm-x86/dma-mapping_32.h
+++ b/include/asm-x86/dma-mapping_32...
i386 gets an empty function
Signed-off-by: Glauber Costa <gcosta@redhat.com>
---
arch/x86/kernel/pci-base_32.c | 1 +
include/asm-x86/dma-mapping.h | 9 +++++++++
include/asm-x86/dma-mapping_32.h | 8 --------
include/asm-x86/dma-mapping_64.h | 8 --------
4 files changed, 10 insertions(+), 16 deletions(-)diff --git a/arch/x86/kernel/pci-base_32.c b/arch/x86/kernel/pci-base_32.c
index 2474152..9205304 100644
--- a/arch/x86/kernel/pci-base_32.c
+++ b/arch/x86/kernel/pci-base_32.c
@@ -34,6 +34,7 @@ static const struct dma_mapping_ops pci32_dma_ops = {
.map_single = pci32_map_single,
.unmap_single = NULL,
.map_sg = pci32_dma_map_sg,
+ .unmap_sg = NULL,
};const struct dma_mapping_ops *dma_ops = &pci32_dma_ops;
diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h
index 0901154..6e7747a 100644
--- a/include/asm-x86/dma-mapping.h
+++ b/include/asm-x86/dma-mapping.h
@@ -82,4 +82,13 @@ dma_map_sg(struct device *hwdev, struct scatterlist *sg,
BUG_ON(!valid_dma_direction(direction));
return dma_ops->map_sg(hwdev, sg, nents, direction);
}
+
+static inline void
+dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
+ int direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+ if (dma_ops->unmap_sg)
+ dma_ops->unmap_sg(hwdev, sg, nents, direction);
+}
#endif
diff --git a/include/asm-x86/dma-mapping_32.h b/include/asm-x86/dma-mapping_32.h
index cdcdeff..55445e3 100644
--- a/include/asm-x86/dma-mapping_32.h
+++ b/include/asm-x86/dma-mapping_32.h
@@ -32,14 +32,6 @@ dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
BUG_ON(!valid_dma_direction(direction));
}-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
- enum dma_data_direction direction)
-{
- BUG_ON(!valid_dma_direction(direction));
-}
-
static inline void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
...
| Greg Kroah-Hartman | [PATCH 001/196] Chinese: Add the known_regression URI to the HOWTO |
| Andrew Morton | -mm merge plans for 2.6.23 |
| david | Re: Dual-Licensing Linux Kernel with GPL V2 and GPL V3 |
| Bart Van Assche | Integration of SCST in the mainstream Linux kernel |
git: | |
| Gerrit Renker | [PATCH 27/37] dccp: Integration of dynamic feature activation - part 2 (server side) |
| David Miller | Re: [PATCH] pkt_sched: Destroy gen estimators under rtnl_lock(). |
| PJ Waskiewicz | [ANNOUNCE] ixgbe: Data Center Bridging (DCB) support for ixgbe |
| David Miller | Re: [GIT]: Networking |
