summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mm/dma-mapping.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 55add24c3b4c..c36abc603712 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -2128,7 +2128,7 @@ static int arm_iommu_init_reserved(struct device *dev,
{
const char *name = "iommu-reserved-mapping";
const __be32 *prop = NULL;
- int len, naddr, nsize;
+ int ret = 0, len, naddr, nsize, regions, cells;
struct device_node *node = dev->of_node;
phys_addr_t phys;
dma_addr_t dma;
@@ -2145,18 +2145,27 @@ static int arm_iommu_init_reserved(struct device *dev,
return 0;
len /= sizeof(u32);
+ cells = 2 * naddr + nsize;
+ regions = len / cells;
- if (len < 2 * naddr + nsize) {
+ if (len % cells) {
dev_err(dev, "invalid length (%d cells) of %s property\n",
len, name);
return -EINVAL;
}
- phys = of_read_number(prop, naddr);
- dma = of_read_number(prop + naddr, naddr);
- size = of_read_number(prop + 2*naddr, nsize);
+ while (regions--) {
+ phys = of_read_number(prop, naddr);
+ dma = of_read_number(prop + naddr, naddr);
+ size = of_read_number(prop + 2*naddr, nsize);
+ prop += cells;
- return arm_iommu_add_reserved(dev, domain, phys, dma, size);
+ ret = arm_iommu_add_reserved(dev, domain, phys, dma, size);
+ if (ret)
+ break;
+ }
+
+ return ret;
}
static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
@@ -2187,6 +2196,14 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
return false;
}
+ if (arm_iommu_init_reserved(dev, mapping) != 0) {
+ pr_warn("Failed to initialize reserved mapping for device %s\n",
+ dev_name(dev));
+ __arm_iommu_detach_device(dev);
+ arm_iommu_release_mapping(mapping);
+ return false;
+ }
+
if (__arm_iommu_attach_device(dev, mapping)) {
pr_warn("Failed to attached device %s to IOMMU_mapping\n",
dev_name(dev));