From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:22:43
This is the second respin on top of Robin's series [1], addressing Alex' comments.
Major changes are:
- MSI-doorbell API now is moved to DMA IOMMU API following Alex suggestion
to put all API pieces at the same place (so eventually in the IOMMU
subsystem)
- new iommu_domain_msi_resv struct and accessor through DOMAIN_ATTR_MSI_RESV
domain with mirror VFIO capability
- more robustness I think in the VFIO layer
- added "iommu/iova: fix __alloc_and_insert_iova_range" since with the current
code I failed allocating an IOVA page in a single page domain with upper part
reserved
IOVA range exclusion will be handled in a separate series
The priority really is to discuss and freeze the API and especially the MSI
doorbell's handling. Do we agree to put that in DMA IOMMU?
Note: the size computation does not take into account possible page overlaps
between doorbells but it would add quite a lot of complexity i think.
Tested on AMD Overdrive (single GICv2m frame) with I350 VF assignment.
dependency:
the series depends on Robin's generic-v7 branch:
[1] [PATCH v7 00/22] Generic DT bindings for PCI IOMMUs and ARM SMMU
http://www.spinics.net/lists/arm-kernel/msg531110.html
Best Regards
Eric
Git: complete series available at
https://github.com/eauger/linux/tree/generic-v7-pcie-passthru-v14
the above branch includes a temporary patch to work around a ThunderX pci
bus reset crash (which I think unrelated to this series):
"vfio: pci: HACK! workaround thunderx pci_try_reset_bus crash"
Do not take this one for other platforms.
Eric Auger (15):
iommu/iova: fix __alloc_and_insert_iova_range
iommu: Introduce DOMAIN_ATTR_MSI_RESV
iommu/dma: MSI doorbell alloc/free
iommu/dma: Introduce iommu_calc_msi_resv
iommu/arm-smmu: Implement domain_get_attr for DOMAIN_ATTR_MSI_RESV
irqchip/gic-v2m: Register the MSI doorbell
irqchip/gicv3-its: Register the MSI doorbell
vfio: Introduce a vfio_dma type field
vfio/type1: vfio_find_dma accepting a type argument
vfio/type1: Implement recursive vfio_find_dma_from_node
vfio/type1: Handle unmap/unpin and replay for VFIO_IOVA_RESERVED slots
vfio: Allow reserved msi iova registration
vfio/type1: Check doorbell safety
iommu/arm-smmu: Do not advertise IOMMU_CAP_INTR_REMAP
vfio/type1: Introduce MSI_RESV capability
Robin Murphy (1):
iommu/dma: Allow MSI-only cookies
drivers/iommu/Kconfig | 4 +-
drivers/iommu/arm-smmu-v3.c | 10 +-
drivers/iommu/arm-smmu.c | 10 +-
drivers/iommu/dma-iommu.c | 184 ++++++++++++++++++++++++++
drivers/iommu/iova.c | 2 +-
drivers/irqchip/irq-gic-v2m.c | 10 +-
drivers/irqchip/irq-gic-v3-its.c | 13 ++
drivers/vfio/vfio_iommu_type1.c | 279 +++++++++++++++++++++++++++++++++++++--
include/linux/dma-iommu.h | 59 +++++++++
include/linux/iommu.h | 8 ++
include/uapi/linux/vfio.h | 30 ++++-
11 files changed, 587 insertions(+), 22 deletions(-)
--
1.9.1
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:22:45
Introduce a new DOMAIN_ATTR_MSI_RESV domain attribute and associated
iommu_domain msi_resv field. It comprises the size and alignment
of the IOVA reserved window dedicated to MSI mapping. This attribute
only is supported when MSI must be IOMMU mapped.
This is the case on ARM.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Suggested-by: Alex Williamson <redacted>
---
v13 -> v14:
- new msi_resv type and name
v12 -> v13:
- reword the commit message
v8 -> v9:
- rename programmable into iommu_msi_supported
- add iommu_domain_msi_aperture_valid
v8: creation
- deprecates DOMAIN_ATTR_MSI_MAPPING flag
---
include/linux/iommu.h | 8 ++++++++
1 file changed, 8 insertions(+)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:23:02
From: Robin Murphy <robin.murphy@arm.com>
IOMMU domain users such as VFIO face a similar problem to DMA API ops
with regard to mapping MSI messages in systems where the MSI write is
subject to IOMMU translation. With the relevant infrastructure now in
place for managed DMA domains, it's actually really simple for other
users to piggyback off that and reap the benefits without giving up
their own IOVA management, and without having to reinvent their own
wheel in the MSI layer.
Allow such users to opt into automatic MSI remapping by dedicating a
region of their IOVA space to a managed cookie.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v14:
- restore reserve_iova for iova >= base + size
v1 -> v13 incorpration:
- compared to Robin's version
- add NULL last param to iommu_dma_init_domain
- set the msi_geometry aperture
- I removed
if (base < U64_MAX - size)
reserve_iova(iovad, iova_pfn(iovad, base + size), ULONG_MAX);
don't get why we would reserve something out of the scope of the iova domain?
what do I miss?
---
drivers/iommu/dma-iommu.c | 39 +++++++++++++++++++++++++++++++++++++++
include/linux/dma-iommu.h | 9 +++++++++
2 files changed, 48 insertions(+)
@@ -67,6 +67,9 @@ int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);/* The DMA API isn't _quite_ the whole story, though... */voidiommu_dma_map_msi_msg(intirq,structmsi_msg*msg);+intiommu_get_dma_msi_region_cookie(structiommu_domain*domain,+dma_addr_tbase,u64size);+#elsestructiommu_domain;
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:23:15
We introduce the capability to (un)register MSI doorbells.
A doorbell region is characterized by its physical address base, size,
and whether it its safe (ie. it implements IRQ remapping). A doorbell
can be per-cpu or global. We currently only care about global doorbells.
A function returns whether all registered doorbells are safe.
MSI controllers likely to work along with IOMMU that translate MSI
transaction must register their doorbells to allow device assignment
with MSI support. Otherwise the MSI transactions will cause IOMMU faults.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v14:
- previously in msi-doorbell.h/c
---
drivers/iommu/dma-iommu.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/dma-iommu.h | 41 ++++++++++++++++++++++++++
2 files changed, 116 insertions(+)
@@ -43,6 +43,38 @@ struct iommu_dma_cookie {spinlock_tmsi_lock;};+/**+*structiommu_msi_doorbell_info-MSIdoorbellregiondescriptor+*@percpu_doorbells:percpudoorbellbaseaddress+*@global_doorbell:baseaddressofthedoorbell+*@doorbell_is_percpu:isthedoorbellpercpuorglobal?+*@safe:trueifirqremappingisimplemented+*@size:sizeofthedoorbell+*/+structiommu_msi_doorbell_info{+union{+phys_addr_t__percpu*percpu_doorbells;+phys_addr_tglobal_doorbell;+};+booldoorbell_is_percpu;+boolsafe;+size_tsize;+};++structiommu_msi_doorbell{+structiommu_msi_doorbell_infoinfo;+structlist_headnext;+};++/* list of registered MSI doorbells */+staticLIST_HEAD(iommu_msi_doorbell_list);++/* counts the number of unsafe registered doorbells */+staticuintnb_unsafe_doorbells;++/* protects the list and nb_unsafe_doorbells */+staticDEFINE_MUTEX(iommu_msi_doorbell_mutex);+staticinlinestructiova_domain*cookie_iovad(structiommu_domain*domain){return&((structiommu_dma_cookie*)domain->iova_cookie)->iovad;
@@ -755,3 +787,46 @@ int iommu_get_dma_msi_region_cookie(struct iommu_domain *domain,return0;}EXPORT_SYMBOL(iommu_get_dma_msi_region_cookie);++structiommu_msi_doorbell_info*+iommu_msi_doorbell_alloc(phys_addr_tbase,size_tsize,boolsafe)+{+structiommu_msi_doorbell*db;++db=kzalloc(sizeof(*db),GFP_KERNEL);+if(!db)+returnERR_PTR(-ENOMEM);++db->info.global_doorbell=base;+db->info.size=size;+db->info.safe=safe;++mutex_lock(&iommu_msi_doorbell_mutex);+list_add(&db->next,&iommu_msi_doorbell_list);+if(!db->info.safe)+nb_unsafe_doorbells++;+mutex_unlock(&iommu_msi_doorbell_mutex);+return&db->info;+}+EXPORT_SYMBOL_GPL(iommu_msi_doorbell_alloc);++voidiommu_msi_doorbell_free(structiommu_msi_doorbell_info*dbinfo)+{+structiommu_msi_doorbell*db;++db=container_of(dbinfo,structiommu_msi_doorbell,info);++mutex_lock(&iommu_msi_doorbell_mutex);+list_del(&db->next);+if(!db->info.safe)+nb_unsafe_doorbells--;+mutex_unlock(&iommu_msi_doorbell_mutex);+kfree(db);+}+EXPORT_SYMBOL_GPL(iommu_msi_doorbell_free);++booliommu_msi_doorbell_safe(void)+{+return!nb_unsafe_doorbells;+}+EXPORT_SYMBOL_GPL(iommu_msi_doorbell_safe);
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:23:24
ARM smmu and smmu-v3 translate MSI transactions so their driver
are must implement domain_get_attr for DOMAIN_ATTR_MSI_RESV.
This allows to retrieve the size and alignment requirements of
the MSI reserved IOVA window.
Also IOMMU_DMA gets selected since it exposes the API to map the
MSIs.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
drivers/iommu/Kconfig | 4 ++--
drivers/iommu/arm-smmu-v3.c | 7 +++++++
drivers/iommu/arm-smmu.c | 7 +++++++
3 files changed, 16 insertions(+), 2 deletions(-)
@@ -943,6 +943,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,domain->geometry.aperture_end=(1UL<<ias)-1;domain->geometry.force_aperture=true;+if(domain->type==IOMMU_DOMAIN_UNMANAGED)+iommu_calc_msi_resv(domain);+/* Initialise the context bank with our page table cfg */arm_smmu_init_context_bank(smmu_domain,&pgtbl_cfg);
@@ -1486,6 +1489,10 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,caseDOMAIN_ATTR_NESTING:*(int*)data=(smmu_domain->stage==ARM_SMMU_DOMAIN_NESTED);return0;+caseDOMAIN_ATTR_MSI_RESV:+*(structiommu_domain_msi_resv*)data=+smmu_domain->domain.msi_resv;+return0;default:return-ENODEV;}
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:23:34
iommu_calc_msi_resv() sum up the number of iommu pages of the lowest
order supported by the iommu domain requested to map all the registered
doorbells. This function will allow to dimension the intermediate
physical address (IPA) aperture requested to map the MSI doorbells.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v14
- name and proto changed, moved to dma-iommu
---
drivers/iommu/dma-iommu.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/dma-iommu.h | 11 +++++++-
2 files changed, 80 insertions(+), 1 deletion(-)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:23:53
This patch registers the ITS global doorbell. Registered information
are needed to set up the KVM passthrough use case.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v14:
- use iommu_msi_doorbell_alloc/free
v12 -> v13:
- use new doorbell registration prototype
v11 -> v12:
- use new irq_get_msi_doorbell_info name
- simplify error handling
v10 -> v11:
- adapt to new doorbell registration API and implement msi_doorbell_info
---
drivers/irqchip/irq-gic-v3-its.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:24:04
Register the GIC V2M global doorbell. The registered information
are used to set up the KVM passthrough use case.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v14:
- use iommu_msi_doorbell_alloc/free
v12 -> v13:
- use new msi doorbell registration prototype
- remove iommu protection attributes
- add unregistration in teardown
v11 -> v12:
- use irq_get_msi_doorbell_info new name
- simplify error handling
v10 -> v11:
- use the new registration API and re-implement the msi_doorbell_info
ops
v9 -> v10:
- introduce the registration concept in place of msi_doorbell_info
callback
v8 -> v9:
- use global_doorbell instead of percpu_doorbells
v7 -> v8:
- gicv2m_msi_doorbell_info does not return a pointer to const
- remove spurious !v2m check
- add IOMMU_MMIO flag
v7: creation
---
drivers/irqchip/irq-gic-v2m.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
@@ -70,6 +70,7 @@ struct v2m_data {u32spi_offset;/* offset to be subtracted from SPI number */unsignedlong*bm;/* MSI vector bitmap */u32flags;/* v2m flags for specific implementation */+structiommu_msi_doorbell_info*doorbell_info;/* MSI doorbell */};staticvoidgicv2m_mask_msi_irq(structirq_data*d)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:24:34
Fix the size check within start_pfn and limit_pfn.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
the issue was observed when playing with 1 page iova domain with
higher iova reserved.
---
drivers/iommu/iova.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:25:04
This patch allows the user-space to retrieve the MSI reserved region
requirements, if any. The implementation is based on capability chains,
now also added to VFIO_IOMMU_GET_INFO.
The returned info comprises the size and the alignment requirements
In case the userspace must provide the IOVA aperture, we currently report
a size/alignment based on all the doorbells registered by the host kernel.
This may exceed the actual needs.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v14:
- new capability struct
- change the padding in vfio_iommu_type1_info
v11 -> v12:
- msi_doorbell_pages was renamed msi_doorbell_calc_pages
v9 -> v10:
- move cap_offset after iova_pgsizes
- replace __u64 alignment by __u32 order
- introduce __u32 flags in vfio_iommu_type1_info_cap_msi_geometry and
fix alignment
- call msi-doorbell API to compute the size/alignment
v8 -> v9:
- use iommu_msi_supported flag instead of programmable
- replace IOMMU_INFO_REQUIRE_MSI_MAP flag by a more sophisticated
capability chain, reporting the MSI geometry
v7 -> v8:
- use iommu_domain_msi_geometry
v6 -> v7:
- remove the computation of the number of IOVA pages to be provisionned.
This number depends on the domain/group/device topology which can
dynamically change. Let's rely instead rely on an arbitrary max depending
on the system
v4 -> v5:
- move msi_info and ret declaration within the conditional code
v3 -> v4:
- replace former vfio_domains_require_msi_mapping by
more complex computation of MSI mapping requirements, especially the
number of pages to be provided by the user-space.
- reword patch title
RFC v1 -> v1:
- derived from
[RFC PATCH 3/6] vfio: Extend iommu-info to return MSIs automap state
- renamed allow_msi_reconfig into require_msi_mapping
- fixed VFIO_IOMMU_GET_INFO
---
drivers/vfio/vfio_iommu_type1.c | 67 ++++++++++++++++++++++++++++++++++++++++-
include/uapi/linux/vfio.h | 20 +++++++++++-
2 files changed, 85 insertions(+), 2 deletions(-)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:32:12
On x86 IRQ remapping is abstracted by the IOMMU. On ARM this is abstracted
by the msi controller.
Since we currently have no way to detect whether the MSI controller is
upstream or downstream to the IOMMU we rely on the MSI doorbell information
registered by the interrupt controllers. In case at least one doorbell
does not implement proper isolation, we state the assignment is unsafe
with regard to interrupts. This is a coarse assessment but should allow to
wait for a better system description.
At this point ARM sMMU still advertises IOMMU_CAP_INTR_REMAP. This is
removed in next patch.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v15:
- check vfio_msi_resv before checking whether msi doorbell is safe
v9 -> v10:
- coarse safety assessment based on MSI doorbell info
v3 -> v4:
- rename vfio_msi_parent_irq_remapping_capable into vfio_safe_irq_domain
and irq_remapping into safe_irq_domains
v2 -> v3:
- protect vfio_msi_parent_irq_remapping_capable with
CONFIG_GENERIC_MSI_IRQ_DOMAIN
---
drivers/vfio/vfio_iommu_type1.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
@@ -945,8 +968,13 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,INIT_LIST_HEAD(&domain->group_list);list_add(&group->next,&domain->group_list);+/*+*toadvertisesafeinterruptseithertheIOMMUortheMSIcontrollers+*mustsupportIRQremapping(aka.interrupttranslation)+*/if(!allow_unsafe_interrupts&&-!iommu_capable(bus,IOMMU_CAP_INTR_REMAP)){+(!iommu_capable(bus,IOMMU_CAP_INTR_REMAP)&&+!(vfio_msi_resv(iommu)&&iommu_msi_doorbell_safe()))){pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",__func__);ret=-EPERM;
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:32:23
Do not advertise IOMMU_CAP_INTR_REMAP for arm-smmu(-v3). Indeed the
irq_remapping capability is abstracted on irqchip side for ARM as
opposed to Intel IOMMU featuring IRQ remapping HW.
So to check IRQ remapping capability, the msi domain needs to be
checked instead.
This commit affects platform and PCIe device assignment use cases
on any platform featuring an unsafe MSI controller (currently the
ARM GICv2m). For those platforms the VFIO module must be loaded with
allow_unsafe_interrupts set to 1.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v9 -> v10:
- reword the commit message (allow_unsafe_interrupts)
---
drivers/iommu/arm-smmu-v3.c | 3 ++-
drivers/iommu/arm-smmu.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:32:43
In our RB-tree we get prepared to insert slots of different types
(USER and RESERVED). It becomes useful to be able to search for dma
slots of a specific type or any type.
This patch introduces vfio_find_dma_from_node which starts the
search from a given node and stops on the first node that matches
the @start and @size parameters. If this node also matches the
@type parameter, the node is returned else NULL is returned.
At the moment we only have USER SLOTS so the type will always match.
In a separate patch, this function will be enhanced to pursue the
search recursively in case a node with a different type is
encountered.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v14:
- remove top_node variable
---
drivers/vfio/vfio_iommu_type1.c | 52 +++++++++++++++++++++++++++++++++--------
1 file changed, 42 insertions(+), 10 deletions(-)
@@ -94,25 +94,55 @@ struct vfio_group {*intoDMA'blespaceusingtheIOMMU*/-staticstructvfio_dma*vfio_find_dma(structvfio_iommu*iommu,-dma_addr_tstart,size_tsize)+/**+*vfio_find_dma_from_node:looksforadmaslotintersectingawindow+*fromagivenrbtreenode+*@top:toprbtreenodewherethesearchstarts(includingthisnode)+*@start:windowstart+*@size:windowsize+*@type:windowtype+*/+staticstructvfio_dma*vfio_find_dma_from_node(structrb_node*top,+dma_addr_tstart,size_tsize,+enumvfio_iova_typetype){-structrb_node*node=iommu->dma_list.rb_node;+structrb_node*node=top;+structvfio_dma*dma;while(node){-structvfio_dma*dma=rb_entry(node,structvfio_dma,node);-+dma=rb_entry(node,structvfio_dma,node);if(start+size<=dma->iova)node=node->rb_left;elseif(start>=dma->iova+dma->size)node=node->rb_right;else-returndma;+break;}+if(!node)+returnNULL;++/* a dma slot intersects our window, check the type also matches */+if(type==VFIO_IOVA_ANY||dma->type==type)+returndma;returnNULL;}+/**+*vfio_find_dma:findadmaslotintersectingagivenwindow+*@iommu:vfioiommuhandle+*@start:windowbaseiova+*@size:windowsize+*@type:windowtype+*/+staticstructvfio_dma*vfio_find_dma(structvfio_iommu*iommu,+dma_addr_tstart,size_tsize,+enumvfio_iova_typetype)+{+returnvfio_find_dma_from_node(iommu->dma_list.rb_node,+start,size,type);+}+staticvoidvfio_link_dma(structvfio_iommu*iommu,structvfio_dma*new){structrb_node**link=&iommu->dma_list.rb_node,*parent=NULL;
@@ -484,19 +514,21 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,*mappingswithintherange.*/if(iommu->v2){-dma=vfio_find_dma(iommu,unmap->iova,0);+dma=vfio_find_dma(iommu,unmap->iova,0,VFIO_IOVA_USER);if(dma&&dma->iova!=unmap->iova){ret=-EINVAL;gotounlock;}-dma=vfio_find_dma(iommu,unmap->iova+unmap->size-1,0);+dma=vfio_find_dma(iommu,unmap->iova+unmap->size-1,0,+VFIO_IOVA_USER);if(dma&&dma->iova+dma->size!=unmap->iova+unmap->size){ret=-EINVAL;gotounlock;}}-while((dma=vfio_find_dma(iommu,unmap->iova,unmap->size))){+while((dma=vfio_find_dma(iommu,unmap->iova,unmap->size,+VFIO_IOVA_USER))){if(!iommu->v2&&unmap->iova>dma->iova)break;unmapped+=dma->size;
@@ -600,7 +632,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,mutex_lock(&iommu->lock);-if(vfio_find_dma(iommu,iova,size)){+if(vfio_find_dma(iommu,iova,size,VFIO_IOVA_ANY)){mutex_unlock(&iommu->lock);return-EEXIST;}
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:33:02
This patch handles the case where a node is encountered, matching
@start and @size arguments but not matching the @type argument.
In that case, we need to skip that node and pursue the search in the
node's leaves. In case @start is inferior to the node's base, we
resume the search on the left leaf. If the recursive search on the left
leaves did not produce any match, we search the right leaves recursively.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Alex Williamson <redacted>
---
v10: creation
---
drivers/vfio/vfio_iommu_type1.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:33:07
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 <eric.auger@redhat.com>
Signed-off-by: Bharat Bhushan <redacted>
---
v13 -> v14:
- in vfio_set_msi_aperture, unfold in case of failure
- Get DOMAIN_ATTR_MSI_RESV attribute to decide whether to set the MSI
aperture
v12 -> v13:
- use iommu_get_dma_msi_region_cookie
v9 -> v10
- use VFIO_IOVA_RESERVED_MSI enum value
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 | 97 ++++++++++++++++++++++++++++++++++++++++-
include/uapi/linux/vfio.h | 10 ++++-
2 files changed, 105 insertions(+), 2 deletions(-)
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:34:15
We introduce a vfio_dma type since we will need to discriminate
different types of dma slots:
- VFIO_IOVA_USER: IOVA region used to map user vaddr
- VFIO_IOVA_RESERVED_MSI: IOVA region reserved to map MSI doorbells
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Alex Williamson <redacted>
---
v9 -> v10:
- renamed VFIO_IOVA_RESERVED into VFIO_IOVA_RESERVED_MSI
- explicitly set type to VFIO_IOVA_USER on dma_map
v6 -> v7:
- add VFIO_IOVA_ANY
- do not introduce yet any VFIO_IOVA_RESERVED handling
---
drivers/vfio/vfio_iommu_type1.c | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -53,6 +53,12 @@ module_param_named(disable_hugepages,MODULE_PARM_DESC(disable_hugepages,"Disable VFIO IOMMU support for IOMMU hugepages.");+enumvfio_iova_type{+VFIO_IOVA_USER=0,/* standard IOVA used to map user vaddr */+VFIO_IOVA_RESERVED_MSI,/* reserved to map MSI doorbells */+VFIO_IOVA_ANY,/* matches any IOVA type */+};+structvfio_iommu{structlist_headdomain_list;structmutexlock;
@@ -75,6 +81,7 @@ struct vfio_dma {unsignedlongvaddr;/* Process virtual addr */size_tsize;/* Map size (bytes) */intprot;/* IOMMU_READ/WRITE */+enumvfio_iova_typetype;/* type of IOVA */};structvfio_group{
@@ -607,6 +614,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,dma->iova=iova;dma->vaddr=vaddr;dma->prot=prot;+dma->type=VFIO_IOVA_USER;/* Insert zero-sized and grow as we map chunks of it */vfio_link_dma(iommu,dma);
From: Eric Auger <eric.auger@redhat.com> Date: 2016-10-12 13:34:45
Before allowing the end-user to create VFIO_IOVA_RESERVED dma slots,
let's implement the expected behavior for removal and replay.
As opposed to user dma slots, reserved IOVAs are not systematically bound
to PAs and PAs are not pinned. VFIO just initializes the IOVA "aperture".
IOVAs are allocated outside of the VFIO framework, by the MSI layer which
is responsible to free and unmap them. The MSI mapping resources are freed
by the IOMMU driver on domain destruction.
On the creation of a new domain, the "replay" of a reserved slot simply
needs to set the MSI aperture on the new domain.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v14:
- make iommu_get_dma_msi_region_cookie's failure not passable
- remove useless "select IOMMU_DMA" causing cyclic dependency
- set the MSI region only if needed
v12 -> v13:
- use dma-iommu iommu_get_dma_msi_region_cookie
v9 -> v10:
- replay of a reserved slot sets the MSI aperture on the new domain
- use VFIO_IOVA_RESERVED_MSI enum value instead of VFIO_IOVA_RESERVED
v7 -> v8:
- do no destroy anything anymore, just bypass unmap/unpin and iommu_map
on replay
---
drivers/vfio/vfio_iommu_type1.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
From: Will Deacon <hidden> Date: 2016-10-20 17:33:30
Hi Eric,
Thanks for posting this.
On Wed, Oct 12, 2016 at 01:22:08PM +0000, Eric Auger wrote:
This is the second respin on top of Robin's series [1], addressing Alex' comments.
Major changes are:
- MSI-doorbell API now is moved to DMA IOMMU API following Alex suggestion
to put all API pieces at the same place (so eventually in the IOMMU
subsystem)
- new iommu_domain_msi_resv struct and accessor through DOMAIN_ATTR_MSI_RESV
domain with mirror VFIO capability
- more robustness I think in the VFIO layer
- added "iommu/iova: fix __alloc_and_insert_iova_range" since with the current
code I failed allocating an IOVA page in a single page domain with upper part
reserved
IOVA range exclusion will be handled in a separate series
The priority really is to discuss and freeze the API and especially the MSI
doorbell's handling. Do we agree to put that in DMA IOMMU?
Note: the size computation does not take into account possible page overlaps
between doorbells but it would add quite a lot of complexity i think.
Tested on AMD Overdrive (single GICv2m frame) with I350 VF assignment.
Marc, Robin and I sat down and had a look at the series and, whilst it's
certainly addressing a problem that we desperately want to see fixed, we
think that it's slightly over-engineering in places and could probably
be simplified in the interest of getting something upstream that can be
used as a base, on which the ABI can be extended as concrete use-cases
become clear.
Stepping back a minute, we're trying to reserve some of the VFIO virtual
address space so that it can be used by devices to map their MSI doorbells
using the SMMU. With your patches, this requires that (a) the kernel
tells userspace about the size and alignment of the doorbell region
(MSI_RESV) and (b) userspace tells the kernel the VA-range that can be
used (RESERVED_MSI_IOVA).
However, this is all special-cased for MSI doorbells and there are
potentially other regions of the VFIO address space that are reserved
and need to be communicated to userspace as well. We already know of
hardware where the PCI RC intercepts p2p accesses before they make it
to the SMMU, and other hardware where the MSI doorbell is at a fixed
address. This means that we need a mechanism to communicate *fixed*
regions of virtual address space that are reserved by VFIO. I don't
even particularly care if VFIO_MAP_DMA enforces that, but we do need
a way to tell userspace "hey, you don't want to put memory here because
it won't work well with devices".
In that case, we end up with something like your MSI_RESV capability,
but actually specifying a virtual address range that is simply not to
be used by MAP_DMA -- we don't say anything about MSIs. Now, taking this
to its logical conclusion, we no longer need to distinguish between
remappable reserved regions and fixed reserved regions in the ABI.
Instead, we can have the kernel allocate the virtual address space for
the remappable reserved regions (probably somewhere in the bottom 4GB)
and expose them via the capability. This simplifies things in the
following ways:
* You don't need to keep track of MSI vs DMA addresses in the VFIO rbtree
* You don't need to try collapsing doorbells into a single region
* You don't need a special MAP flavour to map MSI doorbells
* The ABI is reusable for PCI p2p and fixed doorbells
I really think it would make your patch series both generally useful and
an awful lot smaller, whilst leaving the door open to ABI extension on
a case-by-case basis when we determine that it's really needed.
Thoughts?
Will
From: Auger Eric <eric.auger@redhat.com> Date: 2016-10-21 09:27:02
Hi Will,
On 20/10/2016 19:32, Will Deacon wrote:
Hi Eric,
Thanks for posting this.
On Wed, Oct 12, 2016 at 01:22:08PM +0000, Eric Auger wrote:
quoted
This is the second respin on top of Robin's series [1], addressing Alex' comments.
Major changes are:
- MSI-doorbell API now is moved to DMA IOMMU API following Alex suggestion
to put all API pieces at the same place (so eventually in the IOMMU
subsystem)
- new iommu_domain_msi_resv struct and accessor through DOMAIN_ATTR_MSI_RESV
domain with mirror VFIO capability
- more robustness I think in the VFIO layer
- added "iommu/iova: fix __alloc_and_insert_iova_range" since with the current
code I failed allocating an IOVA page in a single page domain with upper part
reserved
IOVA range exclusion will be handled in a separate series
The priority really is to discuss and freeze the API and especially the MSI
doorbell's handling. Do we agree to put that in DMA IOMMU?
Note: the size computation does not take into account possible page overlaps
between doorbells but it would add quite a lot of complexity i think.
Tested on AMD Overdrive (single GICv2m frame) with I350 VF assignment.
Marc, Robin and I sat down and had a look at the series and, whilst it's
certainly addressing a problem that we desperately want to see fixed, we
think that it's slightly over-engineering in places and could probably
be simplified in the interest of getting something upstream that can be
used as a base, on which the ABI can be extended as concrete use-cases
become clear.
Stepping back a minute, we're trying to reserve some of the VFIO virtual
address space so that it can be used by devices to map their MSI doorbells
using the SMMU. With your patches, this requires that (a) the kernel
tells userspace about the size and alignment of the doorbell region
(MSI_RESV) and (b) userspace tells the kernel the VA-range that can be
used (RESERVED_MSI_IOVA).
However, this is all special-cased for MSI doorbells and there are
potentially other regions of the VFIO address space that are reserved
and need to be communicated to userspace as well. We already know of
hardware where the PCI RC intercepts p2p accesses before they make it
to the SMMU, and other hardware where the MSI doorbell is at a fixed
address. This means that we need a mechanism to communicate *fixed*
regions of virtual address space that are reserved by VFIO. I don't
even particularly care if VFIO_MAP_DMA enforces that, but we do need
a way to tell userspace "hey, you don't want to put memory here because
it won't work well with devices".
I think we all agree on this. Exposing an API to the user space
reporting *fixed* reserved IOVA ranges is a requirement anyway. The
problem was quite clearly stated by Alex in
http://lkml.iu.edu/hypermail/linux/kernel/1610.0/03308.html
(VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE)
I started working on this VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE
capability but to me and I think according to Alex, it was a different
API from MSI_RESV.
In that case, we end up with something like your MSI_RESV capability,
but actually specifying a virtual address range that is simply not to
be used by MAP_DMA -- we don't say anything about MSIs. Now, taking this
to its logical conclusion, we no longer need to distinguish between
remappable reserved regions and fixed reserved regions in the ABI.
Instead, we can have the kernel allocate the virtual address space for
the remappable reserved regions (probably somewhere in the bottom 4GB)
and expose them via the capability.
If I understand correctly you want the host to arbitrarily choose where
it puts the iovas reserved for MSI and not ask the userspace.
Well so we are back to the discussions we had in Dec 2015 (see Marc's
answer in http://thread.gmane.org/gmane.comp.emulators.kvm.arm.devel/3858).
- So I guess you will init an iova_domain seomewhere below the 4GB to
allocate the MSIs. what size are you going to choose. Don't you have the
same need to dimension the iova range.
- we still need to assess the MSI assignment safety. How will we compute
safety for VFIO?
This simplifies things in the
following ways:
* You don't need to keep track of MSI vs DMA addresses in the VFIO rbtree
right: I guess you rely on iommu_map to return an error in case the iova
is already mapped somewhere else.
* You don't need to try collapsing doorbells into a single region
why? at host level I guess you will init a single iova domain?
* You don't need a special MAP flavour to map MSI doorbells
right
* The ABI is reusable for PCI p2p and fixed doorbells
right
Aren't we moving the issue at user-space? Currently QEMU mach-virt
address space is fully static. Adapting mach-virt to adjust to host
constraints is not straightforward. It is simple to reject the
assignment in case of collision but more difficult to react positively.
I really think it would make your patch series both generally useful and
an awful lot smaller, whilst leaving the door open to ABI extension on
a case-by-case basis when we determine that it's really needed.
I would like to have a better understanding of how you assess the
security and dimension the iova domain. This is the purpose of msi
doorbell registration, which is not neat at all I acknowledge but well I
did not find any other solution and did not get any other suggestion.
Besides I think the per-cpu thing is over-engineered and this can
definitively be simplified.
VFIO part was reviewed by Alex and I don't have the impression that this
is the blocking part. besides there is on iova.c fix,
IOMMU_CAP_INTR_REMAP removal; so is it really over-complicated?
Thanks
Eric
From: Robin Murphy <robin.murphy@arm.com> Date: 2016-10-24 19:39:48
On 21/10/16 10:26, Auger Eric wrote:
Hi Will,
On 20/10/2016 19:32, Will Deacon wrote:
quoted
Hi Eric,
Thanks for posting this.
On Wed, Oct 12, 2016 at 01:22:08PM +0000, Eric Auger wrote:
quoted
This is the second respin on top of Robin's series [1], addressing Alex' comments.
Major changes are:
- MSI-doorbell API now is moved to DMA IOMMU API following Alex suggestion
to put all API pieces at the same place (so eventually in the IOMMU
subsystem)
- new iommu_domain_msi_resv struct and accessor through DOMAIN_ATTR_MSI_RESV
domain with mirror VFIO capability
- more robustness I think in the VFIO layer
- added "iommu/iova: fix __alloc_and_insert_iova_range" since with the current
code I failed allocating an IOVA page in a single page domain with upper part
reserved
IOVA range exclusion will be handled in a separate series
The priority really is to discuss and freeze the API and especially the MSI
doorbell's handling. Do we agree to put that in DMA IOMMU?
Note: the size computation does not take into account possible page overlaps
between doorbells but it would add quite a lot of complexity i think.
Tested on AMD Overdrive (single GICv2m frame) with I350 VF assignment.
Marc, Robin and I sat down and had a look at the series and, whilst it's
certainly addressing a problem that we desperately want to see fixed, we
think that it's slightly over-engineering in places and could probably
be simplified in the interest of getting something upstream that can be
used as a base, on which the ABI can be extended as concrete use-cases
become clear.
Stepping back a minute, we're trying to reserve some of the VFIO virtual
address space so that it can be used by devices to map their MSI doorbells
using the SMMU. With your patches, this requires that (a) the kernel
tells userspace about the size and alignment of the doorbell region
(MSI_RESV) and (b) userspace tells the kernel the VA-range that can be
used (RESERVED_MSI_IOVA).
However, this is all special-cased for MSI doorbells and there are
potentially other regions of the VFIO address space that are reserved
and need to be communicated to userspace as well. We already know of
hardware where the PCI RC intercepts p2p accesses before they make it
to the SMMU, and other hardware where the MSI doorbell is at a fixed
address. This means that we need a mechanism to communicate *fixed*
regions of virtual address space that are reserved by VFIO. I don't
even particularly care if VFIO_MAP_DMA enforces that, but we do need
a way to tell userspace "hey, you don't want to put memory here because
it won't work well with devices".
I think we all agree on this. Exposing an API to the user space
reporting *fixed* reserved IOVA ranges is a requirement anyway. The
problem was quite clearly stated by Alex in
http://lkml.iu.edu/hypermail/linux/kernel/1610.0/03308.html
(VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE)
I started working on this VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE
capability but to me and I think according to Alex, it was a different
API from MSI_RESV.
quoted
In that case, we end up with something like your MSI_RESV capability,
but actually specifying a virtual address range that is simply not to
be used by MAP_DMA -- we don't say anything about MSIs. Now, taking this
to its logical conclusion, we no longer need to distinguish between
remappable reserved regions and fixed reserved regions in the ABI.
Instead, we can have the kernel allocate the virtual address space for
the remappable reserved regions (probably somewhere in the bottom 4GB)
and expose them via the capability.
If I understand correctly you want the host to arbitrarily choose where
it puts the iovas reserved for MSI and not ask the userspace.
Well so we are back to the discussions we had in Dec 2015 (see Marc's
answer in http://thread.gmane.org/gmane.comp.emulators.kvm.arm.devel/3858).
To an extent, yes, however the difference is that we now know we
definitely have to deal with situations in which userspace *cannot* be
in total control of the memory map, and that changes the game:
_________
/ \
/ Fixed \
/ things (A) \
( _________ )
\ / MSI \ /
X doorbells X
/ \___(B)___/ \
( )
\ Remappable /
\ things (C)/
\_________/
In the absence of A, then B == C so it was very hard to not want to
implement C. As soon as A *has* to be implemented for other reasons,
then that is also sufficient to encompass B. C can still be implemented
later as a nice-to-have, but is not necessary to get B off the ground.
- So I guess you will init an iova_domain seomewhere below the 4GB to
allocate the MSIs. what size are you going to choose. Don't you have the
same need to dimension the iova range.
- we still need to assess the MSI assignment safety. How will we compute
safety for VFIO?
Absolutely. We're talking in general terms of the userspace ABI here,
although that can't help but colour the underlying implementation
decisions. Of course the VFIO internals still have to handle the
specific case of MSIs, but that's basically no more than this:
static bool msi_isolation = true; /* until proven otherwise */
static unsigned long msi_remap_virt_base = 0x08000000; /* fits QEMU */
static size_t msi_remap_size;
vfio_msi_thing_callback(thing) {
msi_remap_size += thing->info.size;
msi_isolation &= thing->info.flags & PROVIDES_ISOLATION;
}
vfio_msi_init(...) {
...
#ifdef CONFIG_X86
msi_remap_virt_base = 0xfee00000;
msi_remap_size = 0x100000;
msi_isolation = irq_remapping_enabled;
#else
irq_for_each_msi_thing(vfio_msi_thing_callback);
#endif
...
}
vfio_attach_group(...) {
...
if (!msi_isolation && !allow_unsafe_interrupts)
return -ENOWAY;
...
get_msi_region_cookie(domain, msi_remap_base, msi_remap_size);
...
}
And when a well-behaved userspace queries the reserved regions, that
base address and size is just one of potentially several that it should
get back. It's that "querying the reserved regions" bit that needs to be
gotten right first time.
Note that at this point I'm no longer even overly bothered about the
details of irq_for_each_msi_thing(), as it's an internal kernel
interface and thus malleable, although obviously the simpler the better.
I have to say Punit's idea of iterating irq_domains does actually look
really neat and tidy as a proof-of-concept, and also makes me think off
on a tangent that it would be sweet to be able to retrieve base+size
from dev->msi_domain to pre-allocate MSI pages in default domains, and
obviate the compose 'failure' case.
This simplifies things in the
quoted
following ways:
* You don't need to keep track of MSI vs DMA addresses in the VFIO rbtree
right: I guess you rely on iommu_map to return an error in case the iova
is already mapped somewhere else.
quoted
* You don't need to try collapsing doorbells into a single region
why? at host level I guess you will init a single iova domain?
Yeah, right now this one goes either way - as things stand, it does make
life easier on the host side to make a single region to hang off the
back of the current iova_cookie magic, and as illustrated above it's
possibly the most trivial part of the whole thing, but the point is we
still don't *need* to. Since a userspace ABI for generic reservations
has to be able handle more than one region for the sake of non-MSI
things, we'd be free to change the kernel-side implementation in future
to just report multiple doorbells as individual regions - for starters,
if and when we add dynamic reservations and userspace gets to pick its
own IOVAs for those, it'll be a damn sight easier *not* to coalesce
everything.
quoted
* You don't need a special MAP flavour to map MSI doorbells
right
quoted
* The ABI is reusable for PCI p2p and fixed doorbells
right
Aren't we moving the issue at user-space? Currently QEMU mach-virt
address space is fully static. Adapting mach-virt to adjust to host
constraints is not straightforward. It is simple to reject the
assignment in case of collision but more difficult to react positively.
The point is that we *have* to move at least some of the issue to
userspace, and by then I'm struggling to see any real difference between
these situations:
a) QEMU asks VFIO to map some pages for DMA, gets an error back because
VFIO detects it conflicts with a reserved region, and gives up.
b) QEMU starts by asking VFIO what regions are reserved, realises they
will overlap with its hard-coded RAM address, and gives up.
where (a) requires a bunch of kernel machinery to second-guess
userspace, while (b) simply relies on userspace not being broken. And if
userspace fails at not being broken, then we simply retain the behaviour
which actually happens right now:
c) QEMU maps some pages for DMA at the same address as PCI config space
on the underlying hardware. Hilarity ensues.
Of course, userspace could be anything other than QEMU as well, so it's
not necessarily second-guessable at all; maybe we make the arbitrary
msi_remap_virt_base a VFIO module parameter to be more accommodating.
Who knows, maybe it turns out that's enough to keep users happy and we
never need to implement fully dynamic reservations.
Robin.
quoted
I really think it would make your patch series both generally useful and
an awful lot smaller, whilst leaving the door open to ABI extension on
a case-by-case basis when we determine that it's really needed.
I would like to have a better understanding of how you assess the
security and dimension the iova domain. This is the purpose of msi
doorbell registration, which is not neat at all I acknowledge but well I
did not find any other solution and did not get any other suggestion.
Besides I think the per-cpu thing is over-engineered and this can
definitively be simplified.
VFIO part was reviewed by Alex and I don't have the impression that this
is the blocking part. besides there is on iova.c fix,
IOMMU_CAP_INTR_REMAP removal; so is it really over-complicated?
Thanks
Eric
From: Auger Eric <eric.auger@redhat.com> Date: 2016-11-02 16:15:33
Hi Robin,
On 24/10/2016 21:39, Robin Murphy wrote:
On 21/10/16 10:26, Auger Eric wrote:
quoted
Hi Will,
On 20/10/2016 19:32, Will Deacon wrote:
quoted
Hi Eric,
Thanks for posting this.
On Wed, Oct 12, 2016 at 01:22:08PM +0000, Eric Auger wrote:
quoted
This is the second respin on top of Robin's series [1], addressing Alex' comments.
Major changes are:
- MSI-doorbell API now is moved to DMA IOMMU API following Alex suggestion
to put all API pieces at the same place (so eventually in the IOMMU
subsystem)
- new iommu_domain_msi_resv struct and accessor through DOMAIN_ATTR_MSI_RESV
domain with mirror VFIO capability
- more robustness I think in the VFIO layer
- added "iommu/iova: fix __alloc_and_insert_iova_range" since with the current
code I failed allocating an IOVA page in a single page domain with upper part
reserved
IOVA range exclusion will be handled in a separate series
The priority really is to discuss and freeze the API and especially the MSI
doorbell's handling. Do we agree to put that in DMA IOMMU?
Note: the size computation does not take into account possible page overlaps
between doorbells but it would add quite a lot of complexity i think.
Tested on AMD Overdrive (single GICv2m frame) with I350 VF assignment.
Marc, Robin and I sat down and had a look at the series and, whilst it's
certainly addressing a problem that we desperately want to see fixed, we
think that it's slightly over-engineering in places and could probably
be simplified in the interest of getting something upstream that can be
used as a base, on which the ABI can be extended as concrete use-cases
become clear.
Stepping back a minute, we're trying to reserve some of the VFIO virtual
address space so that it can be used by devices to map their MSI doorbells
using the SMMU. With your patches, this requires that (a) the kernel
tells userspace about the size and alignment of the doorbell region
(MSI_RESV) and (b) userspace tells the kernel the VA-range that can be
used (RESERVED_MSI_IOVA).
However, this is all special-cased for MSI doorbells and there are
potentially other regions of the VFIO address space that are reserved
and need to be communicated to userspace as well. We already know of
hardware where the PCI RC intercepts p2p accesses before they make it
to the SMMU, and other hardware where the MSI doorbell is at a fixed
address. This means that we need a mechanism to communicate *fixed*
regions of virtual address space that are reserved by VFIO. I don't
even particularly care if VFIO_MAP_DMA enforces that, but we do need
a way to tell userspace "hey, you don't want to put memory here because
it won't work well with devices".
I think we all agree on this. Exposing an API to the user space
reporting *fixed* reserved IOVA ranges is a requirement anyway. The
problem was quite clearly stated by Alex in
http://lkml.iu.edu/hypermail/linux/kernel/1610.0/03308.html
(VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE)
I started working on this VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE
capability but to me and I think according to Alex, it was a different
API from MSI_RESV.
quoted
In that case, we end up with something like your MSI_RESV capability,
but actually specifying a virtual address range that is simply not to
be used by MAP_DMA -- we don't say anything about MSIs. Now, taking this
to its logical conclusion, we no longer need to distinguish between
remappable reserved regions and fixed reserved regions in the ABI.
Instead, we can have the kernel allocate the virtual address space for
the remappable reserved regions (probably somewhere in the bottom 4GB)
and expose them via the capability.
If I understand correctly you want the host to arbitrarily choose where
it puts the iovas reserved for MSI and not ask the userspace.
Well so we are back to the discussions we had in Dec 2015 (see Marc's
answer in http://thread.gmane.org/gmane.comp.emulators.kvm.arm.devel/3858).
To an extent, yes, however the difference is that we now know we
definitely have to deal with situations in which userspace *cannot* be
in total control of the memory map, and that changes the game:
_________
/ \
/ Fixed \
/ things (A) \
( _________ )
\ / MSI \ /
X doorbells X
/ \___(B)___/ \
( )
\ Remappable /
\ things (C)/
\_________/
In the absence of A, then B == C so it was very hard to not want to
implement C. As soon as A *has* to be implemented for other reasons,
then that is also sufficient to encompass B. C can still be implemented
later as a nice-to-have, but is not necessary to get B off the ground.
quoted
- So I guess you will init an iova_domain seomewhere below the 4GB to
allocate the MSIs. what size are you going to choose. Don't you have the
same need to dimension the iova range.
- we still need to assess the MSI assignment safety. How will we compute
safety for VFIO?
Absolutely. We're talking in general terms of the userspace ABI here,
although that can't help but colour the underlying implementation
decisions.
Sorry for the delay I was out of the office last week.
The userspace ABI to retrieve reserved regions is the *easy* part. It is
based on VFIO capability chain and I have an RFC ready.
Of course the VFIO internals still have to handle the
specific case of MSIs, but that's basically no more than this:
static bool msi_isolation = true; /* until proven otherwise */
static unsigned long msi_remap_virt_base = 0x08000000; /* fits QEMU */
static size_t msi_remap_size;
vfio_msi_thing_callback(thing) {
msi_remap_size += thing->info.size;
msi_isolation &= thing->info.flags & PROVIDES_ISOLATION;
}
vfio_msi_init(...) {
...
#ifdef CONFIG_X86
msi_remap_virt_base = 0xfee00000;
msi_remap_size = 0x100000;
msi_isolation = irq_remapping_enabled;
#else
irq_for_each_msi_thing(vfio_msi_thing_callback);
#endif
...
}
vfio_attach_group(...) {
...
if (!msi_isolation && !allow_unsafe_interrupts)
return -ENOWAY;
...
get_msi_region_cookie(domain, msi_remap_base, msi_remap_size);
...
}
I doubt Alex will accept to put that code in VFIO. He suggested in the
past to use the IOMMU API to retrieve the reserved region(s).
what about adding a reserved_regions list in iommu_domain and add a new
iommu_ops, something like
void add_reserved_regions(struct iommu_domain *, struct device *dev)
whose role would be to populate the list. This add_reserved_regions()
would be called on __iommu_attach_device. The list would be emptied on
iommu_domain_free().
arm-smmu cb implementation would be in charge of
- computing non ACS PCI host bridge windows from @dev,
- computing msi_rebase_map/size computation
on x86, cb would simply populate the MSI window.
vfio would lookup the iommu domain reserved_regions list on
VFIO_IOMMU_GET_INFO
Drawback of this approach is the security aspect is not handled by the
IOMMU API.
Note that combining v14 series and this one would implement everything I
think + giving the flexibility for the userspace to choose where it put
things. But well, LPC discussions will bring the last word obviously.
And when a well-behaved userspace queries the reserved regions, that
base address and size is just one of potentially several that it should
get back. It's that "querying the reserved regions" bit that needs to be
gotten right first time.
Note that at this point I'm no longer even overly bothered about the
details of irq_for_each_msi_thing(), as it's an internal kernel
interface and thus malleable, although obviously the simpler the better.
I have to say Punit's idea of iterating irq_domains does actually look
really neat and tidy as a proof-of-concept, and also makes me think off
on a tangent that it would be sweet to be able to retrieve base+size
from dev->msi_domain to pre-allocate MSI pages in default domains, and
obviate the compose 'failure' case.
As Punit mentionned, the natural place where the msi doorbell base,
size and irq_remapping can be retrieved looks to be the irqchip itself.
It works perfectly fine for v2m and its. Hence my first attempt to use a
cb at this level (irqchip msi_doorbell_info up to v11).
Adding a cb at irq_domain level looks quite impractical to me to
retrieve the info. Actually I don't see how to manage that without
adding new fields in irq_domain struct. If you have any suggestion,
please let me know.
Thanks
Eric
quoted
This simplifies things in the
quoted
following ways:
* You don't need to keep track of MSI vs DMA addresses in the VFIO rbtree
right: I guess you rely on iommu_map to return an error in case the iova
is already mapped somewhere else.
quoted
* You don't need to try collapsing doorbells into a single region
why? at host level I guess you will init a single iova domain?
Yeah, right now this one goes either way - as things stand, it does make
life easier on the host side to make a single region to hang off the
back of the current iova_cookie magic, and as illustrated above it's
possibly the most trivial part of the whole thing, but the point is we
still don't *need* to. Since a userspace ABI for generic reservations
has to be able handle more than one region for the sake of non-MSI
things, we'd be free to change the kernel-side implementation in future
to just report multiple doorbells as individual regions - for starters,
if and when we add dynamic reservations and userspace gets to pick its
own IOVAs for those, it'll be a damn sight easier *not* to coalesce
everything.
quoted
quoted
* You don't need a special MAP flavour to map MSI doorbells
right
quoted
* The ABI is reusable for PCI p2p and fixed doorbells
right
Aren't we moving the issue at user-space? Currently QEMU mach-virt
address space is fully static. Adapting mach-virt to adjust to host
constraints is not straightforward. It is simple to reject the
assignment in case of collision but more difficult to react positively.
The point is that we *have* to move at least some of the issue to
userspace, and by then I'm struggling to see any real difference between
these situations:
a) QEMU asks VFIO to map some pages for DMA, gets an error back because
VFIO detects it conflicts with a reserved region, and gives up.
b) QEMU starts by asking VFIO what regions are reserved, realises they
will overlap with its hard-coded RAM address, and gives up.
where (a) requires a bunch of kernel machinery to second-guess
userspace, while (b) simply relies on userspace not being broken. And if
userspace fails at not being broken, then we simply retain the behaviour
which actually happens right now:
c) QEMU maps some pages for DMA at the same address as PCI config space
on the underlying hardware. Hilarity ensues.
Of course, userspace could be anything other than QEMU as well, so it's
not necessarily second-guessable at all; maybe we make the arbitrary
msi_remap_virt_base a VFIO module parameter to be more accommodating.
Who knows, maybe it turns out that's enough to keep users happy and we
never need to implement fully dynamic reservations.
Robin.
quoted
quoted
I really think it would make your patch series both generally useful and
an awful lot smaller, whilst leaving the door open to ABI extension on
a case-by-case basis when we determine that it's really needed.
I would like to have a better understanding of how you assess the
security and dimension the iova domain. This is the purpose of msi
doorbell registration, which is not neat at all I acknowledge but well I
did not find any other solution and did not get any other suggestion.
Besides I think the per-cpu thing is over-engineered and this can
definitively be simplified.
VFIO part was reviewed by Alex and I don't have the impression that this
is the blocking part. besides there is on iova.c fix,
IOMMU_CAP_INTR_REMAP removal; so is it really over-complicated?
Thanks
Eric
Hi Eric,
On 10/12/2016 04:23 PM, Eric Auger wrote:
quoted hunk
On x86 IRQ remapping is abstracted by the IOMMU. On ARM this is abstracted
by the msi controller.
Since we currently have no way to detect whether the MSI controller is
upstream or downstream to the IOMMU we rely on the MSI doorbell information
registered by the interrupt controllers. In case at least one doorbell
does not implement proper isolation, we state the assignment is unsafe
with regard to interrupts. This is a coarse assessment but should allow to
wait for a better system description.
At this point ARM sMMU still advertises IOMMU_CAP_INTR_REMAP. This is
removed in next patch.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v15:
- check vfio_msi_resv before checking whether msi doorbell is safe
v9 -> v10:
- coarse safety assessment based on MSI doorbell info
v3 -> v4:
- rename vfio_msi_parent_irq_remapping_capable into vfio_safe_irq_domain
and irq_remapping into safe_irq_domains
v2 -> v3:
- protect vfio_msi_parent_irq_remapping_capable with
CONFIG_GENERIC_MSI_IRQ_DOMAIN
---
drivers/vfio/vfio_iommu_type1.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
@@ -945,8 +968,13 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,INIT_LIST_HEAD(&domain->group_list);list_add(&group->next,&domain->group_list);+/*+*toadvertisesafeinterruptseithertheIOMMUortheMSIcontrollers+*mustsupportIRQremapping(aka.interrupttranslation)+*/if(!allow_unsafe_interrupts&&-!iommu_capable(bus,IOMMU_CAP_INTR_REMAP)){+(!iommu_capable(bus,IOMMU_CAP_INTR_REMAP)&&+!(vfio_msi_resv(iommu)&&iommu_msi_doorbell_safe()))){pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",__func__);ret=-EPERM;
I understand from the other discussions that you will respin these
series, but anyway I have tested this version with GICV3 + ITS and it
stops here. As I have a GICv3 I am not supposed to enable allow unsafe
interrupts. What I see is that vfio_msi_resv returns false just because
the iommu->domain_list list is empty. The newly created domain is
actually added to the domain_list at the end of this function, so it
seems normal for the list to be empty at this point.
Thanks,
Diana
From: Auger Eric <eric.auger@redhat.com> Date: 2016-11-03 14:15:05
Hi Diana,
On 03/11/2016 14:45, Diana Madalina Craciun wrote:
Hi Eric,
On 10/12/2016 04:23 PM, Eric Auger wrote:
quoted
On x86 IRQ remapping is abstracted by the IOMMU. On ARM this is abstracted
by the msi controller.
Since we currently have no way to detect whether the MSI controller is
upstream or downstream to the IOMMU we rely on the MSI doorbell information
registered by the interrupt controllers. In case at least one doorbell
does not implement proper isolation, we state the assignment is unsafe
with regard to interrupts. This is a coarse assessment but should allow to
wait for a better system description.
At this point ARM sMMU still advertises IOMMU_CAP_INTR_REMAP. This is
removed in next patch.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v13 -> v15:
- check vfio_msi_resv before checking whether msi doorbell is safe
v9 -> v10:
- coarse safety assessment based on MSI doorbell info
v3 -> v4:
- rename vfio_msi_parent_irq_remapping_capable into vfio_safe_irq_domain
and irq_remapping into safe_irq_domains
v2 -> v3:
- protect vfio_msi_parent_irq_remapping_capable with
CONFIG_GENERIC_MSI_IRQ_DOMAIN
---
drivers/vfio/vfio_iommu_type1.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
@@ -945,8 +968,13 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,INIT_LIST_HEAD(&domain->group_list);list_add(&group->next,&domain->group_list);+/*+*toadvertisesafeinterruptseithertheIOMMUortheMSIcontrollers+*mustsupportIRQremapping(aka.interrupttranslation)+*/if(!allow_unsafe_interrupts&&-!iommu_capable(bus,IOMMU_CAP_INTR_REMAP)){+(!iommu_capable(bus,IOMMU_CAP_INTR_REMAP)&&+!(vfio_msi_resv(iommu)&&iommu_msi_doorbell_safe()))){pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",__func__);ret=-EPERM;
I understand from the other discussions that you will respin these
series, but anyway I have tested this version with GICV3 + ITS and it
stops here. As I have a GICv3 I am not supposed to enable allow unsafe
interrupts. What I see is that vfio_msi_resv returns false just because
the iommu->domain_list list is empty. The newly created domain is
actually added to the domain_list at the end of this function, so it
seems normal for the list to be empty at this point.
Thanks for reporting the issue. You are fully right. I must have missed
that test. I should just check the current iommu_domain attribute I think.
waiting for a fix, please probe the vfio_iommu_type1 module with
allow_unsafe_interrupts=1
Thanks
Eric