Re: [PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-10 Thread Eric Auger
Hi Alex,
On 05/10/2016 05:29 PM, Alex Williamson wrote:
> On Wed,  4 May 2016 11:54:15 +
> Eric Auger  wrote:
> 
>> The user is allowed to register a reserved MSI IOVA range by using the
>> DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
>> This region is stored in the vfio_dma rb tree. At that point the iova
>> range is not mapped to any target address yet. The host kernel will use
>> those iova when needed, typically when MSIs are allocated.
>>
>> Signed-off-by: Eric Auger 
>> Signed-off-by: Bharat Bhushan 
>>
>> ---
>> v7 -> v8:
>> - use iommu_msi_set_aperture function. There is no notion of
>>   unregistration anymore since the reserved msi slot remains
>>   until the container gets closed.
>>
>> v6 -> v7:
>> - use iommu_free_reserved_iova_domain
>> - convey prot attributes downto dma-reserved-iommu iova domain creation
>> - reserved bindings teardown now performed on iommu domain destruction
>> - rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
>>  VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
>> - change title
>> - pass the protection attribute to dma-reserved-iommu API
>>
>> v3 -> v4:
>> - use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
>> - protect vfio_register_reserved_iova_range implementation with
>>   CONFIG_IOMMU_DMA_RESERVED
>> - handle unregistration by user-space and on vfio_iommu_type1 release
>>
>> v1 -> v2:
>> - set returned value according to alloc_reserved_iova_domain result
>> - free the iova domains in case any error occurs
>>
>> RFC v1 -> v1:
>> - takes into account Alex comments, based on
>>   [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
>> - use the existing dma map/unmap ioctl interface with a flag to register
>>   a reserved IOVA range. A single reserved iova region is allowed.
>> ---
>>  drivers/vfio/vfio_iommu_type1.c | 78 
>> -
>>  include/uapi/linux/vfio.h   | 10 +-
>>  2 files changed, 86 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/vfio/vfio_iommu_type1.c 
>> b/drivers/vfio/vfio_iommu_type1.c
>> index 94a9916..4d3a6f1 100644
>> --- a/drivers/vfio/vfio_iommu_type1.c
>> +++ b/drivers/vfio/vfio_iommu_type1.c
>> @@ -36,6 +36,7 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>>  
>>  #define DRIVER_VERSION  "0.2"
>>  #define DRIVER_AUTHOR   "Alex Williamson "
>> @@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
>> struct vfio_dma *dma)
>>  vfio_lock_acct(-unlocked);
>>  }
>>  
>> +static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
>> +dma_addr_t iova, size_t size)
>> +{
>> +struct vfio_domain *d;
>> +int ret = 0;
>> +
>> +list_for_each_entry(d, >domain_list, next) {
>> +ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
>> +if (ret)
>> +break;
>> +}
>> +return ret;
>> +}
>> +
>>  static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
>>  {
>>  vfio_unmap_unpin(iommu, dma);
>> @@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>>  return ret;
>>  }
>>  
>> +static int vfio_register_msi_range(struct vfio_iommu *iommu,
>> +   struct vfio_iommu_type1_dma_map *map)
>> +{
>> +dma_addr_t iova = map->iova;
>> +size_t size = map->size;
>> +int ret = 0;
>> +struct vfio_dma *dma;
>> +unsigned long order;
>> +uint64_t mask;
>> +
>> +/* Verify that none of our __u64 fields overflow */
>> +if (map->size != size || map->iova != iova)
>> +return -EINVAL;
>> +
>> +order =  __ffs(vfio_pgsize_bitmap(iommu));
>> +mask = ((uint64_t)1 << order) - 1;
>> +
>> +WARN_ON(mask & PAGE_MASK);
>> +
>> +if (!size || (size | iova) & mask)
>> +return -EINVAL;
>> +
>> +/* Don't allow IOVA address wrap */
>> +if (iova + size - 1 < iova)
>> +return -EINVAL;
>> +
>> +mutex_lock(>lock);
>> +
>> +if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
>> +ret =  -EEXIST;
>> +goto unlock;
>> +}
>> +
>> +dma = kzalloc(sizeof(*dma), GFP_KERNEL);
>> +if (!dma) {
>> +ret = -ENOMEM;
>> +goto unlock;
>> +}
>> +
>> +dma->iova = iova;
>> +dma->size = size;
>> +dma->type = VFIO_IOVA_RESERVED;
> 
> [oops, forgot to send this reply with the others]
> 
> I'm tempted to suggest we set type explicitly in the USER case too just
> to make that abundantly clear rather than taking advantage of the
> kzalloc struct.

no worries. OK I will set the dma type explicitly in vfio_dma_do_map too.

Thanks

Eric
> 
>> +
>> +ret = vfio_set_msi_aperture(iommu, iova, size);
>> +if (ret)
>> +goto free_unlock;
>> +
>> +vfio_link_dma(iommu, dma);
>> +goto unlock;
>> +
>> 

