diff mbox

[v6,01/25] arm: dma-mapping: add support for creating reserved mappings in iova space

Message ID 1430727380-10912-2-git-send-email-m.szyprowski@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Marek Szyprowski May 4, 2015, 8:15 a.m. UTC
Some devices (like frame buffers) are enabled by bootloader and configured
to perform DMA operations automatically (like displaying boot logo or splash
screen). Such devices operate and perform DMA operation usually until the
proper driver for them is loaded and probed. However before that happens,
system usually loads IOMMU drivers and configures dma parameters for each
device. When such initial configuration is created and enabled, it usually
contains empty translation rules betweem IO address space and physical
memory, because no buffers nor memory regions have been requested by the
respective driver.

This patch adds support for "iommu-reserved-mapping", which can be used
to provide definitions for mappings that need to be created on system
boot to let such devices (enabled by bootloader) to operate properly
until respective driver is probed.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 Documentation/devicetree/bindings/iommu/iommu.txt |  44 +++++++++
 arch/arm/mm/dma-mapping.c                         | 112 ++++++++++++++++++++++
 2 files changed, 156 insertions(+)

Comments

Rob Herring (Arm) May 4, 2015, 10:12 p.m. UTC | #1
On Mon, May 4, 2015 at 3:15 AM, Marek Szyprowski
<m.szyprowski@samsung.com> wrote:
> Some devices (like frame buffers) are enabled by bootloader and configured
> to perform DMA operations automatically (like displaying boot logo or splash
> screen). Such devices operate and perform DMA operation usually until the
> proper driver for them is loaded and probed. However before that happens,
> system usually loads IOMMU drivers and configures dma parameters for each
> device. When such initial configuration is created and enabled, it usually
> contains empty translation rules betweem IO address space and physical
> memory, because no buffers nor memory regions have been requested by the
> respective driver.
>
> This patch adds support for "iommu-reserved-mapping", which can be used
> to provide definitions for mappings that need to be created on system
> boot to let such devices (enabled by bootloader) to operate properly
> until respective driver is probed.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  Documentation/devicetree/bindings/iommu/iommu.txt |  44 +++++++++
>  arch/arm/mm/dma-mapping.c                         | 112 ++++++++++++++++++++++
>  2 files changed, 156 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/iommu/iommu.txt b/Documentation/devicetree/bindings/iommu/iommu.txt
> index 5a8b4624defc..fd54e6b597f0 100644
> --- a/Documentation/devicetree/bindings/iommu/iommu.txt
> +++ b/Documentation/devicetree/bindings/iommu/iommu.txt
> @@ -86,6 +86,35 @@ have a means to turn off translation. But it is invalid in such cases to
>  disable the IOMMU's device tree node in the first place because it would
>  prevent any driver from properly setting up the translations.
>
> +Optional properties:
> +--------------------
> +- iommu-reserved-mapping: A list of entries describing additional
> +  reserved mapping, that will be inserted to the default IO address space
> +  created for given master device. Each entry consist of IO address,
> +  physical memory address and size of the region.
> +
> +Some devices (like frame buffers) are enabled by bootloader and configured
> +to perform DMA operations automatically (like displaying boot logo or splash
> +screen). Such devices operate and perform DMA operation usually until the
> +proper driver for them is loaded and probed. However before that happens,
> +system usually loads IOMMU drivers and configures dma parameters for each

s/dma/DMA/

> +device. When such initial configuration is created and enabled, it usually
> +contains empty translation rules betweem IO address space and physical

s/betweem/between/

