lkml.org 
[lkml]   [2023]   [Feb]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    SubjectRe: [PATCH v2] vhost/vdpa: Add MSI translation tables to iommu for software-managed MSI
    From

    在 2023/2/7 20:08, Nanyong Sun 写道:
    > From: Rong Wang <wangrong68@huawei.com>
    >
    > Once enable iommu domain for one device, the MSI
    > translation tables have to be there for software-managed MSI.
    > Otherwise, platform with software-managed MSI without an
    > irq bypass function, can not get a correct memory write event
    > from pcie, will not get irqs.
    > The solution is to obtain the MSI phy base address from
    > iommu reserved region, and set it to iommu MSI cookie,
    > then translation tables will be created while request irq.
    >
    > Change log
    > ----------
    >
    > v1->v2:
    > - add resv iotlb to avoid overlap mapping.
    >
    > Signed-off-by: Rong Wang <wangrong68@huawei.com>
    > Signed-off-by: Nanyong Sun <sunnanyong@huawei.com>
    > ---
    > drivers/iommu/iommu.c | 1 +
    > drivers/vhost/vdpa.c | 59 ++++++++++++++++++++++++++++++++++++++++---
    > 2 files changed, 57 insertions(+), 3 deletions(-)
    >
    > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
    > index 5f6a85aea501..af9c064ad8b2 100644
    > --- a/drivers/iommu/iommu.c
    > +++ b/drivers/iommu/iommu.c
    > @@ -2623,6 +2623,7 @@ void iommu_get_resv_regions(struct device *dev, struct list_head *list)
    > if (ops->get_resv_regions)
    > ops->get_resv_regions(dev, list);
    > }
    > +EXPORT_SYMBOL(iommu_get_resv_regions);
    >
    > /**
    > * iommu_put_resv_regions - release resered regions
    > diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
    > index ec32f785dfde..a58979da8acd 100644
    > --- a/drivers/vhost/vdpa.c
    > +++ b/drivers/vhost/vdpa.c
    > @@ -49,6 +49,7 @@ struct vhost_vdpa {
    > struct completion completion;
    > struct vdpa_device *vdpa;
    > struct hlist_head as[VHOST_VDPA_IOTLB_BUCKETS];
    > + struct vhost_iotlb resv_iotlb;


    Nit: it might be better to rename this as resv_regions.


    > struct device dev;
    > struct cdev cdev;
    > atomic_t opened;
    > @@ -216,6 +217,8 @@ static int vhost_vdpa_reset(struct vhost_vdpa *v)
    >
    > v->in_batch = 0;
    >
    > + vhost_iotlb_reset(&v->resv_iotlb);
    > +
    > return vdpa_reset(vdpa);
    > }
    >
    > @@ -1013,6 +1016,10 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
    > msg->iova + msg->size - 1 > v->range.last)
    > return -EINVAL;
    >
    > + if (vhost_iotlb_itree_first(&v->resv_iotlb, msg->iova,
    > + msg->iova + msg->size - 1))
    > + return -EINVAL;
    > +
    > if (vhost_iotlb_itree_first(iotlb, msg->iova,
    > msg->iova + msg->size - 1))
    > return -EEXIST;
    > @@ -1103,6 +1110,45 @@ static ssize_t vhost_vdpa_chr_write_iter(struct kiocb *iocb,
    > return vhost_chr_write_iter(dev, from);
    > }
    >
    > +static int vhost_vdpa_resv_iommu_region(struct iommu_domain *domain, struct device *dma_dev,
    > + struct vhost_iotlb *resv_iotlb)
    > +{
    > + struct list_head dev_resv_regions;
    > + phys_addr_t resv_msi_base = 0;
    > + struct iommu_resv_region *region;
    > + int ret = 0;
    > + bool with_sw_msi = false;
    > + bool with_hw_msi = false;
    > +
    > + INIT_LIST_HEAD(&dev_resv_regions);
    > + iommu_get_resv_regions(dma_dev, &dev_resv_regions);
    > +
    > + list_for_each_entry(region, &dev_resv_regions, list) {
    > + ret = vhost_iotlb_add_range_ctx(resv_iotlb, region->start,
    > + region->start + region->length - 1,
    > + 0, 0, NULL);
    > + if (ret) {
    > + vhost_iotlb_reset(resv_iotlb);
    > + break;
    > + }
    > +
    > + if (region->type == IOMMU_RESV_MSI)
    > + with_hw_msi = true;
    > +
    > + if (region->type == IOMMU_RESV_SW_MSI) {
    > + resv_msi_base = region->start;
    > + with_sw_msi = true;
    > + }
    > + }
    > +
    > + if (!ret && !with_hw_msi && with_sw_msi)
    > + ret = iommu_get_msi_cookie(domain, resv_msi_base);
    > +
    > + iommu_put_resv_regions(dma_dev, &dev_resv_regions);
    > +
    > + return ret;
    > +}


    As discussed in v1, I still prefer to factor out the common logic and
    move them to iommu.c. It helps to simplify the future bug fixing and
    enhancement.


    > +
    > static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
    > {
    > struct vdpa_device *vdpa = v->vdpa;
    > @@ -1128,11 +1174,16 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
    >
    > ret = iommu_attach_device(v->domain, dma_dev);
    > if (ret)
    > - goto err_attach;
    > + goto err_alloc_domain;
    >
    > - return 0;
    > + ret = vhost_vdpa_resv_iommu_region(v->domain, dma_dev, &v->resv_iotlb);
    > + if (ret)
    > + goto err_attach_device;
    >
    > -err_attach:
    > + return 0;
    > +err_attach_device:
    > + iommu_detach_device(v->domain, dma_dev);
    > +err_alloc_domain:
    > iommu_domain_free(v->domain);
    > return ret;
    > }
    > @@ -1385,6 +1436,8 @@ static int vhost_vdpa_probe(struct vdpa_device *vdpa)
    > goto err;
    > }
    >
    > + vhost_iotlb_init(&v->resv_iotlb, 0, 0);
    > +
    > r = dev_set_name(&v->dev, "vhost-vdpa-%u", minor);
    > if (r)
    > goto err;


    We need clean resv_iotlb during release().

    Other looks good.

    Thanks

    \
     
     \ /
      Last update: 2023-03-27 00:25    [W:4.494 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site