linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* (no subject)
@ 2009-05-29  8:43 Ian Campbell
  2009-05-29  8:43 ` [PATCH 1/9] ia64: introduce arch-specific dma-mapping interfaces Ian Campbell
                   ` (9 more replies)
  0 siblings, 10 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ian Campbell, Becky Bruce, Benjamin Herrenschmidt,
	FUJITA Tomonori, Greg KH, Ingo Molnar, Jeremy Fitzhardinge,
	Kumar Gala, Olaf Kirch, Tony Luck, linux-ia64, linuxppc-dev, x86

This series:
* removes the swiotlb_(arch_)_phys_to_bus and bus_to_phys __weak
  hooks, replacing them with an architecture-specific phys_to_dma and
  dma_to_phys interface. These are used by both PowerPC and Xen to
  provide the correct mapping from physical to DMA addresses.
* removes the swiotlb_address_needs_mapping and
  swiotlb_range_needs_mapping __weak functions as well as
  is_buffer_dma_capable (which should never have been a generic
  function). All three are replaced by a single architecture-specific
  interface which meets the needs of both PowerPC and Xen.
* removes the swiotlb_virt_to_bus __weak function and replaces it with
  a CONFIG_HIGHMEM compatible version when high memory is in use. This
  is needed for 32 bit PowerPC swiotlb support.

I think these new interfaces are cleaner than the existing __weak
functions and isolate the swiotlb code from architecture internals.

This series does not contain any Xen or PowerPC specific changes, those
will follow in separate postings. The complete patchset has been boot
tested under Xen and native-x86 and compiled for IA64 and PowerPC

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Becky Bruce <beckyb@kernel.crashing.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Greg KH <gregkh@suse.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Olaf Kirch <okir@suse.de>
Cc: Tony Luck <tony.luck@intel.com>
Cc: linux-ia64@vger.kernel.org
Cc: linuxppc-dev@ozlabs.org
Cc: x86@kernel.org

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/9] ia64: introduce arch-specific dma-mapping interfaces
  2009-05-29  8:43 Ian Campbell
@ 2009-05-29  8:43 ` Ian Campbell
  2009-05-29  8:43 ` [PATCH 2/9] x86: introduce arch-specific dma-mapping interface Ian Campbell
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ian Campbell, FUJITA Tomonori, Ingo Molnar, Jeremy Fitzhardinge,
	Tony Luck, linux-ia64

dma_map_range is intended to replace usage of both
swiotlb_arch_range_needs_mapping and
swiotlb_arch_address_needs_mapping as __weak functions as well as
replacing is_buffer_dma_capable.

phys_to_dma and dma_to_phys are intended to replace
swiotlb_phys_to_bus and swiotlb_bus_to_phys.  I choose to use dma
rather than bus since a) it matches the parameters and b) avoids
confusion on x86 with the existing (but deprecated) virt_to_bus
function which relates to ISA device DMA.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Tony Luck <tony.luck@intel.com>
Cc: linux-ia64@vger.kernel.org
---
 arch/ia64/include/asm/dma-mapping.h |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h