> +memory, because no buffers nor memory regions have been requested by the
> +respective driver.
> +
> +To avoid IOMMU page fault, one can provide "iommu-reserved-mapping"
> +property, which defines all memory regions which must be mapped to IO
> +address space to boot properly when device has been enabled by the
> +bootloader. More than one region can be defined for given master device.
> +Each region is defined by the following triplet: first entry is IO
> +address (encoded in "address" cells), second is base physical memory
> +address for this regions (also encoded in "address" cells) and the last
> +is size of the region (encoded in "size" cells). To ensure that that
> +given master device will not trigger page fault after enabling IOMMU,
> +one should define identity mapping between physical memory and IO
> +address space for the range of addresses accessed by the device.
> +
>
>  Notes:
>  ======
> @@ -113,6 +142,21 @@ Single-master IOMMU:
>                 iommus = <&{/iommu}>;
>         };
>
> +
> +Single-master IOMMU, which has been left enabled by bootloader:
> +---------------------------------------------------------------
> +
> +       iommu {
> +               #iommu-cells = <0>;
> +       };
> +
> +       master {
> +               iommus = <&{/iommu}>;
> +               /* bootloader configures framebuffer at 0x40000000 (32MiB)
> +               iommu-reserved-mapping = <0x40000000 0x40000000 0x2000000>;

Is there not an ordering problem if kernel initializes the IOMMU
before parsing this for each master? I would think the IOMMU driver
needs to find all of these mappings and cleanly switch the page tables
with the new reserved mapping.

Rob
Robin Murphy May 6, 2015, 2:01 p.m. UTC | #2
Hi Marek,

On 04/05/15 09:15, Marek Szyprowski wrote:
> Some devices (like frame buffers) are enabled by bootloader and configured
> to perform DMA operations automatically (like displaying boot logo or splash
> screen). Such devices operate and perform DMA operation usually until the
> proper driver for them is loaded and probed. However before that happens,
> system usually loads IOMMU drivers and configures dma parameters for each
> device. When such initial configuration is created and enabled, it usually
> contains empty translation rules betweem IO address space and physical
> memory, because no buffers nor memory regions have been requested by the
> respective driver.
>
> This patch adds support for "iommu-reserved-mapping", which can be used
> to provide definitions for mappings that need to be created on system
> boot to let such devices (enabled by bootloader) to operate properly
> until respective driver is probed.

This appears to only work if you assume the driver is going to tear down 
the existing domain entirely; what about drivers that don't manage 
IOMMUs explicitly, or if there are multiple active devices behind the 
same IOMMU which (in future) start out in the same default domain? If 
any device is happy to remain in the default domain then it would be 
nice to clear the reservations once they are no longer needed.

Could we not address the issue in a more robust way, like fleshing out 
an implementation of the nascent IOMMU_DOMAIN_IDENTITY type, then just 
flagging such devices to stipulate that their boot-time default domain 
must be an identity-mapped one?

> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>   Documentation/devicetree/bindings/iommu/iommu.txt |  44 +++++++++
>   arch/arm/mm/dma-mapping.c                         | 112 ++++++++++++++++++++++
>   2 files changed, 156 insertions(+)
>
[...]
> @@ -2048,6 +2092,66 @@ void arm_iommu_detach_device(struct device *dev)
>   }
>   EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
>
> +static int arm_iommu_add_reserved(struct device *dev,
> +                       struct dma_iommu_mapping *domain, phys_addr_t phys,
> +                       dma_addr_t dma, size_t size)
> +{
> +       int ret;
> +
> +       ret = __reserve_iova(domain, dma, size);
> +       if (ret) {
> +               dev_err(dev, "failed to reserve mapping\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = iommu_map(domain->domain, dma, phys, size, IOMMU_READ);
> +       if (ret != 0) {
> +               dev_err(dev, "create IOMMU mapping\n");
> +               return ret;
> +       }
> +
> +       dev_info(dev, "created reserved DMA mapping (%pa -> %pad, %zu bytes)\n",
> +                &phys, &dma, size);
> +
> +       return 0;
> +}
> +
> +static int arm_iommu_init_reserved(struct device *dev,
> +                                  struct dma_iommu_mapping *domain)
> +{
> +       const char *name = "iommu-reserved-mapping";
> +       const __be32 *prop = NULL;
> +       int len, naddr, nsize;
> +       struct device_node *node = dev->of_node;
> +       phys_addr_t phys;
> +       dma_addr_t dma;
> +       size_t size;
> +
> +       if (!node)
> +               return 0;
> +
> +       naddr = of_n_addr_cells(node);
> +       nsize = of_n_size_cells(node);
> +
> +       prop = of_get_property(node, name, &len);
> +       if (!prop)
> +               return 0;
> +
> +       len /= sizeof(u32);
> +
> +       if (len < 2 * naddr + nsize) {
> +               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);
> +
> +       return arm_iommu_add_reserved(dev, domain, phys, dma, size);
 > +}

I may be missing something, but I don't see how this can handle multiple 
ranges for the same device as the binding says.

>   static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
>   {
>          return coherent ? &iommu_coherent_ops : &iommu_ops;
> @@ -2068,6 +2172,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));

I'm hoping Joerg is still working on his default domain series, because 
the domain creation in arch_setup_dma_ops turns out to be horrible on a 
number of levels (like everything happening in the wrong order for 
platform devices). If that doesn't negate this issue entirely, it's 
going to significantly break this way of hooking up the solution 
(depending on what the drivers do) - worth some consideration, at least.

Robin.
Marek Szyprowski May 18, 2015, 12:09 p.m. UTC | #3
Hello,

On 2015-05-05 00:12, Rob Herring wrote:
> On Mon, May 4, 2015 at 3:15 AM, Marek Szyprowski
> <m.szyprowski@samsung.com> wrote:
>> Some devices (like frame buffers) are enabled by bootloader and configured
>> to perform DMA operations automatically (like displaying boot logo or splash
>> screen). Such devices operate and perform DMA operation usually until the
>> proper driver for them is loaded and probed. However before that happens,
>> system usually loads IOMMU drivers and configures dma parameters for each
>> device. When such initial configuration is created and enabled, it usually
>> contains empty translation rules betweem IO address space and physical
>> memory, because no buffers nor memory regions have been requested by the
>> respective driver.
>>
>> This patch adds support for "iommu-reserved-mapping", which can be used
>> to provide definitions for mappings that need to be created on system
>> boot to let such devices (enabled by bootloader) to operate properly
>> until respective driver is probed.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> ---
>>   Documentation/devicetree/bindings/iommu/iommu.txt |  44 +++++++++
>>   arch/arm/mm/dma-mapping.c                         | 112 ++++++++++++++++++++++
>>   2 files changed, 156 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/iommu/iommu.txt b/Documentation/devicetree/bindings/iommu/iommu.txt
>> index 5a8b4624defc..fd54e6b597f0 100644
>> --- a/Documentation/devicetree/bindings/iommu/iommu.txt
>> +++ b/Documentation/devicetree/bindings/iommu/iommu.txt
>> @@ -86,6 +86,35 @@ have a means to turn off translation. But it is invalid in such cases to
>>   disable the IOMMU's device tree node in the first place because it would
>>   prevent any driver from properly setting up the translations.
>>
>> +Optional properties:
>> +--------------------
>> +- iommu-reserved-mapping: A list of entries describing additional
>> +  reserved mapping, that will be inserted to the default IO address space
>> +  created for given master device. Each entry consist of IO address,
>> +  physical memory address and size of the region.
>> +
>> +Some devices (like frame buffers) are enabled by bootloader and configured
>> +to perform DMA operations automatically (like displaying boot logo or splash
>> +screen). Such devices operate and perform DMA operation usually until the
>> +proper driver for them is loaded and probed. However before that happens,
>> +system usually loads IOMMU drivers and configures dma parameters for each
> s/dma/DMA/
>
>> +device. When such initial configuration is created and enabled, it usually
>> +contains empty translation rules betweem IO address space and physical
> s/betweem/between/
>
>> +memory, because no buffers nor memory regions have been requested by the
>> +respective driver.
>> +
>> +To avoid IOMMU page fault, one can provide "iommu-reserved-mapping"
>> +property, which defines all memory regions which must be mapped to IO
>> +address space to boot properly when device has been enabled by the
>> +bootloader. More than one region can be defined for given master device.
>> +Each region is defined by the following triplet: first entry is IO
>> +address (encoded in "address" cells), second is base physical memory
>> +address for this regions (also encoded in "address" cells) and the last
>> +is size of the region (encoded in "size" cells). To ensure that that
>> +given master device will not trigger page fault after enabling IOMMU,
>> +one should define identity mapping between physical memory and IO
>> +address space for the range of addresses accessed by the device.
>> +
>>
>>   Notes:
>>   ======
>> @@ -113,6 +142,21 @@ Single-master IOMMU:
>>                  iommus = <&{/iommu}>;
>>          };
>>
>> +
>> +Single-master IOMMU, which has been left enabled by bootloader:
>> +---------------------------------------------------------------
>> +
>> +       iommu {
>> +               #iommu-cells = <0>;
>> +       };
>> +
>> +       master {
>> +               iommus = <&{/iommu}>;
>> +               /* bootloader configures framebuffer at 0x40000000 (32MiB)
>> +               iommu-reserved-mapping = <0x40000000 0x40000000 0x2000000>;
> Is there not an ordering problem if kernel initializes the IOMMU
> before parsing this for each master? I would think the IOMMU driver
> needs to find all of these mappings and cleanly switch the page tables
> with the new reserved mapping.

The proper ordering is guaranteed by arm_get_iommu_dma_map_ops function, 
which first
created iommu domain for given master device, then scans for reserved 
regions and
adds them to the given domains. Only then it attaches such domain to the 
iommu
driver.

Best regards
Marek Szyprowski May 19, 2015, 10:49 a.m. UTC | #4
Hello,

On 2015-05-06 16:01, Robin Murphy wrote:
> Hi Marek,
>
> On 04/05/15 09:15, Marek Szyprowski wrote:
>> Some devices (like frame buffers) are enabled by bootloader and 
>> configured
>> to perform DMA operations automatically (like displaying boot logo or 
>> splash
>> screen). Such devices operate and perform DMA operation usually until 
>> the
>> proper driver for them is loaded and probed. However before that 
>> happens,
>> system usually loads IOMMU drivers and configures dma parameters for 
>> each
>> device. When such initial configuration is created and enabled, it 
>> usually
>> contains empty translation rules betweem IO address space and physical
>> memory, because no buffers nor memory regions have been requested by the
>> respective driver.
>>
>> This patch adds support for "iommu-reserved-mapping", which can be used
>> to provide definitions for mappings that need to be created on system
>> boot to let such devices (enabled by bootloader) to operate properly
>> until respective driver is probed.
>
> This appears to only work if you assume the driver is going to tear 
> down the existing domain entirely; what about drivers that don't 
> manage IOMMUs explicitly, or if there are multiple active devices 
> behind the same IOMMU which (in future) start out in the same default 
> domain? If any device is happy to remain in the default domain then it 
> would be nice to clear the reservations once they are no longer needed.

Right, this need to be somehow worked out, but frankly right now I don't 
have
good idea which code should do it. The only idea that comes to my mind 
is using
a BUS_NOTIFY_BOUND_DRIVER notifier, but I don't like this approach.

> Could we not address the issue in a more robust way, like fleshing out 
> an implementation of the nascent IOMMU_DOMAIN_IDENTITY type, then just 
> flagging such devices to stipulate that their boot-time default domain 
> must be an identity-mapped one?

I'm open for any solution that will cover this case. Maybe my idea of iommu
reserved regions is a bit over-engineered? Maybe instead of defining 
reserved
ranges it will be enough to add something like 
'iommu-on-boot-identity-mapping'
property? This way one can later use it for IOMMU_DOMAIN_IDENTITY 
approach or
something else what will be agreed?

>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> ---
>>   Documentation/devicetree/bindings/iommu/iommu.txt |  44 +++++++++
>>   arch/arm/mm/dma-mapping.c                         | 112 
>> ++++++++++++++++++++++
>>   2 files changed, 156 insertions(+)
>>
> [...]
>> @@ -2048,6 +2092,66 @@ void arm_iommu_detach_device(struct device *dev)
>>   }
>>   EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
>>
>> +static int arm_iommu_add_reserved(struct device *dev,
>> +                       struct dma_iommu_mapping *domain, phys_addr_t 
>> phys,
>> +                       dma_addr_t dma, size_t size)
>> +{
>> +       int ret;
>> +
>> +       ret = __reserve_iova(domain, dma, size);
>> +       if (ret) {
>> +               dev_err(dev, "failed to reserve mapping\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       ret = iommu_map(domain->domain, dma, phys, size, IOMMU_READ);
>> +       if (ret != 0) {
>> +               dev_err(dev, "create IOMMU mapping\n");
>> +               return ret;
>> +       }
>> +
>> +       dev_info(dev, "created reserved DMA mapping (%pa -> %pad, %zu 
>> bytes)\n",
>> +                &phys, &dma, size);
>> +
>> +       return 0;
>> +}
>> +
>> +static int arm_iommu_init_reserved(struct device *dev,
>> +                                  struct dma_iommu_mapping *domain)
>> +{
>> +       const char *name = "iommu-reserved-mapping";
>> +       const __be32 *prop = NULL;
>> +       int len, naddr, nsize;
>> +       struct device_node *node = dev->of_node;
>> +       phys_addr_t phys;
>> +       dma_addr_t dma;
>> +       size_t size;
>> +
>> +       if (!node)
>> +               return 0;
>> +
>> +       naddr = of_n_addr_cells(node);
>> +       nsize = of_n_size_cells(node);
>> +
>> +       prop = of_get_property(node, name, &len);
>> +       if (!prop)
>> +               return 0;
>> +
>> +       len /= sizeof(u32);
>> +
>> +       if (len < 2 * naddr + nsize) {
>> +               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);
>> +
>> +       return arm_iommu_add_reserved(dev, domain, phys, dma, size);
> > +}
>
> I may be missing something, but I don't see how this can handle 
> multiple ranges for the same device as the binding says.
>

Right, loop is missing in the above calls.

>>   static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
>>   {
>>          return coherent ? &iommu_coherent_ops : &iommu_ops;
>> @@ -2068,6 +2172,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));
>
> I'm hoping Joerg is still working on his default domain series, 
> because the domain creation in arch_setup_dma_ops turns out to be 
> horrible on a number of levels (like everything happening in the wrong 
> order for platform devices). If that doesn't negate this issue 
> entirely, it's going to significantly break this way of hooking up the 
> solution (depending on what the drivers do) - worth some 
> consideration, at least.

I would really like to have something working soon, it's been a lot of 
discussion but still
very little of code that actually implements anything...

Best regards
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/iommu/iommu.txt b/Documentation/devicetree/bindings/iommu/iommu.txt
index 5a8b4624defc..fd54e6b597f0 100644
--- a/Documentation/devicetree/bindings/iommu/iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/iommu.txt
@@ -86,6 +86,35 @@  have a means to turn off translation. But it is invalid in such cases to
 disable the IOMMU's device tree node in the first place because it would
 prevent any driver from properly setting up the translations.
 
+Optional properties:
+--------------------
+- iommu-reserved-mapping: A list of entries describing additional
+  reserved mapping, that will be inserted to the default IO address space
+  created for given master device. Each entry consist of IO address,
+  physical memory address and size of the region.
+
+Some devices (like frame buffers) are enabled by bootloader and configured
+to perform DMA operations automatically (like displaying boot logo or splash
+screen). Such devices operate and perform DMA operation usually until the
+proper driver for them is loaded and probed. However before that happens,
+system usually loads IOMMU drivers and configures dma parameters for each
+device. When such initial configuration is created and enabled, it usually
+contains empty translation rules betweem IO address space and physical
+memory, because no buffers nor memory regions have been requested by the
+respective driver.
+
+To avoid IOMMU page fault, one can provide "iommu-reserved-mapping"
+property, which defines all memory regions which must be mapped to IO
+address space to boot properly when device has been enabled by the
+bootloader. More than one region can be defined for given master device.
+Each region is defined by the following triplet: first entry is IO
+address (encoded in "address" cells), second is base physical memory
+address for this regions (also encoded in "address" cells) and the last
+is size of the region (encoded in "size" cells). To ensure that that
+given master device will not trigger page fault after enabling IOMMU,
+one should define identity mapping between physical memory and IO
+address space for the range of addresses accessed by the device.
+
 
 Notes:
 ======
@@ -113,6 +142,21 @@  Single-master IOMMU:
 		iommus = <&{/iommu}>;
 	};
 
+
+Single-master IOMMU, which has been left enabled by bootloader:
+---------------------------------------------------------------
+
+	iommu {
+		#iommu-cells = <0>;
+	};
+
+	master {
+		iommus = <&{/iommu}>;
+		/* bootloader configures framebuffer at 0x40000000 (32MiB)
+		iommu-reserved-mapping = <0x40000000 0x40000000 0x2000000>;
+	};
+
+
 Multiple-master IOMMU with fixed associations:
 ----------------------------------------------
 
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7e7583ddd607..3b4a94695b68 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1019,6 +1019,50 @@  fs_initcall(dma_debug_do_init);
 
 static int extend_iommu_mapping(struct dma_iommu_mapping *mapping);
 
+static inline int __reserve_iova(struct dma_iommu_mapping *mapping,
+				 dma_addr_t iova, size_t size)
+{
+	unsigned long count, start;
+	unsigned long flags;
+	int i, sbitmap, ebitmap;
+
+	if (iova < mapping->base)
+		return -EINVAL;
+
+	start = (iova - mapping->base) >> PAGE_SHIFT;
+	count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+	sbitmap = start / mapping->bits;
+	ebitmap = (start + count) / mapping->bits;
+	start = start % mapping->bits;
+
+	if (ebitmap > mapping->extensions)
+		return -EINVAL;
+
+	spin_lock_irqsave(&mapping->lock, flags);
+
+	for (i = mapping->nr_bitmaps; i <= ebitmap; i++) {
+		if (extend_iommu_mapping(mapping)) {
+			spin_unlock_irqrestore(&mapping->lock, flags);
+			return -ENOMEM;
+		}
+	}
+
+	for (i = sbitmap; count && i < mapping->nr_bitmaps; i++) {
+		int bits = count;
+
+		if (bits + start > mapping->bits)
+			bits = mapping->bits - start;
+		bitmap_set(mapping->bitmaps[i], start, bits);
+		start = 0;
+		count -= bits;
+	}
+
+	spin_unlock_irqrestore(&mapping->lock, flags);
+
+	return 0;
+}
+
 static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
 				      size_t size)
 {
@@ -2048,6 +2092,66 @@  void arm_iommu_detach_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
 
+static int arm_iommu_add_reserved(struct device *dev,
+			struct dma_iommu_mapping *domain, phys_addr_t phys,
+			dma_addr_t dma, size_t size)
+{
+	int ret;
+
+	ret = __reserve_iova(domain, dma, size);
+	if (ret) {
+		dev_err(dev, "failed to reserve mapping\n");
+		return -EINVAL;
+	}
+
+	ret = iommu_map(domain->domain, dma, phys, size, IOMMU_READ);
+	if (ret != 0) {
+		dev_err(dev, "create IOMMU mapping\n");
+		return ret;
+	}
+
+	dev_info(dev, "created reserved DMA mapping (%pa -> %pad, %zu bytes)\n",
+		 &phys, &dma, size);
+
+	return 0;
+}
+
+static int arm_iommu_init_reserved(struct device *dev,
+				   struct dma_iommu_mapping *domain)
+{
+	const char *name = "iommu-reserved-mapping";
+	const __be32 *prop = NULL;
+	int len, naddr, nsize;
+	struct device_node *node = dev->of_node;
+	phys_addr_t phys;
+	dma_addr_t dma;
+	size_t size;
+
+	if (!node)
+		return 0;
+
+	naddr = of_n_addr_cells(node);
+	nsize = of_n_size_cells(node);
+
+	prop = of_get_property(node, name, &len);
+	if (!prop)
+		return 0;
+
+	len /= sizeof(u32);
+
+	if (len < 2 * naddr + nsize) {
+		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);
+
+	return arm_iommu_add_reserved(dev, domain, phys, dma, size);
+}
+
 static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
 {
 	return coherent ? &iommu_coherent_ops : &iommu_ops;
@@ -2068,6 +2172,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));