Message ID | 20210930185050.262759-4-jean-philippe@linaro.org |
---|---|
State | New |
Headers | show |
Series | virtio-iommu: Support VIRTIO_IOMMU_F_BYPASS_CONFIG | expand |
Hi jean, On 9/30/21 8:50 PM, Jean-Philippe Brucker wrote: > The driver can create a bypass domain by passing the > VIRTIO_IOMMU_ATTACH_F_BYPASS flag on the ATTACH request. Bypass domains > perform slightly better than domains with identity mappings since they > skip translation. > > Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> > --- > hw/virtio/virtio-iommu.c | 32 ++++++++++++++++++++++++++++++-- > 1 file changed, 30 insertions(+), 2 deletions(-) > > diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c > index 82edeaa101..4f0207a3eb 100644 > --- a/hw/virtio/virtio-iommu.c > +++ b/hw/virtio/virtio-iommu.c > @@ -42,6 +42,7 @@ > > typedef struct VirtIOIOMMUDomain { > uint32_t id; > + bool bypass; > GTree *mappings; > QLIST_HEAD(, VirtIOIOMMUEndpoint) endpoint_list; > } VirtIOIOMMUDomain; > @@ -257,12 +258,16 @@ static void virtio_iommu_put_endpoint(gpointer data) > } > > static VirtIOIOMMUDomain *virtio_iommu_get_domain(VirtIOIOMMU *s, > - uint32_t domain_id) > + uint32_t domain_id, > + bool bypass) > { > VirtIOIOMMUDomain *domain; > > domain = g_tree_lookup(s->domains, GUINT_TO_POINTER(domain_id)); > if (domain) { > + if (domain->bypass != bypass) { > + return NULL; > + } > return domain; > } > domain = g_malloc0(sizeof(*domain)); > @@ -270,6 +275,7 @@ static VirtIOIOMMUDomain *virtio_iommu_get_domain(VirtIOIOMMU *s, > domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, > NULL, (GDestroyNotify)g_free, > (GDestroyNotify)g_free); > + domain->bypass = bypass; > g_tree_insert(s->domains, GUINT_TO_POINTER(domain_id), domain); > QLIST_INIT(&domain->endpoint_list); > trace_virtio_iommu_get_domain(domain_id); > @@ -333,11 +339,16 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, > { > uint32_t domain_id = le32_to_cpu(req->domain); > uint32_t ep_id = le32_to_cpu(req->endpoint); > + uint32_t flags = le32_to_cpu(req->flags); > VirtIOIOMMUDomain *domain; > VirtIOIOMMUEndpoint *ep; > > trace_virtio_iommu_attach(domain_id, ep_id); > > + if (flags & ~VIRTIO_IOMMU_ATTACH_F_BYPASS) { > + return VIRTIO_IOMMU_S_INVAL; > + } > + > ep = virtio_iommu_get_endpoint(s, ep_id); > if (!ep) { > return VIRTIO_IOMMU_S_NOENT; > @@ -355,7 +366,12 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, > } > } > > - domain = virtio_iommu_get_domain(s, domain_id); > + domain = virtio_iommu_get_domain(s, domain_id, > + flags & VIRTIO_IOMMU_ATTACH_F_BYPASS); > + if (!domain) { > + /* Incompatible flags */ Incompatible bypass flag > + return VIRTIO_IOMMU_S_INVAL; > + } > QLIST_INSERT_HEAD(&domain->endpoint_list, ep, next); > > ep->domain = domain; > @@ -418,6 +434,10 @@ static int virtio_iommu_map(VirtIOIOMMU *s, > return VIRTIO_IOMMU_S_NOENT; > } > > + if (domain->bypass) { > + return VIRTIO_IOMMU_S_INVAL; > + } > + > interval = g_malloc0(sizeof(*interval)); > > interval->low = virt_start; > @@ -463,6 +483,11 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s, > if (!domain) { > return VIRTIO_IOMMU_S_NOENT; > } > + > + if (domain->bypass) { > + return VIRTIO_IOMMU_S_INVAL; > + } > + > interval.low = virt_start; > interval.high = virt_end; > > @@ -779,6 +804,9 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, > entry.perm = flag; > } > goto unlock; > + } else if (ep->domain->bypass) { > + entry.perm = flag; > + goto unlock; > } > > found = g_tree_lookup_extended(ep->domain->mappings, (gpointer)(&interval), Otherwise looks good to me. Eric
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 82edeaa101..4f0207a3eb 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -42,6 +42,7 @@ typedef struct VirtIOIOMMUDomain { uint32_t id; + bool bypass; GTree *mappings; QLIST_HEAD(, VirtIOIOMMUEndpoint) endpoint_list; } VirtIOIOMMUDomain; @@ -257,12 +258,16 @@ static void virtio_iommu_put_endpoint(gpointer data) } static VirtIOIOMMUDomain *virtio_iommu_get_domain(VirtIOIOMMU *s, - uint32_t domain_id) + uint32_t domain_id, + bool bypass) { VirtIOIOMMUDomain *domain; domain = g_tree_lookup(s->domains, GUINT_TO_POINTER(domain_id)); if (domain) { + if (domain->bypass != bypass) { + return NULL; + } return domain; } domain = g_malloc0(sizeof(*domain)); @@ -270,6 +275,7 @@ static VirtIOIOMMUDomain *virtio_iommu_get_domain(VirtIOIOMMU *s, domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, NULL, (GDestroyNotify)g_free, (GDestroyNotify)g_free); + domain->bypass = bypass; g_tree_insert(s->domains, GUINT_TO_POINTER(domain_id), domain); QLIST_INIT(&domain->endpoint_list); trace_virtio_iommu_get_domain(domain_id); @@ -333,11 +339,16 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, { uint32_t domain_id = le32_to_cpu(req->domain); uint32_t ep_id = le32_to_cpu(req->endpoint); + uint32_t flags = le32_to_cpu(req->flags); VirtIOIOMMUDomain *domain; VirtIOIOMMUEndpoint *ep; trace_virtio_iommu_attach(domain_id, ep_id); + if (flags & ~VIRTIO_IOMMU_ATTACH_F_BYPASS) { + return VIRTIO_IOMMU_S_INVAL; + } + ep = virtio_iommu_get_endpoint(s, ep_id); if (!ep) { return VIRTIO_IOMMU_S_NOENT; @@ -355,7 +366,12 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, } } - domain = virtio_iommu_get_domain(s, domain_id); + domain = virtio_iommu_get_domain(s, domain_id, + flags & VIRTIO_IOMMU_ATTACH_F_BYPASS); + if (!domain) { + /* Incompatible flags */ + return VIRTIO_IOMMU_S_INVAL; + } QLIST_INSERT_HEAD(&domain->endpoint_list, ep, next); ep->domain = domain; @@ -418,6 +434,10 @@ static int virtio_iommu_map(VirtIOIOMMU *s, return VIRTIO_IOMMU_S_NOENT; } + if (domain->bypass) { + return VIRTIO_IOMMU_S_INVAL; + } + interval = g_malloc0(sizeof(*interval)); interval->low = virt_start; @@ -463,6 +483,11 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s, if (!domain) { return VIRTIO_IOMMU_S_NOENT; } + + if (domain->bypass) { + return VIRTIO_IOMMU_S_INVAL; + } + interval.low = virt_start; interval.high = virt_end; @@ -779,6 +804,9 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, entry.perm = flag; } goto unlock; + } else if (ep->domain->bypass) { + entry.perm = flag; + goto unlock; } found = g_tree_lookup_extended(ep->domain->mappings, (gpointer)(&interval),
The driver can create a bypass domain by passing the VIRTIO_IOMMU_ATTACH_F_BYPASS flag on the ATTACH request. Bypass domains perform slightly better than domains with identity mappings since they skip translation. Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> --- hw/virtio/virtio-iommu.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) -- 2.33.0