index 36c0009..7250e1a 100644
--- a/arch/ia64/include/asm/dma-mapping.h
+++ b/arch/ia64/include/asm/dma-mapping.h
@@ -174,4 +174,27 @@ dma_cache_sync (struct device *dev, void *vaddr, size_t size,
 
 #define dma_is_consistent(d, h)	(1)	/* all we do is coherent memory... */
 
+static inline dma_addr_t phys_to_dma(struct device *hwdev, phys_addr_t paddr)
+{
+        return paddr;
+}
+
+static inline phys_addr_t dma_to_phys(struct device *hwdev, dma_addr_t daddr)
+{
+        return daddr;
+}
+
+static inline bool dma_map_range(struct device *dev, u64 mask,
+				       phys_addr_t addr, size_t size,
+				       dma_addr_t *dma_addr_p)
+{
+	dma_addr_t dma_addr = phys_to_dma(dev, addr);
+
+	if (dma_addr + size > mask)
+		return false;
+
+	*dma_addr_p = dma_addr;
+	return true;
+}
+
 #endif /* _ASM_IA64_DMA_MAPPING_H */
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/9] x86: introduce arch-specific dma-mapping interface
  2009-05-29  8:43 Ian Campbell
  2009-05-29  8:43 ` [PATCH 1/9] ia64: introduce arch-specific dma-mapping interfaces Ian Campbell
@ 2009-05-29  8:43 ` Ian Campbell
  2009-05-29  8:43 ` [PATCH 3/9] x86: use dma_map_range when allocating PCI DMA memory Ian Campbell
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ian Campbell, FUJITA Tomonori, Jeremy Fitzhardinge, Olaf Kirch,
	Greg KH, x86

dma_map_range is intended to replace usage of both
swiotlb_arch_range_needs_mapping and
swiotlb_arch_address_needs_mapping as __weak functions as well as
replacing is_buffer_dma_capable.

phys_to_dma and dma_to_phys are intended to replace
swiotlb_phys_to_bus and swiotlb_bus_to_phys.  I choose to use dma
rather than bus since a) it matches the parameters and b) avoids
confusion on x86 with the existing (but deprecated) virt_to_bus
function which relates to ISA device DMA.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Olaf Kirch <okir@suse.de>
Cc: Greg KH <gregkh@suse.de>
Cc: x86@kernel.org
---
 arch/x86/include/asm/dma-mapping.h |    7 +++++++
 arch/x86/kernel/pci-dma.c          |   26 ++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index 916cbb6..be8cb22 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -47,6 +47,9 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 #define dma_is_consistent(d, h)	(1)
 
+extern dma_addr_t phys_to_dma(struct device *hwdev, phys_addr_t paddr);
+extern phys_addr_t dma_to_phys(struct device *hwdev, dma_addr_t daddr);
+
 extern int dma_supported(struct device *hwdev, u64 mask);
 extern int dma_set_mask(struct device *dev, u64 mask);
 
@@ -309,4 +312,8 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
 		ops->free_coherent(dev, size, vaddr, bus);
 }
 
+extern bool dma_map_range(struct device *dev, u64 mask,
+			  phys_addr_t addr, size_t size,
+			  dma_addr_t *dma_addr_p);
+
 #endif
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 745579b..6a6a116 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -59,6 +59,32 @@ int dma_set_mask(struct device *dev, u64 mask)
 }
 EXPORT_SYMBOL(dma_set_mask);
 
+dma_addr_t phys_to_dma(struct device *hwdev, phys_addr_t paddr)
+{
+        return paddr;
+}
+EXPORT_SYMBOL_GPL(phys_to_dma);
+
+phys_addr_t dma_to_phys(struct device *hwdev, dma_addr_t daddr)
+{
+        return daddr;
+}
+EXPORT_SYMBOL_GPL(dma_to_phys);
+
+bool dma_map_range(struct device *dev, u64 mask,
+		   phys_addr_t addr, size_t size,
+		   dma_addr_t *dma_addr_p)
+{
+	dma_addr_t dma_addr = phys_to_dma(dev, addr);
+
+	if (dma_addr + size > mask)
+		return false;
+
+	*dma_addr_p = dma_addr;
+	return true;
+}
+EXPORT_SYMBOL_GPL(dma_map_range);
+
 #ifdef CONFIG_X86_64
 static __initdata void *dma32_bootmem_ptr;
 static unsigned long dma32_bootmem_size __initdata = (128ULL<<20);
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/9] x86: use dma_map_range when allocating PCI DMA memory
  2009-05-29  8:43 Ian Campbell
  2009-05-29  8:43 ` [PATCH 1/9] ia64: introduce arch-specific dma-mapping interfaces Ian Campbell
  2009-05-29  8:43 ` [PATCH 2/9] x86: introduce arch-specific dma-mapping interface Ian Campbell
@ 2009-05-29  8:43 ` Ian Campbell
  2009-05-29  8:43 ` [PATCH 4/9] x86: use dma_map_range when allocating PCI DMA memory with no IOMMU Ian Campbell
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:43 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ian Campbell, FUJITA Tomonori, Jeremy Fitzhardinge, x86

This function is intended to replaces is_buffer_dma_capable with a
more generic interface.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: x86@kernel.org
---
 arch/x86/kernel/pci-dma.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 6a6a116..a355083 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -160,7 +160,6 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
 {
 	unsigned long dma_mask;
 	struct page *page;
-	dma_addr_t addr;
 
 	dma_mask = dma_alloc_coherent_mask(dev, flag);
 
@@ -170,8 +169,7 @@ again:
 	if (!page)
 		return NULL;
 
-	addr = page_to_phys(page);
-	if (!is_buffer_dma_capable(dma_mask, addr, size)) {
+	if (!dma_map_range(dev, dma_mask, page_to_phys(page), size, dma_addr)) {
 		__free_pages(page, get_order(size));
 
 		if (dma_mask < DMA_BIT_MASK(32) && !(flag & GFP_DMA)) {
@@ -182,7 +180,6 @@ again:
 		return NULL;
 	}
 
-	*dma_addr = addr;
 	return page_address(page);
 }
 
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 4/9] x86: use dma_map_range when allocating PCI DMA memory with no IOMMU
  2009-05-29  8:43 Ian Campbell
                   ` (2 preceding siblings ...)
  2009-05-29  8:43 ` [PATCH 3/9] x86: use dma_map_range when allocating PCI DMA memory Ian Campbell
@ 2009-05-29  8:43 ` Ian Campbell
  2009-05-29  8:43 ` [PATCH 5/9] x86: use dma_map_range when allocating PCI GART memory Ian Campbell
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:43 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ian Campbell, FUJITA Tomonori, Jeremy Fitzhardinge, x86

Replaces use of is_buffer_dma_capable which is going away.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: x86@kernel.org
---
 arch/x86/kernel/pci-nommu.c |   15 ++++++++-------
 1 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c
index 71d412a..a3a61dd 100644
--- a/arch/x86/kernel/pci-nommu.c
+++ b/arch/x86/kernel/pci-nommu.c
@@ -12,13 +12,14 @@
 #include <asm/dma.h>
 
 static int
-check_addr(char *name, struct device *hwdev, dma_addr_t bus, size_t size)
+check_addr(char *name, struct device *hwdev, phys_addr_t phys, size_t size, dma_addr_t *bus)
 {
-	if (hwdev && !is_buffer_dma_capable(*hwdev->dma_mask, bus, size)) {
+	if (hwdev &&
+	    !dma_map_range(hwdev, *hwdev->dma_mask, phys, size, bus)) {
 		if (*hwdev->dma_mask >= DMA_BIT_MASK(32))
 			printk(KERN_ERR
 			    "nommu_%s: overflow %Lx+%zu of device mask %Lx\n",
-				name, (long long)bus, size,
+				name, (long long)phys, size,
 				(long long)*hwdev->dma_mask);
 		return 0;
 	}
@@ -30,9 +31,10 @@ static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
 				 enum dma_data_direction dir,
 				 struct dma_attrs *attrs)
 {
-	dma_addr_t bus = page_to_phys(page) + offset;
+	phys_addr_t phys = page_to_phys(page) + offset;
+	dma_addr_t bus;
 	WARN_ON(size == 0);
-	if (!check_addr("map_single", dev, bus, size))
+	if (!check_addr("map_single", dev, phys, size, &bus))
 		return bad_dma_address;
 	flush_write_buffers();
 	return bus;
@@ -64,8 +66,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 = sg_phys(s);
-		if (!check_addr("map_sg", hwdev, s->dma_address, s->length))
+		if (!check_addr("map_sg", hwdev, sg_phys(s), s->length, &s->dma_address))
 			return 0;
 		s->dma_length = s->length;
 	}
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 5/9] x86: use dma_map_range when allocating PCI GART memory
  2009-05-29  8:43 Ian Campbell
                   ` (3 preceding siblings ...)
  2009-05-29  8:43 ` [PATCH 4/9] x86: use dma_map_range when allocating PCI DMA memory with no IOMMU Ian Campbell
@ 2009-05-29  8:43 ` Ian Campbell
  2009-05-29  8:44 ` [PATCH 6/9] swiotlb: use dma_to_phys and phys_to_dma Ian Campbell
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:43 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ian Campbell, FUJITA Tomonori, Jeremy Fitzhardinge, x86

This function is intended to replaces is_buffer_dma_capable with a
more generic interface.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: x86@kernel.org
---
 arch/x86/kernel/pci-gart_64.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c
index 1e8920d..eb043bd 100644
--- a/arch/x86/kernel/pci-gart_64.c
+++ b/arch/x86/kernel/pci-gart_64.c
@@ -190,14 +190,16 @@ static void iommu_full(struct device *dev, size_t size, int dir)
 static inline int
 need_iommu(struct device *dev, unsigned long addr, size_t size)
 {
+	dma_addr_t dma_addr;
 	return force_iommu ||
-		!is_buffer_dma_capable(*dev->dma_mask, addr, size);
+	       !dma_map_range(dev, *dev->dma_mask, addr, size, &dma_addr);
 }
 
 static inline int
 nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
 {
-	return !is_buffer_dma_capable(*dev->dma_mask, addr, size);
+	dma_addr_t dma_addr;
+	return !dma_map_range(dev, *dev->dma_mask, addr, size, &dma_addr);
 }
 
 /* Map a single continuous physical area into the IOMMU.
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 6/9] swiotlb: use dma_to_phys and phys_to_dma
  2009-05-29  8:43 Ian Campbell
                   ` (4 preceding siblings ...)
  2009-05-29  8:43 ` [PATCH 5/9] x86: use dma_map_range when allocating PCI GART memory Ian Campbell
@ 2009-05-29  8:44 ` Ian Campbell
  2009-05-29 21:09   ` Jeremy Fitzhardinge
  2009-05-29  8:44 ` [PATCH 7/9] swiotlb: use dma_map_range Ian Campbell
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:44 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ian Campbell, FUJITA Tomonori, Jeremy Fitzhardinge, Olaf Kirch,
	Greg KH, Tony Luck, Becky Bruce, Benjamin Herrenschmidt,
	Kumar Gala, x86, linux-ia64, linuxppc-dev

