Re: [PATCH v4 1/6] ACPI: arm64: Move DMA setup operations out of IORT
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 Reviewed-by: Eric Auger 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 ..f16739ad3cc0 > --- /dev/null > +++ b/drivers/acpi/arm64/dma.c > @@ -0,0 +1,50 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +#include > +#include > +#include > +#include > + > +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; > + > +
[PATCH v4 1/6] ACPI: arm64: Move DMA setup operations out of IORT
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 --- 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 ..f16739ad3cc0 --- /dev/null +++ b/drivers/acpi/arm64/dma.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include + +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