[v4,1/6] ACPI: arm64: Move DMA setup operations out of IORT

Message ID 20210610075130.67517-2-jean-philippe@linaro.org
State Superseded
Headers show
Series
  • Add support for ACPI VIOT
Related show

Commit Message

Jean-Philippe Brucker June 10, 2021, 7:51 a.m.
Extract generic DMA setup code out of IORT, so it can be reused by VIOT.
Keep it in drivers/acpi/arm64 for now, since it could break x86
platforms that haven't run this code so far, if they have invalid
tables.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>

---
 drivers/acpi/arm64/Makefile |  1 +
 include/linux/acpi.h        |  3 +++
 include/linux/acpi_iort.h   |  6 ++---
 drivers/acpi/arm64/dma.c    | 50 ++++++++++++++++++++++++++++++++++
 drivers/acpi/arm64/iort.c   | 54 ++++++-------------------------------
 drivers/acpi/scan.c         |  2 +-
 6 files changed, 66 insertions(+), 50 deletions(-)
 create mode 100644 drivers/acpi/arm64/dma.c

-- 
2.31.1

Comments

Eric Auger June 16, 2021, 9:35 a.m. | #1
Hi jean,

On 6/10/21 9:51 AM, Jean-Philippe Brucker wrote:
> Extract generic DMA setup code out of IORT, so it can be reused by VIOT.

> Keep it in drivers/acpi/arm64 for now, since it could break x86

> platforms that haven't run this code so far, if they have invalid

> tables.

>

> Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>

Reviewed-by: Eric Auger <eric.auger@redhat.com>



Eric

> ---

>  drivers/acpi/arm64/Makefile |  1 +

>  include/linux/acpi.h        |  3 +++

>  include/linux/acpi_iort.h   |  6 ++---

>  drivers/acpi/arm64/dma.c    | 50 ++++++++++++++++++++++++++++++++++

>  drivers/acpi/arm64/iort.c   | 54 ++++++-------------------------------

>  drivers/acpi/scan.c         |  2 +-

>  6 files changed, 66 insertions(+), 50 deletions(-)

>  create mode 100644 drivers/acpi/arm64/dma.c

>

> diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile

> index 6ff50f4ed947..66acbe77f46e 100644

> --- a/drivers/acpi/arm64/Makefile

> +++ b/drivers/acpi/arm64/Makefile

> @@ -1,3 +1,4 @@

>  # SPDX-License-Identifier: GPL-2.0-only

>  obj-$(CONFIG_ACPI_IORT) 	+= iort.o

>  obj-$(CONFIG_ACPI_GTDT) 	+= gtdt.o

> +obj-y				+= dma.o

> diff --git a/include/linux/acpi.h b/include/linux/acpi.h

> index c60745f657e9..7aaa9559cc19 100644

> --- a/include/linux/acpi.h

> +++ b/include/linux/acpi.h

> @@ -259,9 +259,12 @@ void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa);

>  

>  #ifdef CONFIG_ARM64

>  void acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa);

> +void acpi_arch_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size);

>  #else

>  static inline void

>  acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa) { }

> +static inline void

> +acpi_arch_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) { }

>  #endif

>  

>  int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);

> diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h

> index 1a12baa58e40..f7f054833afd 100644

> --- a/include/linux/acpi_iort.h

> +++ b/include/linux/acpi_iort.h

> @@ -34,7 +34,7 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,

>  void acpi_configure_pmsi_domain(struct device *dev);

>  int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);

>  /* IOMMU interface */

> -void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size);

> +int iort_dma_get_ranges(struct device *dev, u64 *size);

>  const struct iommu_ops *iort_iommu_configure_id(struct device *dev,

>  						const u32 *id_in);

>  int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head);

> @@ -48,8 +48,8 @@ static inline struct irq_domain *iort_get_device_domain(

>  { return NULL; }

>  static inline void acpi_configure_pmsi_domain(struct device *dev) { }

>  /* IOMMU interface */

> -static inline void iort_dma_setup(struct device *dev, u64 *dma_addr,

> -				  u64 *size) { }

> +static inline int iort_dma_get_ranges(struct device *dev, u64 *size)

> +{ return -ENODEV; }

>  static inline const struct iommu_ops *iort_iommu_configure_id(

>  				      struct device *dev, const u32 *id_in)

>  { return NULL; }

> diff --git a/drivers/acpi/arm64/dma.c b/drivers/acpi/arm64/dma.c

> new file mode 100644

> index 000000000000..f16739ad3cc0

> --- /dev/null

> +++ b/drivers/acpi/arm64/dma.c

> @@ -0,0 +1,50 @@

> +// SPDX-License-Identifier: GPL-2.0-only

> +#include <linux/acpi.h>

> +#include <linux/acpi_iort.h>

> +#include <linux/device.h>

> +#include <linux/dma-direct.h>

> +

> +void acpi_arch_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)

> +{

> +	int ret;

> +	u64 end, mask;

> +	u64 dmaaddr = 0, size = 0, offset = 0;

> +

> +	/*

> +	 * If @dev is expected to be DMA-capable then the bus code that created

> +	 * it should have initialised its dma_mask pointer by this point. For

> +	 * now, we'll continue the legacy behaviour of coercing it to the

> +	 * coherent mask if not, but we'll no longer do so quietly.

> +	 */

> +	if (!dev->dma_mask) {

> +		dev_warn(dev, "DMA mask not set\n");

> +		dev->dma_mask = &dev->coherent_dma_mask;

> +	}

> +

> +	if (dev->coherent_dma_mask)

> +		size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);

> +	else

> +		size = 1ULL << 32;

> +

> +	ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size);

> +	if (ret == -ENODEV)

> +		ret = iort_dma_get_ranges(dev, &size);

> +	if (!ret) {

> +		/*

> +		 * Limit coherent and dma mask based on size retrieved from

> +		 * firmware.

> +		 */

> +		end = dmaaddr + size - 1;

> +		mask = DMA_BIT_MASK(ilog2(end) + 1);

> +		dev->bus_dma_limit = end;

> +		dev->coherent_dma_mask = min(dev->coherent_dma_mask, mask);

> +		*dev->dma_mask = min(*dev->dma_mask, mask);

> +	}

> +

> +	*dma_addr = dmaaddr;

> +	*dma_size = size;

> +

> +	ret = dma_direct_set_offset(dev, dmaaddr + offset, dmaaddr, size);

> +

> +	dev_dbg(dev, "dma_offset(%#08llx)%s\n", offset, ret ? " failed!" : "");

> +}

> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c

> index 3912a1f6058e..a940be1cf2af 100644

> --- a/drivers/acpi/arm64/iort.c

> +++ b/drivers/acpi/arm64/iort.c

> @@ -1144,56 +1144,18 @@ static int rc_dma_get_range(struct device *dev, u64 *size)

>  }

>  

>  /**

> - * iort_dma_setup() - Set-up device DMA parameters.

> + * iort_dma_get_ranges() - Look up DMA addressing limit for the device

> + * @dev: device to lookup

> + * @size: DMA range size result pointer

>   *

> - * @dev: device to configure

> - * @dma_addr: device DMA address result pointer

> - * @dma_size: DMA range size result pointer

> + * Return: 0 on success, an error otherwise.

>   */

> -void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)

> +int iort_dma_get_ranges(struct device *dev, u64 *size)

>  {

> -	u64 end, mask, dmaaddr = 0, size = 0, offset = 0;

> -	int ret;

> -

> -	/*

> -	 * If @dev is expected to be DMA-capable then the bus code that created

> -	 * it should have initialised its dma_mask pointer by this point. For

> -	 * now, we'll continue the legacy behaviour of coercing it to the

> -	 * coherent mask if not, but we'll no longer do so quietly.

> -	 */

> -	if (!dev->dma_mask) {

> -		dev_warn(dev, "DMA mask not set\n");

> -		dev->dma_mask = &dev->coherent_dma_mask;

> -	}

> -

> -	if (dev->coherent_dma_mask)

> -		size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);

> +	if (dev_is_pci(dev))

> +		return rc_dma_get_range(dev, size);