Re: [PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-10 Thread Eric Auger
Hi Alex,
On 05/10/2016 05:29 PM, Alex Williamson wrote:
> On Wed,  4 May 2016 11:54:15 +
> Eric Auger  wrote:
> 
>> The user is allowed to register a reserved MSI IOVA range by using the
>> DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
>> This region is stored in the vfio_dma rb tree. At that point the iova
>> range is not mapped to any target address yet. The host kernel will use
>> those iova when needed, typically when MSIs are allocated.
>>
>> Signed-off-by: Eric Auger 
>> Signed-off-by: Bharat Bhushan 
>>
>> ---
>> v7 -> v8:
>> - use iommu_msi_set_aperture function. There is no notion of
>>   unregistration anymore since the reserved msi slot remains
>>   until the container gets closed.
>>
>> v6 -> v7:
>> - use iommu_free_reserved_iova_domain
>> - convey prot attributes downto dma-reserved-iommu iova domain creation
>> - reserved bindings teardown now performed on iommu domain destruction
>> - rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
>>  VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
>> - change title
>> - pass the protection attribute to dma-reserved-iommu API
>>
>> v3 -> v4:
>> - use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
>> - protect vfio_register_reserved_iova_range implementation with
>>   CONFIG_IOMMU_DMA_RESERVED
>> - handle unregistration by user-space and on vfio_iommu_type1 release
>>
>> v1 -> v2:
>> - set returned value according to alloc_reserved_iova_domain result
>> - free the iova domains in case any error occurs
>>
>> RFC v1 -> v1:
>> - takes into account Alex comments, based on
>>   [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
>> - use the existing dma map/unmap ioctl interface with a flag to register
>>   a reserved IOVA range. A single reserved iova region is allowed.
>> ---
>>  drivers/vfio/vfio_iommu_type1.c | 78 
>> -
>>  include/uapi/linux/vfio.h   | 10 +-
>>  2 files changed, 86 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/vfio/vfio_iommu_type1.c 
>> b/drivers/vfio/vfio_iommu_type1.c
>> index 94a9916..4d3a6f1 100644
>> --- a/drivers/vfio/vfio_iommu_type1.c
>> +++ b/drivers/vfio/vfio_iommu_type1.c
>> @@ -36,6 +36,7 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>>  
>>  #define DRIVER_VERSION  "0.2"
>>  #define DRIVER_AUTHOR   "Alex Williamson "
>> @@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
>> struct vfio_dma *dma)
>>  vfio_lock_acct(-unlocked);
>>  }
>>  
>> +static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
>> +dma_addr_t iova, size_t size)
>> +{
>> +struct vfio_domain *d;
>> +int ret = 0;
>> +
>> +list_for_each_entry(d, >domain_list, next) {
>> +ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
>> +if (ret)
>> +break;
>> +}
>> +return ret;
>> +}
>> +
>>  static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
>>  {
>>  vfio_unmap_unpin(iommu, dma);
>> @@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>>  return ret;
>>  }
>>  
>> +static int vfio_register_msi_range(struct vfio_iommu *iommu,
>> +   struct vfio_iommu_type1_dma_map *map)
>> +{
>> +dma_addr_t iova = map->iova;
>> +size_t size = map->size;
>> +int ret = 0;
>> +struct vfio_dma *dma;
>> +unsigned long order;
>> +uint64_t mask;
>> +
>> +/* Verify that none of our __u64 fields overflow */
>> +if (map->size != size || map->iova != iova)
>> +return -EINVAL;
>> +
>> +order =  __ffs(vfio_pgsize_bitmap(iommu));
>> +mask = ((uint64_t)1 << order) - 1;
>> +
>> +WARN_ON(mask & PAGE_MASK);
>> +
>> +if (!size || (size | iova) & mask)
>> +return -EINVAL;
>> +
>> +/* Don't allow IOVA address wrap */
>> +if (iova + size - 1 < iova)
>> +return -EINVAL;
>> +
>> +mutex_lock(>lock);
>> +
>> +if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
>> +ret =  -EEXIST;
>> +goto unlock;
>> +}
>> +
>> +dma = kzalloc(sizeof(*dma), GFP_KERNEL);
>> +if (!dma) {
>> +ret = -ENOMEM;
>> +goto unlock;
>> +}
>> +
>> +dma->iova = iova;
>> +dma->size = size;
>> +dma->type = VFIO_IOVA_RESERVED;
> 
> [oops, forgot to send this reply with the others]
> 
> I'm tempted to suggest we set type explicitly in the USER case too just
> to make that abundantly clear rather than taking advantage of the
> kzalloc struct.

no worries. OK I will set the dma type explicitly in vfio_dma_do_map too.

Thanks

Eric
> 
>> +
>> +ret = vfio_set_msi_aperture(iommu, iova, size);
>> +if (ret)
>> +goto free_unlock;
>> +
>> +vfio_link_dma(iommu, dma);
>> +goto unlock;
>> +
>> +free_unlock:
>> +kfree(dma);
>> +unlock:
>> +mutex_unlock(>lock);
>> +return ret;
>> +}
>> +
>>  

