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

From: [email-masked] (Marek Szyprowski)
Date: Tue, 19 May 2015 12:49:36 +0200

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 <[email-masked]>
>> ---
>>   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
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland