From c04ac679c6b86e4e36fbb675c6c061b4091f5810 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 7 Aug 2017 11:29:48 +0100 Subject: ACPI: Introduce DMA ranges parsing Some devices have limited addressing capabilities and cannot reference the whole memory address space while carrying out DMA operations (eg some devices with bus address bits range smaller than system bus - which prevents them from using bus addresses that are otherwise valid for the system). The ACPI _DMA object allows bus devices to define the DMA window that is actually addressable by devices that sit upstream the bus, therefore providing a means to parse and initialize the devices DMA masks and addressable DMA range size. By relying on the generic ACPI kernel layer to retrieve and parse resources, introduce ACPI core code to parse the _DMA object. Signed-off-by: Lorenzo Pieralisi Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- include/acpi/acpi_bus.h | 2 ++ include/linux/acpi.h | 8 ++++++++ 2 files changed, 10 insertions(+) (limited to 'include') diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 68bc6be447fd..07eb963b5026 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -578,6 +578,8 @@ struct acpi_pci_root { bool acpi_dma_supported(struct acpi_device *adev); enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev); +int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, + u64 *size); int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr); void acpi_dma_deconfigure(struct device *dev); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c749eef1daa1..a5eaff9f2c6d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -427,6 +427,8 @@ void acpi_dev_free_resource_list(struct list_head *list); int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, int (*preproc)(struct acpi_resource *, void *), void *preproc_data); +int acpi_dev_get_dma_resources(struct acpi_device *adev, + struct list_head *list); int acpi_dev_filter_resource_type(struct acpi_resource *ares, unsigned long types); @@ -774,6 +776,12 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) return DEV_DMA_NOT_SUPPORTED; } +static inline int acpi_dma_get_range(struct device *dev, u64 *dma_addr, + u64 *offset, u64 *size) +{ + return -ENODEV; +} + static inline int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { -- cgit v1.2.3 From 7ad4263980826e8b02e121af22f4f4c9103fe86d Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 7 Aug 2017 11:29:49 +0100 Subject: ACPI: Make acpi_dma_configure() DMA regions aware Current ACPI DMA configuration set-up device DMA capabilities through kernel defaults that do not take into account platform specific DMA configurations reported by firmware. By leveraging the ACPI acpi_dev_get_dma_resources() API, add code in acpi_dma_configure() to retrieve the DMA regions to correctly set-up PCI devices DMA parameters. Rework the ACPI IORT kernel API to make sure they can accommodate the DMA set-up required by firmware. By making PCI devices DMA set-up ACPI IORT specific, the kernel is shielded from unwanted regressions that could be triggered by parsing DMA resources on arches that were previously ignoring them (ie x86/ia64), leaving kernel behaviour unchanged on those arches. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- include/linux/acpi_iort.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 8379d406ad2e..8d3f0bf80379 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -36,7 +36,7 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_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_set_dma_mask(struct device *dev); +void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size); const struct iommu_ops *iort_iommu_configure(struct device *dev); #else static inline void acpi_iort_init(void) { } @@ -47,7 +47,8 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev, { return NULL; } static inline void acpi_configure_pmsi_domain(struct device *dev) { } /* IOMMU interface */ -static inline void iort_set_dma_mask(struct device *dev) { } +static inline void iort_dma_setup(struct device *dev, u64 *dma_addr, + u64 *size) { } static inline const struct iommu_ops *iort_iommu_configure(struct device *dev) { return NULL; } -- cgit v1.2.3