These new architecture-specific interfaces subsume the existing __weak
function hooks.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Olaf Kirch <okir@suse.de>
Cc: Greg KH <gregkh@suse.de>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Becky Bruce <beckyb@kernel.crashing.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: x86@kernel.org
Cc: linux-ia64@vger.kernel.org
Cc: linuxppc-dev@ozlabs.org
---
 include/linux/swiotlb.h |    5 -----
 lib/swiotlb.c           |   18 ++++--------------
 2 files changed, 4 insertions(+), 19 deletions(-)

diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index cb1a663..954feec 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -27,11 +27,6 @@ swiotlb_init(void);
 extern void *swiotlb_alloc_boot(size_t bytes, unsigned long nslabs);
 extern void *swiotlb_alloc(unsigned order, unsigned long nslabs);
 
-extern dma_addr_t swiotlb_phys_to_bus(struct device *hwdev,
-				      phys_addr_t address);
-extern phys_addr_t swiotlb_bus_to_phys(struct device *hwdev,
-				       dma_addr_t address);
-
 extern int swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size);
 
 extern void
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index bffe6d7..baa1991 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -124,25 +124,15 @@ void * __weak swiotlb_alloc(unsigned order, unsigned long nslabs)
 	return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order);
 }
 
-dma_addr_t __weak swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
-{
-	return paddr;
-}
-
-phys_addr_t __weak swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
-{
-	return baddr;
-}
-
 static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
 				      volatile void *address)
 {
-	return swiotlb_phys_to_bus(hwdev, virt_to_phys(address));
+	return phys_to_dma(hwdev, virt_to_phys(address));
 }
 
 void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
 {
-	return phys_to_virt(swiotlb_bus_to_phys(hwdev, address));
+	return phys_to_virt(dma_to_phys(hwdev, address));
 }
 
 int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev,
@@ -646,7 +636,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
 			    struct dma_attrs *attrs)
 {
 	phys_addr_t phys = page_to_phys(page) + offset;
-	dma_addr_t dev_addr = swiotlb_phys_to_bus(dev, phys);
+	dma_addr_t dev_addr = phys_to_dma(dev, phys);
 	void *map;
 
 	BUG_ON(dir == DMA_NONE);
@@ -817,7 +807,7 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
 
 	for_each_sg(sgl, sg, nelems, i) {
 		phys_addr_t paddr = sg_phys(sg);
-		dma_addr_t dev_addr = swiotlb_phys_to_bus(hwdev, paddr);
+		dma_addr_t dev_addr = phys_to_dma(hwdev, paddr);
 
 		if (range_needs_mapping(paddr, sg->length) ||
 		    address_needs_mapping(hwdev, dev_addr, sg->length)) {
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 7/9] swiotlb: use dma_map_range
  2009-05-29  8:43 Ian Campbell
                   ` (5 preceding siblings ...)
  2009-05-29  8:44 ` [PATCH 6/9] swiotlb: use dma_to_phys and phys_to_dma Ian Campbell
@ 2009-05-29  8:44 ` Ian Campbell
  2009-05-29  8:44 ` [PATCH 8/9] swiotlb: support HIGHMEM in swiotlb_bus_to_virt Ian Campbell
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:44 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ian Campbell, FUJITA Tomonori, Jeremy Fitzhardinge, Olaf Kirch,
	Greg KH, Tony Luck, Becky Bruce, Benjamin Herrenschmidt,
	Kumar Gala, x86, linux-ia64, linuxppc-dev

This replaces usages of address_needs_mapping, range_needs_mapping and
is_buffer_dma_capable and the __weak architecture hooks to those
functions with a more flexible single function.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Olaf Kirch <okir@suse.de>
Cc: Greg KH <gregkh@suse.de>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Becky Bruce <beckyb@kernel.crashing.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: x86@kernel.org
Cc: linux-ia64@vger.kernel.org
Cc: linuxppc-dev@ozlabs.org
---
 include/linux/dma-mapping.h |    5 ----
 lib/swiotlb.c               |   57 +++++++++++++------------------------------
 2 files changed, 17 insertions(+), 45 deletions(-)

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 8083b6a..85dafa1 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -96,11 +96,6 @@ static inline int is_device_dma_capable(struct device *dev)
 	return dev->dma_mask != NULL && *dev->dma_mask != DMA_MASK_NONE;
 }
 
-static inline int is_buffer_dma_capable(u64 mask, dma_addr_t addr, size_t size)
-{
-	return addr + size <= mask;
-}
-
 #ifdef CONFIG_HAS_DMA
 #include <asm/dma-mapping.h>
 #else
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index baa1991..e332342 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -135,17 +135,6 @@ void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
 	return phys_to_virt(dma_to_phys(hwdev, address));
 }
 
-int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev,
-					       dma_addr_t addr, size_t size)
-{
-	return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
-}
-
-int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size)
-{
-	return 0;
-}
-
 static void swiotlb_print_info(unsigned long bytes)
 {
 	phys_addr_t pstart, pend;
@@ -305,17 +294,6 @@ cleanup1:
 	return -ENOMEM;
 }
 
-static inline int
-address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size)
-{
-	return swiotlb_arch_address_needs_mapping(hwdev, addr, size);
-}
-
-static inline int range_needs_mapping(phys_addr_t paddr, size_t size)
-{
-	return swiotlb_force || swiotlb_arch_range_needs_mapping(paddr, size);
-}
-
 static int is_swiotlb_buffer(char *addr)
 {
 	return addr >= io_tlb_start && addr < io_tlb_end;
@@ -542,7 +520,7 @@ void *
 swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 		       dma_addr_t *dma_handle, gfp_t flags)
 {
-	dma_addr_t dev_addr;
+	phys_addr_t phys;
 	void *ret;
 	int order = get_order(size);
 	u64 dma_mask = DMA_BIT_MASK(32);
@@ -551,9 +529,8 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 		dma_mask = hwdev->coherent_dma_mask;
 
 	ret = (void *)__get_free_pages(flags, order);
-	if (ret &&
-	    !is_buffer_dma_capable(dma_mask, swiotlb_virt_to_bus(hwdev, ret),
-				   size)) {
+	if (ret && !dma_map_range(hwdev, dma_mask, virt_to_phys(ret),
+				  size, dma_handle)) {
 		/*
 		 * The allocated memory isn't reachable by the device.
 		 */
@@ -572,19 +549,18 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 	}
 
 	memset(ret, 0, size);
-	dev_addr = swiotlb_virt_to_bus(hwdev, ret);
+	phys = virt_to_phys(ret);
 
 	/* Confirm address can be DMA'd by device */
-	if (!is_buffer_dma_capable(dma_mask, dev_addr, size)) {
-		printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
+	if (!dma_map_range(hwdev, dma_mask, phys, size, dma_handle)) {
+		printk("hwdev DMA mask = 0x%016Lx, physical addr = 0x%016Lx\n",
 		       (unsigned long long)dma_mask,
-		       (unsigned long long)dev_addr);
+		       (unsigned long long)phys);
 
 		/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
 		do_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
 		return NULL;
 	}
-	*dma_handle = dev_addr;
 	return ret;
 }
 EXPORT_SYMBOL(swiotlb_alloc_coherent);
@@ -636,7 +612,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
 			    struct dma_attrs *attrs)
 {
 	phys_addr_t phys = page_to_phys(page) + offset;
-	dma_addr_t dev_addr = phys_to_dma(dev, phys);
+	dma_addr_t dev_addr;
 	void *map;
 
 	BUG_ON(dir == DMA_NONE);
@@ -645,8 +621,8 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
 	 * we can safely return the device addr and not worry about bounce
 	 * buffering it.
 	 */
-	if (!address_needs_mapping(dev, dev_addr, size) &&
-	    !range_needs_mapping(phys, size))
+	if (dma_map_range(dev, dma_get_mask(dev), phys, size, &dev_addr) &&
+	    !swiotlb_force)
 		return dev_addr;
 
 	/*
@@ -658,12 +634,12 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
 		map = io_tlb_overflow_buffer;
 	}
 
-	dev_addr = swiotlb_virt_to_bus(dev, map);
+	phys = virt_to_phys(map);
 
 	/*
 	 * Ensure that the address returned is DMA'ble
 	 */
-	if (address_needs_mapping(dev, dev_addr, size))
+	if (!dma_map_range(dev, dma_get_mask(dev), phys, size, &dev_addr))
 		panic("map_single: bounce buffer is not DMA'ble");
 
 	return dev_addr;
@@ -807,10 +783,10 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
 
 	for_each_sg(sgl, sg, nelems, i) {
 		phys_addr_t paddr = sg_phys(sg);
-		dma_addr_t dev_addr = phys_to_dma(hwdev, paddr);
+		dma_addr_t uninitialized_var(dev_addr);
 
-		if (range_needs_mapping(paddr, sg->length) ||
-		    address_needs_mapping(hwdev, dev_addr, sg->length)) {
+		if (!dma_map_range(hwdev, dma_get_mask(hwdev), dev_addr, sg->length, &dev_addr) ||
+		    swiotlb_force) {
 			void *map = map_single(hwdev, sg_phys(sg),
 					       sg->length, dir);
 			if (!map) {
@@ -822,7 +798,8 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
 				sgl[0].dma_length = 0;
 				return 0;
 			}
-			sg->dma_address = swiotlb_virt_to_bus(hwdev, map);
+			paddr = virt_to_phys(map);
+			sg->dma_address = phys_to_dma(hwdev, paddr);
 		} else
 			sg->dma_address = dev_addr;
 		sg->dma_length = sg->length;
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 8/9] swiotlb: support HIGHMEM in swiotlb_bus_to_virt
  2009-05-29  8:43 Ian Campbell
                   ` (6 preceding siblings ...)
  2009-05-29  8:44 ` [PATCH 7/9] swiotlb: use dma_map_range Ian Campbell
@ 2009-05-29  8:44 ` Ian Campbell
  2009-05-29 15:58   ` Jeremy Fitzhardinge
  2009-05-29  8:44 ` [PATCH 9/9] swiotlb: rename swiotlb_virt_to_bus as virt_to_dma Ian Campbell
  2009-05-29  9:06 ` swiotlb: Introduce architecture-specific APIs to replace __weak functions Ian Campbell
  9 siblings, 1 reply; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:44 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ian Campbell, Becky Bruce, Benjamin Herrenschmidt, Kumar Gala,
	FUJITA Tomonori, Ingo Molnar, Jeremy Fitzhardinge, linuxppc-dev

Rather than supplying a __weak hook which architectures which support
highmem can overide simply provide a version of swiotlb_bus_to_virt
which works with high memory. Make it conditional since it is a more
expensive variant than the non-highmem version.

Acutal function contents taken from the PowerPC swiotlb patchset by
Becky Bruce.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Becky Bruce <beckyb@kernel.crashing.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: linuxppc-dev@ozlabs.org
---
 lib/swiotlb.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index e332342..c50a5ed 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -130,10 +130,22 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
 	return phys_to_dma(hwdev, virt_to_phys(address));
 }
 
-void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
+#ifdef CONFIG_HIGHMEM
+static void * swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
+{
+	unsigned long pfn = PFN_DOWN(dma_to_phys(hwdev, addr));
+	void *pageaddr = page_address(pfn_to_page(pfn));
+
+	if (pageaddr != NULL)
+		return pageaddr + (addr % PAGE_SIZE);
+	return NULL;
+}
+#else
+static void * swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
 {
 	return phys_to_virt(dma_to_phys(hwdev, address));
 }
+#endif
 
 static void swiotlb_print_info(unsigned long bytes)
 {
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 9/9] swiotlb: rename swiotlb_virt_to_bus as virt_to_dma
  2009-05-29  8:43 Ian Campbell
                   ` (7 preceding siblings ...)
  2009-05-29  8:44 ` [PATCH 8/9] swiotlb: support HIGHMEM in swiotlb_bus_to_virt Ian Campbell
@ 2009-05-29  8:44 ` Ian Campbell
  2009-05-29  9:06 ` swiotlb: Introduce architecture-specific APIs to replace __weak functions Ian Campbell
  9 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  8:44 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ian Campbell, FUJITA Tomonori, Jeremy Fitzhardinge, Olaf Kirch,
	Greg KH, Ingo Molnar

Rename swiotlb_virt_to_bus as swiotlb_virt_to_dma for consistency with
phys_to_dma.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Olaf Kirch <okir@suse.de>
Cc: Greg KH <gregkh@suse.de>
Cc: Ingo Molnar <mingo@elte.hu>
---
 lib/swiotlb.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index c50a5ed..8479ed9 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -124,14 +124,14 @@ void * __weak swiotlb_alloc(unsigned order, unsigned long nslabs)
 	return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order);
 }
 
-static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
+static dma_addr_t swiotlb_virt_to_dma(struct device *hwdev,
 				      volatile void *address)
 {
 	return phys_to_dma(hwdev, virt_to_phys(address));
 }
 
 #ifdef CONFIG_HIGHMEM
-static void * swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
+static void * swiotlb_dma_to_virt(struct device *hwdev, dma_addr_t address)
 {
 	unsigned long pfn = PFN_DOWN(dma_to_phys(hwdev, addr));
 	void *pageaddr = page_address(pfn_to_page(pfn));
@@ -141,7 +141,7 @@ static void * swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
 	return NULL;
 }
 #else
-static void * swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
+static void * swiotlb_dma_to_virt(struct device *hwdev, dma_addr_t address)
 {
 	return phys_to_virt(dma_to_phys(hwdev, address));
 }
@@ -368,7 +368,7 @@ map_single(struct device *hwdev, phys_addr_t phys, size_t size, int dir)
 	unsigned long max_slots;
 
 	mask = dma_get_seg_boundary(hwdev);
-	start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start) & mask;
+	start_dma_addr = swiotlb_virt_to_dma(hwdev, io_tlb_start) & mask;
 
 	offset_slots = ALIGN(start_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
 
@@ -669,7 +669,7 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page);
 static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
 			 size_t size, int dir)
 {
-	char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr);
+	char *dma_addr = swiotlb_dma_to_virt(hwdev, dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
 
@@ -706,7 +706,7 @@ static void
 swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
 		    size_t size, int dir, int target)
 {
-	char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr);
+	char *dma_addr = swiotlb_dma_to_virt(hwdev, dev_addr);
 
 	BUG_ON(dir == DMA_NONE);
 
@@ -893,19 +893,19 @@ EXPORT_SYMBOL(swiotlb_sync_sg_for_device);
 int
 swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
 {
-	return (dma_addr == swiotlb_virt_to_bus(hwdev, io_tlb_overflow_buffer));
+	return (dma_addr == swiotlb_virt_to_dma(hwdev, io_tlb_overflow_buffer));
 }
 EXPORT_SYMBOL(swiotlb_dma_mapping_error);
 
 /*
  * Return whether the given device DMA address mask can be supported
  * properly.  For example, if your device can only drive the low 24-bits
- * during bus mastering, then you would pass 0x00ffffff as the mask to
+ * during dma mastering, then you would pass 0x00ffffff as the mask to
  * this function.
  */
 int
 swiotlb_dma_supported(struct device *hwdev, u64 mask)
 {
-	return swiotlb_virt_to_bus(hwdev, io_tlb_end - 1) <= mask;
+	return swiotlb_virt_to_dma(hwdev, io_tlb_end - 1) <= mask;
 }
 EXPORT_SYMBOL(swiotlb_dma_supported);
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: swiotlb: Introduce architecture-specific APIs to replace __weak functions
  2009-05-29  8:43 Ian Campbell
                   ` (8 preceding siblings ...)
  2009-05-29  8:44 ` [PATCH 9/9] swiotlb: rename swiotlb_virt_to_bus as virt_to_dma Ian Campbell
@ 2009-05-29  9:06 ` Ian Campbell
  9 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-29  9:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: Becky Bruce, Benjamin Herrenschmidt, FUJITA Tomonori, Greg KH,
	Ingo Molnar, Jeremy Fitzhardinge, Kumar Gala, Olaf Kirch,
	Tony Luck, linux-ia64, linuxppc-dev, x86

[-- Attachment #1: Type: text/plain, Size: 11060 bytes --]

Subject should have been "swiotlb: Introduce architecture-specific APIs
to replace __weak functions". Seems I never drive git send-email right
first time...

On Fri, 2009-05-29 at 04:43 -0400, Ian Campbell wrote:
> This series does not contain any Xen or PowerPC specific changes, those
> will follow in separate postings.

Becky, here is an updated version of your 2/3 "powerpc: Add support for
swiotlb on 32-bit" [0], compile tested with the new interfaces. The
interdiff is attached.

Ian.

[0] http://ozlabs.org/pipermail/linuxppc-dev/2009-May/072140.html

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index cdc9a6f..561abf9 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -296,9 +296,19 @@ config IOMMU_VMERGE
 config IOMMU_HELPER
 	def_bool PPC64
 
+config SWIOTLB
+	bool "SWIOTLB support"
+	default n
+	select IOMMU_HELPER
+	---help---
+	  Support for IO bounce buffering for systems without an IOMMU.
+	  This allows us to DMA to the full physical address space on
+	  platforms where the size of a physical address is larger
+	  than the bus address.  Not all platforms support this.
+
 config PPC_NEED_DMA_SYNC_OPS
 	def_bool y
-	depends on NOT_COHERENT_CACHE
+	depends on (NOT_COHERENT_CACHE || SWIOTLB)
 
 config HOTPLUG_CPU
 	bool "Support for enabling/disabling CPUs"
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index cb448d6..b2fcd2b 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -15,9 +15,18 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-attrs.h>
 #include <asm/io.h>
+#include <asm/swiotlb.h>
 
 #define DMA_ERROR_CODE		(~(dma_addr_t)0x0)
 
+/* Some dma direct funcs must be visible for use in other dma_ops */
+extern void *dma_direct_alloc_coherent(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag);
+extern void dma_direct_free_coherent(struct device *dev, size_t size,
+				     void *vaddr, dma_addr_t dma_handle);
+
+extern unsigned long get_dma_direct_offset(struct device *dev);
+
 #ifdef CONFIG_NOT_COHERENT_CACHE
 /*
  * DMA-consistent mapping functions for PowerPCs that don't support
@@ -78,6 +87,9 @@ struct dma_mapping_ops {
 				dma_addr_t dma_address, size_t size,
 				enum dma_data_direction direction,
 				struct dma_attrs *attrs);
+	bool		(*map_range)(struct device *dev, u64 mask,
+				     phys_addr_t addr, size_t size,
+				     dma_addr_t *dma_addr_p);
 #ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
 	void            (*sync_single_range_for_cpu)(struct device *hwdev,
 				dma_addr_t dma_handle, unsigned long offset,
@@ -290,6 +302,16 @@ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 	dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL);
 }
 
+static inline bool dma_map_range(struct device *hwdev, u64 mask,
+				 phys_addr_t addr, size_t size,
+				 dma_addr_t *dma_addr_p)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(hwdev);
+
+	BUG_ON(!dma_ops);
+	return dma_ops->map_range(hwdev, mask, addr, size, dma_addr_p);
+}
+
 #ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
 static inline void dma_sync_single_for_cpu(struct device *dev,
 		dma_addr_t dma_handle, size_t size,
@@ -409,6 +431,16 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 #define dma_is_consistent(d, h)	(1)
 #endif
 
+static inline dma_addr_t phys_to_dma(struct device *hwdev, phys_addr_t paddr)
+{
+        return paddr + get_dma_direct_offset(hwdev);
+}
+
+static inline phys_addr_t dma_to_phys(struct device *hwdev, dma_addr_t daddr)
+{
+        return daddr + get_dma_direct_offset(hwdev);
+}
+
 static inline int dma_get_cache_alignment(void)
 {
 #ifdef CONFIG_PPC64
diff --git a/arch/powerpc/include/asm/swiotlb.h b/arch/powerpc/include/asm/swiotlb.h
new file mode 100644
index 0000000..30891d6
--- /dev/null
+++ b/arch/powerpc/include/asm/swiotlb.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2009 Becky Bruce, Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __ASM_SWIOTLB_H
+#define __ASM_SWIOTLB_H
+
+#include <linux/swiotlb.h>
+
+extern struct dma_mapping_ops swiotlb_dma_ops;
+extern struct dma_mapping_ops swiotlb_pci_dma_ops;
+
+int swiotlb_arch_address_needs_mapping(struct device *, dma_addr_t,
+				       size_t size);
+
+static inline void dma_mark_clean(void *addr, size_t size) {}
+
+extern unsigned int ppc_swiotlb_enable;
+int __init swiotlb_setup_bus_notifier(void);
+
+#endif /* __ASM_SWIOTLB_H */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 9ba1bb7..f6d720b 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_serial.o udbg_16550.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
+obj-$(CONFIG_SWIOTLB)		+= dma-swiotlb.o
 
 pci64-$(CONFIG_PPC64)		+= pci_dn.o isa-bridge.o
 obj-$(CONFIG_PCI)		+= pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
new file mode 100644
index 0000000..ef2e812
--- /dev/null
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -0,0 +1,137 @@
+/*
+ * Contains routines needed to support swiotlb for ppc.
+ *
+ * Copyright (C) 2009 Becky Bruce, Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/pfn.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+#include <asm/swiotlb.h>
+#include <asm/dma.h>
+#include <asm/abs_addr.h>
+
+int swiotlb __read_mostly;
+unsigned int ppc_swiotlb_enable;
+
+/*
+ * Determine if an address is reachable by a pci device, or if we must bounce.
+ */
+static bool
+pci_map_range(struct device *hwdev, u64 mask,
+	      phys_addr_t addr, size_t size,
+	      dma_addr_t *dma_addr_p)
+{
+	dma_addr_t dma_addr = phys_to_dma(hwdev, addr);
+	dma_addr_t max;
+	struct pci_controller *hose;
+	struct pci_dev *pdev = to_pci_dev(hwdev);
+
+	hose = pci_bus_to_host(pdev->bus);
+	max = hose->dma_window_base_cur + hose->dma_window_size;
+
+	/* check that we're within mapped pci window space */
+	if ((dma_addr + size > max) | (dma_addr < hose->dma_window_base_cur))
+		return false;
+
+	*dma_addr_p = dma_addr;
+	return true;
+}
+
+static bool
+map_range(struct device *dev, u64 mask,
+	  phys_addr_t addr, size_t size,
+	  dma_addr_t *dma_addr_p)
+{
+	dma_addr_t dma_addr = phys_to_dma(dev, addr);
+
+	if (dma_addr + size > mask)
+		return false;
+
+	*dma_addr_p = dma_addr;
+	return true;
+}
+
+
+/*
+ *@the moment, all platforms that use this code only require
+ * swiotlb to be used if we're operating on HIGHMEM.  Since
+ * we don't ever call anything other than map_sg, unmap_sg,
+ * map_page, and unmap_page on highmem, use normal dma_ops
+ * for everything else.
+ */
+struct dma_mapping_ops swiotlb_dma_ops = {
+	.alloc_coherent = dma_direct_alloc_coherent,
+	.free_coherent = dma_direct_free_coherent,
+	.map_sg = swiotlb_map_sg_attrs,
+	.unmap_sg = swiotlb_unmap_sg_attrs,
+	.dma_supported = swiotlb_dma_supported,
+	.map_page = swiotlb_map_page,
+	.unmap_page = swiotlb_unmap_page,
+	.map_range = map_range,
+	.sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
+	.sync_single_range_for_device = swiotlb_sync_single_range_for_device,
+	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = swiotlb_sync_sg_for_device
+};
+
+struct dma_mapping_ops swiotlb_pci_dma_ops = {
+	.alloc_coherent = dma_direct_alloc_coherent,
+	.free_coherent = dma_direct_free_coherent,
+	.map_sg = swiotlb_map_sg_attrs,
+	.unmap_sg = swiotlb_unmap_sg_attrs,
+	.dma_supported = swiotlb_dma_supported,
+	.map_page = swiotlb_map_page,
+	.unmap_page = swiotlb_unmap_page,
+	.map_range = pci_map_range,
+	.sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
+	.sync_single_range_for_device = swiotlb_sync_single_range_for_device,
+	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = swiotlb_sync_sg_for_device
+};
+
+static int ppc_swiotlb_bus_notify(struct notifier_block *nb,
+				  unsigned long action, void *data)
+{
+	struct device *dev = data;
+
+	/* We are only intereted in device addition */
+	if (action != BUS_NOTIFY_ADD_DEVICE)
+		return 0;
+
+	/* May need to bounce if the device can't address all of DRAM */
+	if (dma_get_mask(dev) < lmb_end_of_DRAM())
+		set_dma_ops(dev, &swiotlb_dma_ops);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ppc_swiotlb_plat_bus_notifier = {
+	.notifier_call = ppc_swiotlb_bus_notify,
+	.priority = 0,
+};
+
+static struct notifier_block ppc_swiotlb_of_bus_notifier = {
+	.notifier_call = ppc_swiotlb_bus_notify,
+	.priority = 0,
+};
+
+int __init swiotlb_setup_bus_notifier(void)
+{
+	bus_register_notifier(&platform_bus_type,
+			      &ppc_swiotlb_plat_bus_notifier);
+	bus_register_notifier(&of_platform_bus_type,
+			      &ppc_swiotlb_of_bus_notifier);
+
+	return 0;
+}
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 6b02793..20a60d6 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -19,7 +19,7 @@
  * default the offset is PCI_DRAM_OFFSET.
  */
 
-static unsigned long get_dma_direct_offset(struct device *dev)
+unsigned long get_dma_direct_offset(struct device *dev)
 {
 	if (dev)
 		return (unsigned long)dev->archdata.dma_data;
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 9e1ca74..1d15424 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -39,6 +39,7 @@
 #include <asm/serial.h>
 #include <asm/udbg.h>
 #include <asm/mmu_context.h>
+#include <asm/swiotlb.h>
 
 #include "setup.h"
 
@@ -332,6 +333,11 @@ void __init setup_arch(char **cmdline_p)
 		ppc_md.setup_arch();
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
+#ifdef CONFIG_SWIOTLB
+	if (ppc_swiotlb_enable)
+		swiotlb_init();
+#endif
+
 	paging_init();
 
 	/* Initialize the MMU context management stuff */
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index c410c60..fbcca72 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -61,6 +61,7 @@
 #include <asm/xmon.h>
 #include <asm/udbg.h>
 #include <asm/kexec.h>
+#include <asm/swiotlb.h>
 
 #include "setup.h"
 
@@ -524,6 +525,11 @@ void __init setup_arch(char **cmdline_p)
 	if (ppc_md.setup_arch)
 		ppc_md.setup_arch();
 
+#ifdef CONFIG_SWIOTLB
+	if (ppc_swiotlb_enable)
+		swiotlb_init();
+#endif
+
 	paging_init();
 	ppc64_boot_msg(0x15, "Setup Done");
 }


[-- Attachment #2: interdiff --]
[-- Type: text/x-patch, Size: 5368 bytes --]

diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index 3d9e887..b2fcd2b 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -87,8 +87,9 @@ struct dma_mapping_ops {
 				dma_addr_t dma_address, size_t size,
 				enum dma_data_direction direction,
 				struct dma_attrs *attrs);
-	int		(*addr_needs_map)(struct device *dev, dma_addr_t addr,
-				size_t size);
+	bool		(*map_range)(struct device *dev, u64 mask,
+				     phys_addr_t addr, size_t size,
+				     dma_addr_t *dma_addr_p);
 #ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
 	void            (*sync_single_range_for_cpu)(struct device *hwdev,
 				dma_addr_t dma_handle, unsigned long offset,
@@ -301,6 +302,16 @@ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 	dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL);
 }
 
+static inline bool dma_map_range(struct device *hwdev, u64 mask,
+				 phys_addr_t addr, size_t size,
+				 dma_addr_t *dma_addr_p)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(hwdev);
+
+	BUG_ON(!dma_ops);
+	return dma_ops->map_range(hwdev, mask, addr, size, dma_addr_p);
+}
+
 #ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
 static inline void dma_sync_single_for_cpu(struct device *dev,
 		dma_addr_t dma_handle, size_t size,
@@ -420,6 +431,16 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 #define dma_is_consistent(d, h)	(1)
 #endif
 
+static inline dma_addr_t phys_to_dma(struct device *hwdev, phys_addr_t paddr)
+{
+        return paddr + get_dma_direct_offset(hwdev);
+}
+
+static inline phys_addr_t dma_to_phys(struct device *hwdev, dma_addr_t daddr)
+{
+        return daddr + get_dma_direct_offset(hwdev);
+}
+
 static inline int dma_get_cache_alignment(void)
 {
 #ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
index 6c00667..ef2e812 100644
--- a/arch/powerpc/kernel/dma-swiotlb.c
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -24,50 +24,15 @@
 int swiotlb __read_mostly;
 unsigned int ppc_swiotlb_enable;
 
-void *swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t addr)
-{
-	unsigned long pfn = PFN_DOWN(swiotlb_bus_to_phys(hwdev, addr));
-	void *pageaddr = page_address(pfn_to_page(pfn));
-
-	if (pageaddr != NULL)
-		return pageaddr + (addr % PAGE_SIZE);
-	return NULL;
-}
-
-dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
-{
-	return paddr + get_dma_direct_offset(hwdev);
-}
-
-phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
-
-{
-	return baddr - get_dma_direct_offset(hwdev);
-}
-
-/*
- * Determine if an address needs bounce buffering via swiotlb.
- * Going forward I expect the swiotlb code to generalize on using
- * a dma_ops->addr_needs_map, and this function will move from here to the
- * generic swiotlb code.
- */
-int
-swiotlb_arch_address_needs_mapping(struct device *hwdev, dma_addr_t addr,
-				   size_t size)
-{
-	struct dma_mapping_ops *dma_ops = get_dma_ops(hwdev);
-
-	BUG_ON(!dma_ops);
-	return dma_ops->addr_needs_map(hwdev, addr, size);
-}
-
 /*
  * Determine if an address is reachable by a pci device, or if we must bounce.
  */
-static int
-swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
+static bool
+pci_map_range(struct device *hwdev, u64 mask,
+	      phys_addr_t addr, size_t size,
+	      dma_addr_t *dma_addr_p)
 {
-	u64 mask = dma_get_mask(hwdev);
+	dma_addr_t dma_addr = phys_to_dma(hwdev, addr);
 	dma_addr_t max;
 	struct pci_controller *hose;
 	struct pci_dev *pdev = to_pci_dev(hwdev);
@@ -76,16 +41,25 @@ swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
 	max = hose->dma_window_base_cur + hose->dma_window_size;
 
 	/* check that we're within mapped pci window space */
-	if ((addr + size > max) | (addr < hose->dma_window_base_cur))
-		return 1;
+	if ((dma_addr + size > max) | (dma_addr < hose->dma_window_base_cur))
+		return false;
 
-	return !is_buffer_dma_capable(mask, addr, size);
+	*dma_addr_p = dma_addr;
+	return true;
 }
 
-static int
-swiotlb_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
+static bool
+map_range(struct device *dev, u64 mask,
+	  phys_addr_t addr, size_t size,
+	  dma_addr_t *dma_addr_p)
 {
-	return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
+	dma_addr_t dma_addr = phys_to_dma(dev, addr);
+
+	if (dma_addr + size > mask)
+		return false;
+
+	*dma_addr_p = dma_addr;
+	return true;
 }
 
 
@@ -104,7 +78,7 @@ struct dma_mapping_ops swiotlb_dma_ops = {
 	.dma_supported = swiotlb_dma_supported,
 	.map_page = swiotlb_map_page,
 	.unmap_page = swiotlb_unmap_page,
-	.addr_needs_map = swiotlb_addr_needs_map,
+	.map_range = map_range,
 	.sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
 	.sync_single_range_for_device = swiotlb_sync_single_range_for_device,
 	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
@@ -119,7 +93,7 @@ struct dma_mapping_ops swiotlb_pci_dma_ops = {
 	.dma_supported = swiotlb_dma_supported,
 	.map_page = swiotlb_map_page,
 	.unmap_page = swiotlb_unmap_page,
-	.addr_needs_map = swiotlb_pci_addr_needs_map,
+	.map_range = pci_map_range,
 	.sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
 	.sync_single_range_for_device = swiotlb_sync_single_range_for_device,
 	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 8/9] swiotlb: support HIGHMEM in swiotlb_bus_to_virt
  2009-05-29  8:44 ` [PATCH 8/9] swiotlb: support HIGHMEM in swiotlb_bus_to_virt Ian Campbell