Re: [PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-10 Thread Alex Williamson
On Wed,  4 May 2016 11:54:15 +
Eric Auger  wrote:

> The user is allowed to register a reserved MSI IOVA range by using the
> DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
> This region is stored in the vfio_dma rb tree. At that point the iova
> range is not mapped to any target address yet. The host kernel will use
> those iova when needed, typically when MSIs are allocated.
> 
> Signed-off-by: Eric Auger 
> Signed-off-by: Bharat Bhushan 
> 
> ---
> v7 -> v8:
> - use iommu_msi_set_aperture function. There is no notion of
>   unregistration anymore since the reserved msi slot remains
>   until the container gets closed.
> 
> v6 -> v7:
> - use iommu_free_reserved_iova_domain
> - convey prot attributes downto dma-reserved-iommu iova domain creation
> - reserved bindings teardown now performed on iommu domain destruction
> - rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
>  VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
> - change title
> - pass the protection attribute to dma-reserved-iommu API
> 
> v3 -> v4:
> - use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
> - protect vfio_register_reserved_iova_range implementation with
>   CONFIG_IOMMU_DMA_RESERVED
> - handle unregistration by user-space and on vfio_iommu_type1 release
> 
> v1 -> v2:
> - set returned value according to alloc_reserved_iova_domain result
> - free the iova domains in case any error occurs
> 
> RFC v1 -> v1:
> - takes into account Alex comments, based on
>   [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
> - use the existing dma map/unmap ioctl interface with a flag to register
>   a reserved IOVA range. A single reserved iova region is allowed.
> ---
>  drivers/vfio/vfio_iommu_type1.c | 78 
> -
>  include/uapi/linux/vfio.h   | 10 +-
>  2 files changed, 86 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
> index 94a9916..4d3a6f1 100644
> --- a/drivers/vfio/vfio_iommu_type1.c
> +++ b/drivers/vfio/vfio_iommu_type1.c
> @@ -36,6 +36,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #define DRIVER_VERSION  "0.2"
>  #define DRIVER_AUTHOR   "Alex Williamson "
> @@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
> struct vfio_dma *dma)
>   vfio_lock_acct(-unlocked);
>  }
>  
> +static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
> + dma_addr_t iova, size_t size)
> +{
> + struct vfio_domain *d;
> + int ret = 0;
> +
> + list_for_each_entry(d, >domain_list, next) {
> + ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
> + if (ret)
> + break;
> + }
> + return ret;
> +}
> +
>  static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
>  {
>   vfio_unmap_unpin(iommu, dma);
> @@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>   return ret;
>  }
>  
> +static int vfio_register_msi_range(struct vfio_iommu *iommu,
> +struct vfio_iommu_type1_dma_map *map)
> +{
> + dma_addr_t iova = map->iova;
> + size_t size = map->size;
> + int ret = 0;
> + struct vfio_dma *dma;
> + unsigned long order;
> + uint64_t mask;
> +
> + /* Verify that none of our __u64 fields overflow */
> + if (map->size != size || map->iova != iova)
> + return -EINVAL;
> +
> + order =  __ffs(vfio_pgsize_bitmap(iommu));
> + mask = ((uint64_t)1 << order) - 1;
> +
> + WARN_ON(mask & PAGE_MASK);
> +
> + if (!size || (size | iova) & mask)
> + return -EINVAL;
> +
> + /* Don't allow IOVA address wrap */
> + if (iova + size - 1 < iova)
> + return -EINVAL;
> +
> + mutex_lock(>lock);
> +
> + if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
> + ret =  -EEXIST;
> + goto unlock;
> + }
> +
> + dma = kzalloc(sizeof(*dma), GFP_KERNEL);
> + if (!dma) {
> + ret = -ENOMEM;
> + goto unlock;
> + }
> +
> + dma->iova = iova;
> + dma->size = size;
> + dma->type = VFIO_IOVA_RESERVED;

[oops, forgot to send this reply with the others]

I'm tempted to suggest we set type explicitly in the USER case too just
to make that abundantly clear rather than taking advantage of the
kzalloc struct.

> +
> + ret = vfio_set_msi_aperture(iommu, iova, size);
> + if (ret)
> + goto free_unlock;
> +
> + vfio_link_dma(iommu, dma);
> + goto unlock;
> +
> +free_unlock:
> + kfree(dma);
> +unlock:
> + mutex_unlock(>lock);
> + return ret;
> +}
> +
>  static int vfio_bus_type(struct device *dev, void *data)
>  {
>   struct bus_type **bus = data;
> @@ -1062,7 +1134,8 @@ static long 

Re: [PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-10 Thread Alex Williamson
On Wed,  4 May 2016 11:54:15 +
Eric Auger  wrote:

> The user is allowed to register a reserved MSI IOVA range by using the
> DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
> This region is stored in the vfio_dma rb tree. At that point the iova
> range is not mapped to any target address yet. The host kernel will use
> those iova when needed, typically when MSIs are allocated.
> 
> Signed-off-by: Eric Auger 
> Signed-off-by: Bharat Bhushan 
> 
> ---
> v7 -> v8:
> - use iommu_msi_set_aperture function. There is no notion of
>   unregistration anymore since the reserved msi slot remains
>   until the container gets closed.
> 
> v6 -> v7:
> - use iommu_free_reserved_iova_domain
> - convey prot attributes downto dma-reserved-iommu iova domain creation
> - reserved bindings teardown now performed on iommu domain destruction
> - rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
>  VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
> - change title
> - pass the protection attribute to dma-reserved-iommu API
> 
> v3 -> v4:
> - use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
> - protect vfio_register_reserved_iova_range implementation with
>   CONFIG_IOMMU_DMA_RESERVED
> - handle unregistration by user-space and on vfio_iommu_type1 release
> 
> v1 -> v2:
> - set returned value according to alloc_reserved_iova_domain result
> - free the iova domains in case any error occurs
> 
> RFC v1 -> v1:
> - takes into account Alex comments, based on
>   [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
> - use the existing dma map/unmap ioctl interface with a flag to register
>   a reserved IOVA range. A single reserved iova region is allowed.
> ---
>  drivers/vfio/vfio_iommu_type1.c | 78 
> -
>  include/uapi/linux/vfio.h   | 10 +-
>  2 files changed, 86 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
> index 94a9916..4d3a6f1 100644
> --- a/drivers/vfio/vfio_iommu_type1.c
> +++ b/drivers/vfio/vfio_iommu_type1.c
> @@ -36,6 +36,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #define DRIVER_VERSION  "0.2"
>  #define DRIVER_AUTHOR   "Alex Williamson "
> @@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
> struct vfio_dma *dma)
>   vfio_lock_acct(-unlocked);
>  }
>  
> +static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
> + dma_addr_t iova, size_t size)
> +{
> + struct vfio_domain *d;
> + int ret = 0;
> +
> + list_for_each_entry(d, >domain_list, next) {
> + ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
> + if (ret)
> + break;
> + }
> + return ret;
> +}
> +
>  static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
>  {
>   vfio_unmap_unpin(iommu, dma);
> @@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>   return ret;
>  }
>  
> +static int vfio_register_msi_range(struct vfio_iommu *iommu,
> +struct vfio_iommu_type1_dma_map *map)
> +{
> + dma_addr_t iova = map->iova;
> + size_t size = map->size;
> + int ret = 0;
> + struct vfio_dma *dma;
> + unsigned long order;
> + uint64_t mask;
> +
> + /* Verify that none of our __u64 fields overflow */
> + if (map->size != size || map->iova != iova)
> + return -EINVAL;
> +
> + order =  __ffs(vfio_pgsize_bitmap(iommu));
> + mask = ((uint64_t)1 << order) - 1;
> +
> + WARN_ON(mask & PAGE_MASK);
> +
> + if (!size || (size | iova) & mask)
> + return -EINVAL;
> +
> + /* Don't allow IOVA address wrap */
> + if (iova + size - 1 < iova)
> + return -EINVAL;
> +
> + mutex_lock(>lock);
> +
> + if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
> + ret =  -EEXIST;
> + goto unlock;
> + }
> +
> + dma = kzalloc(sizeof(*dma), GFP_KERNEL);
> + if (!dma) {
> + ret = -ENOMEM;
> + goto unlock;
> + }
> +
> + dma->iova = iova;
> + dma->size = size;
> + dma->type = VFIO_IOVA_RESERVED;

