All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 0/8] enable swiotlb-xen on arm and arm64
@ 2013-07-31 17:44 ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:44 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, Konrad Rzeszutek Wilk,
	Stefano Stabellini, Ian Campbell

Hi all,
this patch series enables xen-swiotlb on arm and arm64.

Considering that all guests, including dom0, run on xen on arm with
second stage translation enabled, it follows that without an IOMMU no
guests could actually drive the hardware.

The solution for platforms without an IOMMU is to use swiotlb-xen,
adapted to autotranslate guests. swiotlb-xen provides a set of dma_ops
that can be used by Linux to setup a contiguous buffer in stage-2
addresses and use it for dma operations.
Basically Linux asks Xen to make a buffer contiguous and gets the
machine address for it. This buffer is going to be used by lib/swiotlb.c
to allocate bounce buffers.


The first 3 patches lay the groundwork on arm and arm64 to have
alternative dma_ops and swiotlb.

The forth patch moves Xen initialization earlier so that we already know
whether we are running on Xen at the time of initializing dma_ops on the
platform.

The following patches adapt swiotlb-xen to autotranslate guests (guest
with second stage translation in hardware) and provide an arm
implementation of xen_create_contiguous_region.


Feedback is very welcome.
Cheers,

Stefano


Stefano Stabellini (8):
      arm: make SWIOTLB available
      arm: introduce a global dma_ops pointer
      arm64: do not initialize arm64_swiotlb if dma_ops is already set
      xen/arm,arm64: move Xen initialization earlier
      xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
      xen: make xen_create_contiguous_region return the dma address
      swiotlb-xen: support autotranslate guests
      xen/arm,arm64: enable SWIOTLB_XEN

 arch/arm/Kconfig                      |    8 ++
 arch/arm/common/dmabounce.c           |   10 +-
 arch/arm/include/asm/dma-mapping.h    |   27 ++++++-
 arch/arm/include/asm/xen/hypervisor.h |    6 ++
 arch/arm/include/asm/xen/page.h       |    2 +
 arch/arm/kernel/setup.c               |    2 +
 arch/arm/mm/dma-mapping.c             |    3 +
 arch/arm/xen/Makefile                 |    2 +-
 arch/arm/xen/enlighten.c              |   24 ++++--
 arch/arm/xen/mm.c                     |  118 ++++++++++++++++++++++++++
 arch/arm64/Kconfig                    |    1 +
 arch/arm64/kernel/setup.c             |    2 +
 arch/arm64/mm/dma-mapping.c           |    2 +
 arch/arm64/xen/Makefile               |    2 +-
 arch/x86/xen/mmu.c                    |    4 +-
 drivers/xen/Kconfig                   |    1 -
 drivers/xen/swiotlb-xen.c             |  147 +++++++++++++++++++++++++++++----
 include/xen/interface/memory.h        |   62 ++++++++++++++
 include/xen/xen-ops.h                 |    3 +-
 19 files changed, 391 insertions(+), 35 deletions(-)
 create mode 100644 arch/arm/xen/mm.c

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

* [PATCH RFC 0/8] enable swiotlb-xen on arm and arm64
@ 2013-07-31 17:44 ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi all,
this patch series enables xen-swiotlb on arm and arm64.

Considering that all guests, including dom0, run on xen on arm with
second stage translation enabled, it follows that without an IOMMU no
guests could actually drive the hardware.

The solution for platforms without an IOMMU is to use swiotlb-xen,
adapted to autotranslate guests. swiotlb-xen provides a set of dma_ops
that can be used by Linux to setup a contiguous buffer in stage-2
addresses and use it for dma operations.
Basically Linux asks Xen to make a buffer contiguous and gets the
machine address for it. This buffer is going to be used by lib/swiotlb.c
to allocate bounce buffers.


The first 3 patches lay the groundwork on arm and arm64 to have
alternative dma_ops and swiotlb.

The forth patch moves Xen initialization earlier so that we already know
whether we are running on Xen at the time of initializing dma_ops on the
platform.

The following patches adapt swiotlb-xen to autotranslate guests (guest
with second stage translation in hardware) and provide an arm
implementation of xen_create_contiguous_region.


Feedback is very welcome.
Cheers,

Stefano


Stefano Stabellini (8):
      arm: make SWIOTLB available
      arm: introduce a global dma_ops pointer
      arm64: do not initialize arm64_swiotlb if dma_ops is already set
      xen/arm,arm64: move Xen initialization earlier
      xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
      xen: make xen_create_contiguous_region return the dma address
      swiotlb-xen: support autotranslate guests
      xen/arm,arm64: enable SWIOTLB_XEN

 arch/arm/Kconfig                      |    8 ++
 arch/arm/common/dmabounce.c           |   10 +-
 arch/arm/include/asm/dma-mapping.h    |   27 ++++++-
 arch/arm/include/asm/xen/hypervisor.h |    6 ++
 arch/arm/include/asm/xen/page.h       |    2 +
 arch/arm/kernel/setup.c               |    2 +
 arch/arm/mm/dma-mapping.c             |    3 +
 arch/arm/xen/Makefile                 |    2 +-
 arch/arm/xen/enlighten.c              |   24 ++++--
 arch/arm/xen/mm.c                     |  118 ++++++++++++++++++++++++++
 arch/arm64/Kconfig                    |    1 +
 arch/arm64/kernel/setup.c             |    2 +
 arch/arm64/mm/dma-mapping.c           |    2 +
 arch/arm64/xen/Makefile               |    2 +-
 arch/x86/xen/mmu.c                    |    4 +-
 drivers/xen/Kconfig                   |    1 -
 drivers/xen/swiotlb-xen.c             |  147 +++++++++++++++++++++++++++++----
 include/xen/interface/memory.h        |   62 ++++++++++++++
 include/xen/xen-ops.h                 |    3 +-
 19 files changed, 391 insertions(+), 35 deletions(-)
 create mode 100644 arch/arm/xen/mm.c

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

* [PATCH RFC 0/8] enable swiotlb-xen on arm and arm64
@ 2013-07-31 17:44 ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:44 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, Konrad Rzeszutek Wilk,
	Stefano Stabellini, Ian Campbell

Hi all,
this patch series enables xen-swiotlb on arm and arm64.

Considering that all guests, including dom0, run on xen on arm with
second stage translation enabled, it follows that without an IOMMU no
guests could actually drive the hardware.

The solution for platforms without an IOMMU is to use swiotlb-xen,
adapted to autotranslate guests. swiotlb-xen provides a set of dma_ops
that can be used by Linux to setup a contiguous buffer in stage-2
addresses and use it for dma operations.
Basically Linux asks Xen to make a buffer contiguous and gets the
machine address for it. This buffer is going to be used by lib/swiotlb.c
to allocate bounce buffers.


The first 3 patches lay the groundwork on arm and arm64 to have
alternative dma_ops and swiotlb.

The forth patch moves Xen initialization earlier so that we already know
whether we are running on Xen at the time of initializing dma_ops on the
platform.

The following patches adapt swiotlb-xen to autotranslate guests (guest
with second stage translation in hardware) and provide an arm
implementation of xen_create_contiguous_region.


Feedback is very welcome.
Cheers,

Stefano


Stefano Stabellini (8):
      arm: make SWIOTLB available
      arm: introduce a global dma_ops pointer
      arm64: do not initialize arm64_swiotlb if dma_ops is already set
      xen/arm,arm64: move Xen initialization earlier
      xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
      xen: make xen_create_contiguous_region return the dma address
      swiotlb-xen: support autotranslate guests
      xen/arm,arm64: enable SWIOTLB_XEN

 arch/arm/Kconfig                      |    8 ++
 arch/arm/common/dmabounce.c           |   10 +-
 arch/arm/include/asm/dma-mapping.h    |   27 ++++++-
 arch/arm/include/asm/xen/hypervisor.h |    6 ++
 arch/arm/include/asm/xen/page.h       |    2 +
 arch/arm/kernel/setup.c               |    2 +
 arch/arm/mm/dma-mapping.c             |    3 +
 arch/arm/xen/Makefile                 |    2 +-
 arch/arm/xen/enlighten.c              |   24 ++++--
 arch/arm/xen/mm.c                     |  118 ++++++++++++++++++++++++++
 arch/arm64/Kconfig                    |    1 +
 arch/arm64/kernel/setup.c             |    2 +
 arch/arm64/mm/dma-mapping.c           |    2 +
 arch/arm64/xen/Makefile               |    2 +-
 arch/x86/xen/mmu.c                    |    4 +-
 drivers/xen/Kconfig                   |    1 -
 drivers/xen/swiotlb-xen.c             |  147 +++++++++++++++++++++++++++++----
 include/xen/interface/memory.h        |   62 ++++++++++++++
 include/xen/xen-ops.h                 |    3 +-
 19 files changed, 391 insertions(+), 35 deletions(-)
 create mode 100644 arch/arm/xen/mm.c

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

* [PATCH RFC 1/8] arm: make SWIOTLB available
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 17:45   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini, will.deacon, linux

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: will.deacon@arm.com
CC: linux@arm.linux.org.uk
---
 arch/arm/Kconfig                   |    7 +++++++
 arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ba412e0..05125ab 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
 	  neutralized via a kernel panic.
 	  This feature requires gcc version 4.2 or above.
 
+config SWIOTLB
+	def_bool y
+	select NEED_SG_DMA_LENGTH
+
+config IOMMU_HELPER
+	def_bool SWIOTLB
+
 config XEN_DOM0
 	def_bool y
 	depends on XEN
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5b579b9..ad89e0f 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -86,6 +86,30 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
 }
 #endif
 
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	unsigned int offset = paddr & ~PAGE_MASK;
+	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
+{
+	unsigned int offset = dev_addr & ~PAGE_MASK;
+	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
+}
+
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	if (!dev->dma_mask)
+		return 0;
+
+	return addr + size - 1 <= *dev->dma_mask;
+}
+
+static inline void dma_mark_clean(void *addr, size_t size)
+{
+}
+
 /*
  * DMA errors are defined by all-bits-set in the DMA address.
  */
-- 
1.7.2.5


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

* [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: will.deacon at arm.com
CC: linux at arm.linux.org.uk
---
 arch/arm/Kconfig                   |    7 +++++++
 arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ba412e0..05125ab 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
 	  neutralized via a kernel panic.
 	  This feature requires gcc version 4.2 or above.
 
+config SWIOTLB
+	def_bool y
+	select NEED_SG_DMA_LENGTH
+
+config IOMMU_HELPER
+	def_bool SWIOTLB
+
 config XEN_DOM0
 	def_bool y
 	depends on XEN
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5b579b9..ad89e0f 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -86,6 +86,30 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
 }
 #endif
 
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	unsigned int offset = paddr & ~PAGE_MASK;
+	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
+{
+	unsigned int offset = dev_addr & ~PAGE_MASK;
+	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
+}
+
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	if (!dev->dma_mask)
+		return 0;
+
+	return addr + size - 1 <= *dev->dma_mask;
+}
+
+static inline void dma_mark_clean(void *addr, size_t size)
+{
+}
+
 /*
  * DMA errors are defined by all-bits-set in the DMA address.
  */
-- 
1.7.2.5

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

* [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini, will.deacon, linux

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: will.deacon@arm.com
CC: linux@arm.linux.org.uk
---
 arch/arm/Kconfig                   |    7 +++++++
 arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ba412e0..05125ab 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
 	  neutralized via a kernel panic.
 	  This feature requires gcc version 4.2 or above.
 
+config SWIOTLB
+	def_bool y
+	select NEED_SG_DMA_LENGTH
+
+config IOMMU_HELPER
+	def_bool SWIOTLB
+
 config XEN_DOM0
 	def_bool y
 	depends on XEN
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5b579b9..ad89e0f 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -86,6 +86,30 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
 }
 #endif
 
+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	unsigned int offset = paddr & ~PAGE_MASK;
+	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
+}
+
+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
+{
+	unsigned int offset = dev_addr & ~PAGE_MASK;
+	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
+}
+
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	if (!dev->dma_mask)
+		return 0;
+
+	return addr + size - 1 <= *dev->dma_mask;
+}
+
+static inline void dma_mark_clean(void *addr, size_t size)
+{
+}
+
 /*
  * DMA errors are defined by all-bits-set in the DMA address.
  */
-- 
1.7.2.5

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

* [PATCH RFC 2/8] arm: introduce a global dma_ops pointer
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 17:45   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini, will.deacon, linux

Initially set dma_ops to arm_dma_ops.
Use dma_ops instead of arm_dma_ops in dmabounce.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: will.deacon@arm.com
CC: linux@arm.linux.org.uk
---
 arch/arm/common/dmabounce.c        |   10 +++++-----
 arch/arm/include/asm/dma-mapping.h |    3 ++-
 arch/arm/mm/dma-mapping.c          |    3 +++
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 1143c4d..b626122 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -325,7 +325,7 @@ static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page,
 		return DMA_ERROR_CODE;
 
 	if (ret == 0) {
-		arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
+		dma_ops->sync_single_for_device(dev, dma_addr, size, dir);
 		return dma_addr;
 	}
 
@@ -353,7 +353,7 @@ static void dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t
 
 	buf = find_safe_buffer_dev(dev, dma_addr, __func__);
 	if (!buf) {
-		arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
+		dma_ops->sync_single_for_cpu(dev, dma_addr, size, dir);
 		return;
 	}
 
@@ -397,7 +397,7 @@ static void dmabounce_sync_for_cpu(struct device *dev,
 	if (!__dmabounce_sync_for_cpu(dev, handle, size, dir))
 		return;
 
-	arm_dma_ops.sync_single_for_cpu(dev, handle, size, dir);
+	dma_ops->sync_single_for_cpu(dev, handle, size, dir);
 }
 
 static int __dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
@@ -437,7 +437,7 @@ static void dmabounce_sync_for_device(struct device *dev,
 	if (!__dmabounce_sync_for_device(dev, handle, size, dir))
 		return;
 
-	arm_dma_ops.sync_single_for_device(dev, handle, size, dir);
+	dma_ops->sync_single_for_device(dev, handle, size, dir);
 }
 
 static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
@@ -445,7 +445,7 @@ static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
 	if (dev->archdata.dmabounce)
 		return 0;
 
-	return arm_dma_ops.set_dma_mask(dev, dma_mask);
+	return dma_ops->set_dma_mask(dev, dma_mask);
 }
 
 static struct dma_map_ops dmabounce_ops = {
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index ad89e0f..f907f65 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -12,6 +12,7 @@
 #include <asm/memory.h>
 
 #define DMA_ERROR_CODE	(~0)
+extern struct dma_map_ops *dma_ops;
 extern struct dma_map_ops arm_dma_ops;
 extern struct dma_map_ops arm_coherent_dma_ops;
 
@@ -19,7 +20,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
 	if (dev && dev->archdata.dma_ops)
 		return dev->archdata.dma_ops;
-	return &arm_dma_ops;
+	return dma_ops;
 }
 
 static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7f9b179..870b12c 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -141,6 +141,9 @@ struct dma_map_ops arm_dma_ops = {
 };
 EXPORT_SYMBOL(arm_dma_ops);
 
+struct dma_map_ops *dma_ops = &arm_dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
 static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
 	dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs);
 static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
-- 
1.7.2.5


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

* [PATCH RFC 2/8] arm: introduce a global dma_ops pointer
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Initially set dma_ops to arm_dma_ops.
Use dma_ops instead of arm_dma_ops in dmabounce.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: will.deacon at arm.com
CC: linux at arm.linux.org.uk
---
 arch/arm/common/dmabounce.c        |   10 +++++-----
 arch/arm/include/asm/dma-mapping.h |    3 ++-
 arch/arm/mm/dma-mapping.c          |    3 +++
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 1143c4d..b626122 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -325,7 +325,7 @@ static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page,
 		return DMA_ERROR_CODE;
 
 	if (ret == 0) {
-		arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
+		dma_ops->sync_single_for_device(dev, dma_addr, size, dir);
 		return dma_addr;
 	}
 
@@ -353,7 +353,7 @@ static void dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t
 
 	buf = find_safe_buffer_dev(dev, dma_addr, __func__);
 	if (!buf) {
-		arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
+		dma_ops->sync_single_for_cpu(dev, dma_addr, size, dir);
 		return;
 	}
 
@@ -397,7 +397,7 @@ static void dmabounce_sync_for_cpu(struct device *dev,
 	if (!__dmabounce_sync_for_cpu(dev, handle, size, dir))
 		return;
 
-	arm_dma_ops.sync_single_for_cpu(dev, handle, size, dir);
+	dma_ops->sync_single_for_cpu(dev, handle, size, dir);
 }
 
 static int __dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
@@ -437,7 +437,7 @@ static void dmabounce_sync_for_device(struct device *dev,
 	if (!__dmabounce_sync_for_device(dev, handle, size, dir))
 		return;
 
-	arm_dma_ops.sync_single_for_device(dev, handle, size, dir);
+	dma_ops->sync_single_for_device(dev, handle, size, dir);
 }
 
 static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
@@ -445,7 +445,7 @@ static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
 	if (dev->archdata.dmabounce)
 		return 0;
 
-	return arm_dma_ops.set_dma_mask(dev, dma_mask);
+	return dma_ops->set_dma_mask(dev, dma_mask);
 }
 
 static struct dma_map_ops dmabounce_ops = {
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index ad89e0f..f907f65 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -12,6 +12,7 @@
 #include <asm/memory.h>
 
 #define DMA_ERROR_CODE	(~0)
+extern struct dma_map_ops *dma_ops;
 extern struct dma_map_ops arm_dma_ops;
 extern struct dma_map_ops arm_coherent_dma_ops;
 
@@ -19,7 +20,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
 	if (dev && dev->archdata.dma_ops)
 		return dev->archdata.dma_ops;
-	return &arm_dma_ops;
+	return dma_ops;
 }
 
 static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7f9b179..870b12c 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -141,6 +141,9 @@ struct dma_map_ops arm_dma_ops = {
 };
 EXPORT_SYMBOL(arm_dma_ops);
 
+struct dma_map_ops *dma_ops = &arm_dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
 static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
 	dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs);
 static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
-- 
1.7.2.5

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

* [PATCH RFC 2/8] arm: introduce a global dma_ops pointer
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux, Ian.Campbell, Stefano Stabellini, will.deacon,
	linux-kernel, linux-arm-kernel

Initially set dma_ops to arm_dma_ops.
Use dma_ops instead of arm_dma_ops in dmabounce.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: will.deacon@arm.com
CC: linux@arm.linux.org.uk
---
 arch/arm/common/dmabounce.c        |   10 +++++-----
 arch/arm/include/asm/dma-mapping.h |    3 ++-
 arch/arm/mm/dma-mapping.c          |    3 +++
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 1143c4d..b626122 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -325,7 +325,7 @@ static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page,
 		return DMA_ERROR_CODE;
 
 	if (ret == 0) {
-		arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
+		dma_ops->sync_single_for_device(dev, dma_addr, size, dir);
 		return dma_addr;
 	}
 
@@ -353,7 +353,7 @@ static void dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t
 
 	buf = find_safe_buffer_dev(dev, dma_addr, __func__);
 	if (!buf) {
-		arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
+		dma_ops->sync_single_for_cpu(dev, dma_addr, size, dir);
 		return;
 	}
 
@@ -397,7 +397,7 @@ static void dmabounce_sync_for_cpu(struct device *dev,
 	if (!__dmabounce_sync_for_cpu(dev, handle, size, dir))
 		return;
 
-	arm_dma_ops.sync_single_for_cpu(dev, handle, size, dir);
+	dma_ops->sync_single_for_cpu(dev, handle, size, dir);
 }
 
 static int __dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
@@ -437,7 +437,7 @@ static void dmabounce_sync_for_device(struct device *dev,
 	if (!__dmabounce_sync_for_device(dev, handle, size, dir))
 		return;
 
-	arm_dma_ops.sync_single_for_device(dev, handle, size, dir);
+	dma_ops->sync_single_for_device(dev, handle, size, dir);
 }
 
 static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
@@ -445,7 +445,7 @@ static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
 	if (dev->archdata.dmabounce)
 		return 0;
 
-	return arm_dma_ops.set_dma_mask(dev, dma_mask);
+	return dma_ops->set_dma_mask(dev, dma_mask);
 }
 
 static struct dma_map_ops dmabounce_ops = {
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index ad89e0f..f907f65 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -12,6 +12,7 @@
 #include <asm/memory.h>
 
 #define DMA_ERROR_CODE	(~0)
+extern struct dma_map_ops *dma_ops;
 extern struct dma_map_ops arm_dma_ops;
 extern struct dma_map_ops arm_coherent_dma_ops;
 
@@ -19,7 +20,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
 	if (dev && dev->archdata.dma_ops)
 		return dev->archdata.dma_ops;
-	return &arm_dma_ops;
+	return dma_ops;
 }
 
 static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7f9b179..870b12c 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -141,6 +141,9 @@ struct dma_map_ops arm_dma_ops = {
 };
 EXPORT_SYMBOL(arm_dma_ops);
 
+struct dma_map_ops *dma_ops = &arm_dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
 static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
 	dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs);
 static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
-- 
1.7.2.5

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

* [PATCH RFC 3/8] arm64: do not initialize arm64_swiotlb if dma_ops is already set
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 17:45   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini, catalin.marinas, will.deacon

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: catalin.marinas@arm.com
CC: will.deacon@arm.com
---
 arch/arm64/mm/dma-mapping.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 4bd7579..a006e84 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -63,6 +63,8 @@ static struct dma_map_ops arm64_swiotlb_dma_ops = {
 
 void __init arm64_swiotlb_init(void)
 {
+	if (dma_ops != NULL)
+		return;
 	dma_ops = &arm64_swiotlb_dma_ops;
 	swiotlb_init(1);
 }
-- 
1.7.2.5


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

* [PATCH RFC 3/8] arm64: do not initialize arm64_swiotlb if dma_ops is already set
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: catalin.marinas at arm.com
CC: will.deacon at arm.com
---
 arch/arm64/mm/dma-mapping.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 4bd7579..a006e84 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -63,6 +63,8 @@ static struct dma_map_ops arm64_swiotlb_dma_ops = {
 
 void __init arm64_swiotlb_init(void)
 {
+	if (dma_ops != NULL)
+		return;
 	dma_ops = &arm64_swiotlb_dma_ops;
 	swiotlb_init(1);
 }
-- 
1.7.2.5

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

* [PATCH RFC 3/8] arm64: do not initialize arm64_swiotlb if dma_ops is already set
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: Ian.Campbell, Stefano Stabellini, catalin.marinas, konrad.wilk,
	will.deacon, linux-kernel, linux-arm-kernel

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: catalin.marinas@arm.com
CC: will.deacon@arm.com
---
 arch/arm64/mm/dma-mapping.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 4bd7579..a006e84 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -63,6 +63,8 @@ static struct dma_map_ops arm64_swiotlb_dma_ops = {
 
 void __init arm64_swiotlb_init(void)
 {
+	if (dma_ops != NULL)
+		return;
 	dma_ops = &arm64_swiotlb_dma_ops;
 	swiotlb_init(1);
 }
-- 
1.7.2.5

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

* [PATCH RFC 4/8] xen/arm,arm64: move Xen initialization earlier
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 17:45   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 arch/arm/include/asm/xen/hypervisor.h |    6 ++++++
 arch/arm/kernel/setup.c               |    2 ++
 arch/arm/xen/enlighten.c              |   21 ++++++++++++++-------
 arch/arm64/kernel/setup.c             |    2 ++
 4 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/arch/arm/include/asm/xen/hypervisor.h b/arch/arm/include/asm/xen/hypervisor.h
index d7ab99a..17b3ea2 100644
--- a/arch/arm/include/asm/xen/hypervisor.h
+++ b/arch/arm/include/asm/xen/hypervisor.h
@@ -16,4 +16,10 @@ static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
 	return PARAVIRT_LAZY_NONE;
 }
 
+#ifdef CONFIG_XEN
+void xen_early_init(void);
+#else
+static inline void xen_early_init(void) { return; }
+#endif
+
 #endif /* _ASM_ARM_XEN_HYPERVISOR_H */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 63af9a7..cb7b8e2 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -45,6 +45,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/tlbflush.h>
+#include <asm/xen/hypervisor.h>
 
 #include <asm/prom.h>
 #include <asm/mach/arch.h>
@@ -889,6 +890,7 @@ void __init setup_arch(char **cmdline_p)
 
 	arm_dt_init_cpu_maps();
 	psci_init();
+	xen_early_init();
 #ifdef CONFIG_SMP
 	if (is_smp()) {
 		if (!mdesc->smp_init || !mdesc->smp_init()) {
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index c9770ba..14d17ab 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -195,21 +195,19 @@ static void xen_power_off(void)
  * documentation of the Xen Device Tree format.
  */
 #define GRANT_TABLE_PHYSADDR 0
-static int __init xen_guest_init(void)
+void __init xen_early_init(void)
 {
-	struct xen_add_to_physmap xatp;
-	static struct shared_info *shared_info_page = 0;
+	struct resource res;
 	struct device_node *node;
 	int len;
 	const char *s = NULL;
 	const char *version = NULL;
 	const char *xen_prefix = "xen,xen-";
-	struct resource res;
 
 	node = of_find_compatible_node(NULL, NULL, "xen,xen");
 	if (!node) {
 		pr_debug("No Xen support\n");
-		return 0;
+		return;
 	}
 	s = of_get_property(node, "compatible", &len);
 	if (strlen(xen_prefix) + 3  < len &&
@@ -217,10 +215,10 @@ static int __init xen_guest_init(void)
 		version = s + strlen(xen_prefix);
 	if (version == NULL) {
 		pr_debug("Xen version not found\n");
-		return 0;
+		return;
 	}
 	if (of_address_to_resource(node, GRANT_TABLE_PHYSADDR, &res))
-		return 0;
+		return;
 	xen_hvm_resume_frames = res.start >> PAGE_SHIFT;
 	xen_events_irq = irq_of_parse_and_map(node, 0);
 	pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n",
@@ -232,6 +230,15 @@ static int __init xen_guest_init(void)
 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
 	else
 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
+}
+
+static int __init xen_guest_init(void)
+{
+	struct xen_add_to_physmap xatp;
+	static struct shared_info *shared_info_page = 0;
+
+	if (!xen_domain())
+		return 0;
 
 	if (!shared_info_page)
 		shared_info_page = (struct shared_info *)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index add6ea6..e0d438a 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -53,6 +53,7 @@
 #include <asm/traps.h>
 #include <asm/memblock.h>
 #include <asm/psci.h>
+#include <asm/xen/hypervisor.h>
 
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);
@@ -267,6 +268,7 @@ void __init setup_arch(char **cmdline_p)
 	unflatten_device_tree();
 
 	psci_init();
+	xen_early_init();
 
 	cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
 #ifdef CONFIG_SMP
-- 
1.7.2.5


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

* [PATCH RFC 4/8] xen/arm,arm64: move Xen initialization earlier
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 arch/arm/include/asm/xen/hypervisor.h |    6 ++++++
 arch/arm/kernel/setup.c               |    2 ++
 arch/arm/xen/enlighten.c              |   21 ++++++++++++++-------
 arch/arm64/kernel/setup.c             |    2 ++
 4 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/arch/arm/include/asm/xen/hypervisor.h b/arch/arm/include/asm/xen/hypervisor.h
index d7ab99a..17b3ea2 100644
--- a/arch/arm/include/asm/xen/hypervisor.h
+++ b/arch/arm/include/asm/xen/hypervisor.h
@@ -16,4 +16,10 @@ static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
 	return PARAVIRT_LAZY_NONE;
 }
 
+#ifdef CONFIG_XEN
+void xen_early_init(void);
+#else
+static inline void xen_early_init(void) { return; }
+#endif
+
 #endif /* _ASM_ARM_XEN_HYPERVISOR_H */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 63af9a7..cb7b8e2 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -45,6 +45,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/tlbflush.h>
+#include <asm/xen/hypervisor.h>
 
 #include <asm/prom.h>
 #include <asm/mach/arch.h>
@@ -889,6 +890,7 @@ void __init setup_arch(char **cmdline_p)
 
 	arm_dt_init_cpu_maps();
 	psci_init();
+	xen_early_init();
 #ifdef CONFIG_SMP
 	if (is_smp()) {
 		if (!mdesc->smp_init || !mdesc->smp_init()) {
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index c9770ba..14d17ab 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -195,21 +195,19 @@ static void xen_power_off(void)
  * documentation of the Xen Device Tree format.
  */
 #define GRANT_TABLE_PHYSADDR 0
-static int __init xen_guest_init(void)
+void __init xen_early_init(void)
 {
-	struct xen_add_to_physmap xatp;
-	static struct shared_info *shared_info_page = 0;
+	struct resource res;
 	struct device_node *node;
 	int len;
 	const char *s = NULL;
 	const char *version = NULL;
 	const char *xen_prefix = "xen,xen-";
-	struct resource res;
 
 	node = of_find_compatible_node(NULL, NULL, "xen,xen");
 	if (!node) {
 		pr_debug("No Xen support\n");
-		return 0;
+		return;
 	}
 	s = of_get_property(node, "compatible", &len);
 	if (strlen(xen_prefix) + 3  < len &&
@@ -217,10 +215,10 @@ static int __init xen_guest_init(void)
 		version = s + strlen(xen_prefix);
 	if (version == NULL) {
 		pr_debug("Xen version not found\n");
-		return 0;
+		return;
 	}
 	if (of_address_to_resource(node, GRANT_TABLE_PHYSADDR, &res))
-		return 0;
+		return;
 	xen_hvm_resume_frames = res.start >> PAGE_SHIFT;
 	xen_events_irq = irq_of_parse_and_map(node, 0);
 	pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n",
@@ -232,6 +230,15 @@ static int __init xen_guest_init(void)
 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
 	else
 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
+}
+
+static int __init xen_guest_init(void)
+{
+	struct xen_add_to_physmap xatp;
+	static struct shared_info *shared_info_page = 0;
+
+	if (!xen_domain())
+		return 0;
 
 	if (!shared_info_page)
 		shared_info_page = (struct shared_info *)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index add6ea6..e0d438a 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -53,6 +53,7 @@
 #include <asm/traps.h>
 #include <asm/memblock.h>
 #include <asm/psci.h>
+#include <asm/xen/hypervisor.h>
 
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);
@@ -267,6 +268,7 @@ void __init setup_arch(char **cmdline_p)
 	unflatten_device_tree();
 
 	psci_init();
+	xen_early_init();
 
 	cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
 #ifdef CONFIG_SMP
-- 
1.7.2.5

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

* [PATCH RFC 4/8] xen/arm,arm64: move Xen initialization earlier
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 arch/arm/include/asm/xen/hypervisor.h |    6 ++++++
 arch/arm/kernel/setup.c               |    2 ++
 arch/arm/xen/enlighten.c              |   21 ++++++++++++++-------
 arch/arm64/kernel/setup.c             |    2 ++
 4 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/arch/arm/include/asm/xen/hypervisor.h b/arch/arm/include/asm/xen/hypervisor.h
index d7ab99a..17b3ea2 100644
--- a/arch/arm/include/asm/xen/hypervisor.h
+++ b/arch/arm/include/asm/xen/hypervisor.h
@@ -16,4 +16,10 @@ static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
 	return PARAVIRT_LAZY_NONE;
 }
 
+#ifdef CONFIG_XEN
+void xen_early_init(void);
+#else
+static inline void xen_early_init(void) { return; }
+#endif
+
 #endif /* _ASM_ARM_XEN_HYPERVISOR_H */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 63af9a7..cb7b8e2 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -45,6 +45,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/tlbflush.h>
+#include <asm/xen/hypervisor.h>
 
 #include <asm/prom.h>
 #include <asm/mach/arch.h>
@@ -889,6 +890,7 @@ void __init setup_arch(char **cmdline_p)
 
 	arm_dt_init_cpu_maps();
 	psci_init();
+	xen_early_init();
 #ifdef CONFIG_SMP
 	if (is_smp()) {
 		if (!mdesc->smp_init || !mdesc->smp_init()) {
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index c9770ba..14d17ab 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -195,21 +195,19 @@ static void xen_power_off(void)
  * documentation of the Xen Device Tree format.
  */
 #define GRANT_TABLE_PHYSADDR 0
-static int __init xen_guest_init(void)
+void __init xen_early_init(void)
 {
-	struct xen_add_to_physmap xatp;
-	static struct shared_info *shared_info_page = 0;
+	struct resource res;
 	struct device_node *node;
 	int len;
 	const char *s = NULL;
 	const char *version = NULL;
 	const char *xen_prefix = "xen,xen-";
-	struct resource res;
 
 	node = of_find_compatible_node(NULL, NULL, "xen,xen");
 	if (!node) {
 		pr_debug("No Xen support\n");
-		return 0;
+		return;
 	}
 	s = of_get_property(node, "compatible", &len);
 	if (strlen(xen_prefix) + 3  < len &&
@@ -217,10 +215,10 @@ static int __init xen_guest_init(void)
 		version = s + strlen(xen_prefix);
 	if (version == NULL) {
 		pr_debug("Xen version not found\n");
-		return 0;
+		return;
 	}
 	if (of_address_to_resource(node, GRANT_TABLE_PHYSADDR, &res))
-		return 0;
+		return;
 	xen_hvm_resume_frames = res.start >> PAGE_SHIFT;
 	xen_events_irq = irq_of_parse_and_map(node, 0);
 	pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n",
@@ -232,6 +230,15 @@ static int __init xen_guest_init(void)
 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
 	else
 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
+}
+
+static int __init xen_guest_init(void)
+{
+	struct xen_add_to_physmap xatp;
+	static struct shared_info *shared_info_page = 0;
+
+	if (!xen_domain())
+		return 0;
 
 	if (!shared_info_page)
 		shared_info_page = (struct shared_info *)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index add6ea6..e0d438a 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -53,6 +53,7 @@
 #include <asm/traps.h>
 #include <asm/memblock.h>
 #include <asm/psci.h>
+#include <asm/xen/hypervisor.h>
 
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);
@@ -267,6 +268,7 @@ void __init setup_arch(char **cmdline_p)
 	unflatten_device_tree();
 
 	psci_init();
+	xen_early_init();
 
 	cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
 #ifdef CONFIG_SMP
-- 
1.7.2.5

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

* [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 17:45   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 include/xen/interface/memory.h |   62 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index 2ecfe4f..ffd7f4e 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
 
+#define XENMEM_get_dma_buf             26
+/*
+ * This hypercall is similar to XENMEM_exchange: it exchanges the pages
+ * passed in with a new set of pages, contiguous and under 4G if so
+ * requested. The new pages are going to be "pinned": it's guaranteed
+ * that their p2m mapping won't be changed until explicitly "unpinned".
+ * If return code is zero then @out.extent_list provides the MFNs of the
+ * newly-allocated memory.  Returns zero on complete success, otherwise
+ * a negative error code.
+ * On complete success then always @nr_exchanged == @in.nr_extents.  On
+ * partial success @nr_exchanged indicates how much work was done.
+ */
+struct xen_get_dma_buf {
+    /*
+     * [IN] Details of memory extents to be exchanged (GMFN bases).
+     * Note that @in.address_bits is ignored and unused.
+     */
+    struct xen_memory_reservation in;
+
+    /*
+     * [IN/OUT] Details of new memory extents.
+     * We require that:
+     *  1. @in.domid == @out.domid
+     *  2. @in.nr_extents  << @in.extent_order == 
+     *     @out.nr_extents << @out.extent_order
+     *  3. @in.extent_start and @out.extent_start lists must not overlap
+     *  4. @out.extent_start lists GPFN bases to be populated
+     *  5. @out.extent_start is overwritten with allocated GMFN bases
+     */
+    struct xen_memory_reservation out;
+
+    /*
+     * [OUT] Number of input extents that were successfully exchanged:
+     *  1. The first @nr_exchanged input extents were successfully
+     *     deallocated.
+     *  2. The corresponding first entries in the output extent list correctly
+     *     indicate the GMFNs that were successfully exchanged.
+     *  3. All other input and output extents are untouched.
+     *  4. If not all input exents are exchanged then the return code of this
+     *     command will be non-zero.
+     *  5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
+     */
+    xen_ulong_t nr_exchanged;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_get_dma_buf);
+
+#define XENMEM_put_dma_buf             27
+/*
+ * XENMEM_put_dma_buf unpins a set of pages, previously pinned by
+ * XENMEM_get_dma_buf. After this call the p2m mapping of the pages can
+ * be transparently changed by the hypervisor, as usual. The pages are
+ * still accessible from the guest.
+ */
+struct xen_put_dma_buf {
+    /*
+     * [IN] Details of memory extents to be exchanged (GMFN bases).
+     * Note that @in.address_bits is ignored and unused.
+     */
+    struct xen_memory_reservation in;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_put_dma_buf);
+
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
-- 
1.7.2.5


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

* [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 include/xen/interface/memory.h |   62 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index 2ecfe4f..ffd7f4e 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
 
+#define XENMEM_get_dma_buf             26
+/*
+ * This hypercall is similar to XENMEM_exchange: it exchanges the pages
+ * passed in with a new set of pages, contiguous and under 4G if so
+ * requested. The new pages are going to be "pinned": it's guaranteed
+ * that their p2m mapping won't be changed until explicitly "unpinned".
+ * If return code is zero then @out.extent_list provides the MFNs of the
+ * newly-allocated memory.  Returns zero on complete success, otherwise
+ * a negative error code.
+ * On complete success then always @nr_exchanged == @in.nr_extents.  On
+ * partial success @nr_exchanged indicates how much work was done.
+ */
+struct xen_get_dma_buf {
+    /*
+     * [IN] Details of memory extents to be exchanged (GMFN bases).
+     * Note that @in.address_bits is ignored and unused.
+     */
+    struct xen_memory_reservation in;
+
+    /*
+     * [IN/OUT] Details of new memory extents.
+     * We require that:
+     *  1. @in.domid == @out.domid
+     *  2. @in.nr_extents  << @in.extent_order == 
+     *     @out.nr_extents << @out.extent_order
+     *  3. @in.extent_start and @out.extent_start lists must not overlap
+     *  4. @out.extent_start lists GPFN bases to be populated
+     *  5. @out.extent_start is overwritten with allocated GMFN bases
+     */
+    struct xen_memory_reservation out;
+
+    /*
+     * [OUT] Number of input extents that were successfully exchanged:
+     *  1. The first @nr_exchanged input extents were successfully
+     *     deallocated.
+     *  2. The corresponding first entries in the output extent list correctly
+     *     indicate the GMFNs that were successfully exchanged.
+     *  3. All other input and output extents are untouched.
+     *  4. If not all input exents are exchanged then the return code of this
+     *     command will be non-zero.
+     *  5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
+     */
+    xen_ulong_t nr_exchanged;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_get_dma_buf);
+
+#define XENMEM_put_dma_buf             27
+/*
+ * XENMEM_put_dma_buf unpins a set of pages, previously pinned by
+ * XENMEM_get_dma_buf. After this call the p2m mapping of the pages can
+ * be transparently changed by the hypervisor, as usual. The pages are
+ * still accessible from the guest.
+ */
+struct xen_put_dma_buf {
+    /*
+     * [IN] Details of memory extents to be exchanged (GMFN bases).
+     * Note that @in.address_bits is ignored and unused.
+     */
+    struct xen_memory_reservation in;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_put_dma_buf);
+
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
-- 
1.7.2.5

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

* [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: Ian.Campbell, Stefano Stabellini, linux-kernel, linux-arm-kernel

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 include/xen/interface/memory.h |   62 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index 2ecfe4f..ffd7f4e 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
 
+#define XENMEM_get_dma_buf             26
+/*
+ * This hypercall is similar to XENMEM_exchange: it exchanges the pages
+ * passed in with a new set of pages, contiguous and under 4G if so
+ * requested. The new pages are going to be "pinned": it's guaranteed
+ * that their p2m mapping won't be changed until explicitly "unpinned".
+ * If return code is zero then @out.extent_list provides the MFNs of the
+ * newly-allocated memory.  Returns zero on complete success, otherwise
+ * a negative error code.
+ * On complete success then always @nr_exchanged == @in.nr_extents.  On
+ * partial success @nr_exchanged indicates how much work was done.
+ */
+struct xen_get_dma_buf {
+    /*
+     * [IN] Details of memory extents to be exchanged (GMFN bases).
+     * Note that @in.address_bits is ignored and unused.
+     */
+    struct xen_memory_reservation in;
+
+    /*
+     * [IN/OUT] Details of new memory extents.
+     * We require that:
+     *  1. @in.domid == @out.domid
+     *  2. @in.nr_extents  << @in.extent_order == 
+     *     @out.nr_extents << @out.extent_order
+     *  3. @in.extent_start and @out.extent_start lists must not overlap
+     *  4. @out.extent_start lists GPFN bases to be populated
+     *  5. @out.extent_start is overwritten with allocated GMFN bases
+     */
+    struct xen_memory_reservation out;
+
+    /*
+     * [OUT] Number of input extents that were successfully exchanged:
+     *  1. The first @nr_exchanged input extents were successfully
+     *     deallocated.
+     *  2. The corresponding first entries in the output extent list correctly
+     *     indicate the GMFNs that were successfully exchanged.
+     *  3. All other input and output extents are untouched.
+     *  4. If not all input exents are exchanged then the return code of this
+     *     command will be non-zero.
+     *  5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
+     */
+    xen_ulong_t nr_exchanged;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_get_dma_buf);
+
+#define XENMEM_put_dma_buf             27
+/*
+ * XENMEM_put_dma_buf unpins a set of pages, previously pinned by
+ * XENMEM_get_dma_buf. After this call the p2m mapping of the pages can
+ * be transparently changed by the hypervisor, as usual. The pages are
+ * still accessible from the guest.
+ */
+struct xen_put_dma_buf {
+    /*
+     * [IN] Details of memory extents to be exchanged (GMFN bases).
+     * Note that @in.address_bits is ignored and unused.
+     */
+    struct xen_memory_reservation in;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_put_dma_buf);
+
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
-- 
1.7.2.5

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

* [PATCH RFC 6/8] xen: make xen_create_contiguous_region return the dma address
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 17:45   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini, david.vrabel

Modify xen_create_contiguous_region to return the dma address of the
newly contiguous buffer.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: david.vrabel@citrix.com
---
 arch/x86/xen/mmu.c        |    4 +++-
 drivers/xen/swiotlb-xen.c |    6 +++---
 include/xen/xen-ops.h     |    3 ++-
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index fdc3ba2..df9ab44 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2329,7 +2329,8 @@ static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in,
 }
 
 int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
-				 unsigned int address_bits)
+				 unsigned int address_bits,
+				 dma_addr_t *dma_handle)
 {
 	unsigned long *in_frames = discontig_frames, out_frame;
 	unsigned long  flags;
@@ -2368,6 +2369,7 @@ int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
 
 	spin_unlock_irqrestore(&xen_reservation_lock, flags);
 
+	*dma_handle = xen_virt_to_bus(vstart);
 	return success ? 0 : -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index aadffcf..353f013 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -126,6 +126,7 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 {
 	int i, rc;
 	int dma_bits;
+	dma_addr_t dma_handle;
 
 	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
 
@@ -137,7 +138,7 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 			rc = xen_create_contiguous_region(
 				(unsigned long)buf + (i << IO_TLB_SHIFT),
 				get_order(slabs << IO_TLB_SHIFT),
-				dma_bits);
+				dma_bits, &dma_handle);
 		} while (rc && dma_bits++ < max_dma_bits);
 		if (rc)
 			return rc;
@@ -294,11 +295,10 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 		*dma_handle = dev_addr;
 	else {
 		if (xen_create_contiguous_region(vstart, order,
-						 fls64(dma_mask)) != 0) {
+						 fls64(dma_mask), dma_handle) != 0) {
 			free_pages(vstart, order);
 			return NULL;
 		}
-		*dma_handle = virt_to_machine(ret).maddr;
 	}
 	memset(ret, 0, size);
 	return ret;
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index d6fe062..9ef704d 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -20,7 +20,8 @@ int xen_setup_shutdown_event(void);
 
 extern unsigned long *xen_contiguous_bitmap;
 int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
-				unsigned int address_bits);
+				unsigned int address_bits,
+				dma_addr_t *dma_handle);
 
 void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
 
-- 
1.7.2.5


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

* [PATCH RFC 6/8] xen: make xen_create_contiguous_region return the dma address
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Modify xen_create_contiguous_region to return the dma address of the
newly contiguous buffer.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: david.vrabel at citrix.com
---
 arch/x86/xen/mmu.c        |    4 +++-
 drivers/xen/swiotlb-xen.c |    6 +++---
 include/xen/xen-ops.h     |    3 ++-
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index fdc3ba2..df9ab44 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2329,7 +2329,8 @@ static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in,
 }
 
 int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
-				 unsigned int address_bits)
+				 unsigned int address_bits,
+				 dma_addr_t *dma_handle)
 {
 	unsigned long *in_frames = discontig_frames, out_frame;
 	unsigned long  flags;
@@ -2368,6 +2369,7 @@ int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
 
 	spin_unlock_irqrestore(&xen_reservation_lock, flags);
 
+	*dma_handle = xen_virt_to_bus(vstart);
 	return success ? 0 : -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index aadffcf..353f013 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -126,6 +126,7 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 {
 	int i, rc;
 	int dma_bits;
+	dma_addr_t dma_handle;
 
 	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
 
@@ -137,7 +138,7 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 			rc = xen_create_contiguous_region(
 				(unsigned long)buf + (i << IO_TLB_SHIFT),
 				get_order(slabs << IO_TLB_SHIFT),
-				dma_bits);
+				dma_bits, &dma_handle);
 		} while (rc && dma_bits++ < max_dma_bits);
 		if (rc)
 			return rc;
@@ -294,11 +295,10 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 		*dma_handle = dev_addr;
 	else {
 		if (xen_create_contiguous_region(vstart, order,
-						 fls64(dma_mask)) != 0) {
+						 fls64(dma_mask), dma_handle) != 0) {
 			free_pages(vstart, order);
 			return NULL;
 		}
-		*dma_handle = virt_to_machine(ret).maddr;
 	}
 	memset(ret, 0, size);
 	return ret;
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index d6fe062..9ef704d 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -20,7 +20,8 @@ int xen_setup_shutdown_event(void);
 
 extern unsigned long *xen_contiguous_bitmap;
 int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
-				unsigned int address_bits);
+				unsigned int address_bits,
+				dma_addr_t *dma_handle);
 
 void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
 
-- 
1.7.2.5

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

* [PATCH RFC 6/8] xen: make xen_create_contiguous_region return the dma address
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: Ian.Campbell, Stefano Stabellini, linux-kernel, david.vrabel,
	linux-arm-kernel

Modify xen_create_contiguous_region to return the dma address of the
newly contiguous buffer.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: david.vrabel@citrix.com
---
 arch/x86/xen/mmu.c        |    4 +++-
 drivers/xen/swiotlb-xen.c |    6 +++---
 include/xen/xen-ops.h     |    3 ++-
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index fdc3ba2..df9ab44 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2329,7 +2329,8 @@ static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in,
 }
 
 int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
-				 unsigned int address_bits)
+				 unsigned int address_bits,
+				 dma_addr_t *dma_handle)
 {
 	unsigned long *in_frames = discontig_frames, out_frame;
 	unsigned long  flags;
@@ -2368,6 +2369,7 @@ int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
 
 	spin_unlock_irqrestore(&xen_reservation_lock, flags);
 
+	*dma_handle = xen_virt_to_bus(vstart);
 	return success ? 0 : -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index aadffcf..353f013 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -126,6 +126,7 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 {
 	int i, rc;
 	int dma_bits;
+	dma_addr_t dma_handle;
 
 	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
 
@@ -137,7 +138,7 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 			rc = xen_create_contiguous_region(
 				(unsigned long)buf + (i << IO_TLB_SHIFT),
 				get_order(slabs << IO_TLB_SHIFT),
-				dma_bits);
+				dma_bits, &dma_handle);
 		} while (rc && dma_bits++ < max_dma_bits);
 		if (rc)
 			return rc;
@@ -294,11 +295,10 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 		*dma_handle = dev_addr;
 	else {
 		if (xen_create_contiguous_region(vstart, order,
-						 fls64(dma_mask)) != 0) {
+						 fls64(dma_mask), dma_handle) != 0) {
 			free_pages(vstart, order);
 			return NULL;
 		}
-		*dma_handle = virt_to_machine(ret).maddr;
 	}
 	memset(ret, 0, size);
 	return ret;
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index d6fe062..9ef704d 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -20,7 +20,8 @@ int xen_setup_shutdown_event(void);
 
 extern unsigned long *xen_contiguous_bitmap;
 int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
-				unsigned int address_bits);
+				unsigned int address_bits,
+				dma_addr_t *dma_handle);
 
 void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
 
-- 
1.7.2.5

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

* [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 17:45   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini, david.vrabel

Support autotranslate guests in swiotlb-xen by keeping track of the
phys-to-bus and bus-to-phys mappings of the swiotlb buffer
(xen_io_tlb_start-xen_io_tlb_end).

Use a simple direct access on a pre-allocated array for phys-to-bus
queries. Use a red-black tree for bus-to-phys queries.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: david.vrabel@citrix.com
---
 drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 111 insertions(+), 16 deletions(-)

diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 353f013..c79ac88 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -38,32 +38,116 @@
 #include <linux/bootmem.h>
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/spinlock_types.h>
+#include <linux/rbtree.h>
 #include <xen/swiotlb-xen.h>
 #include <xen/page.h>
 #include <xen/xen-ops.h>
 #include <xen/hvc-console.h>
+#include <xen/features.h>
 /*
  * Used to do a quick range check in swiotlb_tbl_unmap_single and
  * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
  * API.
  */
 
+#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
 static char *xen_io_tlb_start, *xen_io_tlb_end;
 static unsigned long xen_io_tlb_nslabs;
 /*
  * Quick lookup value of the bus address of the IOTLB.
  */
 
-static u64 start_dma_addr;
+struct xen_dma{
+	dma_addr_t dma_addr;
+	phys_addr_t phys_addr;
+	size_t size;
+	struct rb_node rbnode;
+};
+
+static struct xen_dma *xen_dma_seg;
+static struct rb_root bus_to_phys = RB_ROOT;
+static DEFINE_SPINLOCK(xen_dma_lock);
+
+static void xen_dma_insert(struct xen_dma *entry)
+{
+	struct rb_node **link = &bus_to_phys.rb_node;
+	struct rb_node *parent = NULL;
+	struct xen_dma *e;
+
+	spin_lock(&xen_dma_lock);
+
+	while (*link) {
+		parent = *link;
+		e = rb_entry(parent, struct xen_dma, rbnode);
+
+		WARN_ON(entry->dma_addr == e->dma_addr);
+
+		if (entry->dma_addr < e->dma_addr)
+			link = &(*link)->rb_left;
+		else
+			link = &(*link)->rb_right;
+	}
+	rb_link_node(&entry->rbnode, parent, link);
+	rb_insert_color(&entry->rbnode, &bus_to_phys);
+
+	spin_unlock(&xen_dma_lock);
+}
+
+static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)
+{
+	struct rb_node *n = bus_to_phys.rb_node;
+	struct xen_dma *e;
+	
+	spin_lock(&xen_dma_lock);
+
+	while (n) {
+		e = rb_entry(n, struct xen_dma, rbnode);
+		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
+			spin_unlock(&xen_dma_lock);
+			return e;
+		}
+		if (dma_addr < e->dma_addr)
+			n = n->rb_left;
+		else
+			n = n->rb_right;
+	}
+
+	spin_unlock(&xen_dma_lock);
+	return NULL;
+}
 
 static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
 {
-	return phys_to_machine(XPADDR(paddr)).maddr;
+	int nr_seg;
+	unsigned long offset;
+	char* vaddr;
+
+	if (!xen_feature(XENFEAT_auto_translated_physmap))
+		return phys_to_machine(XPADDR(paddr)).maddr;
+
+	vaddr = (char *) phys_to_virt(paddr);
+	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
+		return ~0;
+
+	offset = vaddr - xen_io_tlb_start;
+	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
+
+	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
 }
 
 static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
 {
-	return machine_to_phys(XMADDR(baddr)).paddr;
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+	{
+		struct xen_dma *dma = xen_dma_retrieve(baddr);
+		if (dma == NULL)
+			return ~0;
+		else
+			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
+	} else
+		return machine_to_phys(XMADDR(baddr)).paddr;
 }
 
 static dma_addr_t xen_virt_to_bus(void *address)
@@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
 	unsigned long pfn = mfn_to_local_pfn(mfn);
 	phys_addr_t paddr;
 
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+		return 1;
+
 	/* If the address is outside our domain, it CAN
 	 * have the same virtual address as another address
 	 * in our domain. Therefore _only_ check address within our domain.
@@ -124,13 +211,12 @@ static int max_dma_bits = 32;
 static int
 xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 {
-	int i, rc;
+	int i, j, rc;
 	int dma_bits;
-	dma_addr_t dma_handle;
 
 	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
 
-	i = 0;
+	i = j = 0;
 	do {
 		int slabs = min(nslabs - i, (unsigned long)IO_TLB_SEGSIZE);
 
@@ -138,12 +224,16 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 			rc = xen_create_contiguous_region(
 				(unsigned long)buf + (i << IO_TLB_SHIFT),
 				get_order(slabs << IO_TLB_SHIFT),
-				dma_bits, &dma_handle);
+				dma_bits, &xen_dma_seg[j].dma_addr);
+			xen_dma_seg[j].phys_addr = virt_to_phys(buf + (i << IO_TLB_SHIFT));
+			xen_dma_seg[j].size = slabs << IO_TLB_SHIFT;
+			xen_dma_insert(&xen_dma_seg[j]);
 		} while (rc && dma_bits++ < max_dma_bits);
 		if (rc)
 			return rc;
 
 		i += slabs;
+		j++;
 	} while (i < nslabs);
 	return 0;
 }
@@ -193,9 +283,10 @@ retry:
 	/*
 	 * Get IO TLB memory from any location.
 	 */
-	if (early)
+	if (early) {
 		xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
-	else {
+		xen_dma_seg = alloc_bootmem(sizeof(struct xen_dma) * NR_DMA_SEGS);
+	} else {
 #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
 #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
 		while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
@@ -210,6 +301,7 @@ retry:
 			xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
 			bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
 		}
+		xen_dma_seg = kzalloc(sizeof(struct xen_dma) * NR_DMA_SEGS, GFP_KERNEL);
 	}
 	if (!xen_io_tlb_start) {
 		m_ret = XEN_SWIOTLB_ENOMEM;
@@ -232,7 +324,6 @@ retry:
 		m_ret = XEN_SWIOTLB_EFIXUP;
 		goto error;
 	}
-	start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
 	if (early) {
 		if (swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs,
 			 verbose))
@@ -290,7 +381,8 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 
 	phys = virt_to_phys(ret);
 	dev_addr = xen_phys_to_bus(phys);
-	if (((dev_addr + size - 1 <= dma_mask)) &&
+	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
+	    ((dev_addr + size - 1 <= dma_mask)) &&
 	    !range_straddles_page_boundary(phys, size))
 		*dma_handle = dev_addr;
 	else {
@@ -321,8 +413,9 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
 
 	phys = virt_to_phys(vaddr);
 
-	if (((dev_addr + size - 1 > dma_mask)) ||
-	    range_straddles_page_boundary(phys, size))
+	if (xen_feature(XENFEAT_auto_translated_physmap) ||
+		(((dev_addr + size - 1 > dma_mask)) ||
+		 range_straddles_page_boundary(phys, size)))
 		xen_destroy_contiguous_region((unsigned long)vaddr, order);
 
 	free_pages((unsigned long)vaddr, order);
@@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
 	 * we can safely return the device addr and not worry about bounce
 	 * buffering it.
 	 */
-	if (dma_capable(dev, dev_addr, size) &&
+	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
+	    dma_capable(dev, dev_addr, size) &&
 	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
 		return dev_addr;
 
 	/*
 	 * Oh well, have to allocate and map a bounce buffer.
 	 */
-	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
+	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);
 	if (map == SWIOTLB_MAP_ERROR)
 		return DMA_ERROR_CODE;
 
@@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
 		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
 
 		if (swiotlb_force ||
+		    xen_feature(XENFEAT_auto_translated_physmap) ||
 		    !dma_capable(hwdev, dev_addr, sg->length) ||
 		    range_straddles_page_boundary(paddr, sg->length)) {
 			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
-								 start_dma_addr,
+								 xen_dma_seg[0].dma_addr,
 								 sg_phys(sg),
 								 sg->length,
 								 dir);
-- 
1.7.2.5


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

* [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Support autotranslate guests in swiotlb-xen by keeping track of the
phys-to-bus and bus-to-phys mappings of the swiotlb buffer
(xen_io_tlb_start-xen_io_tlb_end).

Use a simple direct access on a pre-allocated array for phys-to-bus
queries. Use a red-black tree for bus-to-phys queries.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: david.vrabel at citrix.com
---
 drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 111 insertions(+), 16 deletions(-)

diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 353f013..c79ac88 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -38,32 +38,116 @@
 #include <linux/bootmem.h>
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/spinlock_types.h>
+#include <linux/rbtree.h>
 #include <xen/swiotlb-xen.h>
 #include <xen/page.h>
 #include <xen/xen-ops.h>
 #include <xen/hvc-console.h>
+#include <xen/features.h>
 /*
  * Used to do a quick range check in swiotlb_tbl_unmap_single and
  * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
  * API.
  */
 
+#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
 static char *xen_io_tlb_start, *xen_io_tlb_end;
 static unsigned long xen_io_tlb_nslabs;
 /*
  * Quick lookup value of the bus address of the IOTLB.
  */
 
-static u64 start_dma_addr;
+struct xen_dma{
+	dma_addr_t dma_addr;
+	phys_addr_t phys_addr;
+	size_t size;
+	struct rb_node rbnode;
+};
+
+static struct xen_dma *xen_dma_seg;
+static struct rb_root bus_to_phys = RB_ROOT;
+static DEFINE_SPINLOCK(xen_dma_lock);
+
+static void xen_dma_insert(struct xen_dma *entry)
+{
+	struct rb_node **link = &bus_to_phys.rb_node;
+	struct rb_node *parent = NULL;
+	struct xen_dma *e;
+
+	spin_lock(&xen_dma_lock);
+
+	while (*link) {
+		parent = *link;
+		e = rb_entry(parent, struct xen_dma, rbnode);
+
+		WARN_ON(entry->dma_addr == e->dma_addr);
+
+		if (entry->dma_addr < e->dma_addr)
+			link = &(*link)->rb_left;
+		else
+			link = &(*link)->rb_right;
+	}
+	rb_link_node(&entry->rbnode, parent, link);
+	rb_insert_color(&entry->rbnode, &bus_to_phys);
+
+	spin_unlock(&xen_dma_lock);
+}
+
+static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)
+{
+	struct rb_node *n = bus_to_phys.rb_node;
+	struct xen_dma *e;
+	
+	spin_lock(&xen_dma_lock);
+
+	while (n) {
+		e = rb_entry(n, struct xen_dma, rbnode);
+		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
+			spin_unlock(&xen_dma_lock);
+			return e;
+		}
+		if (dma_addr < e->dma_addr)
+			n = n->rb_left;
+		else
+			n = n->rb_right;
+	}
+
+	spin_unlock(&xen_dma_lock);
+	return NULL;
+}
 
 static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
 {
-	return phys_to_machine(XPADDR(paddr)).maddr;
+	int nr_seg;
+	unsigned long offset;
+	char* vaddr;
+
+	if (!xen_feature(XENFEAT_auto_translated_physmap))
+		return phys_to_machine(XPADDR(paddr)).maddr;
+
+	vaddr = (char *) phys_to_virt(paddr);
+	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
+		return ~0;
+
+	offset = vaddr - xen_io_tlb_start;
+	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
+
+	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
 }
 
 static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
 {
-	return machine_to_phys(XMADDR(baddr)).paddr;
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+	{
+		struct xen_dma *dma = xen_dma_retrieve(baddr);
+		if (dma == NULL)
+			return ~0;
+		else
+			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
+	} else
+		return machine_to_phys(XMADDR(baddr)).paddr;
 }
 
 static dma_addr_t xen_virt_to_bus(void *address)
@@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
 	unsigned long pfn = mfn_to_local_pfn(mfn);
 	phys_addr_t paddr;
 
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+		return 1;
+
 	/* If the address is outside our domain, it CAN
 	 * have the same virtual address as another address
 	 * in our domain. Therefore _only_ check address within our domain.
@@ -124,13 +211,12 @@ static int max_dma_bits = 32;
 static int
 xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 {
-	int i, rc;
+	int i, j, rc;
 	int dma_bits;
-	dma_addr_t dma_handle;
 
 	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
 
-	i = 0;
+	i = j = 0;
 	do {
 		int slabs = min(nslabs - i, (unsigned long)IO_TLB_SEGSIZE);
 
@@ -138,12 +224,16 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 			rc = xen_create_contiguous_region(
 				(unsigned long)buf + (i << IO_TLB_SHIFT),
 				get_order(slabs << IO_TLB_SHIFT),
-				dma_bits, &dma_handle);
+				dma_bits, &xen_dma_seg[j].dma_addr);
+			xen_dma_seg[j].phys_addr = virt_to_phys(buf + (i << IO_TLB_SHIFT));
+			xen_dma_seg[j].size = slabs << IO_TLB_SHIFT;
+			xen_dma_insert(&xen_dma_seg[j]);
 		} while (rc && dma_bits++ < max_dma_bits);
 		if (rc)
 			return rc;
 
 		i += slabs;
+		j++;
 	} while (i < nslabs);
 	return 0;
 }
@@ -193,9 +283,10 @@ retry:
 	/*
 	 * Get IO TLB memory from any location.
 	 */
-	if (early)
+	if (early) {
 		xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
-	else {
+		xen_dma_seg = alloc_bootmem(sizeof(struct xen_dma) * NR_DMA_SEGS);
+	} else {
 #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
 #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
 		while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
@@ -210,6 +301,7 @@ retry:
 			xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
 			bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
 		}
+		xen_dma_seg = kzalloc(sizeof(struct xen_dma) * NR_DMA_SEGS, GFP_KERNEL);
 	}
 	if (!xen_io_tlb_start) {
 		m_ret = XEN_SWIOTLB_ENOMEM;
@@ -232,7 +324,6 @@ retry:
 		m_ret = XEN_SWIOTLB_EFIXUP;
 		goto error;
 	}
-	start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
 	if (early) {
 		if (swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs,
 			 verbose))
@@ -290,7 +381,8 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 
 	phys = virt_to_phys(ret);
 	dev_addr = xen_phys_to_bus(phys);
-	if (((dev_addr + size - 1 <= dma_mask)) &&
+	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
+	    ((dev_addr + size - 1 <= dma_mask)) &&
 	    !range_straddles_page_boundary(phys, size))
 		*dma_handle = dev_addr;
 	else {
@@ -321,8 +413,9 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
 
 	phys = virt_to_phys(vaddr);
 
-	if (((dev_addr + size - 1 > dma_mask)) ||
-	    range_straddles_page_boundary(phys, size))
+	if (xen_feature(XENFEAT_auto_translated_physmap) ||
+		(((dev_addr + size - 1 > dma_mask)) ||
+		 range_straddles_page_boundary(phys, size)))
 		xen_destroy_contiguous_region((unsigned long)vaddr, order);
 
 	free_pages((unsigned long)vaddr, order);
@@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
 	 * we can safely return the device addr and not worry about bounce
 	 * buffering it.
 	 */
-	if (dma_capable(dev, dev_addr, size) &&
+	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
+	    dma_capable(dev, dev_addr, size) &&
 	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
 		return dev_addr;
 
 	/*
 	 * Oh well, have to allocate and map a bounce buffer.
 	 */
-	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
+	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);
 	if (map == SWIOTLB_MAP_ERROR)
 		return DMA_ERROR_CODE;
 
@@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
 		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
 
 		if (swiotlb_force ||
+		    xen_feature(XENFEAT_auto_translated_physmap) ||
 		    !dma_capable(hwdev, dev_addr, sg->length) ||
 		    range_straddles_page_boundary(paddr, sg->length)) {
 			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
-								 start_dma_addr,
+								 xen_dma_seg[0].dma_addr,
 								 sg_phys(sg),
 								 sg->length,
 								 dir);
-- 
1.7.2.5

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

* [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: Ian.Campbell, Stefano Stabellini, linux-kernel, david.vrabel,
	linux-arm-kernel

Support autotranslate guests in swiotlb-xen by keeping track of the
phys-to-bus and bus-to-phys mappings of the swiotlb buffer
(xen_io_tlb_start-xen_io_tlb_end).

Use a simple direct access on a pre-allocated array for phys-to-bus
queries. Use a red-black tree for bus-to-phys queries.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: david.vrabel@citrix.com
---
 drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 111 insertions(+), 16 deletions(-)

diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 353f013..c79ac88 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -38,32 +38,116 @@
 #include <linux/bootmem.h>
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/spinlock_types.h>
+#include <linux/rbtree.h>
 #include <xen/swiotlb-xen.h>
 #include <xen/page.h>
 #include <xen/xen-ops.h>
 #include <xen/hvc-console.h>
+#include <xen/features.h>
 /*
  * Used to do a quick range check in swiotlb_tbl_unmap_single and
  * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
  * API.
  */
 
+#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
 static char *xen_io_tlb_start, *xen_io_tlb_end;
 static unsigned long xen_io_tlb_nslabs;
 /*
  * Quick lookup value of the bus address of the IOTLB.
  */
 
-static u64 start_dma_addr;
+struct xen_dma{
+	dma_addr_t dma_addr;
+	phys_addr_t phys_addr;
+	size_t size;
+	struct rb_node rbnode;
+};
+
+static struct xen_dma *xen_dma_seg;
+static struct rb_root bus_to_phys = RB_ROOT;
+static DEFINE_SPINLOCK(xen_dma_lock);
+
+static void xen_dma_insert(struct xen_dma *entry)
+{
+	struct rb_node **link = &bus_to_phys.rb_node;
+	struct rb_node *parent = NULL;
+	struct xen_dma *e;
+
+	spin_lock(&xen_dma_lock);
+
+	while (*link) {
+		parent = *link;
+		e = rb_entry(parent, struct xen_dma, rbnode);
+
+		WARN_ON(entry->dma_addr == e->dma_addr);
+
+		if (entry->dma_addr < e->dma_addr)
+			link = &(*link)->rb_left;
+		else
+			link = &(*link)->rb_right;
+	}
+	rb_link_node(&entry->rbnode, parent, link);
+	rb_insert_color(&entry->rbnode, &bus_to_phys);
+
+	spin_unlock(&xen_dma_lock);
+}
+
+static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)
+{
+	struct rb_node *n = bus_to_phys.rb_node;
+	struct xen_dma *e;
+	
+	spin_lock(&xen_dma_lock);
+
+	while (n) {
+		e = rb_entry(n, struct xen_dma, rbnode);
+		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
+			spin_unlock(&xen_dma_lock);
+			return e;
+		}
+		if (dma_addr < e->dma_addr)
+			n = n->rb_left;
+		else
+			n = n->rb_right;
+	}
+
+	spin_unlock(&xen_dma_lock);
+	return NULL;
+}
 
 static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
 {
-	return phys_to_machine(XPADDR(paddr)).maddr;
+	int nr_seg;
+	unsigned long offset;
+	char* vaddr;
+
+	if (!xen_feature(XENFEAT_auto_translated_physmap))
+		return phys_to_machine(XPADDR(paddr)).maddr;
+
+	vaddr = (char *) phys_to_virt(paddr);
+	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
+		return ~0;
+
+	offset = vaddr - xen_io_tlb_start;
+	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
+
+	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
 }
 
 static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
 {
-	return machine_to_phys(XMADDR(baddr)).paddr;
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+	{
+		struct xen_dma *dma = xen_dma_retrieve(baddr);
+		if (dma == NULL)
+			return ~0;
+		else
+			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
+	} else
+		return machine_to_phys(XMADDR(baddr)).paddr;
 }
 
 static dma_addr_t xen_virt_to_bus(void *address)
@@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
 	unsigned long pfn = mfn_to_local_pfn(mfn);
 	phys_addr_t paddr;
 
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+		return 1;
+
 	/* If the address is outside our domain, it CAN
 	 * have the same virtual address as another address
 	 * in our domain. Therefore _only_ check address within our domain.
@@ -124,13 +211,12 @@ static int max_dma_bits = 32;
 static int
 xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 {
-	int i, rc;
+	int i, j, rc;
 	int dma_bits;
-	dma_addr_t dma_handle;
 
 	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
 
-	i = 0;
+	i = j = 0;
 	do {
 		int slabs = min(nslabs - i, (unsigned long)IO_TLB_SEGSIZE);
 
@@ -138,12 +224,16 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
 			rc = xen_create_contiguous_region(
 				(unsigned long)buf + (i << IO_TLB_SHIFT),
 				get_order(slabs << IO_TLB_SHIFT),
-				dma_bits, &dma_handle);
+				dma_bits, &xen_dma_seg[j].dma_addr);
+			xen_dma_seg[j].phys_addr = virt_to_phys(buf + (i << IO_TLB_SHIFT));
+			xen_dma_seg[j].size = slabs << IO_TLB_SHIFT;
+			xen_dma_insert(&xen_dma_seg[j]);
 		} while (rc && dma_bits++ < max_dma_bits);
 		if (rc)
 			return rc;
 
 		i += slabs;
+		j++;
 	} while (i < nslabs);
 	return 0;
 }
@@ -193,9 +283,10 @@ retry:
 	/*
 	 * Get IO TLB memory from any location.
 	 */
-	if (early)
+	if (early) {
 		xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
-	else {
+		xen_dma_seg = alloc_bootmem(sizeof(struct xen_dma) * NR_DMA_SEGS);
+	} else {
 #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
 #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
 		while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
@@ -210,6 +301,7 @@ retry:
 			xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
 			bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
 		}
+		xen_dma_seg = kzalloc(sizeof(struct xen_dma) * NR_DMA_SEGS, GFP_KERNEL);
 	}
 	if (!xen_io_tlb_start) {
 		m_ret = XEN_SWIOTLB_ENOMEM;
@@ -232,7 +324,6 @@ retry:
 		m_ret = XEN_SWIOTLB_EFIXUP;
 		goto error;
 	}
-	start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
 	if (early) {
 		if (swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs,
 			 verbose))
@@ -290,7 +381,8 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 
 	phys = virt_to_phys(ret);
 	dev_addr = xen_phys_to_bus(phys);
-	if (((dev_addr + size - 1 <= dma_mask)) &&
+	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
+	    ((dev_addr + size - 1 <= dma_mask)) &&
 	    !range_straddles_page_boundary(phys, size))
 		*dma_handle = dev_addr;
 	else {
@@ -321,8 +413,9 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
 
 	phys = virt_to_phys(vaddr);
 
-	if (((dev_addr + size - 1 > dma_mask)) ||
-	    range_straddles_page_boundary(phys, size))
+	if (xen_feature(XENFEAT_auto_translated_physmap) ||
+		(((dev_addr + size - 1 > dma_mask)) ||
+		 range_straddles_page_boundary(phys, size)))
 		xen_destroy_contiguous_region((unsigned long)vaddr, order);
 
 	free_pages((unsigned long)vaddr, order);
@@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
 	 * we can safely return the device addr and not worry about bounce
 	 * buffering it.
 	 */
-	if (dma_capable(dev, dev_addr, size) &&
+	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
+	    dma_capable(dev, dev_addr, size) &&
 	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
 		return dev_addr;
 
 	/*
 	 * Oh well, have to allocate and map a bounce buffer.
 	 */
-	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
+	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);
 	if (map == SWIOTLB_MAP_ERROR)
 		return DMA_ERROR_CODE;
 
@@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
 		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
 
 		if (swiotlb_force ||
+		    xen_feature(XENFEAT_auto_translated_physmap) ||
 		    !dma_capable(hwdev, dev_addr, sg->length) ||
 		    range_straddles_page_boundary(paddr, sg->length)) {
 			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
-								 start_dma_addr,
+								 xen_dma_seg[0].dma_addr,
 								 sg_phys(sg),
 								 sg->length,
 								 dir);
-- 
1.7.2.5

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

* [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 17:45   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: linux-kernel, linux-arm-kernel, konrad.wilk, Stefano.Stabellini,
	Ian.Campbell, Stefano Stabellini

Xen on arm and arm64 needs SWIOTLB_XEN: when running on Xen we need to
program the hardware with mfns rather than pfns for dma addresses.
Remove SWIOTLB_XEN dependency on X86 and PCI and make XEN select
SWIOTLB_XEN on arm and arm64.

Implement xen_create_contiguous_region on arm and arm64 by using
XENMEM_get_dma_buf.

Initialize the xen-swiotlb from xen_early_init (before the native
dma_ops are initialized), set dma_ops to &xen_swiotlb_dma_ops if we are
running on Xen.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 arch/arm/Kconfig                |    1 +
 arch/arm/include/asm/xen/page.h |    2 +
 arch/arm/xen/Makefile           |    2 +-
 arch/arm/xen/enlighten.c        |    3 +
 arch/arm/xen/mm.c               |  118 +++++++++++++++++++++++++++++++++++++++
 arch/arm64/Kconfig              |    1 +
 arch/arm64/xen/Makefile         |    2 +-
 drivers/xen/Kconfig             |    1 -
 drivers/xen/swiotlb-xen.c       |   18 ++++++
 9 files changed, 145 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/xen/mm.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 05125ab..72b53b9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1849,6 +1849,7 @@ config XEN
 	depends on CPU_V7 && !CPU_V6
 	depends on !GENERIC_ATOMIC64
 	select ARM_PSCI
+	select SWIOTLB_XEN
 	help
 	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
 
diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
index 359a7b5..b0f7150 100644
--- a/arch/arm/include/asm/xen/page.h
+++ b/arch/arm/include/asm/xen/page.h
@@ -6,12 +6,14 @@
 
 #include <linux/pfn.h>
 #include <linux/types.h>
+#include <linux/dma-mapping.h>
 
 #include <xen/interface/grant_table.h>
 
 #define pfn_to_mfn(pfn)			(pfn)
 #define phys_to_machine_mapping_valid(pfn) (1)
 #define mfn_to_pfn(mfn)			(mfn)
+#define mfn_to_local_pfn(m)             (mfn_to_pfn(m))
 #define mfn_to_virt(m)			(__va(mfn_to_pfn(m) << PAGE_SHIFT))
 
 #define pte_mfn	    pte_pfn
diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
index 4384103..66fc35d 100644
--- a/arch/arm/xen/Makefile
+++ b/arch/arm/xen/Makefile
@@ -1 +1 @@
-obj-y		:= enlighten.o hypercall.o grant-table.o
+obj-y		:= enlighten.o hypercall.o grant-table.o mm.o
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index 14d17ab..06a6953 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -195,6 +195,7 @@ static void xen_power_off(void)
  * documentation of the Xen Device Tree format.
  */
 #define GRANT_TABLE_PHYSADDR 0
+extern int xen_mm_init(void);
 void __init xen_early_init(void)
 {
 	struct resource res;
@@ -230,6 +231,8 @@ void __init xen_early_init(void)
 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
 	else
 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
+
+	xen_mm_init();
 }
 
 static int __init xen_guest_init(void)
diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c
new file mode 100644
index 0000000..4ba1add
--- /dev/null
+++ b/arch/arm/xen/mm.c
@@ -0,0 +1,118 @@
+#include <linux/bootmem.h>
+#include <linux/gfp.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/swiotlb.h>
+
+#include <xen/xen.h>
+#include <xen/interface/memory.h>
+#include <xen/swiotlb-xen.h>
+
+#include <asm/cacheflush.h>
+#include <asm/xen/page.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/interface.h>
+
+static int xen_exchange_memory(xen_ulong_t extents_in,
+			       unsigned int order_in,
+			       xen_pfn_t *pfns_in,
+			       xen_ulong_t extents_out,
+			       unsigned int order_out,
+			       xen_pfn_t *mfns_out,
+			       unsigned int address_bits)
+{
+	long rc;
+	int success;
+
+	struct xen_memory_exchange exchange = {
+		.in = {
+			.nr_extents   = extents_in,
+			.extent_order = order_in,
+			.domid        = DOMID_SELF
+		},
+		.out = {
+			.nr_extents   = extents_out,
+			.extent_order = order_out,
+			.address_bits = address_bits,
+			.domid        = DOMID_SELF
+		}
+	};
+	set_xen_guest_handle(exchange.in.extent_start, pfns_in);
+	set_xen_guest_handle(exchange.out.extent_start, mfns_out);
+
+	BUG_ON(extents_in << order_in != extents_out << order_out);
+
+
+	rc = HYPERVISOR_memory_op(XENMEM_get_dma_buf, &exchange);
+	success = (exchange.nr_exchanged == extents_in);
+
+	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
+	BUG_ON(success && (rc != 0));
+
+	return success;
+}
+
+int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
+				 unsigned int address_bits,
+				 dma_addr_t *dma_handle)
+{
+	phys_addr_t pstart = __pa(vstart);
+	xen_pfn_t in_frame, out_frame;
+	int success, i;
+
+	/* 2. Get a new contiguous memory extent. */
+	in_frame = out_frame = pstart >> PAGE_SHIFT;
+	success = xen_exchange_memory(1, order, &in_frame,
+				      1, order, &out_frame,
+				      address_bits);
+
+	if (!success)
+		return -ENOMEM;
+
+	*dma_handle = out_frame << PAGE_SHIFT;
+	
+	return success ? 0 : -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
+
+void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
+{
+	int i;
+	xen_pfn_t in_frame = __pa(vstart) >> PAGE_SHIFT;
+	struct xen_put_dma_buf buf = {
+		.in = {
+			.nr_extents   = 1,
+			.extent_order = order,
+			.domid        = DOMID_SELF
+		},
+	};
+	set_xen_guest_handle(buf.in.extent_start, &in_frame);
+
+	HYPERVISOR_memory_op(XENMEM_put_dma_buf, &buf);
+}
+EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
+
+static struct dma_map_ops xen_swiotlb_dma_ops = {
+	.mapping_error = xen_swiotlb_dma_mapping_error,
+	.alloc = xen_swiotlb_alloc_coherent,
+	.free = xen_swiotlb_free_coherent,
+	.sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu,
+	.sync_single_for_device = xen_swiotlb_sync_single_for_device,
+	.sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = xen_swiotlb_sync_sg_for_device,
+	.map_sg = xen_swiotlb_map_sg_attrs,
+	.unmap_sg = xen_swiotlb_unmap_sg_attrs,
+	.map_page = xen_swiotlb_map_page,
+	.unmap_page = xen_swiotlb_unmap_page,
+	.dma_supported = xen_swiotlb_dma_supported,
+};
+
+int __init xen_mm_init(void)
+{
+	xen_swiotlb_init(1, true);
+	dma_ops = &xen_swiotlb_dma_ops;
+	return 0;
+}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9737e97..aa1f6fb 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -209,6 +209,7 @@ config XEN_DOM0
 config XEN
 	bool "Xen guest support on ARM64 (EXPERIMENTAL)"
 	depends on ARM64 && OF
+	select SWIOTLB_XEN
 	help
 	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
 
diff --git a/arch/arm64/xen/Makefile b/arch/arm64/xen/Makefile
index be24040..0ef9637 100644
--- a/arch/arm64/xen/Makefile
+++ b/arch/arm64/xen/Makefile
@@ -1,2 +1,2 @@
-xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o)
+xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o mm.o)
 obj-y		:= xen-arm.o hypercall.o
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 9e02d60..7e83688 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -140,7 +140,6 @@ config XEN_GRANT_DEV_ALLOC
 
 config SWIOTLB_XEN
 	def_bool y
-	depends on PCI && X86
 	select SWIOTLB
 
 config XEN_TMEM
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index c79ac88..4ae6cf6 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -59,6 +59,24 @@ static unsigned long xen_io_tlb_nslabs;
  * Quick lookup value of the bus address of the IOTLB.
  */
 
+#ifndef DMA_ERROR_CODE
+#define DMA_ERROR_CODE	(~0)
+#endif
+
+#ifndef CONFIG_X86
+static unsigned long dma_alloc_coherent_mask(struct device *dev,
+					    gfp_t gfp)
+{
+	unsigned long dma_mask = 0;
+
+	dma_mask = dev->coherent_dma_mask;
+	if (!dma_mask)
+		dma_mask = (gfp & GFP_DMA) ? DMA_BIT_MASK(24) : DMA_BIT_MASK(32);
+
+	return dma_mask;
+}
+#endif
+
 struct xen_dma{
 	dma_addr_t dma_addr;
 	phys_addr_t phys_addr;
-- 
1.7.2.5


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

* [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: linux-arm-kernel

Xen on arm and arm64 needs SWIOTLB_XEN: when running on Xen we need to
program the hardware with mfns rather than pfns for dma addresses.
Remove SWIOTLB_XEN dependency on X86 and PCI and make XEN select
SWIOTLB_XEN on arm and arm64.

Implement xen_create_contiguous_region on arm and arm64 by using
XENMEM_get_dma_buf.

Initialize the xen-swiotlb from xen_early_init (before the native
dma_ops are initialized), set dma_ops to &xen_swiotlb_dma_ops if we are
running on Xen.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 arch/arm/Kconfig                |    1 +
 arch/arm/include/asm/xen/page.h |    2 +
 arch/arm/xen/Makefile           |    2 +-
 arch/arm/xen/enlighten.c        |    3 +
 arch/arm/xen/mm.c               |  118 +++++++++++++++++++++++++++++++++++++++
 arch/arm64/Kconfig              |    1 +
 arch/arm64/xen/Makefile         |    2 +-
 drivers/xen/Kconfig             |    1 -
 drivers/xen/swiotlb-xen.c       |   18 ++++++
 9 files changed, 145 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/xen/mm.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 05125ab..72b53b9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1849,6 +1849,7 @@ config XEN
 	depends on CPU_V7 && !CPU_V6
 	depends on !GENERIC_ATOMIC64
 	select ARM_PSCI
+	select SWIOTLB_XEN
 	help
 	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
 
diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
index 359a7b5..b0f7150 100644
--- a/arch/arm/include/asm/xen/page.h
+++ b/arch/arm/include/asm/xen/page.h
@@ -6,12 +6,14 @@
 
 #include <linux/pfn.h>
 #include <linux/types.h>
+#include <linux/dma-mapping.h>
 
 #include <xen/interface/grant_table.h>
 
 #define pfn_to_mfn(pfn)			(pfn)
 #define phys_to_machine_mapping_valid(pfn) (1)
 #define mfn_to_pfn(mfn)			(mfn)
+#define mfn_to_local_pfn(m)             (mfn_to_pfn(m))
 #define mfn_to_virt(m)			(__va(mfn_to_pfn(m) << PAGE_SHIFT))
 
 #define pte_mfn	    pte_pfn
diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
index 4384103..66fc35d 100644
--- a/arch/arm/xen/Makefile
+++ b/arch/arm/xen/Makefile
@@ -1 +1 @@
-obj-y		:= enlighten.o hypercall.o grant-table.o
+obj-y		:= enlighten.o hypercall.o grant-table.o mm.o
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index 14d17ab..06a6953 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -195,6 +195,7 @@ static void xen_power_off(void)
  * documentation of the Xen Device Tree format.
  */
 #define GRANT_TABLE_PHYSADDR 0
+extern int xen_mm_init(void);
 void __init xen_early_init(void)
 {
 	struct resource res;
@@ -230,6 +231,8 @@ void __init xen_early_init(void)
 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
 	else
 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
+
+	xen_mm_init();
 }
 
 static int __init xen_guest_init(void)
diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c
new file mode 100644
index 0000000..4ba1add
--- /dev/null
+++ b/arch/arm/xen/mm.c
@@ -0,0 +1,118 @@
+#include <linux/bootmem.h>
+#include <linux/gfp.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/swiotlb.h>
+
+#include <xen/xen.h>
+#include <xen/interface/memory.h>
+#include <xen/swiotlb-xen.h>
+
+#include <asm/cacheflush.h>
+#include <asm/xen/page.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/interface.h>
+
+static int xen_exchange_memory(xen_ulong_t extents_in,
+			       unsigned int order_in,
+			       xen_pfn_t *pfns_in,
+			       xen_ulong_t extents_out,
+			       unsigned int order_out,
+			       xen_pfn_t *mfns_out,
+			       unsigned int address_bits)
+{
+	long rc;
+	int success;
+
+	struct xen_memory_exchange exchange = {
+		.in = {
+			.nr_extents   = extents_in,
+			.extent_order = order_in,
+			.domid        = DOMID_SELF
+		},
+		.out = {
+			.nr_extents   = extents_out,
+			.extent_order = order_out,
+			.address_bits = address_bits,
+			.domid        = DOMID_SELF
+		}
+	};
+	set_xen_guest_handle(exchange.in.extent_start, pfns_in);
+	set_xen_guest_handle(exchange.out.extent_start, mfns_out);
+
+	BUG_ON(extents_in << order_in != extents_out << order_out);
+
+
+	rc = HYPERVISOR_memory_op(XENMEM_get_dma_buf, &exchange);
+	success = (exchange.nr_exchanged == extents_in);
+
+	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
+	BUG_ON(success && (rc != 0));
+
+	return success;
+}
+
+int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
+				 unsigned int address_bits,
+				 dma_addr_t *dma_handle)
+{
+	phys_addr_t pstart = __pa(vstart);
+	xen_pfn_t in_frame, out_frame;
+	int success, i;
+
+	/* 2. Get a new contiguous memory extent. */
+	in_frame = out_frame = pstart >> PAGE_SHIFT;
+	success = xen_exchange_memory(1, order, &in_frame,
+				      1, order, &out_frame,
+				      address_bits);
+
+	if (!success)
+		return -ENOMEM;
+
+	*dma_handle = out_frame << PAGE_SHIFT;
+	
+	return success ? 0 : -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
+
+void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
+{
+	int i;
+	xen_pfn_t in_frame = __pa(vstart) >> PAGE_SHIFT;
+	struct xen_put_dma_buf buf = {
+		.in = {
+			.nr_extents   = 1,
+			.extent_order = order,
+			.domid        = DOMID_SELF
+		},
+	};
+	set_xen_guest_handle(buf.in.extent_start, &in_frame);
+
+	HYPERVISOR_memory_op(XENMEM_put_dma_buf, &buf);
+}
+EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
+
+static struct dma_map_ops xen_swiotlb_dma_ops = {
+	.mapping_error = xen_swiotlb_dma_mapping_error,
+	.alloc = xen_swiotlb_alloc_coherent,
+	.free = xen_swiotlb_free_coherent,
+	.sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu,
+	.sync_single_for_device = xen_swiotlb_sync_single_for_device,
+	.sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = xen_swiotlb_sync_sg_for_device,
+	.map_sg = xen_swiotlb_map_sg_attrs,
+	.unmap_sg = xen_swiotlb_unmap_sg_attrs,
+	.map_page = xen_swiotlb_map_page,
+	.unmap_page = xen_swiotlb_unmap_page,
+	.dma_supported = xen_swiotlb_dma_supported,
+};
+
+int __init xen_mm_init(void)
+{
+	xen_swiotlb_init(1, true);
+	dma_ops = &xen_swiotlb_dma_ops;
+	return 0;
+}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9737e97..aa1f6fb 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -209,6 +209,7 @@ config XEN_DOM0
 config XEN
 	bool "Xen guest support on ARM64 (EXPERIMENTAL)"
 	depends on ARM64 && OF
+	select SWIOTLB_XEN
 	help
 	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
 
diff --git a/arch/arm64/xen/Makefile b/arch/arm64/xen/Makefile
index be24040..0ef9637 100644
--- a/arch/arm64/xen/Makefile
+++ b/arch/arm64/xen/Makefile
@@ -1,2 +1,2 @@
-xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o)
+xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o mm.o)
 obj-y		:= xen-arm.o hypercall.o
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 9e02d60..7e83688 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -140,7 +140,6 @@ config XEN_GRANT_DEV_ALLOC
 
 config SWIOTLB_XEN
 	def_bool y
-	depends on PCI && X86
 	select SWIOTLB
 
 config XEN_TMEM
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index c79ac88..4ae6cf6 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -59,6 +59,24 @@ static unsigned long xen_io_tlb_nslabs;
  * Quick lookup value of the bus address of the IOTLB.
  */
 
+#ifndef DMA_ERROR_CODE
+#define DMA_ERROR_CODE	(~0)
+#endif
+
+#ifndef CONFIG_X86
+static unsigned long dma_alloc_coherent_mask(struct device *dev,
+					    gfp_t gfp)
+{
+	unsigned long dma_mask = 0;
+
+	dma_mask = dev->coherent_dma_mask;
+	if (!dma_mask)
+		dma_mask = (gfp & GFP_DMA) ? DMA_BIT_MASK(24) : DMA_BIT_MASK(32);
+
+	return dma_mask;
+}
+#endif
+
 struct xen_dma{
 	dma_addr_t dma_addr;
 	phys_addr_t phys_addr;
-- 
1.7.2.5

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

* [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN
@ 2013-07-31 17:45   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 17:45 UTC (permalink / raw)
  To: xen-devel
  Cc: Ian.Campbell, Stefano Stabellini, linux-kernel, linux-arm-kernel

Xen on arm and arm64 needs SWIOTLB_XEN: when running on Xen we need to
program the hardware with mfns rather than pfns for dma addresses.
Remove SWIOTLB_XEN dependency on X86 and PCI and make XEN select
SWIOTLB_XEN on arm and arm64.

Implement xen_create_contiguous_region on arm and arm64 by using
XENMEM_get_dma_buf.

Initialize the xen-swiotlb from xen_early_init (before the native
dma_ops are initialized), set dma_ops to &xen_swiotlb_dma_ops if we are
running on Xen.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 arch/arm/Kconfig                |    1 +
 arch/arm/include/asm/xen/page.h |    2 +
 arch/arm/xen/Makefile           |    2 +-
 arch/arm/xen/enlighten.c        |    3 +
 arch/arm/xen/mm.c               |  118 +++++++++++++++++++++++++++++++++++++++
 arch/arm64/Kconfig              |    1 +
 arch/arm64/xen/Makefile         |    2 +-
 drivers/xen/Kconfig             |    1 -
 drivers/xen/swiotlb-xen.c       |   18 ++++++
 9 files changed, 145 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/xen/mm.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 05125ab..72b53b9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1849,6 +1849,7 @@ config XEN
 	depends on CPU_V7 && !CPU_V6
 	depends on !GENERIC_ATOMIC64
 	select ARM_PSCI
+	select SWIOTLB_XEN
 	help
 	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
 
diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
index 359a7b5..b0f7150 100644
--- a/arch/arm/include/asm/xen/page.h
+++ b/arch/arm/include/asm/xen/page.h
@@ -6,12 +6,14 @@
 
 #include <linux/pfn.h>
 #include <linux/types.h>
+#include <linux/dma-mapping.h>
 
 #include <xen/interface/grant_table.h>
 
 #define pfn_to_mfn(pfn)			(pfn)
 #define phys_to_machine_mapping_valid(pfn) (1)
 #define mfn_to_pfn(mfn)			(mfn)
+#define mfn_to_local_pfn(m)             (mfn_to_pfn(m))
 #define mfn_to_virt(m)			(__va(mfn_to_pfn(m) << PAGE_SHIFT))
 
 #define pte_mfn	    pte_pfn
diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
index 4384103..66fc35d 100644
--- a/arch/arm/xen/Makefile
+++ b/arch/arm/xen/Makefile
@@ -1 +1 @@
-obj-y		:= enlighten.o hypercall.o grant-table.o
+obj-y		:= enlighten.o hypercall.o grant-table.o mm.o
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index 14d17ab..06a6953 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -195,6 +195,7 @@ static void xen_power_off(void)
  * documentation of the Xen Device Tree format.
  */
 #define GRANT_TABLE_PHYSADDR 0
+extern int xen_mm_init(void);
 void __init xen_early_init(void)
 {
 	struct resource res;
@@ -230,6 +231,8 @@ void __init xen_early_init(void)
 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
 	else
 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
+
+	xen_mm_init();
 }
 
 static int __init xen_guest_init(void)
diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c
new file mode 100644
index 0000000..4ba1add
--- /dev/null
+++ b/arch/arm/xen/mm.c
@@ -0,0 +1,118 @@
+#include <linux/bootmem.h>
+#include <linux/gfp.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/swiotlb.h>
+
+#include <xen/xen.h>
+#include <xen/interface/memory.h>
+#include <xen/swiotlb-xen.h>
+
+#include <asm/cacheflush.h>
+#include <asm/xen/page.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/interface.h>
+
+static int xen_exchange_memory(xen_ulong_t extents_in,
+			       unsigned int order_in,
+			       xen_pfn_t *pfns_in,
+			       xen_ulong_t extents_out,
+			       unsigned int order_out,
+			       xen_pfn_t *mfns_out,
+			       unsigned int address_bits)
+{
+	long rc;
+	int success;
+
+	struct xen_memory_exchange exchange = {
+		.in = {
+			.nr_extents   = extents_in,
+			.extent_order = order_in,
+			.domid        = DOMID_SELF
+		},
+		.out = {
+			.nr_extents   = extents_out,
+			.extent_order = order_out,
+			.address_bits = address_bits,
+			.domid        = DOMID_SELF
+		}
+	};
+	set_xen_guest_handle(exchange.in.extent_start, pfns_in);
+	set_xen_guest_handle(exchange.out.extent_start, mfns_out);
+
+	BUG_ON(extents_in << order_in != extents_out << order_out);
+
+
+	rc = HYPERVISOR_memory_op(XENMEM_get_dma_buf, &exchange);
+	success = (exchange.nr_exchanged == extents_in);
+
+	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
+	BUG_ON(success && (rc != 0));
+
+	return success;
+}
+
+int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
+				 unsigned int address_bits,
+				 dma_addr_t *dma_handle)
+{
+	phys_addr_t pstart = __pa(vstart);
+	xen_pfn_t in_frame, out_frame;
+	int success, i;
+
+	/* 2. Get a new contiguous memory extent. */
+	in_frame = out_frame = pstart >> PAGE_SHIFT;
+	success = xen_exchange_memory(1, order, &in_frame,
+				      1, order, &out_frame,
+				      address_bits);
+
+	if (!success)
+		return -ENOMEM;
+
+	*dma_handle = out_frame << PAGE_SHIFT;
+	
+	return success ? 0 : -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
+
+void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
+{
+	int i;
+	xen_pfn_t in_frame = __pa(vstart) >> PAGE_SHIFT;
+	struct xen_put_dma_buf buf = {
+		.in = {
+			.nr_extents   = 1,
+			.extent_order = order,
+			.domid        = DOMID_SELF
+		},
+	};
+	set_xen_guest_handle(buf.in.extent_start, &in_frame);
+
+	HYPERVISOR_memory_op(XENMEM_put_dma_buf, &buf);
+}
+EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
+
+static struct dma_map_ops xen_swiotlb_dma_ops = {
+	.mapping_error = xen_swiotlb_dma_mapping_error,
+	.alloc = xen_swiotlb_alloc_coherent,
+	.free = xen_swiotlb_free_coherent,
+	.sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu,
+	.sync_single_for_device = xen_swiotlb_sync_single_for_device,
+	.sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = xen_swiotlb_sync_sg_for_device,
+	.map_sg = xen_swiotlb_map_sg_attrs,
+	.unmap_sg = xen_swiotlb_unmap_sg_attrs,
+	.map_page = xen_swiotlb_map_page,
+	.unmap_page = xen_swiotlb_unmap_page,
+	.dma_supported = xen_swiotlb_dma_supported,
+};
+
+int __init xen_mm_init(void)
+{
+	xen_swiotlb_init(1, true);
+	dma_ops = &xen_swiotlb_dma_ops;
+	return 0;
+}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9737e97..aa1f6fb 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -209,6 +209,7 @@ config XEN_DOM0
 config XEN
 	bool "Xen guest support on ARM64 (EXPERIMENTAL)"
 	depends on ARM64 && OF
+	select SWIOTLB_XEN
 	help
 	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
 
diff --git a/arch/arm64/xen/Makefile b/arch/arm64/xen/Makefile
index be24040..0ef9637 100644
--- a/arch/arm64/xen/Makefile
+++ b/arch/arm64/xen/Makefile
@@ -1,2 +1,2 @@
-xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o)
+xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o mm.o)
 obj-y		:= xen-arm.o hypercall.o
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 9e02d60..7e83688 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -140,7 +140,6 @@ config XEN_GRANT_DEV_ALLOC
 
 config SWIOTLB_XEN
 	def_bool y
-	depends on PCI && X86
 	select SWIOTLB
 
 config XEN_TMEM
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index c79ac88..4ae6cf6 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -59,6 +59,24 @@ static unsigned long xen_io_tlb_nslabs;
  * Quick lookup value of the bus address of the IOTLB.
  */
 
+#ifndef DMA_ERROR_CODE
+#define DMA_ERROR_CODE	(~0)
+#endif
+
+#ifndef CONFIG_X86
+static unsigned long dma_alloc_coherent_mask(struct device *dev,
+					    gfp_t gfp)
+{
+	unsigned long dma_mask = 0;
+
+	dma_mask = dev->coherent_dma_mask;
+	if (!dma_mask)
+		dma_mask = (gfp & GFP_DMA) ? DMA_BIT_MASK(24) : DMA_BIT_MASK(32);
+
+	return dma_mask;
+}
+#endif
+
 struct xen_dma{
 	dma_addr_t dma_addr;
 	phys_addr_t phys_addr;
-- 
1.7.2.5

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

* Re: [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
  2013-07-31 17:45   ` Stefano Stabellini
  (?)
@ 2013-07-31 19:03     ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 19:03 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, konrad.wilk,
	Ian.Campbell, david.vrabel

On Wed, 31 Jul 2013, Stefano Stabellini wrote:
> Support autotranslate guests in swiotlb-xen by keeping track of the
> phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> (xen_io_tlb_start-xen_io_tlb_end).
> 
> Use a simple direct access on a pre-allocated array for phys-to-bus
> queries. Use a red-black tree for bus-to-phys queries.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: david.vrabel@citrix.com
> ---
>  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 111 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> index 353f013..c79ac88 100644
> --- a/drivers/xen/swiotlb-xen.c
> +++ b/drivers/xen/swiotlb-xen.c
> @@ -38,32 +38,116 @@
>  #include <linux/bootmem.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock_types.h>
> +#include <linux/rbtree.h>
>  #include <xen/swiotlb-xen.h>
>  #include <xen/page.h>
>  #include <xen/xen-ops.h>
>  #include <xen/hvc-console.h>
> +#include <xen/features.h>
>  /*
>   * Used to do a quick range check in swiotlb_tbl_unmap_single and
>   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
>   * API.
>   */
>  
> +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
>  static char *xen_io_tlb_start, *xen_io_tlb_end;
>  static unsigned long xen_io_tlb_nslabs;
>  /*
>   * Quick lookup value of the bus address of the IOTLB.
>   */
>  
> -static u64 start_dma_addr;
> +struct xen_dma{
> +	dma_addr_t dma_addr;
> +	phys_addr_t phys_addr;
> +	size_t size;
> +	struct rb_node rbnode;
> +};
> +
> +static struct xen_dma *xen_dma_seg;
> +static struct rb_root bus_to_phys = RB_ROOT;
> +static DEFINE_SPINLOCK(xen_dma_lock);
> +
> +static void xen_dma_insert(struct xen_dma *entry)
> +{
> +	struct rb_node **link = &bus_to_phys.rb_node;
> +	struct rb_node *parent = NULL;
> +	struct xen_dma *e;
> +
> +	spin_lock(&xen_dma_lock);
> +
> +	while (*link) {
> +		parent = *link;
> +		e = rb_entry(parent, struct xen_dma, rbnode);
> +
> +		WARN_ON(entry->dma_addr == e->dma_addr);
> +
> +		if (entry->dma_addr < e->dma_addr)
> +			link = &(*link)->rb_left;
> +		else
> +			link = &(*link)->rb_right;
> +	}
> +	rb_link_node(&entry->rbnode, parent, link);
> +	rb_insert_color(&entry->rbnode, &bus_to_phys);
> +
> +	spin_unlock(&xen_dma_lock);
> +}
> +
> +static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)
> +{
> +	struct rb_node *n = bus_to_phys.rb_node;
> +	struct xen_dma *e;
> +	
> +	spin_lock(&xen_dma_lock);
> +
> +	while (n) {
> +		e = rb_entry(n, struct xen_dma, rbnode);
> +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
> +			spin_unlock(&xen_dma_lock);
> +			return e;
> +		}
> +		if (dma_addr < e->dma_addr)
> +			n = n->rb_left;
> +		else
> +			n = n->rb_right;
> +	}
> +
> +	spin_unlock(&xen_dma_lock);
> +	return NULL;
> +}
>  
>  static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
>  {
> -	return phys_to_machine(XPADDR(paddr)).maddr;
> +	int nr_seg;
> +	unsigned long offset;
> +	char* vaddr;
> +
> +	if (!xen_feature(XENFEAT_auto_translated_physmap))
> +		return phys_to_machine(XPADDR(paddr)).maddr;
> +
> +	vaddr = (char *) phys_to_virt(paddr);
> +	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
> +		return ~0;
> +
> +	offset = vaddr - xen_io_tlb_start;
> +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> +
> +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));

I have just realized that there is a much better way of doing this:

return xen_dma_seg[nr_seg].dma_addr + (paddr - xen_dma_seg[nr_seg].phys_addr);


>  }
>  
>  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
>  {
> -	return machine_to_phys(XMADDR(baddr)).paddr;
> +	if (xen_feature(XENFEAT_auto_translated_physmap))
> +	{
> +		struct xen_dma *dma = xen_dma_retrieve(baddr);
> +		if (dma == NULL)
> +			return ~0;
> +		else
> +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));

same here:

return dma->phys_addr + (baddr - dma->dma_addr);

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

* [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
@ 2013-07-31 19:03     ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 31 Jul 2013, Stefano Stabellini wrote:
> Support autotranslate guests in swiotlb-xen by keeping track of the
> phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> (xen_io_tlb_start-xen_io_tlb_end).
> 
> Use a simple direct access on a pre-allocated array for phys-to-bus
> queries. Use a red-black tree for bus-to-phys queries.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: david.vrabel at citrix.com
> ---
>  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 111 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> index 353f013..c79ac88 100644
> --- a/drivers/xen/swiotlb-xen.c
> +++ b/drivers/xen/swiotlb-xen.c
> @@ -38,32 +38,116 @@
>  #include <linux/bootmem.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock_types.h>
> +#include <linux/rbtree.h>
>  #include <xen/swiotlb-xen.h>
>  #include <xen/page.h>
>  #include <xen/xen-ops.h>
>  #include <xen/hvc-console.h>
> +#include <xen/features.h>
>  /*
>   * Used to do a quick range check in swiotlb_tbl_unmap_single and
>   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
>   * API.
>   */
>  
> +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
>  static char *xen_io_tlb_start, *xen_io_tlb_end;
>  static unsigned long xen_io_tlb_nslabs;
>  /*
>   * Quick lookup value of the bus address of the IOTLB.
>   */
>  
> -static u64 start_dma_addr;
> +struct xen_dma{
> +	dma_addr_t dma_addr;
> +	phys_addr_t phys_addr;
> +	size_t size;
> +	struct rb_node rbnode;
> +};
> +
> +static struct xen_dma *xen_dma_seg;
> +static struct rb_root bus_to_phys = RB_ROOT;
> +static DEFINE_SPINLOCK(xen_dma_lock);
> +
> +static void xen_dma_insert(struct xen_dma *entry)
> +{
> +	struct rb_node **link = &bus_to_phys.rb_node;
> +	struct rb_node *parent = NULL;
> +	struct xen_dma *e;
> +
> +	spin_lock(&xen_dma_lock);
> +
> +	while (*link) {
> +		parent = *link;
> +		e = rb_entry(parent, struct xen_dma, rbnode);
> +
> +		WARN_ON(entry->dma_addr == e->dma_addr);
> +
> +		if (entry->dma_addr < e->dma_addr)
> +			link = &(*link)->rb_left;
> +		else
> +			link = &(*link)->rb_right;
> +	}
> +	rb_link_node(&entry->rbnode, parent, link);
> +	rb_insert_color(&entry->rbnode, &bus_to_phys);
> +
> +	spin_unlock(&xen_dma_lock);
> +}
> +
> +static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)
> +{
> +	struct rb_node *n = bus_to_phys.rb_node;
> +	struct xen_dma *e;
> +	
> +	spin_lock(&xen_dma_lock);
> +
> +	while (n) {
> +		e = rb_entry(n, struct xen_dma, rbnode);
> +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
> +			spin_unlock(&xen_dma_lock);
> +			return e;
> +		}
> +		if (dma_addr < e->dma_addr)
> +			n = n->rb_left;
> +		else
> +			n = n->rb_right;
> +	}
> +
> +	spin_unlock(&xen_dma_lock);
> +	return NULL;
> +}
>  
>  static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
>  {
> -	return phys_to_machine(XPADDR(paddr)).maddr;
> +	int nr_seg;
> +	unsigned long offset;
> +	char* vaddr;
> +
> +	if (!xen_feature(XENFEAT_auto_translated_physmap))
> +		return phys_to_machine(XPADDR(paddr)).maddr;
> +
> +	vaddr = (char *) phys_to_virt(paddr);
> +	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
> +		return ~0;
> +
> +	offset = vaddr - xen_io_tlb_start;
> +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> +
> +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));

I have just realized that there is a much better way of doing this:

return xen_dma_seg[nr_seg].dma_addr + (paddr - xen_dma_seg[nr_seg].phys_addr);


>  }
>  
>  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
>  {
> -	return machine_to_phys(XMADDR(baddr)).paddr;
> +	if (xen_feature(XENFEAT_auto_translated_physmap))
> +	{
> +		struct xen_dma *dma = xen_dma_retrieve(baddr);
> +		if (dma == NULL)
> +			return ~0;
> +		else
> +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));

same here:

return dma->phys_addr + (baddr - dma->dma_addr);

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

* Re: [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
@ 2013-07-31 19:03     ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 19:03 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, konrad.wilk,
	Ian.Campbell, david.vrabel

On Wed, 31 Jul 2013, Stefano Stabellini wrote:
> Support autotranslate guests in swiotlb-xen by keeping track of the
> phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> (xen_io_tlb_start-xen_io_tlb_end).
> 
> Use a simple direct access on a pre-allocated array for phys-to-bus
> queries. Use a red-black tree for bus-to-phys queries.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: david.vrabel@citrix.com
> ---
>  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 111 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> index 353f013..c79ac88 100644
> --- a/drivers/xen/swiotlb-xen.c
> +++ b/drivers/xen/swiotlb-xen.c
> @@ -38,32 +38,116 @@
>  #include <linux/bootmem.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock_types.h>
> +#include <linux/rbtree.h>
>  #include <xen/swiotlb-xen.h>
>  #include <xen/page.h>
>  #include <xen/xen-ops.h>
>  #include <xen/hvc-console.h>
> +#include <xen/features.h>
>  /*
>   * Used to do a quick range check in swiotlb_tbl_unmap_single and
>   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
>   * API.
>   */
>  
> +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
>  static char *xen_io_tlb_start, *xen_io_tlb_end;
>  static unsigned long xen_io_tlb_nslabs;
>  /*
>   * Quick lookup value of the bus address of the IOTLB.
>   */
>  
> -static u64 start_dma_addr;
> +struct xen_dma{
> +	dma_addr_t dma_addr;
> +	phys_addr_t phys_addr;
> +	size_t size;
> +	struct rb_node rbnode;
> +};
> +
> +static struct xen_dma *xen_dma_seg;
> +static struct rb_root bus_to_phys = RB_ROOT;
> +static DEFINE_SPINLOCK(xen_dma_lock);
> +
> +static void xen_dma_insert(struct xen_dma *entry)
> +{
> +	struct rb_node **link = &bus_to_phys.rb_node;
> +	struct rb_node *parent = NULL;
> +	struct xen_dma *e;
> +
> +	spin_lock(&xen_dma_lock);
> +
> +	while (*link) {
> +		parent = *link;
> +		e = rb_entry(parent, struct xen_dma, rbnode);
> +
> +		WARN_ON(entry->dma_addr == e->dma_addr);
> +
> +		if (entry->dma_addr < e->dma_addr)
> +			link = &(*link)->rb_left;
> +		else
> +			link = &(*link)->rb_right;
> +	}
> +	rb_link_node(&entry->rbnode, parent, link);
> +	rb_insert_color(&entry->rbnode, &bus_to_phys);
> +
> +	spin_unlock(&xen_dma_lock);
> +}
> +
> +static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)
> +{
> +	struct rb_node *n = bus_to_phys.rb_node;
> +	struct xen_dma *e;
> +	
> +	spin_lock(&xen_dma_lock);
> +
> +	while (n) {
> +		e = rb_entry(n, struct xen_dma, rbnode);
> +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
> +			spin_unlock(&xen_dma_lock);
> +			return e;
> +		}
> +		if (dma_addr < e->dma_addr)
> +			n = n->rb_left;
> +		else
> +			n = n->rb_right;
> +	}
> +
> +	spin_unlock(&xen_dma_lock);
> +	return NULL;
> +}
>  
>  static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
>  {
> -	return phys_to_machine(XPADDR(paddr)).maddr;
> +	int nr_seg;
> +	unsigned long offset;
> +	char* vaddr;
> +
> +	if (!xen_feature(XENFEAT_auto_translated_physmap))
> +		return phys_to_machine(XPADDR(paddr)).maddr;
> +
> +	vaddr = (char *) phys_to_virt(paddr);
> +	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
> +		return ~0;
> +
> +	offset = vaddr - xen_io_tlb_start;
> +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> +
> +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));

I have just realized that there is a much better way of doing this:

return xen_dma_seg[nr_seg].dma_addr + (paddr - xen_dma_seg[nr_seg].phys_addr);


>  }
>  
>  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
>  {
> -	return machine_to_phys(XMADDR(baddr)).paddr;
> +	if (xen_feature(XENFEAT_auto_translated_physmap))
> +	{
> +		struct xen_dma *dma = xen_dma_retrieve(baddr);
> +		if (dma == NULL)
> +			return ~0;
> +		else
> +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));

same here:

return dma->phys_addr + (baddr - dma->dma_addr);

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

* Re: [PATCH RFC 0/8] enable swiotlb-xen on arm and arm64
  2013-07-31 17:44 ` Stefano Stabellini
  (?)
@ 2013-07-31 19:44   ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 19:44 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, Konrad Rzeszutek Wilk,
	Ian Campbell

Although the series should be enough to demonstrate the concept, it
contains a couple of errors. I'll send an update.

On Wed, 31 Jul 2013, Stefano Stabellini wrote:
> Hi all,
> this patch series enables xen-swiotlb on arm and arm64.
> 
> Considering that all guests, including dom0, run on xen on arm with
> second stage translation enabled, it follows that without an IOMMU no
> guests could actually drive the hardware.
> 
> The solution for platforms without an IOMMU is to use swiotlb-xen,
> adapted to autotranslate guests. swiotlb-xen provides a set of dma_ops
> that can be used by Linux to setup a contiguous buffer in stage-2
> addresses and use it for dma operations.
> Basically Linux asks Xen to make a buffer contiguous and gets the
> machine address for it. This buffer is going to be used by lib/swiotlb.c
> to allocate bounce buffers.
> 
> 
> The first 3 patches lay the groundwork on arm and arm64 to have
> alternative dma_ops and swiotlb.
> 
> The forth patch moves Xen initialization earlier so that we already know
> whether we are running on Xen at the time of initializing dma_ops on the
> platform.
> 
> The following patches adapt swiotlb-xen to autotranslate guests (guest
> with second stage translation in hardware) and provide an arm
> implementation of xen_create_contiguous_region.
> 
> 
> Feedback is very welcome.
> Cheers,
> 
> Stefano
> 
> 
> Stefano Stabellini (8):
>       arm: make SWIOTLB available
>       arm: introduce a global dma_ops pointer
>       arm64: do not initialize arm64_swiotlb if dma_ops is already set
>       xen/arm,arm64: move Xen initialization earlier
>       xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
>       xen: make xen_create_contiguous_region return the dma address
>       swiotlb-xen: support autotranslate guests
>       xen/arm,arm64: enable SWIOTLB_XEN
> 
>  arch/arm/Kconfig                      |    8 ++
>  arch/arm/common/dmabounce.c           |   10 +-
>  arch/arm/include/asm/dma-mapping.h    |   27 ++++++-
>  arch/arm/include/asm/xen/hypervisor.h |    6 ++
>  arch/arm/include/asm/xen/page.h       |    2 +
>  arch/arm/kernel/setup.c               |    2 +
>  arch/arm/mm/dma-mapping.c             |    3 +
>  arch/arm/xen/Makefile                 |    2 +-
>  arch/arm/xen/enlighten.c              |   24 ++++--
>  arch/arm/xen/mm.c                     |  118 ++++++++++++++++++++++++++
>  arch/arm64/Kconfig                    |    1 +
>  arch/arm64/kernel/setup.c             |    2 +
>  arch/arm64/mm/dma-mapping.c           |    2 +
>  arch/arm64/xen/Makefile               |    2 +-
>  arch/x86/xen/mmu.c                    |    4 +-
>  drivers/xen/Kconfig                   |    1 -
>  drivers/xen/swiotlb-xen.c             |  147 +++++++++++++++++++++++++++++----
>  include/xen/interface/memory.h        |   62 ++++++++++++++
>  include/xen/xen-ops.h                 |    3 +-
>  19 files changed, 391 insertions(+), 35 deletions(-)
>  create mode 100644 arch/arm/xen/mm.c
> 

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

* [PATCH RFC 0/8] enable swiotlb-xen on arm and arm64
@ 2013-07-31 19:44   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 19:44 UTC (permalink / raw)
  To: linux-arm-kernel

Although the series should be enough to demonstrate the concept, it
contains a couple of errors. I'll send an update.

On Wed, 31 Jul 2013, Stefano Stabellini wrote:
> Hi all,
> this patch series enables xen-swiotlb on arm and arm64.
> 
> Considering that all guests, including dom0, run on xen on arm with
> second stage translation enabled, it follows that without an IOMMU no
> guests could actually drive the hardware.
> 
> The solution for platforms without an IOMMU is to use swiotlb-xen,
> adapted to autotranslate guests. swiotlb-xen provides a set of dma_ops
> that can be used by Linux to setup a contiguous buffer in stage-2
> addresses and use it for dma operations.
> Basically Linux asks Xen to make a buffer contiguous and gets the
> machine address for it. This buffer is going to be used by lib/swiotlb.c
> to allocate bounce buffers.
> 
> 
> The first 3 patches lay the groundwork on arm and arm64 to have
> alternative dma_ops and swiotlb.
> 
> The forth patch moves Xen initialization earlier so that we already know
> whether we are running on Xen at the time of initializing dma_ops on the
> platform.
> 
> The following patches adapt swiotlb-xen to autotranslate guests (guest
> with second stage translation in hardware) and provide an arm
> implementation of xen_create_contiguous_region.
> 
> 
> Feedback is very welcome.
> Cheers,
> 
> Stefano
> 
> 
> Stefano Stabellini (8):
>       arm: make SWIOTLB available
>       arm: introduce a global dma_ops pointer
>       arm64: do not initialize arm64_swiotlb if dma_ops is already set
>       xen/arm,arm64: move Xen initialization earlier
>       xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
>       xen: make xen_create_contiguous_region return the dma address
>       swiotlb-xen: support autotranslate guests
>       xen/arm,arm64: enable SWIOTLB_XEN
> 
>  arch/arm/Kconfig                      |    8 ++
>  arch/arm/common/dmabounce.c           |   10 +-
>  arch/arm/include/asm/dma-mapping.h    |   27 ++++++-
>  arch/arm/include/asm/xen/hypervisor.h |    6 ++
>  arch/arm/include/asm/xen/page.h       |    2 +
>  arch/arm/kernel/setup.c               |    2 +
>  arch/arm/mm/dma-mapping.c             |    3 +
>  arch/arm/xen/Makefile                 |    2 +-
>  arch/arm/xen/enlighten.c              |   24 ++++--
>  arch/arm/xen/mm.c                     |  118 ++++++++++++++++++++++++++
>  arch/arm64/Kconfig                    |    1 +
>  arch/arm64/kernel/setup.c             |    2 +
>  arch/arm64/mm/dma-mapping.c           |    2 +
>  arch/arm64/xen/Makefile               |    2 +-
>  arch/x86/xen/mmu.c                    |    4 +-
>  drivers/xen/Kconfig                   |    1 -
>  drivers/xen/swiotlb-xen.c             |  147 +++++++++++++++++++++++++++++----
>  include/xen/interface/memory.h        |   62 ++++++++++++++
>  include/xen/xen-ops.h                 |    3 +-
>  19 files changed, 391 insertions(+), 35 deletions(-)
>  create mode 100644 arch/arm/xen/mm.c
> 

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

* Re: [PATCH RFC 0/8] enable swiotlb-xen on arm and arm64
@ 2013-07-31 19:44   ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-07-31 19:44 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, Konrad Rzeszutek Wilk,
	Ian Campbell

Although the series should be enough to demonstrate the concept, it
contains a couple of errors. I'll send an update.

On Wed, 31 Jul 2013, Stefano Stabellini wrote:
> Hi all,
> this patch series enables xen-swiotlb on arm and arm64.
> 
> Considering that all guests, including dom0, run on xen on arm with
> second stage translation enabled, it follows that without an IOMMU no
> guests could actually drive the hardware.
> 
> The solution for platforms without an IOMMU is to use swiotlb-xen,
> adapted to autotranslate guests. swiotlb-xen provides a set of dma_ops
> that can be used by Linux to setup a contiguous buffer in stage-2
> addresses and use it for dma operations.
> Basically Linux asks Xen to make a buffer contiguous and gets the
> machine address for it. This buffer is going to be used by lib/swiotlb.c
> to allocate bounce buffers.
> 
> 
> The first 3 patches lay the groundwork on arm and arm64 to have
> alternative dma_ops and swiotlb.
> 
> The forth patch moves Xen initialization earlier so that we already know
> whether we are running on Xen at the time of initializing dma_ops on the
> platform.
> 
> The following patches adapt swiotlb-xen to autotranslate guests (guest
> with second stage translation in hardware) and provide an arm
> implementation of xen_create_contiguous_region.
> 
> 
> Feedback is very welcome.
> Cheers,
> 
> Stefano
> 
> 
> Stefano Stabellini (8):
>       arm: make SWIOTLB available
>       arm: introduce a global dma_ops pointer
>       arm64: do not initialize arm64_swiotlb if dma_ops is already set
>       xen/arm,arm64: move Xen initialization earlier
>       xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
>       xen: make xen_create_contiguous_region return the dma address
>       swiotlb-xen: support autotranslate guests
>       xen/arm,arm64: enable SWIOTLB_XEN
> 
>  arch/arm/Kconfig                      |    8 ++
>  arch/arm/common/dmabounce.c           |   10 +-
>  arch/arm/include/asm/dma-mapping.h    |   27 ++++++-
>  arch/arm/include/asm/xen/hypervisor.h |    6 ++
>  arch/arm/include/asm/xen/page.h       |    2 +
>  arch/arm/kernel/setup.c               |    2 +
>  arch/arm/mm/dma-mapping.c             |    3 +
>  arch/arm/xen/Makefile                 |    2 +-
>  arch/arm/xen/enlighten.c              |   24 ++++--
>  arch/arm/xen/mm.c                     |  118 ++++++++++++++++++++++++++
>  arch/arm64/Kconfig                    |    1 +
>  arch/arm64/kernel/setup.c             |    2 +
>  arch/arm64/mm/dma-mapping.c           |    2 +
>  arch/arm64/xen/Makefile               |    2 +-
>  arch/x86/xen/mmu.c                    |    4 +-
>  drivers/xen/Kconfig                   |    1 -
>  drivers/xen/swiotlb-xen.c             |  147 +++++++++++++++++++++++++++++----
>  include/xen/interface/memory.h        |   62 ++++++++++++++
>  include/xen/xen-ops.h                 |    3 +-
>  19 files changed, 391 insertions(+), 35 deletions(-)
>  create mode 100644 arch/arm/xen/mm.c
> 

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
  2013-07-31 17:45   ` Stefano Stabellini
  (?)
@ 2013-08-01  0:32     ` Konrad Rzeszutek Wilk
  -1 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:32 UTC (permalink / raw)
  To: Stefano Stabellini, xen-devel
  Cc: linux-kernel, linux-arm-kernel, Stefano.Stabellini, Ian.Campbell,
	will.deacon, linux

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>CC: will.deacon@arm.com
>CC: linux@arm.linux.org.uk
>---
> arch/arm/Kconfig                   |    7 +++++++
> arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> 2 files changed, 31 insertions(+), 0 deletions(-)
>
>diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>index ba412e0..05125ab 100644
>--- a/arch/arm/Kconfig
>+++ b/arch/arm/Kconfig
>@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> 	  neutralized via a kernel panic.
> 	  This feature requires gcc version 4.2 or above.
> 
>+config SWIOTLB
>+	def_bool y
>+	select NEED_SG_DMA_LENGTH
>+
>+config IOMMU_HELPER
>+	def_bool SWIOTLB
>+

Could you explain the purpose of these two a bit more please? 

> config XEN_DOM0
> 	def_bool y
> 	depends on XEN
>diff --git a/arch/arm/include/asm/dma-mapping.h
>b/arch/arm/include/asm/dma-mapping.h
>index 5b579b9..ad89e0f 100644
>--- a/arch/arm/include/asm/dma-mapping.h
>+++ b/arch/arm/include/asm/dma-mapping.h
>@@ -86,6 +86,30 @@ static inline dma_addr_t virt_to_dma(struct device
>*dev, void *addr)
> }
> #endif
> 
>+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t
>paddr)
>+{
>+	unsigned int offset = paddr & ~PAGE_MASK;
>+	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
>+}
>+
>+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t
>dev_addr)
>+{
>+	unsigned int offset = dev_addr & ~PAGE_MASK;
>+	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
>+}
>+
>+static inline bool dma_capable(struct device *dev, dma_addr_t addr,
>size_t size)
>+{
>+	if (!dev->dma_mask)
>+		return 0;
>+
>+	return addr + size - 1 <= *dev->dma_mask;
>+}
>+
>+static inline void dma_mark_clean(void *addr, size_t size)
>+{
>+}
>+
> /*
>  * DMA errors are defined by all-bits-set in the DMA address.
>  */



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

* [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-01  0:32     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:32 UTC (permalink / raw)
  To: linux-arm-kernel

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>CC: will.deacon at arm.com
>CC: linux at arm.linux.org.uk
>---
> arch/arm/Kconfig                   |    7 +++++++
> arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> 2 files changed, 31 insertions(+), 0 deletions(-)
>
>diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>index ba412e0..05125ab 100644
>--- a/arch/arm/Kconfig
>+++ b/arch/arm/Kconfig
>@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> 	  neutralized via a kernel panic.
> 	  This feature requires gcc version 4.2 or above.
> 
>+config SWIOTLB
>+	def_bool y
>+	select NEED_SG_DMA_LENGTH
>+
>+config IOMMU_HELPER
>+	def_bool SWIOTLB
>+

Could you explain the purpose of these two a bit more please? 

> config XEN_DOM0
> 	def_bool y
> 	depends on XEN
>diff --git a/arch/arm/include/asm/dma-mapping.h
>b/arch/arm/include/asm/dma-mapping.h
>index 5b579b9..ad89e0f 100644
>--- a/arch/arm/include/asm/dma-mapping.h
>+++ b/arch/arm/include/asm/dma-mapping.h
>@@ -86,6 +86,30 @@ static inline dma_addr_t virt_to_dma(struct device
>*dev, void *addr)
> }
> #endif
> 
>+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t
>paddr)
>+{
>+	unsigned int offset = paddr & ~PAGE_MASK;
>+	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
>+}
>+
>+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t
>dev_addr)
>+{
>+	unsigned int offset = dev_addr & ~PAGE_MASK;
>+	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
>+}
>+
>+static inline bool dma_capable(struct device *dev, dma_addr_t addr,
>size_t size)
>+{
>+	if (!dev->dma_mask)
>+		return 0;
>+
>+	return addr + size - 1 <= *dev->dma_mask;
>+}
>+
>+static inline void dma_mark_clean(void *addr, size_t size)
>+{
>+}
>+
> /*
>  * DMA errors are defined by all-bits-set in the DMA address.
>  */

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-01  0:32     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:32 UTC (permalink / raw)
  To: Stefano Stabellini, xen-devel
  Cc: linux, Ian.Campbell, Stefano.Stabellini, will.deacon,
	linux-kernel, linux-arm-kernel

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>CC: will.deacon@arm.com
>CC: linux@arm.linux.org.uk
>---
> arch/arm/Kconfig                   |    7 +++++++
> arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> 2 files changed, 31 insertions(+), 0 deletions(-)
>
>diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>index ba412e0..05125ab 100644
>--- a/arch/arm/Kconfig
>+++ b/arch/arm/Kconfig
>@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> 	  neutralized via a kernel panic.
> 	  This feature requires gcc version 4.2 or above.
> 
>+config SWIOTLB
>+	def_bool y
>+	select NEED_SG_DMA_LENGTH
>+
>+config IOMMU_HELPER
>+	def_bool SWIOTLB
>+

Could you explain the purpose of these two a bit more please? 

> config XEN_DOM0
> 	def_bool y
> 	depends on XEN
>diff --git a/arch/arm/include/asm/dma-mapping.h
>b/arch/arm/include/asm/dma-mapping.h
>index 5b579b9..ad89e0f 100644
>--- a/arch/arm/include/asm/dma-mapping.h
>+++ b/arch/arm/include/asm/dma-mapping.h
>@@ -86,6 +86,30 @@ static inline dma_addr_t virt_to_dma(struct device
>*dev, void *addr)
> }
> #endif
> 
>+static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t
>paddr)
>+{
>+	unsigned int offset = paddr & ~PAGE_MASK;
>+	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
>+}
>+
>+static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t
>dev_addr)
>+{
>+	unsigned int offset = dev_addr & ~PAGE_MASK;
>+	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
>+}
>+
>+static inline bool dma_capable(struct device *dev, dma_addr_t addr,
>size_t size)
>+{
>+	if (!dev->dma_mask)
>+		return 0;
>+
>+	return addr + size - 1 <= *dev->dma_mask;
>+}
>+
>+static inline void dma_mark_clean(void *addr, size_t size)
>+{
>+}
>+
> /*
>  * DMA errors are defined by all-bits-set in the DMA address.
>  */

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

* Re: [PATCH RFC 4/8] xen/arm,arm64: move Xen initialization earlier
  2013-07-31 17:45   ` Stefano Stabellini
  (?)
@ 2013-08-01  0:35     ` Konrad Rzeszutek Wilk
  -1 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:35 UTC (permalink / raw)
  To: Stefano Stabellini, xen-devel
  Cc: linux-kernel, linux-arm-kernel, Stefano.Stabellini, Ian.Campbell

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>---
> arch/arm/include/asm/xen/hypervisor.h |    6 ++++++
> arch/arm/kernel/setup.c               |    2 ++
> arch/arm/xen/enlighten.c              |   21 ++++++++++++++-------
> arch/arm64/kernel/setup.c             |    2 ++
> 4 files changed, 24 insertions(+), 7 deletions(-)
>
>diff --git a/arch/arm/include/asm/xen/hypervisor.h
>b/arch/arm/include/asm/xen/hypervisor.h
>index d7ab99a..17b3ea2 100644
>--- a/arch/arm/include/asm/xen/hypervisor.h
>+++ b/arch/arm/include/asm/xen/hypervisor.h
>@@ -16,4 +16,10 @@ static inline enum paravirt_lazy_mode
>paravirt_get_lazy_mode(void)
> 	return PARAVIRT_LAZY_NONE;
> }
> 
>+#ifdef CONFIG_XEN
>+void xen_early_init(void);