@ 2009-05-29 15:58   ` Jeremy Fitzhardinge
  2009-05-30 13:02     ` Ian Campbell
  0 siblings, 1 reply; 15+ messages in thread
From: Jeremy Fitzhardinge @ 2009-05-29 15:58 UTC (permalink / raw)
  To: Ian Campbell
  Cc: linux-kernel, Becky Bruce, Benjamin Herrenschmidt, Kumar Gala,
	FUJITA Tomonori, Ingo Molnar, linuxppc-dev

Ian Campbell wrote:
> Rather than supplying a __weak hook which architectures which support
> highmem can overide simply provide a version of swiotlb_bus_to_virt
> which works with high memory. Make it conditional since it is a more
> expensive variant than the non-highmem version.
>
> Acutal function contents taken from the PowerPC swiotlb patchset by
> Becky Bruce.
>
> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> Cc: Becky Bruce <beckyb@kernel.crashing.org>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Kumar Gala <galak@kernel.crashing.org>
> Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Jeremy Fitzhardinge <jeremy@goop.org>
> Cc: linuxppc-dev@ozlabs.org
> ---
>  lib/swiotlb.c |   14 +++++++++++++-
>  1 files changed, 13 insertions(+), 1 deletions(-)
>
> diff --git a/lib/swiotlb.c b/lib/swiotlb.c
> index e332342..c50a5ed 100644
> --- a/lib/swiotlb.c
> +++ b/lib/swiotlb.c
> @@ -130,10 +130,22 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
>  	return phys_to_dma(hwdev, virt_to_phys(address));
>  }
>  
> -void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
> +#ifdef CONFIG_HIGHMEM
> +static void * swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
>   

I think it would be better to put the #ifdef within the function body so 
that there's no chance of prototype-drift.
> +{
> +	unsigned long pfn = PFN_DOWN(dma_to_phys(hwdev, addr));
> +	void *pageaddr = page_address(pfn_to_page(pfn));
> +
> +	if (pageaddr != NULL)
> +		return pageaddr + (addr % PAGE_SIZE);
>   
Is there an arch-independent test to see if a pfn is considered highmem 
or not (which returns a constant on non-highmem configurations)?  If so, 
then I think this could be common without having to go via a struct page.

    J

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 6/9] swiotlb: use dma_to_phys and phys_to_dma
  2009-05-29  8:44 ` [PATCH 6/9] swiotlb: use dma_to_phys and phys_to_dma Ian Campbell
@ 2009-05-29 21:09   ` Jeremy Fitzhardinge
  2009-05-30 13:02     ` Ian Campbell
  0 siblings, 1 reply; 15+ messages in thread
From: Jeremy Fitzhardinge @ 2009-05-29 21:09 UTC (permalink / raw)
  To: Ian Campbell
  Cc: linux-kernel, FUJITA Tomonori, Olaf Kirch, Greg KH, Tony Luck,
	Becky Bruce, Benjamin Herrenschmidt, Kumar Gala, x86, linux-ia64,
	linuxppc-dev

Ian Campbell wrote:
> static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
>  				      volatile void *address)
>  {
> -	return swiotlb_phys_to_bus(hwdev, virt_to_phys(address));
> +	return phys_to_dma(hwdev, virt_to_phys(address));
>  }
>  
>  void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
>   

Does this need to be weak too?

    J

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 8/9] swiotlb: support HIGHMEM in swiotlb_bus_to_virt
  2009-05-29 15:58   ` Jeremy Fitzhardinge
@ 2009-05-30 13:02     ` Ian Campbell
  0 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-30 13:02 UTC (permalink / raw)
  To: Jeremy Fitzhardinge
  Cc: linux-kernel, Becky Bruce, Benjamin Herrenschmidt, Kumar Gala,
	FUJITA Tomonori, Ingo Molnar, linuxppc-dev

On Fri, 2009-05-29 at 08:58 -0700, Jeremy Fitzhardinge wrote:
> Ian Campbell wrote:

> > -void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
> > +#ifdef CONFIG_HIGHMEM
> > +static void * swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
> >   
> 
> I think it would be better to put the #ifdef within the function body so 
> that there's no chance of prototype-drift.

Yes, good idea.

> > +{
> > +	unsigned long pfn = PFN_DOWN(dma_to_phys(hwdev, addr));
> > +	void *pageaddr = page_address(pfn_to_page(pfn));
> > +
> > +	if (pageaddr != NULL)
> > +		return pageaddr + (addr % PAGE_SIZE);
> >   
> Is there an arch-independent test to see if a pfn is considered highmem 
> or not (which returns a constant on non-highmem configurations)?  If so, 
> then I think this could be common without having to go via a struct page.

I'm not aware of a way apart from PageHighMem -- which needs the struct
page. Highmem is a property of the zone, I think, so you have to go
through the struct page back to the zone to find out if it is high or
not.

At first glance it looks like many of the callers of bus_to_virt
eventually end up in swiotlb_bounce which converts to a struct page
anyway. I'll take a look next week whether it makes any sense to go to
struct page further up the call chain and pass that around instead.

Ian.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 6/9] swiotlb: use dma_to_phys and phys_to_dma
  2009-05-29 21:09   ` Jeremy Fitzhardinge
@ 2009-05-30 13:02     ` Ian Campbell
  0 siblings, 0 replies; 15+ messages in thread
From: Ian Campbell @ 2009-05-30 13:02 UTC (permalink / raw)
  To: Jeremy Fitzhardinge
  Cc: linux-kernel, FUJITA Tomonori, Olaf Kirch, Greg KH, Tony Luck,
	Becky Bruce, Benjamin Herrenschmidt, Kumar Gala, x86, linux-ia64,
	linuxppc-dev

On Fri, 2009-05-29 at 14:09 -0700, Jeremy Fitzhardinge wrote:
> Ian Campbell wrote:
> >  void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address)
> >   
> 
> Does this need to be weak too?

It's was wanted by PowerPC to support highmem, that's what patch 8/9
tries to address in an arch-independent way.

Ian.



^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2009-05-30 13:03 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-05-29  8:43 Ian Campbell
2009-05-29  8:43 ` [PATCH 1/9] ia64: introduce arch-specific dma-mapping interfaces Ian Campbell
2009-05-29  8:43 ` [PATCH 2/9] x86: introduce arch-specific dma-mapping interface Ian Campbell
2009-05-29  8:43 ` [PATCH 3/9] x86: use dma_map_range when allocating PCI DMA memory Ian Campbell
2009-05-29  8:43 ` [PATCH 4/9] x86: use dma_map_range when allocating PCI DMA memory with no IOMMU Ian Campbell
2009-05-29  8:43 ` [PATCH 5/9] x86: use dma_map_range when allocating PCI GART memory Ian Campbell
2009-05-29  8:44 ` [PATCH 6/9] swiotlb: use dma_to_phys and phys_to_dma Ian Campbell
2009-05-29 21:09   ` Jeremy Fitzhardinge
2009-05-30 13:02     ` Ian Campbell
2009-05-29  8:44 ` [PATCH 7/9] swiotlb: use dma_map_range Ian Campbell
2009-05-29  8:44 ` [PATCH 8/9] swiotlb: support HIGHMEM in swiotlb_bus_to_virt Ian Campbell
2009-05-29 15:58   ` Jeremy Fitzhardinge
2009-05-30 13:02     ` Ian Campbell
2009-05-29  8:44 ` [PATCH 9/9] swiotlb: rename swiotlb_virt_to_bus as virt_to_dma Ian Campbell
2009-05-29  9:06 ` swiotlb: Introduce architecture-specific APIs to replace __weak functions Ian Campbell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).