[oops, forgot to send this reply with the others]

I'm tempted to suggest we set type explicitly in the USER case too just
to make that abundantly clear rather than taking advantage of the
kzalloc struct.

> +
> + ret = vfio_set_msi_aperture(iommu, iova, size);
> + if (ret)
> + goto free_unlock;
> +
> + vfio_link_dma(iommu, dma);
> + goto unlock;
> +
> +free_unlock:
> + kfree(dma);
> +unlock:
> + mutex_unlock(>lock);
> + return ret;
> +}
> +
>  static int vfio_bus_type(struct device *dev, void *data)
>  {
>   struct bus_type **bus = data;
> @@ -1062,7 +1134,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>   } else if (cmd == VFIO_IOMMU_MAP_DMA) {
>   struct 

Re: [PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-09 Thread Eric Auger
Hi Chalamarla,
On 05/05/2016 09:22 PM, Chalamarla, Tirumalesh wrote:
> 
> 
> 
> 
> 
> On 5/4/16, 4:54 AM, "linux-arm-kernel on behalf of Eric Auger" 
>  eric.au...@linaro.org> wrote:
> 
>> The user is allowed to register a reserved MSI IOVA range by using the
>> DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
>> This region is stored in the vfio_dma rb tree. At that point the iova
>> range is not mapped to any target address yet. The host kernel will use
>> those iova when needed, typically when MSIs are allocated.
>>
>> Signed-off-by: Eric Auger 
>> Signed-off-by: Bharat Bhushan 
>>
>> ---
>> v7 -> v8:
>> - use iommu_msi_set_aperture function. There is no notion of
>>  unregistration anymore since the reserved msi slot remains
>>  until the container gets closed.
>>
>> v6 -> v7:
>> - use iommu_free_reserved_iova_domain
>> - convey prot attributes downto dma-reserved-iommu iova domain creation
>> - reserved bindings teardown now performed on iommu domain destruction
>> - rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
>> VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
>> - change title
>> - pass the protection attribute to dma-reserved-iommu API
>>
>> v3 -> v4:
>> - use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
>> - protect vfio_register_reserved_iova_range implementation with
>>  CONFIG_IOMMU_DMA_RESERVED
>> - handle unregistration by user-space and on vfio_iommu_type1 release
>>
>> v1 -> v2:
>> - set returned value according to alloc_reserved_iova_domain result
>> - free the iova domains in case any error occurs
>>
>> RFC v1 -> v1:
>> - takes into account Alex comments, based on
>>  [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
>> - use the existing dma map/unmap ioctl interface with a flag to register
>>  a reserved IOVA range. A single reserved iova region is allowed.
>> ---
>> drivers/vfio/vfio_iommu_type1.c | 78 
>> -
>> include/uapi/linux/vfio.h   | 10 +-
>> 2 files changed, 86 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/vfio/vfio_iommu_type1.c 
>> b/drivers/vfio/vfio_iommu_type1.c
>> index 94a9916..4d3a6f1 100644
>> --- a/drivers/vfio/vfio_iommu_type1.c
>> +++ b/drivers/vfio/vfio_iommu_type1.c
>> @@ -36,6 +36,7 @@
>> #include 
>> #include 
>> #include 
>> +#include 
>>
>> #define DRIVER_VERSION  "0.2"
>> #define DRIVER_AUTHOR   "Alex Williamson "
>> @@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
>> struct vfio_dma *dma)
>>  vfio_lock_acct(-unlocked);
>> }
>>
>> +static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
>> +dma_addr_t iova, size_t size)
>> +{
>> +struct vfio_domain *d;
>> +int ret = 0;
>> +
>> +list_for_each_entry(d, >domain_list, next) {
>> +ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
>> +if (ret)
>> +break;
>> +}
>> +return ret;
>> +}
>> +
>> static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
>> {
>>  vfio_unmap_unpin(iommu, dma);
>> @@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>>  return ret;
>> }
>>
>> +static int vfio_register_msi_range(struct vfio_iommu *iommu,
>> +   struct vfio_iommu_type1_dma_map *map)
>> +{
>> +dma_addr_t iova = map->iova;
>> +size_t size = map->size;
>> +int ret = 0;
>> +struct vfio_dma *dma;
>> +unsigned long order;
>> +uint64_t mask;
>> +
>> +/* Verify that none of our __u64 fields overflow */
>> +if (map->size != size || map->iova != iova)
>> +return -EINVAL;
>> +
>> +order =  __ffs(vfio_pgsize_bitmap(iommu));
>> +mask = ((uint64_t)1 << order) - 1;
>> +
>> +WARN_ON(mask & PAGE_MASK);
>> +
>> +if (!size || (size | iova) & mask)
>> +return -EINVAL;
>> +
>> +/* Don't allow IOVA address wrap */
>> +if (iova + size - 1 < iova)
>> +return -EINVAL;
>> +
>> +mutex_lock(>lock);
>> +
>> +if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
>> +ret =  -EEXIST;
>> +goto unlock;
>> +}
>> +
>> +dma = kzalloc(sizeof(*dma), GFP_KERNEL);
>> +if (!dma) {
>> +ret = -ENOMEM;
>> +goto unlock;
>> +}
>> +
>> +dma->iova = iova;
>> +dma->size = size;
>> +dma->type = VFIO_IOVA_RESERVED;
>> +
>> +ret = vfio_set_msi_aperture(iommu, iova, size);
>> +if (ret)
>> +goto free_unlock;
>> +
>> +vfio_link_dma(iommu, dma);
>> +goto unlock;
>> +
>> +free_unlock:
>> +kfree(dma);
>> +unlock:
>> +mutex_unlock(>lock);
>> +return ret;
>> +}
>> +
>> static int vfio_bus_type(struct device *dev, void *data)
>> {
>>  struct bus_type **bus = data;
>> @@ -1062,7 +1134,8 @@ 

Re: [PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-09 Thread Eric Auger
Hi Chalamarla,
On 05/05/2016 09:22 PM, Chalamarla, Tirumalesh wrote:
> 
> 
> 
> 
> 
> On 5/4/16, 4:54 AM, "linux-arm-kernel on behalf of Eric Auger" 
>  eric.au...@linaro.org> wrote:
> 
>> The user is allowed to register a reserved MSI IOVA range by using the
>> DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
>> This region is stored in the vfio_dma rb tree. At that point the iova
>> range is not mapped to any target address yet. The host kernel will use
>> those iova when needed, typically when MSIs are allocated.
>>
>> Signed-off-by: Eric Auger 
>> Signed-off-by: Bharat Bhushan 
>>
>> ---
>> v7 -> v8:
>> - use iommu_msi_set_aperture function. There is no notion of
>>  unregistration anymore since the reserved msi slot remains
>>  until the container gets closed.
>>
>> v6 -> v7:
>> - use iommu_free_reserved_iova_domain
>> - convey prot attributes downto dma-reserved-iommu iova domain creation
>> - reserved bindings teardown now performed on iommu domain destruction
>> - rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
>> VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
>> - change title
>> - pass the protection attribute to dma-reserved-iommu API
>>
>> v3 -> v4:
>> - use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
>> - protect vfio_register_reserved_iova_range implementation with
>>  CONFIG_IOMMU_DMA_RESERVED
>> - handle unregistration by user-space and on vfio_iommu_type1 release
>>
>> v1 -> v2:
>> - set returned value according to alloc_reserved_iova_domain result
>> - free the iova domains in case any error occurs
>>
>> RFC v1 -> v1:
>> - takes into account Alex comments, based on
>>  [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
>> - use the existing dma map/unmap ioctl interface with a flag to register
>>  a reserved IOVA range. A single reserved iova region is allowed.
>> ---
>> drivers/vfio/vfio_iommu_type1.c | 78 
>> -
>> include/uapi/linux/vfio.h   | 10 +-
>> 2 files changed, 86 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/vfio/vfio_iommu_type1.c 
>> b/drivers/vfio/vfio_iommu_type1.c
>> index 94a9916..4d3a6f1 100644
>> --- a/drivers/vfio/vfio_iommu_type1.c
>> +++ b/drivers/vfio/vfio_iommu_type1.c
>> @@ -36,6 +36,7 @@
>> #include 
>> #include 
>> #include 
>> +#include 
>>
>> #define DRIVER_VERSION  "0.2"
>> #define DRIVER_AUTHOR   "Alex Williamson "
>> @@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
>> struct vfio_dma *dma)
>>  vfio_lock_acct(-unlocked);
>> }
>>
>> +static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
>> +dma_addr_t iova, size_t size)
>> +{
>> +struct vfio_domain *d;
>> +int ret = 0;
>> +
>> +list_for_each_entry(d, >domain_list, next) {
>> +ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
>> +if (ret)
>> +break;
>> +}
>> +return ret;
>> +}
>> +
>> static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
>> {
>>  vfio_unmap_unpin(iommu, dma);
>> @@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>>  return ret;
>> }
>>
>> +static int vfio_register_msi_range(struct vfio_iommu *iommu,
>> +   struct vfio_iommu_type1_dma_map *map)
>> +{
>> +dma_addr_t iova = map->iova;
>> +size_t size = map->size;
>> +int ret = 0;
>> +struct vfio_dma *dma;
>> +unsigned long order;
>> +uint64_t mask;
>> +
>> +/* Verify that none of our __u64 fields overflow */
>> +if (map->size != size || map->iova != iova)
>> +return -EINVAL;
>> +
>> +order =  __ffs(vfio_pgsize_bitmap(iommu));
>> +mask = ((uint64_t)1 << order) - 1;
>> +
>> +WARN_ON(mask & PAGE_MASK);
>> +
>> +if (!size || (size | iova) & mask)
>> +return -EINVAL;
>> +
>> +/* Don't allow IOVA address wrap */
>> +if (iova + size - 1 < iova)
>> +return -EINVAL;
>> +
>> +mutex_lock(>lock);
>> +
>> +if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
>> +ret =  -EEXIST;
>> +goto unlock;
>> +}
>> +
>> +dma = kzalloc(sizeof(*dma), GFP_KERNEL);
>> +if (!dma) {
>> +ret = -ENOMEM;
>> +goto unlock;
>> +}
>> +
>> +dma->iova = iova;
>> +dma->size = size;
>> +dma->type = VFIO_IOVA_RESERVED;
>> +
>> +ret = vfio_set_msi_aperture(iommu, iova, size);
>> +if (ret)
>> +goto free_unlock;
>> +
>> +vfio_link_dma(iommu, dma);
>> +goto unlock;
>> +
>> +free_unlock:
>> +kfree(dma);
>> +unlock:
>> +mutex_unlock(>lock);
>> +return ret;
>> +}
>> +
>> static int vfio_bus_type(struct device *dev, void *data)
>> {
>>  struct bus_type **bus = data;
>> @@ -1062,7 +1134,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>>  } else if (cmd == VFIO_IOMMU_MAP_DMA) {
>>  struct 

Re: [PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-05 Thread Chalamarla, Tirumalesh





On 5/4/16, 4:54 AM, "linux-arm-kernel on behalf of Eric Auger" 
 wrote:

>The user is allowed to register a reserved MSI IOVA range by using the
>DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
>This region is stored in the vfio_dma rb tree. At that point the iova
>range is not mapped to any target address yet. The host kernel will use
>those iova when needed, typically when MSIs are allocated.
>
>Signed-off-by: Eric Auger 
>Signed-off-by: Bharat Bhushan 
>
>---
>v7 -> v8:
>- use iommu_msi_set_aperture function. There is no notion of
>  unregistration anymore since the reserved msi slot remains
>  until the container gets closed.
>
>v6 -> v7:
>- use iommu_free_reserved_iova_domain
>- convey prot attributes downto dma-reserved-iommu iova domain creation
>- reserved bindings teardown now performed on iommu domain destruction
>- rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
> VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
>- change title
>- pass the protection attribute to dma-reserved-iommu API
>
>v3 -> v4:
>- use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
>- protect vfio_register_reserved_iova_range implementation with
>  CONFIG_IOMMU_DMA_RESERVED
>- handle unregistration by user-space and on vfio_iommu_type1 release
>
>v1 -> v2:
>- set returned value according to alloc_reserved_iova_domain result
>- free the iova domains in case any error occurs
>
>RFC v1 -> v1:
>- takes into account Alex comments, based on
>  [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
>- use the existing dma map/unmap ioctl interface with a flag to register
>  a reserved IOVA range. A single reserved iova region is allowed.
>---
> drivers/vfio/vfio_iommu_type1.c | 78 -
> include/uapi/linux/vfio.h   | 10 +-
> 2 files changed, 86 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
>index 94a9916..4d3a6f1 100644
>--- a/drivers/vfio/vfio_iommu_type1.c
>+++ b/drivers/vfio/vfio_iommu_type1.c
>@@ -36,6 +36,7 @@
> #include 
> #include 
> #include 
>+#include 
> 
> #define DRIVER_VERSION  "0.2"
> #define DRIVER_AUTHOR   "Alex Williamson "
>@@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
>struct vfio_dma *dma)
>   vfio_lock_acct(-unlocked);
> }
> 
>+static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
>+  dma_addr_t iova, size_t size)
>+{
>+  struct vfio_domain *d;
>+  int ret = 0;
>+
>+  list_for_each_entry(d, >domain_list, next) {
>+  ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
>+  if (ret)
>+  break;
>+  }
>+  return ret;
>+}
>+
> static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
> {
>   vfio_unmap_unpin(iommu, dma);
>@@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>   return ret;
> }
> 
>+static int vfio_register_msi_range(struct vfio_iommu *iommu,
>+ struct vfio_iommu_type1_dma_map *map)
>+{
>+  dma_addr_t iova = map->iova;
>+  size_t size = map->size;
>+  int ret = 0;
>+  struct vfio_dma *dma;
>+  unsigned long order;
>+  uint64_t mask;
>+
>+  /* Verify that none of our __u64 fields overflow */
>+  if (map->size != size || map->iova != iova)
>+  return -EINVAL;
>+
>+  order =  __ffs(vfio_pgsize_bitmap(iommu));
>+  mask = ((uint64_t)1 << order) - 1;
>+
>+  WARN_ON(mask & PAGE_MASK);
>+
>+  if (!size || (size | iova) & mask)
>+  return -EINVAL;
>+
>+  /* Don't allow IOVA address wrap */
>+  if (iova + size - 1 < iova)
>+  return -EINVAL;
>+
>+  mutex_lock(>lock);
>+
>+  if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
>+  ret =  -EEXIST;
>+  goto unlock;
>+  }
>+
>+  dma = kzalloc(sizeof(*dma), GFP_KERNEL);
>+  if (!dma) {
>+  ret = -ENOMEM;
>+  goto unlock;
>+  }
>+
>+  dma->iova = iova;
>+  dma->size = size;
>+  dma->type = VFIO_IOVA_RESERVED;
>+
>+  ret = vfio_set_msi_aperture(iommu, iova, size);
>+  if (ret)
>+  goto free_unlock;
>+
>+  vfio_link_dma(iommu, dma);
>+  goto unlock;
>+
>+free_unlock:
>+  kfree(dma);
>+unlock:
>+  mutex_unlock(>lock);
>+  return ret;
>+}
>+
> static int vfio_bus_type(struct device *dev, void *data)
> {
>   struct bus_type **bus = data;
>@@ -1062,7 +1134,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>   } else if (cmd == VFIO_IOMMU_MAP_DMA) {
>   struct vfio_iommu_type1_dma_map map;
>   uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
>-  

Re: [PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-05 Thread Chalamarla, Tirumalesh





On 5/4/16, 4:54 AM, "linux-arm-kernel on behalf of Eric Auger" 
 wrote:

>The user is allowed to register a reserved MSI IOVA range by using the
>DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
>This region is stored in the vfio_dma rb tree. At that point the iova
>range is not mapped to any target address yet. The host kernel will use
>those iova when needed, typically when MSIs are allocated.
>
>Signed-off-by: Eric Auger 
>Signed-off-by: Bharat Bhushan 
>
>---
>v7 -> v8:
>- use iommu_msi_set_aperture function. There is no notion of
>  unregistration anymore since the reserved msi slot remains
>  until the container gets closed.
>
>v6 -> v7:
>- use iommu_free_reserved_iova_domain
>- convey prot attributes downto dma-reserved-iommu iova domain creation
>- reserved bindings teardown now performed on iommu domain destruction
>- rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
> VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
>- change title
>- pass the protection attribute to dma-reserved-iommu API
>
>v3 -> v4:
>- use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
>- protect vfio_register_reserved_iova_range implementation with
>  CONFIG_IOMMU_DMA_RESERVED
>- handle unregistration by user-space and on vfio_iommu_type1 release
>
>v1 -> v2:
>- set returned value according to alloc_reserved_iova_domain result
>- free the iova domains in case any error occurs
>
>RFC v1 -> v1:
>- takes into account Alex comments, based on
>  [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
>- use the existing dma map/unmap ioctl interface with a flag to register
>  a reserved IOVA range. A single reserved iova region is allowed.
>---
> drivers/vfio/vfio_iommu_type1.c | 78 -
> include/uapi/linux/vfio.h   | 10 +-
> 2 files changed, 86 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
>index 94a9916..4d3a6f1 100644
>--- a/drivers/vfio/vfio_iommu_type1.c
>+++ b/drivers/vfio/vfio_iommu_type1.c
>@@ -36,6 +36,7 @@
> #include 
> #include 
> #include 
>+#include 
> 
> #define DRIVER_VERSION  "0.2"
> #define DRIVER_AUTHOR   "Alex Williamson "
>@@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
>struct vfio_dma *dma)
>   vfio_lock_acct(-unlocked);
> }
> 
>+static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
>+  dma_addr_t iova, size_t size)
>+{
>+  struct vfio_domain *d;
>+  int ret = 0;
>+
>+  list_for_each_entry(d, >domain_list, next) {
>+  ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
>+  if (ret)
>+  break;
>+  }
>+  return ret;
>+}
>+
> static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
> {
>   vfio_unmap_unpin(iommu, dma);
>@@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>   return ret;
> }
> 
>+static int vfio_register_msi_range(struct vfio_iommu *iommu,
>+ struct vfio_iommu_type1_dma_map *map)
>+{
>+  dma_addr_t iova = map->iova;
>+  size_t size = map->size;
>+  int ret = 0;
>+  struct vfio_dma *dma;
>+  unsigned long order;
>+  uint64_t mask;
>+
>+  /* Verify that none of our __u64 fields overflow */
>+  if (map->size != size || map->iova != iova)
>+  return -EINVAL;
>+
>+  order =  __ffs(vfio_pgsize_bitmap(iommu));
>+  mask = ((uint64_t)1 << order) - 1;
>+
>+  WARN_ON(mask & PAGE_MASK);
>+
>+  if (!size || (size | iova) & mask)
>+  return -EINVAL;
>+
>+  /* Don't allow IOVA address wrap */
>+  if (iova + size - 1 < iova)
>+  return -EINVAL;
>+
>+  mutex_lock(>lock);
>+
>+  if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
>+  ret =  -EEXIST;
>+  goto unlock;
>+  }
>+
>+  dma = kzalloc(sizeof(*dma), GFP_KERNEL);
>+  if (!dma) {
>+  ret = -ENOMEM;
>+  goto unlock;
>+  }
>+
>+  dma->iova = iova;
>+  dma->size = size;
>+  dma->type = VFIO_IOVA_RESERVED;
>+
>+  ret = vfio_set_msi_aperture(iommu, iova, size);
>+  if (ret)
>+  goto free_unlock;
>+
>+  vfio_link_dma(iommu, dma);
>+  goto unlock;
>+
>+free_unlock:
>+  kfree(dma);
>+unlock:
>+  mutex_unlock(>lock);
>+  return ret;
>+}
>+
> static int vfio_bus_type(struct device *dev, void *data)
> {
>   struct bus_type **bus = data;
>@@ -1062,7 +1134,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>   } else if (cmd == VFIO_IOMMU_MAP_DMA) {
>   struct vfio_iommu_type1_dma_map map;
>   uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
>-  VFIO_DMA_MAP_FLAG_WRITE;
>+  VFIO_DMA_MAP_FLAG_WRITE |
>+  VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA;
> 
> 

[PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-04 Thread Eric Auger
The user is allowed to register a reserved MSI IOVA range by using the
DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
This region is stored in the vfio_dma rb tree. At that point the iova
range is not mapped to any target address yet. The host kernel will use
those iova when needed, typically when MSIs are allocated.

Signed-off-by: Eric Auger 
Signed-off-by: Bharat Bhushan 

---
v7 -> v8:
- use iommu_msi_set_aperture function. There is no notion of
  unregistration anymore since the reserved msi slot remains
  until the container gets closed.

v6 -> v7:
- use iommu_free_reserved_iova_domain
- convey prot attributes downto dma-reserved-iommu iova domain creation
- reserved bindings teardown now performed on iommu domain destruction
- rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
 VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
- change title
- pass the protection attribute to dma-reserved-iommu API

v3 -> v4:
- use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
- protect vfio_register_reserved_iova_range implementation with
  CONFIG_IOMMU_DMA_RESERVED
- handle unregistration by user-space and on vfio_iommu_type1 release

v1 -> v2:
- set returned value according to alloc_reserved_iova_domain result
- free the iova domains in case any error occurs

RFC v1 -> v1:
- takes into account Alex comments, based on
  [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
- use the existing dma map/unmap ioctl interface with a flag to register
  a reserved IOVA range. A single reserved iova region is allowed.
---
 drivers/vfio/vfio_iommu_type1.c | 78 -
 include/uapi/linux/vfio.h   | 10 +-
 2 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 94a9916..4d3a6f1 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define DRIVER_VERSION  "0.2"
 #define DRIVER_AUTHOR   "Alex Williamson "
@@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
struct vfio_dma *dma)
vfio_lock_acct(-unlocked);
 }
 
+static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
+   dma_addr_t iova, size_t size)
+{
+   struct vfio_domain *d;
+   int ret = 0;
+
+   list_for_each_entry(d, >domain_list, next) {
+   ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
+   if (ret)
+   break;
+   }
+   return ret;
+}
+
 static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
 {
vfio_unmap_unpin(iommu, dma);
@@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
return ret;
 }
 
