diff options
author | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2017-08-07 06:29:49 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-08-07 08:28:51 -0400 |
commit | 7ad4263980826e8b02e121af22f4f4c9103fe86d (patch) | |
tree | 436c849f4eb9c25377579743121d8b956ae2e57d | |
parent | c04ac679c6b86e4e36fbb675c6c061b4091f5810 (diff) |
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 <lorenzo.pieralisi@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Tested-by: Nate Watterson <nwatters@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/arm64/iort.c | 37 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 12 | ||||
-rw-r--r-- | include/linux/acpi_iort.h | 5 |
3 files changed, 42 insertions, 12 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index a3215ee671c1..606af87c425f 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c | |||
@@ -681,12 +681,17 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, | |||
681 | } | 681 | } |
682 | 682 | ||
683 | /** | 683 | /** |
684 | * iort_set_dma_mask - Set-up dma mask for a device. | 684 | * iort_dma_setup() - Set-up device DMA parameters. |
685 | * | 685 | * |
686 | * @dev: device to configure | 686 | * @dev: device to configure |
687 | * @dma_addr: device DMA address result pointer | ||
688 | * @size: DMA range size result pointer | ||
687 | */ | 689 | */ |
688 | void iort_set_dma_mask(struct device *dev) | 690 | void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) |
689 | { | 691 | { |
692 | u64 mask, dmaaddr = 0, size = 0, offset = 0; | ||
693 | int ret, msb; | ||
694 | |||
690 | /* | 695 | /* |
691 | * Set default coherent_dma_mask to 32 bit. Drivers are expected to | 696 | * Set default coherent_dma_mask to 32 bit. Drivers are expected to |
692 | * setup the correct supported mask. | 697 | * setup the correct supported mask. |
@@ -700,6 +705,34 @@ void iort_set_dma_mask(struct device *dev) | |||
700 | */ | 705 | */ |
701 | if (!dev->dma_mask) | 706 | if (!dev->dma_mask) |
702 | dev->dma_mask = &dev->coherent_dma_mask; | 707 | dev->dma_mask = &dev->coherent_dma_mask; |
708 | |||
709 | size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); | ||
710 | |||
711 | if (dev_is_pci(dev)) { | ||
712 | ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size); | ||
713 | if (!ret) { | ||
714 | msb = fls64(dmaaddr + size - 1); | ||
715 | /* | ||
716 | * Round-up to the power-of-two mask or set | ||
717 | * the mask to the whole 64-bit address space | ||
718 | * in case the DMA region covers the full | ||
719 | * memory window. | ||
720 | */ | ||
721 | mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; | ||
722 | /* | ||
723 | * Limit coherent and dma mask based on size | ||
724 | * retrieved from firmware. | ||
725 | */ | ||
726 | dev->coherent_dma_mask = mask; | ||
727 | *dev->dma_mask = mask; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | *dma_addr = dmaaddr; | ||
732 | *dma_size = size; | ||
733 | |||
734 | dev->dma_pfn_offset = PFN_DOWN(offset); | ||
735 | dev_dbg(dev, "dma_pfn_offset(%#08llx)\n", offset); | ||
703 | } | 736 | } |
704 | 737 | ||
705 | /** | 738 | /** |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 94500d99f2d6..0483d36433ac 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -1446,20 +1446,16 @@ int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, | |||
1446 | int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) | 1446 | int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) |
1447 | { | 1447 | { |
1448 | const struct iommu_ops *iommu; | 1448 | const struct iommu_ops *iommu; |
1449 | u64 size; | 1449 | u64 dma_addr = 0, size = 0; |
1450 | 1450 | ||
1451 | iort_set_dma_mask(dev); | 1451 | iort_dma_setup(dev, &dma_addr, &size); |
1452 | 1452 | ||
1453 | iommu = iort_iommu_configure(dev); | 1453 | iommu = iort_iommu_configure(dev); |
1454 | if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER) | 1454 | if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER) |
1455 | return -EPROBE_DEFER; | 1455 | return -EPROBE_DEFER; |
1456 | 1456 | ||
1457 | size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); | 1457 | arch_setup_dma_ops(dev, dma_addr, size, |
1458 | /* | 1458 | iommu, attr == DEV_DMA_COHERENT); |
1459 | * Assume dma valid range starts at 0 and covers the whole | ||
1460 | * coherent_dma_mask. | ||
1461 | */ | ||
1462 | arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT); | ||
1463 | 1459 | ||
1464 | return 0; | 1460 | return 0; |
1465 | } | 1461 | } |
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); | |||
36 | void acpi_configure_pmsi_domain(struct device *dev); | 36 | void acpi_configure_pmsi_domain(struct device *dev); |
37 | int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id); | 37 | int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id); |
38 | /* IOMMU interface */ | 38 | /* IOMMU interface */ |
39 | void iort_set_dma_mask(struct device *dev); | 39 | void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size); |
40 | const struct iommu_ops *iort_iommu_configure(struct device *dev); | 40 | const struct iommu_ops *iort_iommu_configure(struct device *dev); |
41 | #else | 41 | #else |
42 | static inline void acpi_iort_init(void) { } | 42 | static inline void acpi_iort_init(void) { } |
@@ -47,7 +47,8 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev, | |||
47 | { return NULL; } | 47 | { return NULL; } |
48 | static inline void acpi_configure_pmsi_domain(struct device *dev) { } | 48 | static inline void acpi_configure_pmsi_domain(struct device *dev) { } |
49 | /* IOMMU interface */ | 49 | /* IOMMU interface */ |
50 | static inline void iort_set_dma_mask(struct device *dev) { } | 50 | static inline void iort_dma_setup(struct device *dev, u64 *dma_addr, |
51 | u64 *size) { } | ||
51 | static inline | 52 | static inline |
52 | const struct iommu_ops *iort_iommu_configure(struct device *dev) | 53 | const struct iommu_ops *iort_iommu_configure(struct device *dev) |
53 | { return NULL; } | 54 | { return NULL; } |