You look to be missing an __init here
>+#else
>+static inline void xen_early_init(void) { return; }
>+#endif
>+
> #endif /* _ASM_ARM_XEN_HYPERVISOR_H */
>diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
>index 63af9a7..cb7b8e2 100644
>--- a/arch/arm/kernel/setup.c
>+++ b/arch/arm/kernel/setup.c
>@@ -45,6 +45,7 @@
> #include <asm/cacheflush.h>
> #include <asm/cachetype.h>
> #include <asm/tlbflush.h>
>+#include <asm/xen/hypervisor.h>
> 
> #include <asm/prom.h>
> #include <asm/mach/arch.h>
>@@ -889,6 +890,7 @@ void __init setup_arch(char **cmdline_p)
> 
> 	arm_dt_init_cpu_maps();
> 	psci_init();
>+	xen_early_init();
> #ifdef CONFIG_SMP
> 	if (is_smp()) {
> 		if (!mdesc->smp_init || !mdesc->smp_init()) {
>diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
>index c9770ba..14d17ab 100644
>--- a/arch/arm/xen/enlighten.c
>+++ b/arch/arm/xen/enlighten.c
>@@ -195,21 +195,19 @@ static void xen_power_off(void)
>  * documentation of the Xen Device Tree format.
>  */
> #define GRANT_TABLE_PHYSADDR 0
>-static int __init xen_guest_init(void)
>+void __init xen_early_init(void)
> {
>-	struct xen_add_to_physmap xatp;
>-	static struct shared_info *shared_info_page = 0;
>+	struct resource res;
> 	struct device_node *node;
> 	int len;
> 	const char *s = NULL;
> 	const char *version = NULL;
> 	const char *xen_prefix = "xen,xen-";
>-	struct resource res;
> 
> 	node = of_find_compatible_node(NULL, NULL, "xen,xen");
> 	if (!node) {
> 		pr_debug("No Xen support\n");
>-		return 0;
>+		return;
> 	}
> 	s = of_get_property(node, "compatible", &len);
> 	if (strlen(xen_prefix) + 3  < len &&
>@@ -217,10 +215,10 @@ static int __init xen_guest_init(void)
> 		version = s + strlen(xen_prefix);
> 	if (version == NULL) {
> 		pr_debug("Xen version not found\n");
>-		return 0;
>+		return;
> 	}
> 	if (of_address_to_resource(node, GRANT_TABLE_PHYSADDR, &res))
>-		return 0;
>+		return;
> 	xen_hvm_resume_frames = res.start >> PAGE_SHIFT;
> 	xen_events_irq = irq_of_parse_and_map(node, 0);
> 	pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n",
>@@ -232,6 +230,15 @@ static int __init xen_guest_init(void)
> 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
> 	else
> 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
>+}
>+
>+static int __init xen_guest_init(void)
>+{
>+	struct xen_add_to_physmap xatp;
>+	static struct shared_info *shared_info_page = 0;
>+
>+	if (!xen_domain())
>+		return 0;
> 
> 	if (!shared_info_page)
> 		shared_info_page = (struct shared_info *)
>diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
>index add6ea6..e0d438a 100644
>--- a/arch/arm64/kernel/setup.c
>+++ b/arch/arm64/kernel/setup.c
>@@ -53,6 +53,7 @@
> #include <asm/traps.h>
> #include <asm/memblock.h>
> #include <asm/psci.h>
>+#include <asm/xen/hypervisor.h>
> 
> unsigned int processor_id;
> EXPORT_SYMBOL(processor_id);
>@@ -267,6 +268,7 @@ void __init setup_arch(char **cmdline_p)
> 	unflatten_device_tree();
> 
> 	psci_init();
>+	xen_early_init();
> 
> 	cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
> #ifdef CONFIG_SMP



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

* [PATCH RFC 4/8] xen/arm,arm64: move Xen initialization earlier
@ 2013-08-01  0:35     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:35 UTC (permalink / raw)
  To: linux-arm-kernel

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>---
> arch/arm/include/asm/xen/hypervisor.h |    6 ++++++
> arch/arm/kernel/setup.c               |    2 ++
> arch/arm/xen/enlighten.c              |   21 ++++++++++++++-------
> arch/arm64/kernel/setup.c             |    2 ++
> 4 files changed, 24 insertions(+), 7 deletions(-)
>
>diff --git a/arch/arm/include/asm/xen/hypervisor.h
>b/arch/arm/include/asm/xen/hypervisor.h
>index d7ab99a..17b3ea2 100644
>--- a/arch/arm/include/asm/xen/hypervisor.h
>+++ b/arch/arm/include/asm/xen/hypervisor.h
>@@ -16,4 +16,10 @@ static inline enum paravirt_lazy_mode
>paravirt_get_lazy_mode(void)
> 	return PARAVIRT_LAZY_NONE;
> }
> 
>+#ifdef CONFIG_XEN
>+void xen_early_init(void);

You look to be missing an __init here
>+#else
>+static inline void xen_early_init(void) { return; }
>+#endif
>+
> #endif /* _ASM_ARM_XEN_HYPERVISOR_H */
>diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
>index 63af9a7..cb7b8e2 100644
>--- a/arch/arm/kernel/setup.c
>+++ b/arch/arm/kernel/setup.c
>@@ -45,6 +45,7 @@
> #include <asm/cacheflush.h>
> #include <asm/cachetype.h>
> #include <asm/tlbflush.h>
>+#include <asm/xen/hypervisor.h>
> 
> #include <asm/prom.h>
> #include <asm/mach/arch.h>
>@@ -889,6 +890,7 @@ void __init setup_arch(char **cmdline_p)
> 
> 	arm_dt_init_cpu_maps();
> 	psci_init();
>+	xen_early_init();
> #ifdef CONFIG_SMP
> 	if (is_smp()) {
> 		if (!mdesc->smp_init || !mdesc->smp_init()) {
>diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
>index c9770ba..14d17ab 100644
>--- a/arch/arm/xen/enlighten.c
>+++ b/arch/arm/xen/enlighten.c
>@@ -195,21 +195,19 @@ static void xen_power_off(void)
>  * documentation of the Xen Device Tree format.
>  */
> #define GRANT_TABLE_PHYSADDR 0
>-static int __init xen_guest_init(void)
>+void __init xen_early_init(void)
> {
>-	struct xen_add_to_physmap xatp;
>-	static struct shared_info *shared_info_page = 0;
>+	struct resource res;
> 	struct device_node *node;
> 	int len;
> 	const char *s = NULL;
> 	const char *version = NULL;
> 	const char *xen_prefix = "xen,xen-";
>-	struct resource res;
> 
> 	node = of_find_compatible_node(NULL, NULL, "xen,xen");
> 	if (!node) {
> 		pr_debug("No Xen support\n");
>-		return 0;
>+		return;
> 	}
> 	s = of_get_property(node, "compatible", &len);
> 	if (strlen(xen_prefix) + 3  < len &&
>@@ -217,10 +215,10 @@ static int __init xen_guest_init(void)
> 		version = s + strlen(xen_prefix);
> 	if (version == NULL) {
> 		pr_debug("Xen version not found\n");
>-		return 0;
>+		return;
> 	}
> 	if (of_address_to_resource(node, GRANT_TABLE_PHYSADDR, &res))
>-		return 0;
>+		return;
> 	xen_hvm_resume_frames = res.start >> PAGE_SHIFT;
> 	xen_events_irq = irq_of_parse_and_map(node, 0);
> 	pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n",
>@@ -232,6 +230,15 @@ static int __init xen_guest_init(void)
> 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
> 	else
> 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
>+}
>+
>+static int __init xen_guest_init(void)
>+{
>+	struct xen_add_to_physmap xatp;
>+	static struct shared_info *shared_info_page = 0;
>+
>+	if (!xen_domain())
>+		return 0;
> 
> 	if (!shared_info_page)
> 		shared_info_page = (struct shared_info *)
>diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
>index add6ea6..e0d438a 100644
>--- a/arch/arm64/kernel/setup.c
>+++ b/arch/arm64/kernel/setup.c
>@@ -53,6 +53,7 @@
> #include <asm/traps.h>
> #include <asm/memblock.h>
> #include <asm/psci.h>
>+#include <asm/xen/hypervisor.h>
> 
> unsigned int processor_id;
> EXPORT_SYMBOL(processor_id);
>@@ -267,6 +268,7 @@ void __init setup_arch(char **cmdline_p)
> 	unflatten_device_tree();
> 
> 	psci_init();
>+	xen_early_init();
> 
> 	cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
> #ifdef CONFIG_SMP

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

* Re: [PATCH RFC 4/8] xen/arm,arm64: move Xen initialization earlier
@ 2013-08-01  0:35     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:35 UTC (permalink / raw)
  To: Stefano Stabellini, xen-devel
  Cc: Ian.Campbell, linux-kernel, linux-arm-kernel, Stefano.Stabellini

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>---
> arch/arm/include/asm/xen/hypervisor.h |    6 ++++++
> arch/arm/kernel/setup.c               |    2 ++
> arch/arm/xen/enlighten.c              |   21 ++++++++++++++-------
> arch/arm64/kernel/setup.c             |    2 ++
> 4 files changed, 24 insertions(+), 7 deletions(-)
>
>diff --git a/arch/arm/include/asm/xen/hypervisor.h
>b/arch/arm/include/asm/xen/hypervisor.h
>index d7ab99a..17b3ea2 100644
>--- a/arch/arm/include/asm/xen/hypervisor.h
>+++ b/arch/arm/include/asm/xen/hypervisor.h
>@@ -16,4 +16,10 @@ static inline enum paravirt_lazy_mode
>paravirt_get_lazy_mode(void)
> 	return PARAVIRT_LAZY_NONE;
> }
> 
>+#ifdef CONFIG_XEN
>+void xen_early_init(void);

You look to be missing an __init here
>+#else
>+static inline void xen_early_init(void) { return; }
>+#endif
>+
> #endif /* _ASM_ARM_XEN_HYPERVISOR_H */
>diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
>index 63af9a7..cb7b8e2 100644
>--- a/arch/arm/kernel/setup.c
>+++ b/arch/arm/kernel/setup.c
>@@ -45,6 +45,7 @@
> #include <asm/cacheflush.h>
> #include <asm/cachetype.h>
> #include <asm/tlbflush.h>
>+#include <asm/xen/hypervisor.h>
> 
> #include <asm/prom.h>
> #include <asm/mach/arch.h>
>@@ -889,6 +890,7 @@ void __init setup_arch(char **cmdline_p)
> 
> 	arm_dt_init_cpu_maps();
> 	psci_init();
>+	xen_early_init();
> #ifdef CONFIG_SMP
> 	if (is_smp()) {
> 		if (!mdesc->smp_init || !mdesc->smp_init()) {
>diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
>index c9770ba..14d17ab 100644
>--- a/arch/arm/xen/enlighten.c
>+++ b/arch/arm/xen/enlighten.c
>@@ -195,21 +195,19 @@ static void xen_power_off(void)
>  * documentation of the Xen Device Tree format.
>  */
> #define GRANT_TABLE_PHYSADDR 0
>-static int __init xen_guest_init(void)
>+void __init xen_early_init(void)
> {
>-	struct xen_add_to_physmap xatp;
>-	static struct shared_info *shared_info_page = 0;
>+	struct resource res;
> 	struct device_node *node;
> 	int len;
> 	const char *s = NULL;
> 	const char *version = NULL;
> 	const char *xen_prefix = "xen,xen-";
>-	struct resource res;
> 
> 	node = of_find_compatible_node(NULL, NULL, "xen,xen");
> 	if (!node) {
> 		pr_debug("No Xen support\n");
>-		return 0;
>+		return;
> 	}
> 	s = of_get_property(node, "compatible", &len);
> 	if (strlen(xen_prefix) + 3  < len &&
>@@ -217,10 +215,10 @@ static int __init xen_guest_init(void)
> 		version = s + strlen(xen_prefix);
> 	if (version == NULL) {
> 		pr_debug("Xen version not found\n");
>-		return 0;
>+		return;
> 	}
> 	if (of_address_to_resource(node, GRANT_TABLE_PHYSADDR, &res))
>-		return 0;
>+		return;
> 	xen_hvm_resume_frames = res.start >> PAGE_SHIFT;
> 	xen_events_irq = irq_of_parse_and_map(node, 0);
> 	pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n",
>@@ -232,6 +230,15 @@ static int __init xen_guest_init(void)
> 		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
> 	else
> 		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
>+}
>+
>+static int __init xen_guest_init(void)
>+{
>+	struct xen_add_to_physmap xatp;
>+	static struct shared_info *shared_info_page = 0;
>+
>+	if (!xen_domain())
>+		return 0;
> 
> 	if (!shared_info_page)
> 		shared_info_page = (struct shared_info *)
>diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
>index add6ea6..e0d438a 100644
>--- a/arch/arm64/kernel/setup.c
>+++ b/arch/arm64/kernel/setup.c
>@@ -53,6 +53,7 @@
> #include <asm/traps.h>
> #include <asm/memblock.h>
> #include <asm/psci.h>
>+#include <asm/xen/hypervisor.h>
> 
> unsigned int processor_id;
> EXPORT_SYMBOL(processor_id);
>@@ -267,6 +268,7 @@ void __init setup_arch(char **cmdline_p)
> 	unflatten_device_tree();
> 
> 	psci_init();
>+	xen_early_init();
> 
> 	cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
> #ifdef CONFIG_SMP

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

* Re: [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
  2013-07-31 17:45   ` Stefano Stabellini
  (?)
@ 2013-08-01  0:36     ` Konrad Rzeszutek Wilk
  -1 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:36 UTC (permalink / raw)
  To: Stefano Stabellini, xen-devel
  Cc: linux-kernel, linux-arm-kernel, Stefano.Stabellini, Ian.Campbell

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>---
>include/xen/interface/memory.h |   62
>++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 62 insertions(+), 0 deletions(-)
>
>diff --git a/include/xen/interface/memory.h
>b/include/xen/interface/memory.h
>index 2ecfe4f..ffd7f4e 100644
>--- a/include/xen/interface/memory.h
>+++ b/include/xen/interface/memory.h
>@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
> };
> DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
> 
>+#define XENMEM_get_dma_buf             26
>+/*
>+ * This hypercall is similar to XENMEM_exchange: it exchanges the
>pages

Could you elaborate why the existing hyper call won't work? 

>+ * passed in with a new set of pages, contiguous and under 4G if so
>+ * requested. The new pages are going to be "pinned": it's guaranteed
>+ * that their p2m mapping won't be changed until explicitly
>"unpinned".
>+ * If return code is zero then @out.extent_list provides the MFNs of
>the
>+ * newly-allocated memory.  Returns zero on complete success,
>otherwise
>+ * a negative error code.
>+ * On complete success then always @nr_exchanged == @in.nr_extents. 
>On
>+ * partial success @nr_exchanged indicates how much work was done.
>+ */
>+struct xen_get_dma_buf {
>+    /*
>+     * [IN] Details of memory extents to be exchanged (GMFN bases).
>+     * Note that @in.address_bits is ignored and unused.
>+     */
>+    struct xen_memory_reservation in;
>+
>+    /*
>+     * [IN/OUT] Details of new memory extents.
>+     * We require that:
>+     *  1. @in.domid == @out.domid
>+     *  2. @in.nr_extents  << @in.extent_order == 
>+     *     @out.nr_extents << @out.extent_order
>+     *  3. @in.extent_start and @out.extent_start lists must not
>overlap
>+     *  4. @out.extent_start lists GPFN bases to be populated
>+     *  5. @out.extent_start is overwritten with allocated GMFN bases
>+     */
>+    struct xen_memory_reservation out;
>+
>+    /*
>+     * [OUT] Number of input extents that were successfully exchanged:
>+     *  1. The first @nr_exchanged input extents were successfully
>+     *     deallocated.
>+     *  2. The corresponding first entries in the output extent list
>correctly
>+     *     indicate the GMFNs that were successfully exchanged.
>+     *  3. All other input and output extents are untouched.
>+     *  4. If not all input exents are exchanged then the return code
>of this
>+     *     command will be non-zero.
>+     *  5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
>+     */
>+    xen_ulong_t nr_exchanged;
>+};
>+DEFINE_GUEST_HANDLE_STRUCT(xen_get_dma_buf);
>+
>+#define XENMEM_put_dma_buf             27
>+/*
>+ * XENMEM_put_dma_buf unpins a set of pages, previously pinned by
>+ * XENMEM_get_dma_buf. After this call the p2m mapping of the pages
>can
>+ * be transparently changed by the hypervisor, as usual. The pages are
>+ * still accessible from the guest.
>+ */
>+struct xen_put_dma_buf {
>+    /*
>+     * [IN] Details of memory extents to be exchanged (GMFN bases).
>+     * Note that @in.address_bits is ignored and unused.
>+     */
>+    struct xen_memory_reservation in;
>+};
>+DEFINE_GUEST_HANDLE_STRUCT(xen_put_dma_buf);
>+
> #endif /* __XEN_PUBLIC_MEMORY_H__ */



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

* [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
@ 2013-08-01  0:36     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:36 UTC (permalink / raw)
  To: linux-arm-kernel

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>---
>include/xen/interface/memory.h |   62
>++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 62 insertions(+), 0 deletions(-)
>
>diff --git a/include/xen/interface/memory.h
>b/include/xen/interface/memory.h
>index 2ecfe4f..ffd7f4e 100644
>--- a/include/xen/interface/memory.h
>+++ b/include/xen/interface/memory.h
>@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
> };
> DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
> 
>+#define XENMEM_get_dma_buf             26
>+/*
>+ * This hypercall is similar to XENMEM_exchange: it exchanges the
>pages

Could you elaborate why the existing hyper call won't work? 

>+ * passed in with a new set of pages, contiguous and under 4G if so
>+ * requested. The new pages are going to be "pinned": it's guaranteed
>+ * that their p2m mapping won't be changed until explicitly
>"unpinned".
>+ * If return code is zero then @out.extent_list provides the MFNs of
>the
>+ * newly-allocated memory.  Returns zero on complete success,
>otherwise
>+ * a negative error code.
>+ * On complete success then always @nr_exchanged == @in.nr_extents. 
>On
>+ * partial success @nr_exchanged indicates how much work was done.
>+ */
>+struct xen_get_dma_buf {
>+    /*
>+     * [IN] Details of memory extents to be exchanged (GMFN bases).
>+     * Note that @in.address_bits is ignored and unused.
>+     */
>+    struct xen_memory_reservation in;
>+
>+    /*
>+     * [IN/OUT] Details of new memory extents.
>+     * We require that:
>+     *  1. @in.domid == @out.domid
>+     *  2. @in.nr_extents  << @in.extent_order == 
>+     *     @out.nr_extents << @out.extent_order
>+     *  3. @in.extent_start and @out.extent_start lists must not
>overlap
>+     *  4. @out.extent_start lists GPFN bases to be populated
>+     *  5. @out.extent_start is overwritten with allocated GMFN bases
>+     */
>+    struct xen_memory_reservation out;
>+
>+    /*
>+     * [OUT] Number of input extents that were successfully exchanged:
>+     *  1. The first @nr_exchanged input extents were successfully
>+     *     deallocated.
>+     *  2. The corresponding first entries in the output extent list
>correctly
>+     *     indicate the GMFNs that were successfully exchanged.
>+     *  3. All other input and output extents are untouched.
>+     *  4. If not all input exents are exchanged then the return code
>of this
>+     *     command will be non-zero.
>+     *  5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
>+     */
>+    xen_ulong_t nr_exchanged;
>+};
>+DEFINE_GUEST_HANDLE_STRUCT(xen_get_dma_buf);
>+
>+#define XENMEM_put_dma_buf             27
>+/*
>+ * XENMEM_put_dma_buf unpins a set of pages, previously pinned by
>+ * XENMEM_get_dma_buf. After this call the p2m mapping of the pages
>can
>+ * be transparently changed by the hypervisor, as usual. The pages are
>+ * still accessible from the guest.
>+ */
>+struct xen_put_dma_buf {
>+    /*
>+     * [IN] Details of memory extents to be exchanged (GMFN bases).
>+     * Note that @in.address_bits is ignored and unused.
>+     */
>+    struct xen_memory_reservation in;
>+};
>+DEFINE_GUEST_HANDLE_STRUCT(xen_put_dma_buf);
>+
> #endif /* __XEN_PUBLIC_MEMORY_H__ */

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

* Re: [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
@ 2013-08-01  0:36     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-01  0:36 UTC (permalink / raw)
  To: Stefano Stabellini, xen-devel
  Cc: Ian.Campbell, linux-kernel, linux-arm-kernel, Stefano.Stabellini

Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
>Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>---
>include/xen/interface/memory.h |   62
>++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 62 insertions(+), 0 deletions(-)
>
>diff --git a/include/xen/interface/memory.h
>b/include/xen/interface/memory.h
>index 2ecfe4f..ffd7f4e 100644
>--- a/include/xen/interface/memory.h
>+++ b/include/xen/interface/memory.h
>@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
> };
> DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
> 
>+#define XENMEM_get_dma_buf             26
>+/*
>+ * This hypercall is similar to XENMEM_exchange: it exchanges the
>pages

Could you elaborate why the existing hyper call won't work? 

>+ * passed in with a new set of pages, contiguous and under 4G if so
>+ * requested. The new pages are going to be "pinned": it's guaranteed
>+ * that their p2m mapping won't be changed until explicitly
>"unpinned".
>+ * If return code is zero then @out.extent_list provides the MFNs of
>the
>+ * newly-allocated memory.  Returns zero on complete success,
>otherwise
>+ * a negative error code.
>+ * On complete success then always @nr_exchanged == @in.nr_extents. 
>On
>+ * partial success @nr_exchanged indicates how much work was done.
>+ */
>+struct xen_get_dma_buf {
>+    /*
>+     * [IN] Details of memory extents to be exchanged (GMFN bases).
>+     * Note that @in.address_bits is ignored and unused.
>+     */
>+    struct xen_memory_reservation in;
>+
>+    /*
>+     * [IN/OUT] Details of new memory extents.
>+     * We require that:
>+     *  1. @in.domid == @out.domid
>+     *  2. @in.nr_extents  << @in.extent_order == 
>+     *     @out.nr_extents << @out.extent_order
>+     *  3. @in.extent_start and @out.extent_start lists must not
>overlap
>+     *  4. @out.extent_start lists GPFN bases to be populated
>+     *  5. @out.extent_start is overwritten with allocated GMFN bases
>+     */
>+    struct xen_memory_reservation out;
>+
>+    /*
>+     * [OUT] Number of input extents that were successfully exchanged:
>+     *  1. The first @nr_exchanged input extents were successfully
>+     *     deallocated.
>+     *  2. The corresponding first entries in the output extent list
>correctly
>+     *     indicate the GMFNs that were successfully exchanged.
>+     *  3. All other input and output extents are untouched.
>+     *  4. If not all input exents are exchanged then the return code
>of this
>+     *     command will be non-zero.
>+     *  5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
>+     */
>+    xen_ulong_t nr_exchanged;
>+};
>+DEFINE_GUEST_HANDLE_STRUCT(xen_get_dma_buf);
>+
>+#define XENMEM_put_dma_buf             27
>+/*
>+ * XENMEM_put_dma_buf unpins a set of pages, previously pinned by
>+ * XENMEM_get_dma_buf. After this call the p2m mapping of the pages
>can
>+ * be transparently changed by the hypervisor, as usual. The pages are
>+ * still accessible from the guest.
>+ */
>+struct xen_put_dma_buf {
>+    /*
>+     * [IN] Details of memory extents to be exchanged (GMFN bases).
>+     * Note that @in.address_bits is ignored and unused.
>+     */
>+    struct xen_memory_reservation in;
>+};
>+DEFINE_GUEST_HANDLE_STRUCT(xen_put_dma_buf);
>+
> #endif /* __XEN_PUBLIC_MEMORY_H__ */

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
  2013-07-31 17:45   ` Stefano Stabellini
@ 2013-08-01 11:09     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 73+ messages in thread
From: Russell King - ARM Linux @ 2013-08-01 11:09 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, konrad.wilk,
	Ian.Campbell, will.deacon

On Wed, Jul 31, 2013 at 06:45:25PM +0100, Stefano Stabellini wrote:
> +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
> +{
> +	unsigned int offset = paddr & ~PAGE_MASK;
> +	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
> +}
> +
> +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
> +{
> +	unsigned int offset = dev_addr & ~PAGE_MASK;
> +	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
> +}

These two helpers look fine on the face of it.

> +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
> +{
> +	if (!dev->dma_mask)
> +		return 0;
> +
> +	return addr + size - 1 <= *dev->dma_mask;
> +}

You may wish to have a closer look at the DMA bounce code, because this
assumes that DMA masks are a set of zeros followed by a set of ones.
That may not always be the case (and we have the odd platform where that
isn't the case.)

It has always bugged me that we call this thing a dma _mask_ and then
much kernel code treats it as a limit - it should've been called "dma
limit" if that's how it was to be interpreted.  If it really is a _mask_
then the right way to test whether a DMA address/size is possible is:

	u64 limit, mask = *dev->dma_mask;

	limit = (mask + 1) & ~mask;
	if (limit && size > limit)
		return 0;

	if ((addr | (addr + size - 1)) & ~mask)
		return 0;

	return 1;

The first checks whether 'size' fits within the least significant
contiguous set of '1' bits in the DMA mask, and the second checks
whether the region itself contains any address bits which may not
meet the DMA mask.

I guess if we aren't going to encounter any of these cases anymore,
your test is entirely sufficient.

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

* [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-01 11:09     ` Russell King - ARM Linux
  0 siblings, 0 replies; 73+ messages in thread
From: Russell King - ARM Linux @ 2013-08-01 11:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 31, 2013 at 06:45:25PM +0100, Stefano Stabellini wrote:
> +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
> +{
> +	unsigned int offset = paddr & ~PAGE_MASK;
> +	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
> +}
> +
> +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
> +{
> +	unsigned int offset = dev_addr & ~PAGE_MASK;
> +	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
> +}

These two helpers look fine on the face of it.

> +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
> +{
> +	if (!dev->dma_mask)
> +		return 0;
> +
> +	return addr + size - 1 <= *dev->dma_mask;
> +}

You may wish to have a closer look at the DMA bounce code, because this
assumes that DMA masks are a set of zeros followed by a set of ones.
That may not always be the case (and we have the odd platform where that
isn't the case.)

It has always bugged me that we call this thing a dma _mask_ and then
much kernel code treats it as a limit - it should've been called "dma
limit" if that's how it was to be interpreted.  If it really is a _mask_
then the right way to test whether a DMA address/size is possible is:

	u64 limit, mask = *dev->dma_mask;

	limit = (mask + 1) & ~mask;
	if (limit && size > limit)
		return 0;

	if ((addr | (addr + size - 1)) & ~mask)
		return 0;

	return 1;

The first checks whether 'size' fits within the least significant
contiguous set of '1' bits in the DMA mask, and the second checks
whether the region itself contains any address bits which may not
meet the DMA mask.

I guess if we aren't going to encounter any of these cases anymore,
your test is entirely sufficient.

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

* Re: [PATCH RFC 6/8] xen: make xen_create_contiguous_region return the dma address
  2013-07-31 17:45   ` Stefano Stabellini
  (?)
@ 2013-08-01 11:34     ` David Vrabel
  -1 siblings, 0 replies; 73+ messages in thread
From: David Vrabel @ 2013-08-01 11:34 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, konrad.wilk, Ian.Campbell

On 31/07/13 18:45, Stefano Stabellini wrote:
> Modify xen_create_contiguous_region to return the dma address of the
> newly contiguous buffer.

Seems sensible.

Reviewed-by: David Vrabel <david.vrabel@citrix.com>

David

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

* [PATCH RFC 6/8] xen: make xen_create_contiguous_region return the dma address
@ 2013-08-01 11:34     ` David Vrabel
  0 siblings, 0 replies; 73+ messages in thread
From: David Vrabel @ 2013-08-01 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

On 31/07/13 18:45, Stefano Stabellini wrote:
> Modify xen_create_contiguous_region to return the dma address of the
> newly contiguous buffer.

Seems sensible.

Reviewed-by: David Vrabel <david.vrabel@citrix.com>

David

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

* Re: [PATCH RFC 6/8] xen: make xen_create_contiguous_region return the dma address
@ 2013-08-01 11:34     ` David Vrabel
  0 siblings, 0 replies; 73+ messages in thread
From: David Vrabel @ 2013-08-01 11:34 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, konrad.wilk, Ian.Campbell

On 31/07/13 18:45, Stefano Stabellini wrote:
> Modify xen_create_contiguous_region to return the dma address of the
> newly contiguous buffer.

Seems sensible.

Reviewed-by: David Vrabel <david.vrabel@citrix.com>

David

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

* Re: [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
  2013-08-01  0:36     ` Konrad Rzeszutek Wilk
  (?)
@ 2013-08-01 15:13       ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-01 15:13 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	Ian.Campbell

On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> >---
> >include/xen/interface/memory.h |   62
> >++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 62 insertions(+), 0 deletions(-)
> >
> >diff --git a/include/xen/interface/memory.h
> >b/include/xen/interface/memory.h
> >index 2ecfe4f..ffd7f4e 100644
> >--- a/include/xen/interface/memory.h
> >+++ b/include/xen/interface/memory.h
> >@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
> > };
> > DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
> > 
> >+#define XENMEM_get_dma_buf             26
> >+/*
> >+ * This hypercall is similar to XENMEM_exchange: it exchanges the
> >pages
> 
> Could you elaborate why the existing hyper call won't work? 

Two reasons:

- the existing XENMEM_exchange hypercall does not copy back the mfns
into the out field for autotranslate guests;

- the existing XENMEM_exchange hypercall does not guarantee that the
hypervisor won't change the p2m mappings for the exchanged pages while
the guest is using them. Keep in mind that Xen never promises to keep
the p2m mapping stable for autotranslate guests in general.
In practice it won't happen unless you use uncommon features like memory
sharing or paging.

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

* [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
@ 2013-08-01 15:13       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-01 15:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> >---
> >include/xen/interface/memory.h |   62
> >++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 62 insertions(+), 0 deletions(-)
> >
> >diff --git a/include/xen/interface/memory.h
> >b/include/xen/interface/memory.h
> >index 2ecfe4f..ffd7f4e 100644
> >--- a/include/xen/interface/memory.h
> >+++ b/include/xen/interface/memory.h
> >@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
> > };
> > DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
> > 
> >+#define XENMEM_get_dma_buf             26
> >+/*
> >+ * This hypercall is similar to XENMEM_exchange: it exchanges the
> >pages
> 
> Could you elaborate why the existing hyper call won't work? 

Two reasons:

- the existing XENMEM_exchange hypercall does not copy back the mfns
into the out field for autotranslate guests;

- the existing XENMEM_exchange hypercall does not guarantee that the
hypervisor won't change the p2m mappings for the exchanged pages while
the guest is using them. Keep in mind that Xen never promises to keep
the p2m mapping stable for autotranslate guests in general.
In practice it won't happen unless you use uncommon features like memory
sharing or paging.

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

* Re: [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf
@ 2013-08-01 15:13       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-01 15:13 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	Ian.Campbell

On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> >---
> >include/xen/interface/memory.h |   62
> >++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 62 insertions(+), 0 deletions(-)
> >
> >diff --git a/include/xen/interface/memory.h
> >b/include/xen/interface/memory.h
> >index 2ecfe4f..ffd7f4e 100644
> >--- a/include/xen/interface/memory.h
> >+++ b/include/xen/interface/memory.h
> >@@ -263,4 +263,66 @@ struct xen_remove_from_physmap {
> > };
> > DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
> > 
> >+#define XENMEM_get_dma_buf             26
> >+/*
> >+ * This hypercall is similar to XENMEM_exchange: it exchanges the
> >pages
> 
> Could you elaborate why the existing hyper call won't work? 

Two reasons:

- the existing XENMEM_exchange hypercall does not copy back the mfns
into the out field for autotranslate guests;

- the existing XENMEM_exchange hypercall does not guarantee that the
hypervisor won't change the p2m mappings for the exchanged pages while
the guest is using them. Keep in mind that Xen never promises to keep
the p2m mapping stable for autotranslate guests in general.
In practice it won't happen unless you use uncommon features like memory
sharing or paging.

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
  2013-08-01  0:32     ` Konrad Rzeszutek Wilk
  (?)
@ 2013-08-02 11:59       ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 11:59 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	Ian.Campbell, will.deacon, linux

On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> >CC: will.deacon@arm.com
> >CC: linux@arm.linux.org.uk
> >---
> > arch/arm/Kconfig                   |    7 +++++++
> > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > 2 files changed, 31 insertions(+), 0 deletions(-)
> >
> >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> >index ba412e0..05125ab 100644
> >--- a/arch/arm/Kconfig
> >+++ b/arch/arm/Kconfig
> >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > 	  neutralized via a kernel panic.
> > 	  This feature requires gcc version 4.2 or above.
> > 
> >+config SWIOTLB
> >+	def_bool y
> >+	select NEED_SG_DMA_LENGTH
> >+
> >+config IOMMU_HELPER
> >+	def_bool SWIOTLB
> >+
> 
> Could you explain the purpose of these two a bit more please? 

SWIOTLB is not available on arm at the moment.
We need to make it available, otherwise SWIOTLB_XEN won't be able to
select it.

Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
to compile.

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

* [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-02 11:59       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> >CC: will.deacon at arm.com
> >CC: linux at arm.linux.org.uk
> >---
> > arch/arm/Kconfig                   |    7 +++++++
> > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > 2 files changed, 31 insertions(+), 0 deletions(-)
> >
> >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> >index ba412e0..05125ab 100644
> >--- a/arch/arm/Kconfig
> >+++ b/arch/arm/Kconfig
> >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > 	  neutralized via a kernel panic.
> > 	  This feature requires gcc version 4.2 or above.
> > 
> >+config SWIOTLB
> >+	def_bool y
> >+	select NEED_SG_DMA_LENGTH
> >+
> >+config IOMMU_HELPER
> >+	def_bool SWIOTLB
> >+
> 
> Could you explain the purpose of these two a bit more please? 

SWIOTLB is not available on arm at the moment.
We need to make it available, otherwise SWIOTLB_XEN won't be able to
select it.

Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
to compile.

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-02 11:59       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 11:59 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: xen-devel, linux, Ian.Campbell, Stefano Stabellini, will.deacon,
	linux-kernel, linux-arm-kernel

On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> >CC: will.deacon@arm.com
> >CC: linux@arm.linux.org.uk
> >---
> > arch/arm/Kconfig                   |    7 +++++++
> > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > 2 files changed, 31 insertions(+), 0 deletions(-)
> >
> >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> >index ba412e0..05125ab 100644
> >--- a/arch/arm/Kconfig
> >+++ b/arch/arm/Kconfig
> >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > 	  neutralized via a kernel panic.
> > 	  This feature requires gcc version 4.2 or above.
> > 
> >+config SWIOTLB
> >+	def_bool y
> >+	select NEED_SG_DMA_LENGTH
> >+
> >+config IOMMU_HELPER
> >+	def_bool SWIOTLB
> >+
> 
> Could you explain the purpose of these two a bit more please? 

SWIOTLB is not available on arm at the moment.
We need to make it available, otherwise SWIOTLB_XEN won't be able to
select it.

Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
to compile.

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
  2013-08-01 11:09     ` Russell King - ARM Linux
  (?)
@ 2013-08-02 12:09       ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 12:09 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	konrad.wilk, Ian.Campbell, will.deacon

On Thu, 1 Aug 2013, Russell King - ARM Linux wrote:
> On Wed, Jul 31, 2013 at 06:45:25PM +0100, Stefano Stabellini wrote:
> > +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
> > +{
> > +	unsigned int offset = paddr & ~PAGE_MASK;
> > +	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
> > +}
> > +
> > +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
> > +{
> > +	unsigned int offset = dev_addr & ~PAGE_MASK;
> > +	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
> > +}
> 
> These two helpers look fine on the face of it.
> 
> > +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
> > +{
> > +	if (!dev->dma_mask)
> > +		return 0;
> > +
> > +	return addr + size - 1 <= *dev->dma_mask;
> > +}
> 
> You may wish to have a closer look at the DMA bounce code, because this
> assumes that DMA masks are a set of zeros followed by a set of ones.
> That may not always be the case (and we have the odd platform where that
> isn't the case.)
> 
> It has always bugged me that we call this thing a dma _mask_ and then
> much kernel code treats it as a limit - it should've been called "dma
> limit" if that's how it was to be interpreted.  If it really is a _mask_
> then the right way to test whether a DMA address/size is possible is:
> 
> 	u64 limit, mask = *dev->dma_mask;
> 
> 	limit = (mask + 1) & ~mask;
> 	if (limit && size > limit)
> 		return 0;
> 
> 	if ((addr | (addr + size - 1)) & ~mask)
> 		return 0;
> 
> 	return 1;
> 
> The first checks whether 'size' fits within the least significant
> contiguous set of '1' bits in the DMA mask, and the second checks
> whether the region itself contains any address bits which may not
> meet the DMA mask.
 
I'll make the change, thanks for the explanation.


> I guess if we aren't going to encounter any of these cases anymore,
> your test is entirely sufficient.

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

* [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-02 12:09       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 12:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 1 Aug 2013, Russell King - ARM Linux wrote:
> On Wed, Jul 31, 2013 at 06:45:25PM +0100, Stefano Stabellini wrote:
> > +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
> > +{
> > +	unsigned int offset = paddr & ~PAGE_MASK;
> > +	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
> > +}
> > +
> > +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
> > +{
> > +	unsigned int offset = dev_addr & ~PAGE_MASK;
> > +	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
> > +}
> 
> These two helpers look fine on the face of it.
> 
> > +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
> > +{
> > +	if (!dev->dma_mask)
> > +		return 0;
> > +
> > +	return addr + size - 1 <= *dev->dma_mask;
> > +}
> 
> You may wish to have a closer look at the DMA bounce code, because this
> assumes that DMA masks are a set of zeros followed by a set of ones.
> That may not always be the case (and we have the odd platform where that
> isn't the case.)
> 
> It has always bugged me that we call this thing a dma _mask_ and then
> much kernel code treats it as a limit - it should've been called "dma
> limit" if that's how it was to be interpreted.  If it really is a _mask_
> then the right way to test whether a DMA address/size is possible is:
> 
> 	u64 limit, mask = *dev->dma_mask;
> 
> 	limit = (mask + 1) & ~mask;
> 	if (limit && size > limit)
> 		return 0;
> 
> 	if ((addr | (addr + size - 1)) & ~mask)
> 		return 0;
> 
> 	return 1;
> 
> The first checks whether 'size' fits within the least significant
> contiguous set of '1' bits in the DMA mask, and the second checks
> whether the region itself contains any address bits which may not
> meet the DMA mask.
 
I'll make the change, thanks for the explanation.


> I guess if we aren't going to encounter any of these cases anymore,
> your test is entirely sufficient.

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-02 12:09       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 12:09 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	konrad.wilk, Ian.Campbell, will.deacon

On Thu, 1 Aug 2013, Russell King - ARM Linux wrote:
> On Wed, Jul 31, 2013 at 06:45:25PM +0100, Stefano Stabellini wrote:
> > +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
> > +{
> > +	unsigned int offset = paddr & ~PAGE_MASK;
> > +	return pfn_to_dma(dev, paddr >> PAGE_SHIFT) + offset;
> > +}
> > +
> > +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
> > +{
> > +	unsigned int offset = dev_addr & ~PAGE_MASK;
> > +	return (dma_to_pfn(dev, dev_addr) << PAGE_SHIFT) + offset;
> > +}
> 
> These two helpers look fine on the face of it.
> 
> > +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
> > +{
> > +	if (!dev->dma_mask)
> > +		return 0;
> > +
> > +	return addr + size - 1 <= *dev->dma_mask;
> > +}
> 
> You may wish to have a closer look at the DMA bounce code, because this
> assumes that DMA masks are a set of zeros followed by a set of ones.
> That may not always be the case (and we have the odd platform where that
> isn't the case.)
> 
> It has always bugged me that we call this thing a dma _mask_ and then
> much kernel code treats it as a limit - it should've been called "dma
> limit" if that's how it was to be interpreted.  If it really is a _mask_
> then the right way to test whether a DMA address/size is possible is:
> 
> 	u64 limit, mask = *dev->dma_mask;
> 
> 	limit = (mask + 1) & ~mask;
> 	if (limit && size > limit)
> 		return 0;
> 
> 	if ((addr | (addr + size - 1)) & ~mask)
> 		return 0;
> 
> 	return 1;
> 
> The first checks whether 'size' fits within the least significant
> contiguous set of '1' bits in the DMA mask, and the second checks
> whether the region itself contains any address bits which may not
> meet the DMA mask.
 
I'll make the change, thanks for the explanation.


> I guess if we aren't going to encounter any of these cases anymore,
> your test is entirely sufficient.

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
  2013-08-02 11:59       ` Stefano Stabellini
  (?)
@ 2013-08-02 12:13         ` Konrad Rzeszutek Wilk
  -1 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-02 12:13 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, Ian.Campbell,
	will.deacon, linux

On Fri, Aug 02, 2013 at 12:59:00PM +0100, Stefano Stabellini wrote:
> On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> > Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> > >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > >CC: will.deacon@arm.com
> > >CC: linux@arm.linux.org.uk
> > >---
> > > arch/arm/Kconfig                   |    7 +++++++
> > > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > > 2 files changed, 31 insertions(+), 0 deletions(-)
> > >
> > >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > >index ba412e0..05125ab 100644
> > >--- a/arch/arm/Kconfig
> > >+++ b/arch/arm/Kconfig
> > >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > > 	  neutralized via a kernel panic.
> > > 	  This feature requires gcc version 4.2 or above.
> > > 
> > >+config SWIOTLB
> > >+	def_bool y
> > >+	select NEED_SG_DMA_LENGTH
> > >+
> > >+config IOMMU_HELPER
> > >+	def_bool SWIOTLB
> > >+
> > 
> > Could you explain the purpose of these two a bit more please? 
> 
> SWIOTLB is not available on arm at the moment.
> We need to make it available, otherwise SWIOTLB_XEN won't be able to
> select it.
> 
> Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
> to compile.

I was more curious about the NEED_SG_DMA_LENGTH and IOMMU_HELPER.
I think the NEED_SG_DMA_LENGTH is optional? Or does SWIOTLB complain
about? I do recall seeing a patch for this at some point but it was
malformed. It was just changing SWIOTLB to use a macro for
sg->dma_length or such.

But the IOMMU_HELPER? That seems odds as the DMA API (which as you know
is what SWIOTLB hooks up to) is _below_ the IOMMU API.  Ah, it is 
'iommu_is_span_boundary' function.  Gotcha.

Could you mention that in the git commit please? Just say that SWIOTLB
uses some of the common code that IOMMU API uses - which is in the
lib/iommu_helper.c hence the need for that.

And for the NEED_SG_DMA_LENGTH let me dig up the patch at some point and
send it your way so you can make it part of this series.



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

* [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-02 12:13         ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-02 12:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Aug 02, 2013 at 12:59:00PM +0100, Stefano Stabellini wrote:
> On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> > Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> > >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > >CC: will.deacon at arm.com
> > >CC: linux at arm.linux.org.uk
> > >---
> > > arch/arm/Kconfig                   |    7 +++++++
> > > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > > 2 files changed, 31 insertions(+), 0 deletions(-)
> > >
> > >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > >index ba412e0..05125ab 100644
> > >--- a/arch/arm/Kconfig
> > >+++ b/arch/arm/Kconfig
> > >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > > 	  neutralized via a kernel panic.
> > > 	  This feature requires gcc version 4.2 or above.
> > > 
> > >+config SWIOTLB
> > >+	def_bool y
> > >+	select NEED_SG_DMA_LENGTH
> > >+
> > >+config IOMMU_HELPER
> > >+	def_bool SWIOTLB
> > >+
> > 
> > Could you explain the purpose of these two a bit more please? 
> 
> SWIOTLB is not available on arm at the moment.
> We need to make it available, otherwise SWIOTLB_XEN won't be able to
> select it.
> 
> Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
> to compile.

I was more curious about the NEED_SG_DMA_LENGTH and IOMMU_HELPER.
I think the NEED_SG_DMA_LENGTH is optional? Or does SWIOTLB complain
about? I do recall seeing a patch for this at some point but it was
malformed. It was just changing SWIOTLB to use a macro for
sg->dma_length or such.

But the IOMMU_HELPER? That seems odds as the DMA API (which as you know
is what SWIOTLB hooks up to) is _below_ the IOMMU API.  Ah, it is 
'iommu_is_span_boundary' function.  Gotcha.

Could you mention that in the git commit please? Just say that SWIOTLB
uses some of the common code that IOMMU API uses - which is in the
lib/iommu_helper.c hence the need for that.

And for the NEED_SG_DMA_LENGTH let me dig up the patch at some point and
send it your way so you can make it part of this series.

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-02 12:13         ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-02 12:13 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux, Ian.Campbell, will.deacon, linux-kernel,
	linux-arm-kernel

On Fri, Aug 02, 2013 at 12:59:00PM +0100, Stefano Stabellini wrote:
> On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> > Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> > >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > >CC: will.deacon@arm.com
> > >CC: linux@arm.linux.org.uk
> > >---
> > > arch/arm/Kconfig                   |    7 +++++++
> > > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > > 2 files changed, 31 insertions(+), 0 deletions(-)
> > >
> > >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > >index ba412e0..05125ab 100644
> > >--- a/arch/arm/Kconfig
> > >+++ b/arch/arm/Kconfig
> > >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > > 	  neutralized via a kernel panic.
> > > 	  This feature requires gcc version 4.2 or above.
> > > 
> > >+config SWIOTLB
> > >+	def_bool y
> > >+	select NEED_SG_DMA_LENGTH
> > >+
> > >+config IOMMU_HELPER
> > >+	def_bool SWIOTLB
> > >+
> > 
> > Could you explain the purpose of these two a bit more please? 
> 
> SWIOTLB is not available on arm at the moment.
> We need to make it available, otherwise SWIOTLB_XEN won't be able to
> select it.
> 
> Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
> to compile.

I was more curious about the NEED_SG_DMA_LENGTH and IOMMU_HELPER.
I think the NEED_SG_DMA_LENGTH is optional? Or does SWIOTLB complain
about? I do recall seeing a patch for this at some point but it was
malformed. It was just changing SWIOTLB to use a macro for
sg->dma_length or such.

But the IOMMU_HELPER? That seems odds as the DMA API (which as you know
is what SWIOTLB hooks up to) is _below_ the IOMMU API.  Ah, it is 
'iommu_is_span_boundary' function.  Gotcha.

Could you mention that in the git commit please? Just say that SWIOTLB
uses some of the common code that IOMMU API uses - which is in the
lib/iommu_helper.c hence the need for that.

And for the NEED_SG_DMA_LENGTH let me dig up the patch at some point and
send it your way so you can make it part of this series.

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
  2013-08-02 12:13         ` Konrad Rzeszutek Wilk
  (?)
@ 2013-08-02 12:18           ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 12:18 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	Ian.Campbell, will.deacon, linux

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Fri, Aug 02, 2013 at 12:59:00PM +0100, Stefano Stabellini wrote:
> > On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> > > Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> > > >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > > >CC: will.deacon@arm.com
> > > >CC: linux@arm.linux.org.uk
> > > >---
> > > > arch/arm/Kconfig                   |    7 +++++++
> > > > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > > > 2 files changed, 31 insertions(+), 0 deletions(-)
> > > >
> > > >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > > >index ba412e0..05125ab 100644
> > > >--- a/arch/arm/Kconfig
> > > >+++ b/arch/arm/Kconfig
> > > >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > > > 	  neutralized via a kernel panic.
> > > > 	  This feature requires gcc version 4.2 or above.
> > > > 
> > > >+config SWIOTLB
> > > >+	def_bool y
> > > >+	select NEED_SG_DMA_LENGTH
> > > >+
> > > >+config IOMMU_HELPER
> > > >+	def_bool SWIOTLB
> > > >+
> > > 
> > > Could you explain the purpose of these two a bit more please? 
> > 
> > SWIOTLB is not available on arm at the moment.
> > We need to make it available, otherwise SWIOTLB_XEN won't be able to
> > select it.
> > 
> > Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
> > to compile.
> 
> I was more curious about the NEED_SG_DMA_LENGTH and IOMMU_HELPER.
> I think the NEED_SG_DMA_LENGTH is optional? Or does SWIOTLB complain
> about?

Yes, it does:

lib/swiotlb.c: In function 'swiotlb_map_sg_attrs':
lib/swiotlb.c:873:11: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c:879:5: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c: In function 'swiotlb_unmap_sg_attrs':
lib/swiotlb.c:907:42: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c: In function 'swiotlb_sync_sg':
lib/swiotlb.c:937:11: error: 'struct scatterlist' has no member named 'dma_length'


> I do recall seeing a patch for this at some point but it was
> malformed. It was just changing SWIOTLB to use a macro for
> sg->dma_length or such.
> 
> But the IOMMU_HELPER? That seems odds as the DMA API (which as you know
> is what SWIOTLB hooks up to) is _below_ the IOMMU API.  Ah, it is 
> 'iommu_is_span_boundary' function.  Gotcha.

Yep, that's the one.


> Could you mention that in the git commit please? Just say that SWIOTLB
> uses some of the common code that IOMMU API uses - which is in the
> lib/iommu_helper.c hence the need for that.
> 
> And for the NEED_SG_DMA_LENGTH let me dig up the patch at some point and
> send it your way so you can make it part of this series.

OK

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

* [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-02 12:18           ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 12:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Fri, Aug 02, 2013 at 12:59:00PM +0100, Stefano Stabellini wrote:
> > On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> > > Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> > > >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > > >CC: will.deacon at arm.com
> > > >CC: linux at arm.linux.org.uk
> > > >---
> > > > arch/arm/Kconfig                   |    7 +++++++
> > > > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > > > 2 files changed, 31 insertions(+), 0 deletions(-)
> > > >
> > > >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > > >index ba412e0..05125ab 100644
> > > >--- a/arch/arm/Kconfig
> > > >+++ b/arch/arm/Kconfig
> > > >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > > > 	  neutralized via a kernel panic.
> > > > 	  This feature requires gcc version 4.2 or above.
> > > > 
> > > >+config SWIOTLB
> > > >+	def_bool y
> > > >+	select NEED_SG_DMA_LENGTH
> > > >+
> > > >+config IOMMU_HELPER
> > > >+	def_bool SWIOTLB
> > > >+
> > > 
> > > Could you explain the purpose of these two a bit more please? 
> > 
> > SWIOTLB is not available on arm at the moment.
> > We need to make it available, otherwise SWIOTLB_XEN won't be able to
> > select it.
> > 
> > Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
> > to compile.
> 
> I was more curious about the NEED_SG_DMA_LENGTH and IOMMU_HELPER.
> I think the NEED_SG_DMA_LENGTH is optional? Or does SWIOTLB complain
> about?

Yes, it does:

lib/swiotlb.c: In function 'swiotlb_map_sg_attrs':
lib/swiotlb.c:873:11: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c:879:5: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c: In function 'swiotlb_unmap_sg_attrs':
lib/swiotlb.c:907:42: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c: In function 'swiotlb_sync_sg':
lib/swiotlb.c:937:11: error: 'struct scatterlist' has no member named 'dma_length'


> I do recall seeing a patch for this at some point but it was
> malformed. It was just changing SWIOTLB to use a macro for
> sg->dma_length or such.
> 
> But the IOMMU_HELPER? That seems odds as the DMA API (which as you know
> is what SWIOTLB hooks up to) is _below_ the IOMMU API.  Ah, it is 
> 'iommu_is_span_boundary' function.  Gotcha.

Yep, that's the one.


> Could you mention that in the git commit please? Just say that SWIOTLB
> uses some of the common code that IOMMU API uses - which is in the
> lib/iommu_helper.c hence the need for that.
> 
> And for the NEED_SG_DMA_LENGTH let me dig up the patch at some point and
> send it your way so you can make it part of this series.

OK

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

* Re: [PATCH RFC 1/8] arm: make SWIOTLB available
@ 2013-08-02 12:18           ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 12:18 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	Ian.Campbell, will.deacon, linux

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Fri, Aug 02, 2013 at 12:59:00PM +0100, Stefano Stabellini wrote:
> > On Wed, 31 Jul 2013, Konrad Rzeszutek Wilk wrote:
> > > Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:
> > > >Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > > >CC: will.deacon@arm.com
> > > >CC: linux@arm.linux.org.uk
> > > >---
> > > > arch/arm/Kconfig                   |    7 +++++++
> > > > arch/arm/include/asm/dma-mapping.h |   24 ++++++++++++++++++++++++
> > > > 2 files changed, 31 insertions(+), 0 deletions(-)
> > > >
> > > >diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > > >index ba412e0..05125ab 100644
> > > >--- a/arch/arm/Kconfig
> > > >+++ b/arch/arm/Kconfig
> > > >@@ -1832,6 +1832,13 @@ config CC_STACKPROTECTOR
> > > > 	  neutralized via a kernel panic.
> > > > 	  This feature requires gcc version 4.2 or above.
> > > > 
> > > >+config SWIOTLB
> > > >+	def_bool y
> > > >+	select NEED_SG_DMA_LENGTH
> > > >+
> > > >+config IOMMU_HELPER
> > > >+	def_bool SWIOTLB
> > > >+
> > > 
> > > Could you explain the purpose of these two a bit more please? 
> > 
> > SWIOTLB is not available on arm at the moment.
> > We need to make it available, otherwise SWIOTLB_XEN won't be able to
> > select it.
> > 
> > Similarly, IOMMU_HELPER is another lib Kconfig symbol needed by SWIOTLB
> > to compile.
> 
> I was more curious about the NEED_SG_DMA_LENGTH and IOMMU_HELPER.
> I think the NEED_SG_DMA_LENGTH is optional? Or does SWIOTLB complain
> about?

Yes, it does:

lib/swiotlb.c: In function 'swiotlb_map_sg_attrs':
lib/swiotlb.c:873:11: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c:879:5: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c: In function 'swiotlb_unmap_sg_attrs':
lib/swiotlb.c:907:42: error: 'struct scatterlist' has no member named 'dma_length'
lib/swiotlb.c: In function 'swiotlb_sync_sg':
lib/swiotlb.c:937:11: error: 'struct scatterlist' has no member named 'dma_length'


> I do recall seeing a patch for this at some point but it was
> malformed. It was just changing SWIOTLB to use a macro for
> sg->dma_length or such.
> 
> But the IOMMU_HELPER? That seems odds as the DMA API (which as you know
> is what SWIOTLB hooks up to) is _below_ the IOMMU API.  Ah, it is 
> 'iommu_is_span_boundary' function.  Gotcha.

Yep, that's the one.


> Could you mention that in the git commit please? Just say that SWIOTLB
> uses some of the common code that IOMMU API uses - which is in the
> lib/iommu_helper.c hence the need for that.
> 
> And for the NEED_SG_DMA_LENGTH let me dig up the patch at some point and
> send it your way so you can make it part of this series.

OK

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

* Re: [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
  2013-07-31 17:45   ` Stefano Stabellini
  (?)
@ 2013-08-02 12:37     ` Konrad Rzeszutek Wilk
  -1 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-02 12:37 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, Ian.Campbell, david.vrabel

On Wed, Jul 31, 2013 at 06:45:31PM +0100, Stefano Stabellini wrote:
> Support autotranslate guests in swiotlb-xen by keeping track of the
> phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> (xen_io_tlb_start-xen_io_tlb_end).
> 
> Use a simple direct access on a pre-allocated array for phys-to-bus
> queries. Use a red-black tree for bus-to-phys queries.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: david.vrabel@citrix.com
> ---
>  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 111 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> index 353f013..c79ac88 100644
> --- a/drivers/xen/swiotlb-xen.c
> +++ b/drivers/xen/swiotlb-xen.c
> @@ -38,32 +38,116 @@
>  #include <linux/bootmem.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock_types.h>
> +#include <linux/rbtree.h>
>  #include <xen/swiotlb-xen.h>
>  #include <xen/page.h>
>  #include <xen/xen-ops.h>
>  #include <xen/hvc-console.h>
> +#include <xen/features.h>
>  /*
>   * Used to do a quick range check in swiotlb_tbl_unmap_single and
>   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
>   * API.
>   */
>  
> +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
>  static char *xen_io_tlb_start, *xen_io_tlb_end;
>  static unsigned long xen_io_tlb_nslabs;
>  /*
>   * Quick lookup value of the bus address of the IOTLB.
>   */
>  
> -static u64 start_dma_addr;
> +struct xen_dma{
                 ^
Ahem! I think scripts/checkpath.pl would tell you about.

You did run checkpath.pl right :-)

The name is very generic. Xen DMA. Brings a lot of ideas around but none
of them to do with tracking a tuple. Perhaps a name of 'xen_dma_entry'?
'xen_dma_node' ? 'xen_dma_info' ?


> +	dma_addr_t dma_addr;
> +	phys_addr_t phys_addr;
> +	size_t size;
> +	struct rb_node rbnode;
> +};
> +
> +static struct xen_dma *xen_dma_seg;
> +static struct rb_root bus_to_phys = RB_ROOT;

That needs a bit of explanation of what this tree is suppose to do. I
have an idea, but it would be good to have it right there explained.

> +static DEFINE_SPINLOCK(xen_dma_lock);

And this name should also change. And you need a comment explainig what
this protects please.

> +
> +static void xen_dma_insert(struct xen_dma *entry)

A better name for the function please. Sounds like a IOMMU operation at
first glance (as in inserting an phys and dma addr in the IOMMU
context). But that is not what this does. It just adds an entry to a
tree.

Perhaps 'xen_dma_add_entry' ?

> +{
> +	struct rb_node **link = &bus_to_phys.rb_node;
> +	struct rb_node *parent = NULL;
> +	struct xen_dma *e;

'e' ?

eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee?

Ah, 'entry'!!!

Perhaps 'entry'? Oh wait, already taken. How about you call the one that
is passed in as 'new' and this one as 'entry'?

> +
> +	spin_lock(&xen_dma_lock);
> +
> +	while (*link) {
> +		parent = *link;
> +		e = rb_entry(parent, struct xen_dma, rbnode);
> +
> +		WARN_ON(entry->dma_addr == e->dma_addr);

You probably also want to print out the physical address of both of them?

And do you really want to continue if the physical address for the two
entries is different? That would mean you lose one of them when the
entry is being deleted from it.

Perhaps you should just return -EINVAL?

> +
> +		if (entry->dma_addr < e->dma_addr)
> +			link = &(*link)->rb_left;
> +		else
> +			link = &(*link)->rb_right;
> +	}
> +	rb_link_node(&entry->rbnode, parent, link);
> +	rb_insert_color(&entry->rbnode, &bus_to_phys);
> +
> +	spin_unlock(&xen_dma_lock);

How come we don't return 0 here?
> +}
> +
> +static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)

get?

> +{
> +	struct rb_node *n = bus_to_phys.rb_node;
> +	struct xen_dma *e;
> +	

Stray spaces, and 'eeeeeeeeeeeee' strikes again :-)
> +	spin_lock(&xen_dma_lock);
> +
> +	while (n) {
> +		e = rb_entry(n, struct xen_dma, rbnode);
> +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {

Shouldn't this check be for '==' not '<=' ?

Hm, maybe I am not sure what this tree is suppose to do. Somehow I
thought it was to keep a consistent mapping of phys and dma addresses.
But this seems to be more of 'free' phys and dma addresses. In which
case I think you need to change the name of the rb root node to have the
word 'free' in it.

> +			spin_unlock(&xen_dma_lock);
> +			return e;
> +		}
> +		if (dma_addr < e->dma_addr)
> +			n = n->rb_left;
> +		else
> +			n = n->rb_right;
> +	}
> +
> +	spin_unlock(&xen_dma_lock);
> +	return NULL;
> +}
>  
>  static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
>  {
> -	return phys_to_machine(XPADDR(paddr)).maddr;
> +	int nr_seg;
> +	unsigned long offset;
> +	char* vaddr;

Ahem!
> +
> +	if (!xen_feature(XENFEAT_auto_translated_physmap))
> +		return phys_to_machine(XPADDR(paddr)).maddr;
> +
> +	vaddr = (char *) phys_to_virt(paddr);

Ahem!
> +	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
> +		return ~0;

No no no. Please please use a proper #define.

> +
> +	offset = vaddr - xen_io_tlb_start;
> +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> +
> +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
>  }
>  
>  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
>  {
> -	return machine_to_phys(XMADDR(baddr)).paddr;
> +	if (xen_feature(XENFEAT_auto_translated_physmap))

I am curios to how this will work with PVH x86 which is
auto_translated_physmap, but maps the whole kernel in its IOMMU context.

Perhaps we should have some extra logic here? For guests that have IOMMU
support and for those that don't?

B/c in some way this could be used on x86 with VT-x + without an VT-d
and PVH for dom0 I think.

> +	{
> +		struct xen_dma *dma = xen_dma_retrieve(baddr);
> +		if (dma == NULL)
> +			return ~0;

I think you know what I am going to say.

> +		else
> +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> +	} else
> +		return machine_to_phys(XMADDR(baddr)).paddr;
>  }
>  
>  static dma_addr_t xen_virt_to_bus(void *address)
> @@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
>  	unsigned long pfn = mfn_to_local_pfn(mfn);
>  	phys_addr_t paddr;
>  
> +	if (xen_feature(XENFEAT_auto_translated_physmap))
> +		return 1;
> +

That does not look right to me. I think this would make PVH go bonk.

>  	/* If the address is outside our domain, it CAN
>  	 * have the same virtual address as another address
>  	 * in our domain. Therefore _only_ check address within our domain.
> @@ -124,13 +211,12 @@ static int max_dma_bits = 32;
>  static int
>  xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
>  {
> -	int i, rc;
> +	int i, j, rc;
>  	int dma_bits;
> -	dma_addr_t dma_handle;
>  
>  	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
>  
> -	i = 0;
> +	i = j = 0;
>  	do {
>  		int slabs = min(nslabs - i, (unsigned long)IO_TLB_SEGSIZE);
>  
> @@ -138,12 +224,16 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
>  			rc = xen_create_contiguous_region(
>  				(unsigned long)buf + (i << IO_TLB_SHIFT),
>  				get_order(slabs << IO_TLB_SHIFT),
> -				dma_bits, &dma_handle);
> +				dma_bits, &xen_dma_seg[j].dma_addr);
> +			xen_dma_seg[j].phys_addr = virt_to_phys(buf + (i << IO_TLB_SHIFT));
> +			xen_dma_seg[j].size = slabs << IO_TLB_SHIFT;
> +			xen_dma_insert(&xen_dma_seg[j]);
>  		} while (rc && dma_bits++ < max_dma_bits);
>  		if (rc)
>  			return rc;
>  
>  		i += slabs;
> +		j++;
>  	} while (i < nslabs);
>  	return 0;
>  }
> @@ -193,9 +283,10 @@ retry:
>  	/*
>  	 * Get IO TLB memory from any location.
>  	 */
> -	if (early)
> +	if (early) {
>  		xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
> -	else {
> +		xen_dma_seg = alloc_bootmem(sizeof(struct xen_dma) * NR_DMA_SEGS);
> +	} else {
>  #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
>  #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
>  		while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
> @@ -210,6 +301,7 @@ retry:
>  			xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
>  			bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
>  		}
> +		xen_dma_seg = kzalloc(sizeof(struct xen_dma) * NR_DMA_SEGS, GFP_KERNEL);
>  	}
>  	if (!xen_io_tlb_start) {
>  		m_ret = XEN_SWIOTLB_ENOMEM;
> @@ -232,7 +324,6 @@ retry:
>  		m_ret = XEN_SWIOTLB_EFIXUP;
>  		goto error;
>  	}
> -	start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
>  	if (early) {
>  		if (swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs,
>  			 verbose))
> @@ -290,7 +381,8 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
>  
>  	phys = virt_to_phys(ret);
>  	dev_addr = xen_phys_to_bus(phys);
> -	if (((dev_addr + size - 1 <= dma_mask)) &&
> +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> +	    ((dev_addr + size - 1 <= dma_mask)) &&
>  	    !range_straddles_page_boundary(phys, size))
>  		*dma_handle = dev_addr;
>  	else {
> @@ -321,8 +413,9 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
>  
>  	phys = virt_to_phys(vaddr);
>  
> -	if (((dev_addr + size - 1 > dma_mask)) ||
> -	    range_straddles_page_boundary(phys, size))
> +	if (xen_feature(XENFEAT_auto_translated_physmap) ||
> +		(((dev_addr + size - 1 > dma_mask)) ||
> +		 range_straddles_page_boundary(phys, size)))
>  		xen_destroy_contiguous_region((unsigned long)vaddr, order);
>  
>  	free_pages((unsigned long)vaddr, order);
> @@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
>  	 * we can safely return the device addr and not worry about bounce
>  	 * buffering it.
>  	 */
> -	if (dma_capable(dev, dev_addr, size) &&
> +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> +	    dma_capable(dev, dev_addr, size) &&
>  	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
>  		return dev_addr;

I am returning back to PVH on these and just not sure what the impact
is. Mukesh, thoughts?
>  
>  	/*
>  	 * Oh well, have to allocate and map a bounce buffer.
>  	 */
> -	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
> +	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);

At 0? Not some index?
>  	if (map == SWIOTLB_MAP_ERROR)
>  		return DMA_ERROR_CODE;
>  
> @@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
>  		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
>  
>  		if (swiotlb_force ||
> +		    xen_feature(XENFEAT_auto_translated_physmap) ||
>  		    !dma_capable(hwdev, dev_addr, sg->length) ||
>  		    range_straddles_page_boundary(paddr, sg->length)) {
>  			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
> -								 start_dma_addr,
> +								 xen_dma_seg[0].dma_addr,

I am not sure I understand the purpose of 'xen_dma_seg'. Could you
clarify that please?

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

* [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
@ 2013-08-02 12:37     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-02 12:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 31, 2013 at 06:45:31PM +0100, Stefano Stabellini wrote:
> Support autotranslate guests in swiotlb-xen by keeping track of the
> phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> (xen_io_tlb_start-xen_io_tlb_end).
> 
> Use a simple direct access on a pre-allocated array for phys-to-bus
> queries. Use a red-black tree for bus-to-phys queries.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: david.vrabel at citrix.com
> ---
>  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 111 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> index 353f013..c79ac88 100644
> --- a/drivers/xen/swiotlb-xen.c
> +++ b/drivers/xen/swiotlb-xen.c
> @@ -38,32 +38,116 @@
>  #include <linux/bootmem.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock_types.h>
> +#include <linux/rbtree.h>
>  #include <xen/swiotlb-xen.h>
>  #include <xen/page.h>
>  #include <xen/xen-ops.h>
>  #include <xen/hvc-console.h>
> +#include <xen/features.h>
>  /*
>   * Used to do a quick range check in swiotlb_tbl_unmap_single and
>   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
>   * API.
>   */
>  
> +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
>  static char *xen_io_tlb_start, *xen_io_tlb_end;
>  static unsigned long xen_io_tlb_nslabs;
>  /*
>   * Quick lookup value of the bus address of the IOTLB.
>   */
>  
> -static u64 start_dma_addr;
> +struct xen_dma{
                 ^
Ahem! I think scripts/checkpath.pl would tell you about.

You did run checkpath.pl right :-)

The name is very generic. Xen DMA. Brings a lot of ideas around but none
of them to do with tracking a tuple. Perhaps a name of 'xen_dma_entry'?
'xen_dma_node' ? 'xen_dma_info' ?


> +	dma_addr_t dma_addr;
> +	phys_addr_t phys_addr;
> +	size_t size;
> +	struct rb_node rbnode;
> +};
> +
> +static struct xen_dma *xen_dma_seg;
> +static struct rb_root bus_to_phys = RB_ROOT;

That needs a bit of explanation of what this tree is suppose to do. I
have an idea, but it would be good to have it right there explained.

> +static DEFINE_SPINLOCK(xen_dma_lock);

And this name should also change. And you need a comment explainig what
this protects please.

> +
> +static void xen_dma_insert(struct xen_dma *entry)

A better name for the function please. Sounds like a IOMMU operation at
first glance (as in inserting an phys and dma addr in the IOMMU
context). But that is not what this does. It just adds an entry to a
tree.

Perhaps 'xen_dma_add_entry' ?

> +{
> +	struct rb_node **link = &bus_to_phys.rb_node;
> +	struct rb_node *parent = NULL;
> +	struct xen_dma *e;

'e' ?

eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee?

Ah, 'entry'!!!

Perhaps 'entry'? Oh wait, already taken. How about you call the one that
is passed in as 'new' and this one as 'entry'?

> +
> +	spin_lock(&xen_dma_lock);
> +
> +	while (*link) {
> +		parent = *link;
> +		e = rb_entry(parent, struct xen_dma, rbnode);
> +
> +		WARN_ON(entry->dma_addr == e->dma_addr);

You probably also want to print out the physical address of both of them?

And do you really want to continue if the physical address for the two
entries is different? That would mean you lose one of them when the
entry is being deleted from it.

Perhaps you should just return -EINVAL?

> +
> +		if (entry->dma_addr < e->dma_addr)
> +			link = &(*link)->rb_left;
> +		else
> +			link = &(*link)->rb_right;
> +	}
> +	rb_link_node(&entry->rbnode, parent, link);
> +	rb_insert_color(&entry->rbnode, &bus_to_phys);
> +
> +	spin_unlock(&xen_dma_lock);

How come we don't return 0 here?
> +}
> +
> +static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)

get?

> +{
> +	struct rb_node *n = bus_to_phys.rb_node;
> +	struct xen_dma *e;
> +	

Stray spaces, and 'eeeeeeeeeeeee' strikes again :-)
> +	spin_lock(&xen_dma_lock);
> +
> +	while (n) {
> +		e = rb_entry(n, struct xen_dma, rbnode);
> +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {

Shouldn't this check be for '==' not '<=' ?

Hm, maybe I am not sure what this tree is suppose to do. Somehow I
thought it was to keep a consistent mapping of phys and dma addresses.
But this seems to be more of 'free' phys and dma addresses. In which
case I think you need to change the name of the rb root node to have the
word 'free' in it.

> +			spin_unlock(&xen_dma_lock);
> +			return e;
> +		}
> +		if (dma_addr < e->dma_addr)
> +			n = n->rb_left;
> +		else
> +			n = n->rb_right;
> +	}
> +
> +	spin_unlock(&xen_dma_lock);
> +	return NULL;
> +}
>  
>  static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
>  {
> -	return phys_to_machine(XPADDR(paddr)).maddr;
> +	int nr_seg;
> +	unsigned long offset;
> +	char* vaddr;

Ahem!
> +
> +	if (!xen_feature(XENFEAT_auto_translated_physmap))
> +		return phys_to_machine(XPADDR(paddr)).maddr;
> +
> +	vaddr = (char *) phys_to_virt(paddr);

Ahem!
> +	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
> +		return ~0;

No no no. Please please use a proper #define.

> +
> +	offset = vaddr - xen_io_tlb_start;
> +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> +
> +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
>  }
>  
>  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
>  {
> -	return machine_to_phys(XMADDR(baddr)).paddr;
> +	if (xen_feature(XENFEAT_auto_translated_physmap))

I am curios to how this will work with PVH x86 which is
auto_translated_physmap, but maps the whole kernel in its IOMMU context.

Perhaps we should have some extra logic here? For guests that have IOMMU
support and for those that don't?

B/c in some way this could be used on x86 with VT-x + without an VT-d
and PVH for dom0 I think.

> +	{
> +		struct xen_dma *dma = xen_dma_retrieve(baddr);
> +		if (dma == NULL)
> +			return ~0;

I think you know what I am going to say.

> +		else
> +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> +	} else
> +		return machine_to_phys(XMADDR(baddr)).paddr;
>  }
>  
>  static dma_addr_t xen_virt_to_bus(void *address)
> @@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
>  	unsigned long pfn = mfn_to_local_pfn(mfn);
>  	phys_addr_t paddr;
>  
> +	if (xen_feature(XENFEAT_auto_translated_physmap))
> +		return 1;
> +

That does not look right to me. I think this would make PVH go bonk.

>  	/* If the address is outside our domain, it CAN
>  	 * have the same virtual address as another address
>  	 * in our domain. Therefore _only_ check address within our domain.
> @@ -124,13 +211,12 @@ static int max_dma_bits = 32;
>  static int
>  xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
>  {
> -	int i, rc;
> +	int i, j, rc;
>  	int dma_bits;
> -	dma_addr_t dma_handle;
>  
>  	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
>  
> -	i = 0;
> +	i = j = 0;
>  	do {
>  		int slabs = min(nslabs - i, (unsigned long)IO_TLB_SEGSIZE);
>  
> @@ -138,12 +224,16 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
>  			rc = xen_create_contiguous_region(
>  				(unsigned long)buf + (i << IO_TLB_SHIFT),
>  				get_order(slabs << IO_TLB_SHIFT),
> -				dma_bits, &dma_handle);
> +				dma_bits, &xen_dma_seg[j].dma_addr);
> +			xen_dma_seg[j].phys_addr = virt_to_phys(buf + (i << IO_TLB_SHIFT));
> +			xen_dma_seg[j].size = slabs << IO_TLB_SHIFT;
> +			xen_dma_insert(&xen_dma_seg[j]);
>  		} while (rc && dma_bits++ < max_dma_bits);
>  		if (rc)
>  			return rc;
>  
>  		i += slabs;
> +		j++;
>  	} while (i < nslabs);
>  	return 0;
>  }
> @@ -193,9 +283,10 @@ retry:
>  	/*
>  	 * Get IO TLB memory from any location.
>  	 */
> -	if (early)
> +	if (early) {
>  		xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
> -	else {
> +		xen_dma_seg = alloc_bootmem(sizeof(struct xen_dma) * NR_DMA_SEGS);
> +	} else {
>  #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
>  #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
>  		while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
> @@ -210,6 +301,7 @@ retry:
>  			xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
>  			bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
>  		}
> +		xen_dma_seg = kzalloc(sizeof(struct xen_dma) * NR_DMA_SEGS, GFP_KERNEL);
>  	}
>  	if (!xen_io_tlb_start) {
>  		m_ret = XEN_SWIOTLB_ENOMEM;
> @@ -232,7 +324,6 @@ retry:
>  		m_ret = XEN_SWIOTLB_EFIXUP;
>  		goto error;
>  	}
> -	start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
>  	if (early) {
>  		if (swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs,
>  			 verbose))
> @@ -290,7 +381,8 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
>  
>  	phys = virt_to_phys(ret);
>  	dev_addr = xen_phys_to_bus(phys);
> -	if (((dev_addr + size - 1 <= dma_mask)) &&
> +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> +	    ((dev_addr + size - 1 <= dma_mask)) &&
>  	    !range_straddles_page_boundary(phys, size))
>  		*dma_handle = dev_addr;
>  	else {
> @@ -321,8 +413,9 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
>  
>  	phys = virt_to_phys(vaddr);
>  
> -	if (((dev_addr + size - 1 > dma_mask)) ||
> -	    range_straddles_page_boundary(phys, size))
> +	if (xen_feature(XENFEAT_auto_translated_physmap) ||
> +		(((dev_addr + size - 1 > dma_mask)) ||
> +		 range_straddles_page_boundary(phys, size)))
>  		xen_destroy_contiguous_region((unsigned long)vaddr, order);
>  
>  	free_pages((unsigned long)vaddr, order);
> @@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
>  	 * we can safely return the device addr and not worry about bounce
>  	 * buffering it.
>  	 */
> -	if (dma_capable(dev, dev_addr, size) &&
> +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> +	    dma_capable(dev, dev_addr, size) &&
>  	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
>  		return dev_addr;

I am returning back to PVH on these and just not sure what the impact
is. Mukesh, thoughts?
>  
>  	/*
>  	 * Oh well, have to allocate and map a bounce buffer.
>  	 */
> -	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
> +	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);

At 0? Not some index?
>  	if (map == SWIOTLB_MAP_ERROR)
>  		return DMA_ERROR_CODE;
>  
> @@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
>  		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
>  
>  		if (swiotlb_force ||
> +		    xen_feature(XENFEAT_auto_translated_physmap) ||
>  		    !dma_capable(hwdev, dev_addr, sg->length) ||
>  		    range_straddles_page_boundary(paddr, sg->length)) {
>  			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
> -								 start_dma_addr,
> +								 xen_dma_seg[0].dma_addr,

I am not sure I understand the purpose of 'xen_dma_seg'. Could you
clarify that please?

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

* Re: [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
@ 2013-08-02 12:37     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-02 12:37 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: david.vrabel, xen-devel, linux-kernel, linux-arm-kernel, Ian.Campbell

On Wed, Jul 31, 2013 at 06:45:31PM +0100, Stefano Stabellini wrote:
> Support autotranslate guests in swiotlb-xen by keeping track of the
> phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> (xen_io_tlb_start-xen_io_tlb_end).
> 
> Use a simple direct access on a pre-allocated array for phys-to-bus
> queries. Use a red-black tree for bus-to-phys queries.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: david.vrabel@citrix.com
> ---
>  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 111 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> index 353f013..c79ac88 100644
> --- a/drivers/xen/swiotlb-xen.c
> +++ b/drivers/xen/swiotlb-xen.c
> @@ -38,32 +38,116 @@
>  #include <linux/bootmem.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock_types.h>
> +#include <linux/rbtree.h>
>  #include <xen/swiotlb-xen.h>
>  #include <xen/page.h>
>  #include <xen/xen-ops.h>
>  #include <xen/hvc-console.h>
> +#include <xen/features.h>
>  /*
>   * Used to do a quick range check in swiotlb_tbl_unmap_single and
>   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
>   * API.
>   */
>  
> +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
>  static char *xen_io_tlb_start, *xen_io_tlb_end;
>  static unsigned long xen_io_tlb_nslabs;
>  /*
>   * Quick lookup value of the bus address of the IOTLB.
>   */
>  
> -static u64 start_dma_addr;
> +struct xen_dma{
                 ^
Ahem! I think scripts/checkpath.pl would tell you about.

You did run checkpath.pl right :-)

The name is very generic. Xen DMA. Brings a lot of ideas around but none
of them to do with tracking a tuple. Perhaps a name of 'xen_dma_entry'?
'xen_dma_node' ? 'xen_dma_info' ?


> +	dma_addr_t dma_addr;
> +	phys_addr_t phys_addr;
> +	size_t size;
> +	struct rb_node rbnode;
> +};
> +
> +static struct xen_dma *xen_dma_seg;
> +static struct rb_root bus_to_phys = RB_ROOT;

That needs a bit of explanation of what this tree is suppose to do. I
have an idea, but it would be good to have it right there explained.

> +static DEFINE_SPINLOCK(xen_dma_lock);

And this name should also change. And you need a comment explainig what
this protects please.

> +
> +static void xen_dma_insert(struct xen_dma *entry)

A better name for the function please. Sounds like a IOMMU operation at
first glance (as in inserting an phys and dma addr in the IOMMU
context). But that is not what this does. It just adds an entry to a
tree.

Perhaps 'xen_dma_add_entry' ?

> +{
> +	struct rb_node **link = &bus_to_phys.rb_node;
> +	struct rb_node *parent = NULL;
> +	struct xen_dma *e;

'e' ?

eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee?

Ah, 'entry'!!!

Perhaps 'entry'? Oh wait, already taken. How about you call the one that
is passed in as 'new' and this one as 'entry'?

> +
> +	spin_lock(&xen_dma_lock);
> +
> +	while (*link) {
> +		parent = *link;
> +		e = rb_entry(parent, struct xen_dma, rbnode);
> +
> +		WARN_ON(entry->dma_addr == e->dma_addr);

You probably also want to print out the physical address of both of them?

And do you really want to continue if the physical address for the two
entries is different? That would mean you lose one of them when the
entry is being deleted from it.

Perhaps you should just return -EINVAL?

> +
> +		if (entry->dma_addr < e->dma_addr)
> +			link = &(*link)->rb_left;
> +		else
> +			link = &(*link)->rb_right;
> +	}
> +	rb_link_node(&entry->rbnode, parent, link);
> +	rb_insert_color(&entry->rbnode, &bus_to_phys);
> +
> +	spin_unlock(&xen_dma_lock);

How come we don't return 0 here?
> +}
> +
> +static struct xen_dma *xen_dma_retrieve(dma_addr_t dma_addr)

get?

> +{
> +	struct rb_node *n = bus_to_phys.rb_node;
> +	struct xen_dma *e;
> +	

Stray spaces, and 'eeeeeeeeeeeee' strikes again :-)
> +	spin_lock(&xen_dma_lock);
> +
> +	while (n) {
> +		e = rb_entry(n, struct xen_dma, rbnode);
> +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {

Shouldn't this check be for '==' not '<=' ?

Hm, maybe I am not sure what this tree is suppose to do. Somehow I
thought it was to keep a consistent mapping of phys and dma addresses.
But this seems to be more of 'free' phys and dma addresses. In which
case I think you need to change the name of the rb root node to have the
word 'free' in it.

> +			spin_unlock(&xen_dma_lock);
> +			return e;
> +		}
> +		if (dma_addr < e->dma_addr)
> +			n = n->rb_left;
> +		else
> +			n = n->rb_right;
> +	}
> +
> +	spin_unlock(&xen_dma_lock);
> +	return NULL;
> +}
>  
>  static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
>  {
> -	return phys_to_machine(XPADDR(paddr)).maddr;
> +	int nr_seg;
> +	unsigned long offset;
> +	char* vaddr;

Ahem!
> +
> +	if (!xen_feature(XENFEAT_auto_translated_physmap))
> +		return phys_to_machine(XPADDR(paddr)).maddr;
> +
> +	vaddr = (char *) phys_to_virt(paddr);

Ahem!
> +	if (vaddr >= xen_io_tlb_end || vaddr < xen_io_tlb_start)
> +		return ~0;

No no no. Please please use a proper #define.

> +
> +	offset = vaddr - xen_io_tlb_start;
> +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> +
> +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
>  }
>  
>  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
>  {
> -	return machine_to_phys(XMADDR(baddr)).paddr;
> +	if (xen_feature(XENFEAT_auto_translated_physmap))

I am curios to how this will work with PVH x86 which is
auto_translated_physmap, but maps the whole kernel in its IOMMU context.

Perhaps we should have some extra logic here? For guests that have IOMMU
support and for those that don't?

B/c in some way this could be used on x86 with VT-x + without an VT-d
and PVH for dom0 I think.

> +	{
> +		struct xen_dma *dma = xen_dma_retrieve(baddr);
> +		if (dma == NULL)
> +			return ~0;

I think you know what I am going to say.

> +		else
> +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> +	} else
> +		return machine_to_phys(XMADDR(baddr)).paddr;
>  }
>  
>  static dma_addr_t xen_virt_to_bus(void *address)
> @@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
>  	unsigned long pfn = mfn_to_local_pfn(mfn);
>  	phys_addr_t paddr;
>  
> +	if (xen_feature(XENFEAT_auto_translated_physmap))
> +		return 1;
> +

That does not look right to me. I think this would make PVH go bonk.

>  	/* If the address is outside our domain, it CAN
>  	 * have the same virtual address as another address
>  	 * in our domain. Therefore _only_ check address within our domain.
> @@ -124,13 +211,12 @@ static int max_dma_bits = 32;
>  static int
>  xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
>  {
> -	int i, rc;
> +	int i, j, rc;
>  	int dma_bits;
> -	dma_addr_t dma_handle;
>  
>  	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
>  
> -	i = 0;
> +	i = j = 0;
>  	do {
>  		int slabs = min(nslabs - i, (unsigned long)IO_TLB_SEGSIZE);
>  
> @@ -138,12 +224,16 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
>  			rc = xen_create_contiguous_region(
>  				(unsigned long)buf + (i << IO_TLB_SHIFT),
>  				get_order(slabs << IO_TLB_SHIFT),
> -				dma_bits, &dma_handle);
> +				dma_bits, &xen_dma_seg[j].dma_addr);
> +			xen_dma_seg[j].phys_addr = virt_to_phys(buf + (i << IO_TLB_SHIFT));
> +			xen_dma_seg[j].size = slabs << IO_TLB_SHIFT;
> +			xen_dma_insert(&xen_dma_seg[j]);
>  		} while (rc && dma_bits++ < max_dma_bits);
>  		if (rc)
>  			return rc;
>  
>  		i += slabs;
> +		j++;
>  	} while (i < nslabs);
>  	return 0;
>  }
> @@ -193,9 +283,10 @@ retry:
>  	/*
>  	 * Get IO TLB memory from any location.
>  	 */
> -	if (early)
> +	if (early) {
>  		xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
> -	else {
> +		xen_dma_seg = alloc_bootmem(sizeof(struct xen_dma) * NR_DMA_SEGS);
> +	} else {
>  #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
>  #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
>  		while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
> @@ -210,6 +301,7 @@ retry:
>  			xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
>  			bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
>  		}
> +		xen_dma_seg = kzalloc(sizeof(struct xen_dma) * NR_DMA_SEGS, GFP_KERNEL);
>  	}
>  	if (!xen_io_tlb_start) {
>  		m_ret = XEN_SWIOTLB_ENOMEM;
> @@ -232,7 +324,6 @@ retry:
>  		m_ret = XEN_SWIOTLB_EFIXUP;
>  		goto error;
>  	}
> -	start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
>  	if (early) {
>  		if (swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs,
>  			 verbose))
> @@ -290,7 +381,8 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
>  
>  	phys = virt_to_phys(ret);
>  	dev_addr = xen_phys_to_bus(phys);
> -	if (((dev_addr + size - 1 <= dma_mask)) &&
> +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> +	    ((dev_addr + size - 1 <= dma_mask)) &&
>  	    !range_straddles_page_boundary(phys, size))
>  		*dma_handle = dev_addr;
>  	else {
> @@ -321,8 +413,9 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
>  
>  	phys = virt_to_phys(vaddr);
>  
> -	if (((dev_addr + size - 1 > dma_mask)) ||
> -	    range_straddles_page_boundary(phys, size))
> +	if (xen_feature(XENFEAT_auto_translated_physmap) ||
> +		(((dev_addr + size - 1 > dma_mask)) ||
> +		 range_straddles_page_boundary(phys, size)))
>  		xen_destroy_contiguous_region((unsigned long)vaddr, order);
>  
>  	free_pages((unsigned long)vaddr, order);
> @@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
>  	 * we can safely return the device addr and not worry about bounce
>  	 * buffering it.
>  	 */
> -	if (dma_capable(dev, dev_addr, size) &&
> +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> +	    dma_capable(dev, dev_addr, size) &&
>  	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
>  		return dev_addr;

I am returning back to PVH on these and just not sure what the impact
is. Mukesh, thoughts?
>  
>  	/*
>  	 * Oh well, have to allocate and map a bounce buffer.
>  	 */
> -	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
> +	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);

At 0? Not some index?
>  	if (map == SWIOTLB_MAP_ERROR)
>  		return DMA_ERROR_CODE;
>  
> @@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
>  		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
>  
>  		if (swiotlb_force ||
> +		    xen_feature(XENFEAT_auto_translated_physmap) ||
>  		    !dma_capable(hwdev, dev_addr, sg->length) ||
>  		    range_straddles_page_boundary(paddr, sg->length)) {
>  			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
> -								 start_dma_addr,
> +								 xen_dma_seg[0].dma_addr,

I am not sure I understand the purpose of 'xen_dma_seg'. Could you
clarify that please?

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

* Re: [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN
  2013-07-31 17:45   ` Stefano Stabellini
@ 2013-08-02 12:40     ` Konrad Rzeszutek Wilk
  -1 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-02 12:40 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, linux-kernel, linux-arm-kernel, Ian.Campbell

On Wed, Jul 31, 2013 at 06:45:32PM +0100, Stefano Stabellini wrote:
> Xen on arm and arm64 needs SWIOTLB_XEN: when running on Xen we need to
> program the hardware with mfns rather than pfns for dma addresses.
> Remove SWIOTLB_XEN dependency on X86 and PCI and make XEN select
> SWIOTLB_XEN on arm and arm64.
> 
> Implement xen_create_contiguous_region on arm and arm64 by using
> XENMEM_get_dma_buf.
> 
> Initialize the xen-swiotlb from xen_early_init (before the native
> dma_ops are initialized), set dma_ops to &xen_swiotlb_dma_ops if we are
> running on Xen.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> ---
>  arch/arm/Kconfig                |    1 +
>  arch/arm/include/asm/xen/page.h |    2 +
>  arch/arm/xen/Makefile           |    2 +-
>  arch/arm/xen/enlighten.c        |    3 +
>  arch/arm/xen/mm.c               |  118 +++++++++++++++++++++++++++++++++++++++
>  arch/arm64/Kconfig              |    1 +
>  arch/arm64/xen/Makefile         |    2 +-
>  drivers/xen/Kconfig             |    1 -
>  drivers/xen/swiotlb-xen.c       |   18 ++++++
>  9 files changed, 145 insertions(+), 3 deletions(-)
>  create mode 100644 arch/arm/xen/mm.c
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 05125ab..72b53b9 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1849,6 +1849,7 @@ config XEN
>  	depends on CPU_V7 && !CPU_V6
>  	depends on !GENERIC_ATOMIC64
>  	select ARM_PSCI
> +	select SWIOTLB_XEN
>  	help
>  	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
>  
> diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
> index 359a7b5..b0f7150 100644
> --- a/arch/arm/include/asm/xen/page.h
> +++ b/arch/arm/include/asm/xen/page.h
> @@ -6,12 +6,14 @@
>  
>  #include <linux/pfn.h>
>  #include <linux/types.h>
> +#include <linux/dma-mapping.h>
>  
>  #include <xen/interface/grant_table.h>
>  
>  #define pfn_to_mfn(pfn)			(pfn)
>  #define phys_to_machine_mapping_valid(pfn) (1)
>  #define mfn_to_pfn(mfn)			(mfn)
> +#define mfn_to_local_pfn(m)             (mfn_to_pfn(m))
>  #define mfn_to_virt(m)			(__va(mfn_to_pfn(m) << PAGE_SHIFT))
>  
>  #define pte_mfn	    pte_pfn
> diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
> index 4384103..66fc35d 100644
> --- a/arch/arm/xen/Makefile
> +++ b/arch/arm/xen/Makefile
> @@ -1 +1 @@
> -obj-y		:= enlighten.o hypercall.o grant-table.o
> +obj-y		:= enlighten.o hypercall.o grant-table.o mm.o
> diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
> index 14d17ab..06a6953 100644
> --- a/arch/arm/xen/enlighten.c
> +++ b/arch/arm/xen/enlighten.c
> @@ -195,6 +195,7 @@ static void xen_power_off(void)
>   * documentation of the Xen Device Tree format.
>   */
>  #define GRANT_TABLE_PHYSADDR 0
> +extern int xen_mm_init(void);
>  void __init xen_early_init(void)
>  {
>  	struct resource res;
> @@ -230,6 +231,8 @@ void __init xen_early_init(void)
>  		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
>  	else
>  		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
> +
> +	xen_mm_init();
>  }
>  
>  static int __init xen_guest_init(void)
> diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c
> new file mode 100644
> index 0000000..4ba1add
> --- /dev/null
> +++ b/arch/arm/xen/mm.c
> @@ -0,0 +1,118 @@
> +#include <linux/bootmem.h>
> +#include <linux/gfp.h>
> +#include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/vmalloc.h>
> +#include <linux/swiotlb.h>
> +
> +#include <xen/xen.h>
> +#include <xen/interface/memory.h>
> +#include <xen/swiotlb-xen.h>
> +
> +#include <asm/cacheflush.h>
> +#include <asm/xen/page.h>
> +#include <asm/xen/hypercall.h>
> +#include <asm/xen/interface.h>
> +
> +static int xen_exchange_memory(xen_ulong_t extents_in,
> +			       unsigned int order_in,
> +			       xen_pfn_t *pfns_in,
> +			       xen_ulong_t extents_out,
> +			       unsigned int order_out,
> +			       xen_pfn_t *mfns_out,
> +			       unsigned int address_bits)
> +{
> +	long rc;
> +	int success;
> +
> +	struct xen_memory_exchange exchange = {
> +		.in = {
> +			.nr_extents   = extents_in,
> +			.extent_order = order_in,
> +			.domid        = DOMID_SELF
> +		},
> +		.out = {
> +			.nr_extents   = extents_out,
> +			.extent_order = order_out,
> +			.address_bits = address_bits,
> +			.domid        = DOMID_SELF
> +		}
> +	};
> +	set_xen_guest_handle(exchange.in.extent_start, pfns_in);
> +	set_xen_guest_handle(exchange.out.extent_start, mfns_out);
> +
> +	BUG_ON(extents_in << order_in != extents_out << order_out);
> +
> +
> +	rc = HYPERVISOR_memory_op(XENMEM_get_dma_buf, &exchange);
> +	success = (exchange.nr_exchanged == extents_in);
> +
> +	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
> +	BUG_ON(success && (rc != 0));
> +
> +	return success;
> +}

Could this code be made out to be more generic? It is almost the same on
x86 - it just a different hypercall.
> +
> +int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
> +				 unsigned int address_bits,
> +				 dma_addr_t *dma_handle)
> +{
> +	phys_addr_t pstart = __pa(vstart);
> +	xen_pfn_t in_frame, out_frame;
> +	int success, i;
> +
> +	/* 2. Get a new contiguous memory extent. */

Step 1) is missing.

> +	in_frame = out_frame = pstart >> PAGE_SHIFT;
> +	success = xen_exchange_memory(1, order, &in_frame,
> +				      1, order, &out_frame,
> +				      address_bits);
> +
> +	if (!success)
> +		return -ENOMEM;
> +
> +	*dma_handle = out_frame << PAGE_SHIFT;
> +	

Ahem! Stray white-space
> +	return success ? 0 : -ENOMEM;
> +}
> +EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
> +
> +void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
> +{
> +	int i;
> +	xen_pfn_t in_frame = __pa(vstart) >> PAGE_SHIFT;
> +	struct xen_put_dma_buf buf = {
> +		.in = {
> +			.nr_extents   = 1,
> +			.extent_order = order,
> +			.domid        = DOMID_SELF
> +		},
> +	};
> +	set_xen_guest_handle(buf.in.extent_start, &in_frame);
> +
> +	HYPERVISOR_memory_op(XENMEM_put_dma_buf, &buf);
> +}
> +EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
> +
> +static struct dma_map_ops xen_swiotlb_dma_ops = {
> +	.mapping_error = xen_swiotlb_dma_mapping_error,
> +	.alloc = xen_swiotlb_alloc_coherent,
> +	.free = xen_swiotlb_free_coherent,
> +	.sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu,
> +	.sync_single_for_device = xen_swiotlb_sync_single_for_device,
> +	.sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu,
> +	.sync_sg_for_device = xen_swiotlb_sync_sg_for_device,
> +	.map_sg = xen_swiotlb_map_sg_attrs,
> +	.unmap_sg = xen_swiotlb_unmap_sg_attrs,
> +	.map_page = xen_swiotlb_map_page,
> +	.unmap_page = xen_swiotlb_unmap_page,
> +	.dma_supported = xen_swiotlb_dma_supported,
> +};
> +
> +int __init xen_mm_init(void)
> +{
> +	xen_swiotlb_init(1, true);
> +	dma_ops = &xen_swiotlb_dma_ops;
> +	return 0;
> +}
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 9737e97..aa1f6fb 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -209,6 +209,7 @@ config XEN_DOM0
>  config XEN
>  	bool "Xen guest support on ARM64 (EXPERIMENTAL)"
>  	depends on ARM64 && OF
> +	select SWIOTLB_XEN
>  	help
>  	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
>  
> diff --git a/arch/arm64/xen/Makefile b/arch/arm64/xen/Makefile
> index be24040..0ef9637 100644
> --- a/arch/arm64/xen/Makefile
> +++ b/arch/arm64/xen/Makefile
> @@ -1,2 +1,2 @@
> -xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o)
> +xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o mm.o)
>  obj-y		:= xen-arm.o hypercall.o
> diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
> index 9e02d60..7e83688 100644
> --- a/drivers/xen/Kconfig
> +++ b/drivers/xen/Kconfig
> @@ -140,7 +140,6 @@ config XEN_GRANT_DEV_ALLOC
>  
>  config SWIOTLB_XEN
>  	def_bool y
> -	depends on PCI && X86
>  	select SWIOTLB
>  
>  config XEN_TMEM
> diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> index c79ac88..4ae6cf6 100644
> --- a/drivers/xen/swiotlb-xen.c
> +++ b/drivers/xen/swiotlb-xen.c
> @@ -59,6 +59,24 @@ static unsigned long xen_io_tlb_nslabs;
>   * Quick lookup value of the bus address of the IOTLB.
>   */
>  
> +#ifndef DMA_ERROR_CODE
> +#define DMA_ERROR_CODE	(~0)
> +#endif
> +
> +#ifndef CONFIG_X86
> +static unsigned long dma_alloc_coherent_mask(struct device *dev,
> +					    gfp_t gfp)
> +{
> +	unsigned long dma_mask = 0;
> +
> +	dma_mask = dev->coherent_dma_mask;
> +	if (!dma_mask)
> +		dma_mask = (gfp & GFP_DMA) ? DMA_BIT_MASK(24) : DMA_BIT_MASK(32);
> +
> +	return dma_mask;
> +}
> +#endif
> +
>  struct xen_dma{
>  	dma_addr_t dma_addr;
>  	phys_addr_t phys_addr;
> -- 
> 1.7.2.5
> 

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

* [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN
@ 2013-08-02 12:40     ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 73+ messages in thread
From: Konrad Rzeszutek Wilk @ 2013-08-02 12:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 31, 2013 at 06:45:32PM +0100, Stefano Stabellini wrote:
> Xen on arm and arm64 needs SWIOTLB_XEN: when running on Xen we need to
> program the hardware with mfns rather than pfns for dma addresses.
> Remove SWIOTLB_XEN dependency on X86 and PCI and make XEN select
> SWIOTLB_XEN on arm and arm64.
> 
> Implement xen_create_contiguous_region on arm and arm64 by using
> XENMEM_get_dma_buf.
> 
> Initialize the xen-swiotlb from xen_early_init (before the native
> dma_ops are initialized), set dma_ops to &xen_swiotlb_dma_ops if we are
> running on Xen.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> ---
>  arch/arm/Kconfig                |    1 +
>  arch/arm/include/asm/xen/page.h |    2 +
>  arch/arm/xen/Makefile           |    2 +-
>  arch/arm/xen/enlighten.c        |    3 +
>  arch/arm/xen/mm.c               |  118 +++++++++++++++++++++++++++++++++++++++
>  arch/arm64/Kconfig              |    1 +
>  arch/arm64/xen/Makefile         |    2 +-
>  drivers/xen/Kconfig             |    1 -
>  drivers/xen/swiotlb-xen.c       |   18 ++++++
>  9 files changed, 145 insertions(+), 3 deletions(-)
>  create mode 100644 arch/arm/xen/mm.c
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 05125ab..72b53b9 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1849,6 +1849,7 @@ config XEN
>  	depends on CPU_V7 && !CPU_V6
>  	depends on !GENERIC_ATOMIC64
>  	select ARM_PSCI
> +	select SWIOTLB_XEN
>  	help
>  	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
>  
> diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
> index 359a7b5..b0f7150 100644
> --- a/arch/arm/include/asm/xen/page.h
> +++ b/arch/arm/include/asm/xen/page.h
> @@ -6,12 +6,14 @@
>  
>  #include <linux/pfn.h>
>  #include <linux/types.h>
> +#include <linux/dma-mapping.h>
>  
>  #include <xen/interface/grant_table.h>
>  
>  #define pfn_to_mfn(pfn)			(pfn)
>  #define phys_to_machine_mapping_valid(pfn) (1)
>  #define mfn_to_pfn(mfn)			(mfn)
> +#define mfn_to_local_pfn(m)             (mfn_to_pfn(m))
>  #define mfn_to_virt(m)			(__va(mfn_to_pfn(m) << PAGE_SHIFT))
>  
>  #define pte_mfn	    pte_pfn
> diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
> index 4384103..66fc35d 100644
> --- a/arch/arm/xen/Makefile
> +++ b/arch/arm/xen/Makefile
> @@ -1 +1 @@
> -obj-y		:= enlighten.o hypercall.o grant-table.o
> +obj-y		:= enlighten.o hypercall.o grant-table.o mm.o
> diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
> index 14d17ab..06a6953 100644
> --- a/arch/arm/xen/enlighten.c
> +++ b/arch/arm/xen/enlighten.c
> @@ -195,6 +195,7 @@ static void xen_power_off(void)
>   * documentation of the Xen Device Tree format.
>   */
>  #define GRANT_TABLE_PHYSADDR 0
> +extern int xen_mm_init(void);
>  void __init xen_early_init(void)
>  {
>  	struct resource res;
> @@ -230,6 +231,8 @@ void __init xen_early_init(void)
>  		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
>  	else
>  		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
> +
> +	xen_mm_init();
>  }
>  
>  static int __init xen_guest_init(void)
> diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c
> new file mode 100644
> index 0000000..4ba1add
> --- /dev/null
> +++ b/arch/arm/xen/mm.c
> @@ -0,0 +1,118 @@
> +#include <linux/bootmem.h>
> +#include <linux/gfp.h>
> +#include <linux/export.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/vmalloc.h>
> +#include <linux/swiotlb.h>
> +
> +#include <xen/xen.h>
> +#include <xen/interface/memory.h>
> +#include <xen/swiotlb-xen.h>
> +
> +#include <asm/cacheflush.h>
> +#include <asm/xen/page.h>
> +#include <asm/xen/hypercall.h>
> +#include <asm/xen/interface.h>
> +
> +static int xen_exchange_memory(xen_ulong_t extents_in,
> +			       unsigned int order_in,
> +			       xen_pfn_t *pfns_in,
> +			       xen_ulong_t extents_out,
> +			       unsigned int order_out,
> +			       xen_pfn_t *mfns_out,
> +			       unsigned int address_bits)
> +{
> +	long rc;
> +	int success;
> +
> +	struct xen_memory_exchange exchange = {
> +		.in = {
> +			.nr_extents   = extents_in,
> +			.extent_order = order_in,
> +			.domid        = DOMID_SELF
> +		},
> +		.out = {
> +			.nr_extents   = extents_out,
> +			.extent_order = order_out,
> +			.address_bits = address_bits,
> +			.domid        = DOMID_SELF
> +		}
> +	};
> +	set_xen_guest_handle(exchange.in.extent_start, pfns_in);
> +	set_xen_guest_handle(exchange.out.extent_start, mfns_out);
> +
> +	BUG_ON(extents_in << order_in != extents_out << order_out);
> +
> +
> +	rc = HYPERVISOR_memory_op(XENMEM_get_dma_buf, &exchange);
> +	success = (exchange.nr_exchanged == extents_in);
> +
> +	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
> +	BUG_ON(success && (rc != 0));
> +
> +	return success;
> +}

Could this code be made out to be more generic? It is almost the same on
x86 - it just a different hypercall.
> +
> +int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
> +				 unsigned int address_bits,
> +				 dma_addr_t *dma_handle)
> +{
> +	phys_addr_t pstart = __pa(vstart);
> +	xen_pfn_t in_frame, out_frame;
> +	int success, i;
> +
> +	/* 2. Get a new contiguous memory extent. */

Step 1) is missing.

> +	in_frame = out_frame = pstart >> PAGE_SHIFT;
> +	success = xen_exchange_memory(1, order, &in_frame,
> +				      1, order, &out_frame,
> +				      address_bits);
> +
> +	if (!success)
> +		return -ENOMEM;
> +
> +	*dma_handle = out_frame << PAGE_SHIFT;
> +	

Ahem! Stray white-space
> +	return success ? 0 : -ENOMEM;
> +}
> +EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
> +
> +void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
> +{
> +	int i;
> +	xen_pfn_t in_frame = __pa(vstart) >> PAGE_SHIFT;
> +	struct xen_put_dma_buf buf = {
> +		.in = {
> +			.nr_extents   = 1,
> +			.extent_order = order,
> +			.domid        = DOMID_SELF
> +		},
> +	};
> +	set_xen_guest_handle(buf.in.extent_start, &in_frame);
> +
> +	HYPERVISOR_memory_op(XENMEM_put_dma_buf, &buf);
> +}
> +EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
> +
> +static struct dma_map_ops xen_swiotlb_dma_ops = {
> +	.mapping_error = xen_swiotlb_dma_mapping_error,
> +	.alloc = xen_swiotlb_alloc_coherent,
> +	.free = xen_swiotlb_free_coherent,
> +	.sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu,
> +	.sync_single_for_device = xen_swiotlb_sync_single_for_device,
> +	.sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu,
> +	.sync_sg_for_device = xen_swiotlb_sync_sg_for_device,
> +	.map_sg = xen_swiotlb_map_sg_attrs,
> +	.unmap_sg = xen_swiotlb_unmap_sg_attrs,
> +	.map_page = xen_swiotlb_map_page,
> +	.unmap_page = xen_swiotlb_unmap_page,
> +	.dma_supported = xen_swiotlb_dma_supported,
> +};
> +
> +int __init xen_mm_init(void)
> +{
> +	xen_swiotlb_init(1, true);
> +	dma_ops = &xen_swiotlb_dma_ops;
> +	return 0;
> +}
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 9737e97..aa1f6fb 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -209,6 +209,7 @@ config XEN_DOM0
>  config XEN
>  	bool "Xen guest support on ARM64 (EXPERIMENTAL)"
>  	depends on ARM64 && OF
> +	select SWIOTLB_XEN
>  	help
>  	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
>  
> diff --git a/arch/arm64/xen/Makefile b/arch/arm64/xen/Makefile
> index be24040..0ef9637 100644
> --- a/arch/arm64/xen/Makefile
> +++ b/arch/arm64/xen/Makefile
> @@ -1,2 +1,2 @@
> -xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o)
> +xen-arm-y	+= $(addprefix ../../arm/xen/, enlighten.o grant-table.o mm.o)
>  obj-y		:= xen-arm.o hypercall.o
> diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
> index 9e02d60..7e83688 100644
> --- a/drivers/xen/Kconfig
> +++ b/drivers/xen/Kconfig
> @@ -140,7 +140,6 @@ config XEN_GRANT_DEV_ALLOC
>  
>  config SWIOTLB_XEN
>  	def_bool y
> -	depends on PCI && X86
>  	select SWIOTLB
>  
>  config XEN_TMEM
> diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> index c79ac88..4ae6cf6 100644
> --- a/drivers/xen/swiotlb-xen.c
> +++ b/drivers/xen/swiotlb-xen.c
> @@ -59,6 +59,24 @@ static unsigned long xen_io_tlb_nslabs;
>   * Quick lookup value of the bus address of the IOTLB.
>   */
>  
> +#ifndef DMA_ERROR_CODE
> +#define DMA_ERROR_CODE	(~0)
> +#endif
> +
> +#ifndef CONFIG_X86
> +static unsigned long dma_alloc_coherent_mask(struct device *dev,
> +					    gfp_t gfp)
> +{
> +	unsigned long dma_mask = 0;
> +
> +	dma_mask = dev->coherent_dma_mask;
> +	if (!dma_mask)
> +		dma_mask = (gfp & GFP_DMA) ? DMA_BIT_MASK(24) : DMA_BIT_MASK(32);
> +
> +	return dma_mask;
> +}
> +#endif
> +
>  struct xen_dma{
>  	dma_addr_t dma_addr;
>  	phys_addr_t phys_addr;
> -- 
> 1.7.2.5
> 

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

* Re: [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
  2013-08-02 12:37     ` Konrad Rzeszutek Wilk
  (?)
@ 2013-08-02 16:12       ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 16:12 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	Ian.Campbell, david.vrabel

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Wed, Jul 31, 2013 at 06:45:31PM +0100, Stefano Stabellini wrote:
> > Support autotranslate guests in swiotlb-xen by keeping track of the
> > phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> > (xen_io_tlb_start-xen_io_tlb_end).
> > 
> > Use a simple direct access on a pre-allocated array for phys-to-bus
> > queries. Use a red-black tree for bus-to-phys queries.
> > 
> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > CC: david.vrabel@citrix.com
> > ---
> >  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
> >  1 files changed, 111 insertions(+), 16 deletions(-)
> > 
> > diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> > index 353f013..c79ac88 100644
> > --- a/drivers/xen/swiotlb-xen.c
> > +++ b/drivers/xen/swiotlb-xen.c
> > @@ -38,32 +38,116 @@
> >  #include <linux/bootmem.h>
> >  #include <linux/dma-mapping.h>
> >  #include <linux/export.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock_types.h>
> > +#include <linux/rbtree.h>
> >  #include <xen/swiotlb-xen.h>
> >  #include <xen/page.h>
> >  #include <xen/xen-ops.h>
> >  #include <xen/hvc-console.h>
> > +#include <xen/features.h>
> >  /*
> >   * Used to do a quick range check in swiotlb_tbl_unmap_single and
> >   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
> >   * API.
> >   */
> >  
> > +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
> >  static char *xen_io_tlb_start, *xen_io_tlb_end;
> >  static unsigned long xen_io_tlb_nslabs;
> >  /*
> >   * Quick lookup value of the bus address of the IOTLB.
> >   */
> >  
> > -static u64 start_dma_addr;
> > +struct xen_dma{
>                  ^
> Ahem! I think scripts/checkpath.pl would tell you about.
> 
> You did run checkpath.pl right :-)
> 
> The name is very generic. Xen DMA. Brings a lot of ideas around but none
> of them to do with tracking a tuple. Perhaps a name of 'xen_dma_entry'?
> 'xen_dma_node' ? 'xen_dma_info' ?

Thanks for the detailed review. I have made this and all the other
changes that you mentioned, except the ones commented below.


> > +	spin_lock(&xen_dma_lock);
> > +
> > +	while (n) {
> > +		e = rb_entry(n, struct xen_dma, rbnode);
> > +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
> 
> Shouldn't this check be for '==' not '<=' ?

Nope: e->dma_addr is the start address of one of the contiguous chucks of
memory of size (IO_TLB_SEGSIZE << IO_TLB_SHIFT). However
xen_swiotlb_map_page can be called asking for a smaller buffer. As a
result xen_phys_to_bus is going to be called passing dma addresses that
do not always match the beginning of a contiguous region.


> Hm, maybe I am not sure what this tree is suppose to do. Somehow I
> thought it was to keep a consistent mapping of phys and dma addresses.
> But this seems to be more of 'free' phys and dma addresses. In which
> case I think you need to change the name of the rb root node to have the
> word 'free' in it.

It keeps track of the bus to phys mappings.  It doesn't matter whether
the corresponding buffers are free or in use as long as the mapping is
valid.


> > +
> > +	offset = vaddr - xen_io_tlb_start;
> > +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> > +
> > +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> >  }
> >  
> >  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
> >  {
> > -	return machine_to_phys(XMADDR(baddr)).paddr;
> > +	if (xen_feature(XENFEAT_auto_translated_physmap))
> 
> I am curios to how this will work with PVH x86 which is
> auto_translated_physmap, but maps the whole kernel in its IOMMU context.
> 
> Perhaps we should have some extra logic here? For guests that have IOMMU
> support and for those that don't?

I would avoid using the swiotlb altogether if an IOMMU is available.
Maybe we can pass a flag in xen_features.


> B/c in some way this could be used on x86 with VT-x + without an VT-d
> and PVH for dom0 I think.

Right, it could be a good fit for that.
We could spot whether Xen passes a certain flag in xen_features and
enable the swiotlb if we need it.


> > +		else
> > +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> > +	} else
> > +		return machine_to_phys(XMADDR(baddr)).paddr;
> >  }
> >  
> >  static dma_addr_t xen_virt_to_bus(void *address)
> > @@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
> >  	unsigned long pfn = mfn_to_local_pfn(mfn);
> >  	phys_addr_t paddr;
> >  
> > +	if (xen_feature(XENFEAT_auto_translated_physmap))
> > +		return 1;
> > +
> 
> That does not look right to me. I think this would make PVH go bonk.

On PVH if an IOMMU is available we would never initialize the swiotlb
and we would never use this function.
If no IOMMUs are available and we initialized the swiotlb, then this
assumption is correct: all contiguous buffers used with
xen_swiotlb_sync_single and xen_unmap_single are swiotlb bounce buffers.


> > @@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
> >  	 * we can safely return the device addr and not worry about bounce
> >  	 * buffering it.
> >  	 */
> > -	if (dma_capable(dev, dev_addr, size) &&
> > +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> > +	    dma_capable(dev, dev_addr, size) &&
> >  	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
> >  		return dev_addr;
> 
> I am returning back to PVH on these and just not sure what the impact
> is. Mukesh, thoughts?

Same as before: any dma_capable and range_straddles_page_boundary checks
on a random buffer are meaningless for XENFEAT_auto_translated_physmap
guests (we don't know the p2m mapping of a given page and that mapping
might be transient).
It's best to avoid them altogether and take the slow path.

It should have no impact for PVH today though: PVH guests should just
assume that an IOMMU is present and avoid initializing the swiotlb for
now.  If we want to give them a backup option in case no IOMMU is
available, then we can come back to this later.


> >  	/*
> >  	 * Oh well, have to allocate and map a bounce buffer.
> >  	 */
> > -	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
> > +	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);
> 
> At 0? Not some index?

Right, I agree with you, I doesn't make sense to me either.
However the code does exactly the same thing that was done before. It's
just a naming change.


> >  	if (map == SWIOTLB_MAP_ERROR)
> >  		return DMA_ERROR_CODE;
> >  
> > @@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
> >  		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
> >  
> >  		if (swiotlb_force ||
> > +		    xen_feature(XENFEAT_auto_translated_physmap) ||
> >  		    !dma_capable(hwdev, dev_addr, sg->length) ||
> >  		    range_straddles_page_boundary(paddr, sg->length)) {
> >  			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
> > -								 start_dma_addr,
> > +								 xen_dma_seg[0].dma_addr,
> 
> I am not sure I understand the purpose of 'xen_dma_seg'. Could you
> clarify that please?

xen_dma_seg is an array of struct xen_dma that keeps track of the phys
to bus mappings. Each entry is (IO_TLB_SEGSIZE << IO_TLB_SHIFT) bytes,
except for the last one that could be smaller. Getting the dma address
corresponding to a physical address within xen_io_tlb_start -
xen_io_tlb_end is just a matter of calculating the index in the array,
see xen_phys_to_bus.

Also the bus_to_phys tree is conveniently built upon these pre-allocated
xen_dma_seg entries.

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

* [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
@ 2013-08-02 16:12       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 16:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Wed, Jul 31, 2013 at 06:45:31PM +0100, Stefano Stabellini wrote:
> > Support autotranslate guests in swiotlb-xen by keeping track of the
> > phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> > (xen_io_tlb_start-xen_io_tlb_end).
> > 
> > Use a simple direct access on a pre-allocated array for phys-to-bus
> > queries. Use a red-black tree for bus-to-phys queries.
> > 
> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > CC: david.vrabel at citrix.com
> > ---
> >  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
> >  1 files changed, 111 insertions(+), 16 deletions(-)
> > 
> > diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> > index 353f013..c79ac88 100644
> > --- a/drivers/xen/swiotlb-xen.c
> > +++ b/drivers/xen/swiotlb-xen.c
> > @@ -38,32 +38,116 @@
> >  #include <linux/bootmem.h>
> >  #include <linux/dma-mapping.h>
> >  #include <linux/export.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock_types.h>
> > +#include <linux/rbtree.h>
> >  #include <xen/swiotlb-xen.h>
> >  #include <xen/page.h>
> >  #include <xen/xen-ops.h>
> >  #include <xen/hvc-console.h>
> > +#include <xen/features.h>
> >  /*
> >   * Used to do a quick range check in swiotlb_tbl_unmap_single and
> >   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
> >   * API.
> >   */
> >  
> > +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
> >  static char *xen_io_tlb_start, *xen_io_tlb_end;
> >  static unsigned long xen_io_tlb_nslabs;
> >  /*
> >   * Quick lookup value of the bus address of the IOTLB.
> >   */
> >  
> > -static u64 start_dma_addr;
> > +struct xen_dma{
>                  ^
> Ahem! I think scripts/checkpath.pl would tell you about.
> 
> You did run checkpath.pl right :-)
> 
> The name is very generic. Xen DMA. Brings a lot of ideas around but none
> of them to do with tracking a tuple. Perhaps a name of 'xen_dma_entry'?
> 'xen_dma_node' ? 'xen_dma_info' ?

Thanks for the detailed review. I have made this and all the other
changes that you mentioned, except the ones commented below.


> > +	spin_lock(&xen_dma_lock);
> > +
> > +	while (n) {
> > +		e = rb_entry(n, struct xen_dma, rbnode);
> > +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
> 
> Shouldn't this check be for '==' not '<=' ?

Nope: e->dma_addr is the start address of one of the contiguous chucks of
memory of size (IO_TLB_SEGSIZE << IO_TLB_SHIFT). However
xen_swiotlb_map_page can be called asking for a smaller buffer. As a
result xen_phys_to_bus is going to be called passing dma addresses that
do not always match the beginning of a contiguous region.


> Hm, maybe I am not sure what this tree is suppose to do. Somehow I
> thought it was to keep a consistent mapping of phys and dma addresses.
> But this seems to be more of 'free' phys and dma addresses. In which
> case I think you need to change the name of the rb root node to have the
> word 'free' in it.

It keeps track of the bus to phys mappings.  It doesn't matter whether
the corresponding buffers are free or in use as long as the mapping is
valid.


> > +
> > +	offset = vaddr - xen_io_tlb_start;
> > +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> > +
> > +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> >  }
> >  
> >  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
> >  {
> > -	return machine_to_phys(XMADDR(baddr)).paddr;
> > +	if (xen_feature(XENFEAT_auto_translated_physmap))
> 
> I am curios to how this will work with PVH x86 which is
> auto_translated_physmap, but maps the whole kernel in its IOMMU context.
> 
> Perhaps we should have some extra logic here? For guests that have IOMMU
> support and for those that don't?

I would avoid using the swiotlb altogether if an IOMMU is available.
Maybe we can pass a flag in xen_features.


> B/c in some way this could be used on x86 with VT-x + without an VT-d
> and PVH for dom0 I think.

Right, it could be a good fit for that.
We could spot whether Xen passes a certain flag in xen_features and
enable the swiotlb if we need it.


> > +		else
> > +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> > +	} else
> > +		return machine_to_phys(XMADDR(baddr)).paddr;
> >  }
> >  
> >  static dma_addr_t xen_virt_to_bus(void *address)
> > @@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
> >  	unsigned long pfn = mfn_to_local_pfn(mfn);
> >  	phys_addr_t paddr;
> >  
> > +	if (xen_feature(XENFEAT_auto_translated_physmap))
> > +		return 1;
> > +
> 
> That does not look right to me. I think this would make PVH go bonk.

On PVH if an IOMMU is available we would never initialize the swiotlb
and we would never use this function.
If no IOMMUs are available and we initialized the swiotlb, then this
assumption is correct: all contiguous buffers used with
xen_swiotlb_sync_single and xen_unmap_single are swiotlb bounce buffers.


> > @@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
> >  	 * we can safely return the device addr and not worry about bounce
> >  	 * buffering it.
> >  	 */
> > -	if (dma_capable(dev, dev_addr, size) &&
> > +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> > +	    dma_capable(dev, dev_addr, size) &&
> >  	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
> >  		return dev_addr;
> 
> I am returning back to PVH on these and just not sure what the impact
> is. Mukesh, thoughts?

Same as before: any dma_capable and range_straddles_page_boundary checks
on a random buffer are meaningless for XENFEAT_auto_translated_physmap
guests (we don't know the p2m mapping of a given page and that mapping
might be transient).
It's best to avoid them altogether and take the slow path.

It should have no impact for PVH today though: PVH guests should just
assume that an IOMMU is present and avoid initializing the swiotlb for
now.  If we want to give them a backup option in case no IOMMU is
available, then we can come back to this later.


> >  	/*
> >  	 * Oh well, have to allocate and map a bounce buffer.
> >  	 */
> > -	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
> > +	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);
> 
> At 0? Not some index?

Right, I agree with you, I doesn't make sense to me either.
However the code does exactly the same thing that was done before. It's
just a naming change.


> >  	if (map == SWIOTLB_MAP_ERROR)
> >  		return DMA_ERROR_CODE;
> >  
> > @@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
> >  		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
> >  
> >  		if (swiotlb_force ||
> > +		    xen_feature(XENFEAT_auto_translated_physmap) ||
> >  		    !dma_capable(hwdev, dev_addr, sg->length) ||
> >  		    range_straddles_page_boundary(paddr, sg->length)) {
> >  			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
> > -								 start_dma_addr,
> > +								 xen_dma_seg[0].dma_addr,
> 
> I am not sure I understand the purpose of 'xen_dma_seg'. Could you
> clarify that please?

xen_dma_seg is an array of struct xen_dma that keeps track of the phys
to bus mappings. Each entry is (IO_TLB_SEGSIZE << IO_TLB_SHIFT) bytes,
except for the last one that could be smaller. Getting the dma address
corresponding to a physical address within xen_io_tlb_start -
xen_io_tlb_end is just a matter of calculating the index in the array,
see xen_phys_to_bus.

Also the bus_to_phys tree is conveniently built upon these pre-allocated
xen_dma_seg entries.

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

* Re: [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests
@ 2013-08-02 16:12       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 16:12 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: xen-devel, Ian.Campbell, Stefano Stabellini, linux-kernel,
	david.vrabel, linux-arm-kernel

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Wed, Jul 31, 2013 at 06:45:31PM +0100, Stefano Stabellini wrote:
> > Support autotranslate guests in swiotlb-xen by keeping track of the
> > phys-to-bus and bus-to-phys mappings of the swiotlb buffer
> > (xen_io_tlb_start-xen_io_tlb_end).
> > 
> > Use a simple direct access on a pre-allocated array for phys-to-bus
> > queries. Use a red-black tree for bus-to-phys queries.
> > 
> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > CC: david.vrabel@citrix.com
> > ---
> >  drivers/xen/swiotlb-xen.c |  127 +++++++++++++++++++++++++++++++++++++++------
> >  1 files changed, 111 insertions(+), 16 deletions(-)
> > 
> > diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
> > index 353f013..c79ac88 100644
> > --- a/drivers/xen/swiotlb-xen.c
> > +++ b/drivers/xen/swiotlb-xen.c
> > @@ -38,32 +38,116 @@
> >  #include <linux/bootmem.h>
> >  #include <linux/dma-mapping.h>
> >  #include <linux/export.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock_types.h>
> > +#include <linux/rbtree.h>
> >  #include <xen/swiotlb-xen.h>
> >  #include <xen/page.h>
> >  #include <xen/xen-ops.h>
> >  #include <xen/hvc-console.h>
> > +#include <xen/features.h>
> >  /*
> >   * Used to do a quick range check in swiotlb_tbl_unmap_single and
> >   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
> >   * API.
> >   */
> >  
> > +#define NR_DMA_SEGS  ((xen_io_tlb_nslabs + IO_TLB_SEGSIZE - 1) / IO_TLB_SEGSIZE)
> >  static char *xen_io_tlb_start, *xen_io_tlb_end;
> >  static unsigned long xen_io_tlb_nslabs;
> >  /*
> >   * Quick lookup value of the bus address of the IOTLB.
> >   */
> >  
> > -static u64 start_dma_addr;
> > +struct xen_dma{
>                  ^
> Ahem! I think scripts/checkpath.pl would tell you about.
> 
> You did run checkpath.pl right :-)
> 
> The name is very generic. Xen DMA. Brings a lot of ideas around but none
> of them to do with tracking a tuple. Perhaps a name of 'xen_dma_entry'?
> 'xen_dma_node' ? 'xen_dma_info' ?

Thanks for the detailed review. I have made this and all the other
changes that you mentioned, except the ones commented below.


> > +	spin_lock(&xen_dma_lock);
> > +
> > +	while (n) {
> > +		e = rb_entry(n, struct xen_dma, rbnode);
> > +		if (e->dma_addr <= dma_addr && e->dma_addr + e->size > dma_addr) {
> 
> Shouldn't this check be for '==' not '<=' ?

Nope: e->dma_addr is the start address of one of the contiguous chucks of
memory of size (IO_TLB_SEGSIZE << IO_TLB_SHIFT). However
xen_swiotlb_map_page can be called asking for a smaller buffer. As a
result xen_phys_to_bus is going to be called passing dma addresses that
do not always match the beginning of a contiguous region.


> Hm, maybe I am not sure what this tree is suppose to do. Somehow I
> thought it was to keep a consistent mapping of phys and dma addresses.
> But this seems to be more of 'free' phys and dma addresses. In which
> case I think you need to change the name of the rb root node to have the
> word 'free' in it.

It keeps track of the bus to phys mappings.  It doesn't matter whether
the corresponding buffers are free or in use as long as the mapping is
valid.


> > +
> > +	offset = vaddr - xen_io_tlb_start;
> > +	nr_seg = offset / (IO_TLB_SEGSIZE << IO_TLB_SHIFT);
> > +
> > +	return xen_dma_seg[nr_seg].dma_addr + (paddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> >  }
> >  
> >  static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
> >  {
> > -	return machine_to_phys(XMADDR(baddr)).paddr;
> > +	if (xen_feature(XENFEAT_auto_translated_physmap))
> 
> I am curios to how this will work with PVH x86 which is
> auto_translated_physmap, but maps the whole kernel in its IOMMU context.
> 
> Perhaps we should have some extra logic here? For guests that have IOMMU
> support and for those that don't?

I would avoid using the swiotlb altogether if an IOMMU is available.
Maybe we can pass a flag in xen_features.


> B/c in some way this could be used on x86 with VT-x + without an VT-d
> and PVH for dom0 I think.

Right, it could be a good fit for that.
We could spot whether Xen passes a certain flag in xen_features and
enable the swiotlb if we need it.


> > +		else
> > +			return dma->phys_addr + (baddr & ((IO_TLB_SEGSIZE << IO_TLB_SHIFT) - 1));
> > +	} else
> > +		return machine_to_phys(XMADDR(baddr)).paddr;
> >  }
> >  
> >  static dma_addr_t xen_virt_to_bus(void *address)
> > @@ -107,6 +191,9 @@ static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
> >  	unsigned long pfn = mfn_to_local_pfn(mfn);
> >  	phys_addr_t paddr;
> >  
> > +	if (xen_feature(XENFEAT_auto_translated_physmap))
> > +		return 1;
> > +
> 
> That does not look right to me. I think this would make PVH go bonk.

On PVH if an IOMMU is available we would never initialize the swiotlb
and we would never use this function.
If no IOMMUs are available and we initialized the swiotlb, then this
assumption is correct: all contiguous buffers used with
xen_swiotlb_sync_single and xen_unmap_single are swiotlb bounce buffers.


> > @@ -351,14 +444,15 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
> >  	 * we can safely return the device addr and not worry about bounce
> >  	 * buffering it.
> >  	 */
> > -	if (dma_capable(dev, dev_addr, size) &&
> > +	if (!xen_feature(XENFEAT_auto_translated_physmap) &&
> > +	    dma_capable(dev, dev_addr, size) &&
> >  	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
> >  		return dev_addr;
> 
> I am returning back to PVH on these and just not sure what the impact
> is. Mukesh, thoughts?

Same as before: any dma_capable and range_straddles_page_boundary checks
on a random buffer are meaningless for XENFEAT_auto_translated_physmap
guests (we don't know the p2m mapping of a given page and that mapping
might be transient).
It's best to avoid them altogether and take the slow path.

It should have no impact for PVH today though: PVH guests should just
assume that an IOMMU is present and avoid initializing the swiotlb for
now.  If we want to give them a backup option in case no IOMMU is
available, then we can come back to this later.


> >  	/*
> >  	 * Oh well, have to allocate and map a bounce buffer.
> >  	 */
> > -	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
> > +	map = swiotlb_tbl_map_single(dev, xen_dma_seg[0].dma_addr, phys, size, dir);
> 
> At 0? Not some index?

Right, I agree with you, I doesn't make sense to me either.
However the code does exactly the same thing that was done before. It's
just a naming change.


> >  	if (map == SWIOTLB_MAP_ERROR)
> >  		return DMA_ERROR_CODE;
> >  
> > @@ -494,10 +588,11 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
> >  		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
> >  
> >  		if (swiotlb_force ||
> > +		    xen_feature(XENFEAT_auto_translated_physmap) ||
> >  		    !dma_capable(hwdev, dev_addr, sg->length) ||
> >  		    range_straddles_page_boundary(paddr, sg->length)) {
> >  			phys_addr_t map = swiotlb_tbl_map_single(hwdev,
> > -								 start_dma_addr,
> > +								 xen_dma_seg[0].dma_addr,
> 
> I am not sure I understand the purpose of 'xen_dma_seg'. Could you
> clarify that please?

xen_dma_seg is an array of struct xen_dma that keeps track of the phys
to bus mappings. Each entry is (IO_TLB_SEGSIZE << IO_TLB_SHIFT) bytes,
except for the last one that could be smaller. Getting the dma address
corresponding to a physical address within xen_io_tlb_start -
xen_io_tlb_end is just a matter of calculating the index in the array,
see xen_phys_to_bus.

Also the bus_to_phys tree is conveniently built upon these pre-allocated
xen_dma_seg entries.

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

* Re: [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN
  2013-08-02 12:40     ` Konrad Rzeszutek Wilk
  (?)
@ 2013-08-02 16:25       ` Stefano Stabellini
  -1 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 16:25 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	Ian.Campbell

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Wed, Jul 31, 2013 at 06:45:32PM +0100, Stefano Stabellini wrote:
> > Xen on arm and arm64 needs SWIOTLB_XEN: when running on Xen we need to
> > program the hardware with mfns rather than pfns for dma addresses.
> > Remove SWIOTLB_XEN dependency on X86 and PCI and make XEN select
> > SWIOTLB_XEN on arm and arm64.
> > 
> > Implement xen_create_contiguous_region on arm and arm64 by using
> > XENMEM_get_dma_buf.
> > 
> > Initialize the xen-swiotlb from xen_early_init (before the native
> > dma_ops are initialized), set dma_ops to &xen_swiotlb_dma_ops if we are
> > running on Xen.
> > 
> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > ---
> >  arch/arm/Kconfig                |    1 +
> >  arch/arm/include/asm/xen/page.h |    2 +
> >  arch/arm/xen/Makefile           |    2 +-
> >  arch/arm/xen/enlighten.c        |    3 +
> >  arch/arm/xen/mm.c               |  118 +++++++++++++++++++++++++++++++++++++++
> >  arch/arm64/Kconfig              |    1 +
> >  arch/arm64/xen/Makefile         |    2 +-
> >  drivers/xen/Kconfig             |    1 -
> >  drivers/xen/swiotlb-xen.c       |   18 ++++++
> >  9 files changed, 145 insertions(+), 3 deletions(-)
> >  create mode 100644 arch/arm/xen/mm.c
> > 
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 05125ab..72b53b9 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -1849,6 +1849,7 @@ config XEN
> >  	depends on CPU_V7 && !CPU_V6
> >  	depends on !GENERIC_ATOMIC64
> >  	select ARM_PSCI
> > +	select SWIOTLB_XEN
> >  	help
> >  	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
> >  
> > diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
> > index 359a7b5..b0f7150 100644
> > --- a/arch/arm/include/asm/xen/page.h
> > +++ b/arch/arm/include/asm/xen/page.h
> > @@ -6,12 +6,14 @@
> >  
> >  #include <linux/pfn.h>
> >  #include <linux/types.h>
> > +#include <linux/dma-mapping.h>
> >  
> >  #include <xen/interface/grant_table.h>
> >  
> >  #define pfn_to_mfn(pfn)			(pfn)
> >  #define phys_to_machine_mapping_valid(pfn) (1)
> >  #define mfn_to_pfn(mfn)			(mfn)
> > +#define mfn_to_local_pfn(m)             (mfn_to_pfn(m))
> >  #define mfn_to_virt(m)			(__va(mfn_to_pfn(m) << PAGE_SHIFT))
> >  
> >  #define pte_mfn	    pte_pfn
> > diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
> > index 4384103..66fc35d 100644
> > --- a/arch/arm/xen/Makefile
> > +++ b/arch/arm/xen/Makefile
> > @@ -1 +1 @@
> > -obj-y		:= enlighten.o hypercall.o grant-table.o
> > +obj-y		:= enlighten.o hypercall.o grant-table.o mm.o
> > diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
> > index 14d17ab..06a6953 100644
> > --- a/arch/arm/xen/enlighten.c
> > +++ b/arch/arm/xen/enlighten.c
> > @@ -195,6 +195,7 @@ static void xen_power_off(void)
> >   * documentation of the Xen Device Tree format.
> >   */
> >  #define GRANT_TABLE_PHYSADDR 0
> > +extern int xen_mm_init(void);
> >  void __init xen_early_init(void)
> >  {
> >  	struct resource res;
> > @@ -230,6 +231,8 @@ void __init xen_early_init(void)
> >  		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
> >  	else
> >  		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
> > +
> > +	xen_mm_init();
> >  }
> >  
> >  static int __init xen_guest_init(void)
> > diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c
> > new file mode 100644
> > index 0000000..4ba1add
> > --- /dev/null
> > +++ b/arch/arm/xen/mm.c
> > @@ -0,0 +1,118 @@
> > +#include <linux/bootmem.h>
> > +#include <linux/gfp.h>
> > +#include <linux/export.h>
> > +#include <linux/slab.h>
> > +#include <linux/types.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/vmalloc.h>
> > +#include <linux/swiotlb.h>
> > +
> > +#include <xen/xen.h>
> > +#include <xen/interface/memory.h>
> > +#include <xen/swiotlb-xen.h>
> > +
> > +#include <asm/cacheflush.h>
> > +#include <asm/xen/page.h>
> > +#include <asm/xen/hypercall.h>
> > +#include <asm/xen/interface.h>
> > +
> > +static int xen_exchange_memory(xen_ulong_t extents_in,
> > +			       unsigned int order_in,
> > +			       xen_pfn_t *pfns_in,
> > +			       xen_ulong_t extents_out,
> > +			       unsigned int order_out,
> > +			       xen_pfn_t *mfns_out,
> > +			       unsigned int address_bits)
> > +{
> > +	long rc;
> > +	int success;
> > +
> > +	struct xen_memory_exchange exchange = {
> > +		.in = {
> > +			.nr_extents   = extents_in,
> > +			.extent_order = order_in,
> > +			.domid        = DOMID_SELF
> > +		},
> > +		.out = {
> > +			.nr_extents   = extents_out,
> > +			.extent_order = order_out,
> > +			.address_bits = address_bits,
> > +			.domid        = DOMID_SELF
> > +		}
> > +	};
> > +	set_xen_guest_handle(exchange.in.extent_start, pfns_in);
> > +	set_xen_guest_handle(exchange.out.extent_start, mfns_out);
> > +
> > +	BUG_ON(extents_in << order_in != extents_out << order_out);
> > +
> > +
> > +	rc = HYPERVISOR_memory_op(XENMEM_get_dma_buf, &exchange);
> > +	success = (exchange.nr_exchanged == extents_in);
> > +
> > +	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
> > +	BUG_ON(success && (rc != 0));
> > +
> > +	return success;
> > +}
> 
> Could this code be made out to be more generic? It is almost the same on
> x86 - it just a different hypercall.

Maybe, but I wasn't planning on implementing XENMEM_get_dma_buf on x86
(guest_physmap_pin_range and guest_physmap_unpin_range in particular),
mostly because I admit I don't quite understand the x86 page_type system
in Xen.

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

* [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN
@ 2013-08-02 16:25       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 16:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Wed, Jul 31, 2013 at 06:45:32PM +0100, Stefano Stabellini wrote:
> > Xen on arm and arm64 needs SWIOTLB_XEN: when running on Xen we need to
> > program the hardware with mfns rather than pfns for dma addresses.
> > Remove SWIOTLB_XEN dependency on X86 and PCI and make XEN select
> > SWIOTLB_XEN on arm and arm64.
> > 
> > Implement xen_create_contiguous_region on arm and arm64 by using
> > XENMEM_get_dma_buf.
> > 
> > Initialize the xen-swiotlb from xen_early_init (before the native
> > dma_ops are initialized), set dma_ops to &xen_swiotlb_dma_ops if we are
> > running on Xen.
> > 
> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > ---
> >  arch/arm/Kconfig                |    1 +
> >  arch/arm/include/asm/xen/page.h |    2 +
> >  arch/arm/xen/Makefile           |    2 +-
> >  arch/arm/xen/enlighten.c        |    3 +
> >  arch/arm/xen/mm.c               |  118 +++++++++++++++++++++++++++++++++++++++
> >  arch/arm64/Kconfig              |    1 +
> >  arch/arm64/xen/Makefile         |    2 +-
> >  drivers/xen/Kconfig             |    1 -
> >  drivers/xen/swiotlb-xen.c       |   18 ++++++
> >  9 files changed, 145 insertions(+), 3 deletions(-)
> >  create mode 100644 arch/arm/xen/mm.c
> > 
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 05125ab..72b53b9 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -1849,6 +1849,7 @@ config XEN
> >  	depends on CPU_V7 && !CPU_V6
> >  	depends on !GENERIC_ATOMIC64
> >  	select ARM_PSCI
> > +	select SWIOTLB_XEN
> >  	help
> >  	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
> >  
> > diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
> > index 359a7b5..b0f7150 100644
> > --- a/arch/arm/include/asm/xen/page.h
> > +++ b/arch/arm/include/asm/xen/page.h
> > @@ -6,12 +6,14 @@
> >  
> >  #include <linux/pfn.h>
> >  #include <linux/types.h>
> > +#include <linux/dma-mapping.h>
> >  
> >  #include <xen/interface/grant_table.h>
> >  
> >  #define pfn_to_mfn(pfn)			(pfn)
> >  #define phys_to_machine_mapping_valid(pfn) (1)
> >  #define mfn_to_pfn(mfn)			(mfn)
> > +#define mfn_to_local_pfn(m)             (mfn_to_pfn(m))
> >  #define mfn_to_virt(m)			(__va(mfn_to_pfn(m) << PAGE_SHIFT))
> >  
> >  #define pte_mfn	    pte_pfn
> > diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
> > index 4384103..66fc35d 100644
> > --- a/arch/arm/xen/Makefile
> > +++ b/arch/arm/xen/Makefile
> > @@ -1 +1 @@
> > -obj-y		:= enlighten.o hypercall.o grant-table.o
> > +obj-y		:= enlighten.o hypercall.o grant-table.o mm.o
> > diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
> > index 14d17ab..06a6953 100644
> > --- a/arch/arm/xen/enlighten.c
> > +++ b/arch/arm/xen/enlighten.c
> > @@ -195,6 +195,7 @@ static void xen_power_off(void)
> >   * documentation of the Xen Device Tree format.
> >   */
> >  #define GRANT_TABLE_PHYSADDR 0
> > +extern int xen_mm_init(void);
> >  void __init xen_early_init(void)
> >  {
> >  	struct resource res;
> > @@ -230,6 +231,8 @@ void __init xen_early_init(void)
> >  		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
> >  	else
> >  		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
> > +
> > +	xen_mm_init();
> >  }
> >  
> >  static int __init xen_guest_init(void)
> > diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c
> > new file mode 100644
> > index 0000000..4ba1add
> > --- /dev/null
> > +++ b/arch/arm/xen/mm.c
> > @@ -0,0 +1,118 @@
> > +#include <linux/bootmem.h>
> > +#include <linux/gfp.h>
> > +#include <linux/export.h>
> > +#include <linux/slab.h>
> > +#include <linux/types.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/vmalloc.h>
> > +#include <linux/swiotlb.h>
> > +
> > +#include <xen/xen.h>
> > +#include <xen/interface/memory.h>
> > +#include <xen/swiotlb-xen.h>
> > +
> > +#include <asm/cacheflush.h>
> > +#include <asm/xen/page.h>
> > +#include <asm/xen/hypercall.h>
> > +#include <asm/xen/interface.h>
> > +
> > +static int xen_exchange_memory(xen_ulong_t extents_in,
> > +			       unsigned int order_in,
> > +			       xen_pfn_t *pfns_in,
> > +			       xen_ulong_t extents_out,
> > +			       unsigned int order_out,
> > +			       xen_pfn_t *mfns_out,
> > +			       unsigned int address_bits)
> > +{
> > +	long rc;
> > +	int success;
> > +
> > +	struct xen_memory_exchange exchange = {
> > +		.in = {
> > +			.nr_extents   = extents_in,
> > +			.extent_order = order_in,
> > +			.domid        = DOMID_SELF
> > +		},
> > +		.out = {
> > +			.nr_extents   = extents_out,
> > +			.extent_order = order_out,
> > +			.address_bits = address_bits,
> > +			.domid        = DOMID_SELF
> > +		}
> > +	};
> > +	set_xen_guest_handle(exchange.in.extent_start, pfns_in);
> > +	set_xen_guest_handle(exchange.out.extent_start, mfns_out);
> > +
> > +	BUG_ON(extents_in << order_in != extents_out << order_out);
> > +
> > +
> > +	rc = HYPERVISOR_memory_op(XENMEM_get_dma_buf, &exchange);
> > +	success = (exchange.nr_exchanged == extents_in);
> > +
> > +	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
> > +	BUG_ON(success && (rc != 0));
> > +
> > +	return success;
> > +}
> 
> Could this code be made out to be more generic? It is almost the same on
> x86 - it just a different hypercall.

Maybe, but I wasn't planning on implementing XENMEM_get_dma_buf on x86
(guest_physmap_pin_range and guest_physmap_unpin_range in particular),
mostly because I admit I don't quite understand the x86 page_type system
in Xen.

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

* Re: [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN
@ 2013-08-02 16:25       ` Stefano Stabellini
  0 siblings, 0 replies; 73+ messages in thread
From: Stefano Stabellini @ 2013-08-02 16:25 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Stefano Stabellini, xen-devel, linux-kernel, linux-arm-kernel,
	Ian.Campbell

On Fri, 2 Aug 2013, Konrad Rzeszutek Wilk wrote:
> On Wed, Jul 31, 2013 at 06:45:32PM +0100, Stefano Stabellini wrote:
> > Xen on arm and arm64 needs SWIOTLB_XEN: when running on Xen we need to
> > program the hardware with mfns rather than pfns for dma addresses.
> > Remove SWIOTLB_XEN dependency on X86 and PCI and make XEN select
> > SWIOTLB_XEN on arm and arm64.
> > 
> > Implement xen_create_contiguous_region on arm and arm64 by using
> > XENMEM_get_dma_buf.
> > 
> > Initialize the xen-swiotlb from xen_early_init (before the native
> > dma_ops are initialized), set dma_ops to &xen_swiotlb_dma_ops if we are
> > running on Xen.
> > 
> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > ---
> >  arch/arm/Kconfig                |    1 +
> >  arch/arm/include/asm/xen/page.h |    2 +
> >  arch/arm/xen/Makefile           |    2 +-
> >  arch/arm/xen/enlighten.c        |    3 +
> >  arch/arm/xen/mm.c               |  118 +++++++++++++++++++++++++++++++++++++++
> >  arch/arm64/Kconfig              |    1 +
> >  arch/arm64/xen/Makefile         |    2 +-
> >  drivers/xen/Kconfig             |    1 -
> >  drivers/xen/swiotlb-xen.c       |   18 ++++++
> >  9 files changed, 145 insertions(+), 3 deletions(-)
> >  create mode 100644 arch/arm/xen/mm.c
> > 
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 05125ab..72b53b9 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -1849,6 +1849,7 @@ config XEN
> >  	depends on CPU_V7 && !CPU_V6
> >  	depends on !GENERIC_ATOMIC64
> >  	select ARM_PSCI
> > +	select SWIOTLB_XEN
> >  	help
> >  	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
> >  
> > diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
> > index 359a7b5..b0f7150 100644
> > --- a/arch/arm/include/asm/xen/page.h
> > +++ b/arch/arm/include/asm/xen/page.h
> > @@ -6,12 +6,14 @@
> >  
> >  #include <linux/pfn.h>
> >  #include <linux/types.h>
> > +#include <linux/dma-mapping.h>
> >  
> >  #include <xen/interface/grant_table.h>
> >  
> >  #define pfn_to_mfn(pfn)			(pfn)
> >  #define phys_to_machine_mapping_valid(pfn) (1)
> >  #define mfn_to_pfn(mfn)			(mfn)
> > +#define mfn_to_local_pfn(m)             (mfn_to_pfn(m))
> >  #define mfn_to_virt(m)			(__va(mfn_to_pfn(m) << PAGE_SHIFT))
> >  
> >  #define pte_mfn	    pte_pfn
> > diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
> > index 4384103..66fc35d 100644
> > --- a/arch/arm/xen/Makefile
> > +++ b/arch/arm/xen/Makefile
> > @@ -1 +1 @@
> > -obj-y		:= enlighten.o hypercall.o grant-table.o
> > +obj-y		:= enlighten.o hypercall.o grant-table.o mm.o
> > diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
> > index 14d17ab..06a6953 100644
> > --- a/arch/arm/xen/enlighten.c
> > +++ b/arch/arm/xen/enlighten.c
> > @@ -195,6 +195,7 @@ static void xen_power_off(void)
> >   * documentation of the Xen Device Tree format.
> >   */
> >  #define GRANT_TABLE_PHYSADDR 0
> > +extern int xen_mm_init(void);
> >  void __init xen_early_init(void)
> >  {
> >  	struct resource res;
> > @@ -230,6 +231,8 @@ void __init xen_early_init(void)
> >  		xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
> >  	else
> >  		xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
> > +
> > +	xen_mm_init();
> >  }
> >  
> >  static int __init xen_guest_init(void)
> > diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c
> > new file mode 100644
> > index 0000000..4ba1add
> > --- /dev/null
> > +++ b/arch/arm/xen/mm.c
> > @@ -0,0 +1,118 @@
> > +#include <linux/bootmem.h>
> > +#include <linux/gfp.h>
> > +#include <linux/export.h>
> > +#include <linux/slab.h>
> > +#include <linux/types.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/vmalloc.h>
> > +#include <linux/swiotlb.h>
> > +
> > +#include <xen/xen.h>
> > +#include <xen/interface/memory.h>
> > +#include <xen/swiotlb-xen.h>
> > +
> > +#include <asm/cacheflush.h>
> > +#include <asm/xen/page.h>
> > +#include <asm/xen/hypercall.h>
> > +#include <asm/xen/interface.h>
> > +
> > +static int xen_exchange_memory(xen_ulong_t extents_in,
> > +			       unsigned int order_in,
> > +			       xen_pfn_t *pfns_in,
> > +			       xen_ulong_t extents_out,
> > +			       unsigned int order_out,
> > +			       xen_pfn_t *mfns_out,
> > +			       unsigned int address_bits)
> > +{
> > +	long rc;
> > +	int success;
> > +
> > +	struct xen_memory_exchange exchange = {
> > +		.in = {
> > +			.nr_extents   = extents_in,
> > +			.extent_order = order_in,
> > +			.domid        = DOMID_SELF
> > +		},
> > +		.out = {
> > +			.nr_extents   = extents_out,
> > +			.extent_order = order_out,
> > +			.address_bits = address_bits,
> > +			.domid        = DOMID_SELF
> > +		}
> > +	};
> > +	set_xen_guest_handle(exchange.in.extent_start, pfns_in);
> > +	set_xen_guest_handle(exchange.out.extent_start, mfns_out);
> > +
> > +	BUG_ON(extents_in << order_in != extents_out << order_out);
> > +
> > +
> > +	rc = HYPERVISOR_memory_op(XENMEM_get_dma_buf, &exchange);
> > +	success = (exchange.nr_exchanged == extents_in);
> > +
> > +	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
> > +	BUG_ON(success && (rc != 0));
> > +
> > +	return success;
> > +}
> 
> Could this code be made out to be more generic? It is almost the same on
> x86 - it just a different hypercall.

Maybe, but I wasn't planning on implementing XENMEM_get_dma_buf on x86
(guest_physmap_pin_range and guest_physmap_unpin_range in particular),
mostly because I admit I don't quite understand the x86 page_type system
in Xen.

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

end of thread, other threads:[~2013-08-02 16:25 UTC | newest]

Thread overview: 73+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-31 17:44 [PATCH RFC 0/8] enable swiotlb-xen on arm and arm64 Stefano Stabellini
2013-07-31 17:44 ` Stefano Stabellini
2013-07-31 17:44 ` Stefano Stabellini
2013-07-31 17:45 ` [PATCH RFC 1/8] arm: make SWIOTLB available Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-08-01  0:32   ` Konrad Rzeszutek Wilk
2013-08-01  0:32     ` Konrad Rzeszutek Wilk
2013-08-01  0:32     ` Konrad Rzeszutek Wilk
2013-08-02 11:59     ` Stefano Stabellini
2013-08-02 11:59       ` Stefano Stabellini
2013-08-02 11:59       ` Stefano Stabellini
2013-08-02 12:13       ` Konrad Rzeszutek Wilk
2013-08-02 12:13         ` Konrad Rzeszutek Wilk
2013-08-02 12:13         ` Konrad Rzeszutek Wilk
2013-08-02 12:18         ` Stefano Stabellini
2013-08-02 12:18           ` Stefano Stabellini
2013-08-02 12:18           ` Stefano Stabellini
2013-08-01 11:09   ` Russell King - ARM Linux
2013-08-01 11:09     ` Russell King - ARM Linux
2013-08-02 12:09     ` Stefano Stabellini
2013-08-02 12:09       ` Stefano Stabellini
2013-08-02 12:09       ` Stefano Stabellini
2013-07-31 17:45 ` [PATCH RFC 2/8] arm: introduce a global dma_ops pointer Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45 ` [PATCH RFC 3/8] arm64: do not initialize arm64_swiotlb if dma_ops is already set Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45 ` [PATCH RFC 4/8] xen/arm,arm64: move Xen initialization earlier Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-08-01  0:35   ` Konrad Rzeszutek Wilk
2013-08-01  0:35     ` Konrad Rzeszutek Wilk
2013-08-01  0:35     ` Konrad Rzeszutek Wilk
2013-07-31 17:45 ` [PATCH RFC 5/8] xen: introduce XENMEM_get_dma_buf and xen_put_dma_buf Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-08-01  0:36   ` Konrad Rzeszutek Wilk
2013-08-01  0:36     ` Konrad Rzeszutek Wilk
2013-08-01  0:36     ` Konrad Rzeszutek Wilk
2013-08-01 15:13     ` Stefano Stabellini
2013-08-01 15:13       ` Stefano Stabellini
2013-08-01 15:13       ` Stefano Stabellini
2013-07-31 17:45 ` [PATCH RFC 6/8] xen: make xen_create_contiguous_region return the dma address Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-08-01 11:34   ` David Vrabel
2013-08-01 11:34     ` David Vrabel
2013-08-01 11:34     ` David Vrabel
2013-07-31 17:45 ` [PATCH RFC 7/8] swiotlb-xen: support autotranslate guests Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 19:03   ` Stefano Stabellini
2013-07-31 19:03     ` Stefano Stabellini
2013-07-31 19:03     ` Stefano Stabellini
2013-08-02 12:37   ` Konrad Rzeszutek Wilk
2013-08-02 12:37     ` Konrad Rzeszutek Wilk
2013-08-02 12:37     ` Konrad Rzeszutek Wilk
2013-08-02 16:12     ` Stefano Stabellini
2013-08-02 16:12       ` Stefano Stabellini
2013-08-02 16:12       ` Stefano Stabellini
2013-07-31 17:45 ` [PATCH RFC 8/8] xen/arm,arm64: enable SWIOTLB_XEN Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-07-31 17:45   ` Stefano Stabellini
2013-08-02 12:40   ` Konrad Rzeszutek Wilk
2013-08-02 12:40     ` Konrad Rzeszutek Wilk
2013-08-02 16:25     ` Stefano Stabellini
2013-08-02 16:25       ` Stefano Stabellini
2013-08-02 16:25       ` Stefano Stabellini
2013-07-31 19:44 ` [PATCH RFC 0/8] enable swiotlb-xen on arm and arm64 Stefano Stabellini
2013-07-31 19:44   ` Stefano Stabellini
2013-07-31 19:44   ` Stefano Stabellini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.