+static int vfio_register_msi_range(struct vfio_iommu *iommu,
+  struct vfio_iommu_type1_dma_map *map)
+{
+   dma_addr_t iova = map->iova;
+   size_t size = map->size;
+   int ret = 0;
+   struct vfio_dma *dma;
+   unsigned long order;
+   uint64_t mask;
+
+   /* Verify that none of our __u64 fields overflow */
+   if (map->size != size || map->iova != iova)
+   return -EINVAL;
+
+   order =  __ffs(vfio_pgsize_bitmap(iommu));
+   mask = ((uint64_t)1 << order) - 1;
+
+   WARN_ON(mask & PAGE_MASK);
+
+   if (!size || (size | iova) & mask)
+   return -EINVAL;
+
+   /* Don't allow IOVA address wrap */
+   if (iova + size - 1 < iova)
+   return -EINVAL;
+
+   mutex_lock(>lock);
+
+   if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
+   ret =  -EEXIST;
+   goto unlock;
+   }
+
+   dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+   if (!dma) {
+   ret = -ENOMEM;
+   goto unlock;
+   }
+
+   dma->iova = iova;
+   dma->size = size;
+   dma->type = VFIO_IOVA_RESERVED;
+
+   ret = vfio_set_msi_aperture(iommu, iova, size);
+   if (ret)
+   goto free_unlock;
+
+   vfio_link_dma(iommu, dma);
+   goto unlock;
+
+free_unlock:
+   kfree(dma);
+unlock:
+   mutex_unlock(>lock);
+   return ret;
+}
+
 static int vfio_bus_type(struct device *dev, void *data)
 {
struct bus_type **bus = data;
@@ -1062,7 +1134,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
} else if (cmd == VFIO_IOMMU_MAP_DMA) {
struct vfio_iommu_type1_dma_map map;
uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
-   VFIO_DMA_MAP_FLAG_WRITE;
+   VFIO_DMA_MAP_FLAG_WRITE |
+   VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA;
 
minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
 
@@ -1072,6 +1145,9 @@ 

[PATCH v9 4/7] vfio: allow reserved msi iova registration

2016-05-04 Thread Eric Auger
The user is allowed to register a reserved MSI IOVA range by using the
DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
This region is stored in the vfio_dma rb tree. At that point the iova
range is not mapped to any target address yet. The host kernel will use
those iova when needed, typically when MSIs are allocated.

Signed-off-by: Eric Auger 
Signed-off-by: Bharat Bhushan 

---
v7 -> v8:
- use iommu_msi_set_aperture function. There is no notion of
  unregistration anymore since the reserved msi slot remains
  until the container gets closed.

v6 -> v7:
- use iommu_free_reserved_iova_domain
- convey prot attributes downto dma-reserved-iommu iova domain creation
- reserved bindings teardown now performed on iommu domain destruction
- rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
 VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
- change title
- pass the protection attribute to dma-reserved-iommu API

v3 -> v4:
- use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
- protect vfio_register_reserved_iova_range implementation with
  CONFIG_IOMMU_DMA_RESERVED
- handle unregistration by user-space and on vfio_iommu_type1 release

v1 -> v2:
- set returned value according to alloc_reserved_iova_domain result
- free the iova domains in case any error occurs

RFC v1 -> v1:
- takes into account Alex comments, based on
  [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
- use the existing dma map/unmap ioctl interface with a flag to register
  a reserved IOVA range. A single reserved iova region is allowed.
---
 drivers/vfio/vfio_iommu_type1.c | 78 -
 include/uapi/linux/vfio.h   | 10 +-
 2 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 94a9916..4d3a6f1 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define DRIVER_VERSION  "0.2"
 #define DRIVER_AUTHOR   "Alex Williamson "
@@ -445,6 +446,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
struct vfio_dma *dma)
vfio_lock_acct(-unlocked);
 }
 