>  	else

> -		size = 1ULL << 32;

> -

> -	ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size);

> -	if (ret == -ENODEV)

> -		ret = dev_is_pci(dev) ? rc_dma_get_range(dev, &size)

> -				      : nc_dma_get_range(dev, &size);

> -

> -	if (!ret) {

> -		/*

> -		 * Limit coherent and dma mask based on size retrieved from

> -		 * firmware.

> -		 */

> -		end = dmaaddr + size - 1;

> -		mask = DMA_BIT_MASK(ilog2(end) + 1);

> -		dev->bus_dma_limit = end;

> -		dev->coherent_dma_mask = min(dev->coherent_dma_mask, mask);

> -		*dev->dma_mask = min(*dev->dma_mask, mask);

> -	}

> -

> -	*dma_addr = dmaaddr;

> -	*dma_size = size;

> -

> -	ret = dma_direct_set_offset(dev, dmaaddr + offset, dmaaddr, size);

> -

> -	dev_dbg(dev, "dma_offset(%#08llx)%s\n", offset, ret ? " failed!" : "");

> +		return nc_dma_get_range(dev, size);

>  }

>  

>  static void __init acpi_iort_register_irq(int hwirq, const char *name,

> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c

> index e10d38ac7cf2..ea613df8f913 100644

> --- a/drivers/acpi/scan.c

> +++ b/drivers/acpi/scan.c

> @@ -1537,7 +1537,7 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr,

>  		return 0;

>  	}

>  

> -	iort_dma_setup(dev, &dma_addr, &size);

> +	acpi_arch_dma_setup(dev, &dma_addr, &size);

>  

>  	iommu = iort_iommu_configure_id(dev, input_id);

>  	if (PTR_ERR(iommu) == -EPROBE_DEFER)

Patch

diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 6ff50f4ed947..66acbe77f46e 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1,3 +1,4 @@ 
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_ACPI_IORT) 	+= iort.o
 obj-$(CONFIG_ACPI_GTDT) 	+= gtdt.o
+obj-y				+= dma.o
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index c60745f657e9..7aaa9559cc19 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -259,9 +259,12 @@  void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa);
 
 #ifdef CONFIG_ARM64
 void acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa);
+void acpi_arch_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size);
 #else
 static inline void
 acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa) { }
+static inline void
+acpi_arch_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) { }
 #endif
 
 int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 1a12baa58e40..f7f054833afd 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -34,7 +34,7 @@  struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
 void acpi_configure_pmsi_domain(struct device *dev);
 int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
 /* IOMMU interface */
-void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size);
+int iort_dma_get_ranges(struct device *dev, u64 *size);
 const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
 						const u32 *id_in);
 int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head);
@@ -48,8 +48,8 @@  static inline struct irq_domain *iort_get_device_domain(
 { return NULL; }
 static inline void acpi_configure_pmsi_domain(struct device *dev) { }
 /* IOMMU interface */
-static inline void iort_dma_setup(struct device *dev, u64 *dma_addr,
-				  u64 *size) { }
+static inline int iort_dma_get_ranges(struct device *dev, u64 *size)
+{ return -ENODEV; }
 static inline const struct iommu_ops *iort_iommu_configure_id(
 				      struct device *dev, const u32 *id_in)
 { return NULL; }
diff --git a/drivers/acpi/arm64/dma.c b/drivers/acpi/arm64/dma.c
new file mode 100644
index 000000000000..f16739ad3cc0
--- /dev/null
+++ b/drivers/acpi/arm64/dma.c
@@ -0,0 +1,50 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
+#include <linux/device.h>
+#include <linux/dma-direct.h>
+
+void acpi_arch_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)
+{
+	int ret;
+	u64 end, mask;
+	u64 dmaaddr = 0, size = 0, offset = 0;
+
+	/*
+	 * If @dev is expected to be DMA-capable then the bus code that created
+	 * it should have initialised its dma_mask pointer by this point. For
+	 * now, we'll continue the legacy behaviour of coercing it to the
+	 * coherent mask if not, but we'll no longer do so quietly.
+	 */
+	if (!dev->dma_mask) {
+		dev_warn(dev, "DMA mask not set\n");
+		dev->dma_mask = &dev->coherent_dma_mask;
+	}
+
+	if (dev->coherent_dma_mask)
+		size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
+	else
+		size = 1ULL << 32;
+
+	ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size);
+	if (ret == -ENODEV)
+		ret = iort_dma_get_ranges(dev, &size);
+	if (!ret) {
+		/*
+		 * Limit coherent and dma mask based on size retrieved from
+		 * firmware.
+		 */
+		end = dmaaddr + size - 1;
+		mask = DMA_BIT_MASK(ilog2(end) + 1);
+		dev->bus_dma_limit = end;
+		dev->coherent_dma_mask = min(dev->coherent_dma_mask, mask);
+		*dev->dma_mask = min(*dev->dma_mask, mask);
+	}
+
+	*dma_addr = dmaaddr;
+	*dma_size = size;
+
+	ret = dma_direct_set_offset(dev, dmaaddr + offset, dmaaddr, size);
+
+	dev_dbg(dev, "dma_offset(%#08llx)%s\n", offset, ret ? " failed!" : "");
+}
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 3912a1f6058e..a940be1cf2af 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -1144,56 +1144,18 @@  static int rc_dma_get_range(struct device *dev, u64 *size)
 }
 
 /**
- * iort_dma_setup() - Set-up device DMA parameters.
+ * iort_dma_get_ranges() - Look up DMA addressing limit for the device
+ * @dev: device to lookup
+ * @size: DMA range size result pointer
  *
- * @dev: device to configure
- * @dma_addr: device DMA address result pointer
- * @dma_size: DMA range size result pointer
+ * Return: 0 on success, an error otherwise.
  */
-void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)
+int iort_dma_get_ranges(struct device *dev, u64 *size)
 {
-	u64 end, mask, dmaaddr = 0, size = 0, offset = 0;
-	int ret;
-
-	/*
-	 * If @dev is expected to be DMA-capable then the bus code that created
-	 * it should have initialised its dma_mask pointer by this point. For
-	 * now, we'll continue the legacy behaviour of coercing it to the
-	 * coherent mask if not, but we'll no longer do so quietly.
-	 */
-	if (!dev->dma_mask) {
-		dev_warn(dev, "DMA mask not set\n");
-		dev->dma_mask = &dev->coherent_dma_mask;
-	}
-
-	if (dev->coherent_dma_mask)
-		size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
+	if (dev_is_pci(dev))
+		return rc_dma_get_range(dev, size);
 	else
-		size = 1ULL << 32;
-
-	ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size);
-	if (ret == -ENODEV)
-		ret = dev_is_pci(dev) ? rc_dma_get_range(dev, &size)
-				      : nc_dma_get_range(dev, &size);
-
-	if (!ret) {
-		/*
-		 * Limit coherent and dma mask based on size retrieved from
-		 * firmware.
-		 */
-		end = dmaaddr + size - 1;
-		mask = DMA_BIT_MASK(ilog2(end) + 1);
-		dev->bus_dma_limit = end;
-		dev->coherent_dma_mask = min(dev->coherent_dma_mask, mask);
-		*dev->dma_mask = min(*dev->dma_mask, mask);
-	}
-
-	*dma_addr = dmaaddr;
-	*dma_size = size;
-
-	ret = dma_direct_set_offset(dev, dmaaddr + offset, dmaaddr, size);
-
-	dev_dbg(dev, "dma_offset(%#08llx)%s\n", offset, ret ? " failed!" : "");
+		return nc_dma_get_range(dev, size);
 }
 
 static void __init acpi_iort_register_irq(int hwirq, const char *name,
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e10d38ac7cf2..ea613df8f913 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1537,7 +1537,7 @@  int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr,
 		return 0;
 	}
 
-	iort_dma_setup(dev, &dma_addr, &size);
+	acpi_arch_dma_setup(dev, &dma_addr, &size);
 
 	iommu = iort_iommu_configure_id(dev, input_id);
 	if (PTR_ERR(iommu) == -EPROBE_DEFER)