+static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
+   dma_addr_t iova, size_t size)
+{
+   struct vfio_domain *d;
+   int ret = 0;
+
+   list_for_each_entry(d, >domain_list, next) {
+   ret = iommu_msi_set_aperture(d->domain, iova, iova + size - 1);
+   if (ret)
+   break;
+   }
+   return ret;
+}
+
 static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
 {
vfio_unmap_unpin(iommu, dma);
@@ -693,6 +708,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
return ret;
 }
 
+static int vfio_register_msi_range(struct vfio_iommu *iommu,
+  struct vfio_iommu_type1_dma_map *map)
+{
+   dma_addr_t iova = map->iova;
+   size_t size = map->size;
+   int ret = 0;
+   struct vfio_dma *dma;
+   unsigned long order;
+   uint64_t mask;
+
+   /* Verify that none of our __u64 fields overflow */
+   if (map->size != size || map->iova != iova)
+   return -EINVAL;
+
+   order =  __ffs(vfio_pgsize_bitmap(iommu));
+   mask = ((uint64_t)1 << order) - 1;
+
+   WARN_ON(mask & PAGE_MASK);
+
+   if (!size || (size | iova) & mask)
+   return -EINVAL;
+
+   /* Don't allow IOVA address wrap */
+   if (iova + size - 1 < iova)
+   return -EINVAL;
+
+   mutex_lock(>lock);
+
+   if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
+   ret =  -EEXIST;
+   goto unlock;
+   }
+
+   dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+   if (!dma) {
+   ret = -ENOMEM;
+   goto unlock;
+   }
+
+   dma->iova = iova;
+   dma->size = size;
+   dma->type = VFIO_IOVA_RESERVED;
+
+   ret = vfio_set_msi_aperture(iommu, iova, size);
+   if (ret)
+   goto free_unlock;
+
+   vfio_link_dma(iommu, dma);
+   goto unlock;
+
+free_unlock:
+   kfree(dma);
+unlock:
+   mutex_unlock(>lock);
+   return ret;
+}
+
 static int vfio_bus_type(struct device *dev, void *data)
 {
struct bus_type **bus = data;
@@ -1062,7 +1134,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
} else if (cmd == VFIO_IOMMU_MAP_DMA) {
struct vfio_iommu_type1_dma_map map;
uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
-   VFIO_DMA_MAP_FLAG_WRITE;
+   VFIO_DMA_MAP_FLAG_WRITE |
+   VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA;
 
minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
 
@@ -1072,6 +1145,9 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
if (map.argsz