From: Jean-Philippe Brucker <jean-philippe.bruc...@arm.com>

The device may provide information about hardware tables and additional
capabilities for each device. Parse the new probe fields.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.bruc...@arm.com>
[Vivek: Refactor to use "struct virtio_iommu_probe_table_format" rather
        than separate structures for page table and pasid table format.]
Signed-off-by: Vivek Gautam <vivek.gau...@arm.com>
Cc: Joerg Roedel <j...@8bytes.org>
Cc: Will Deacon <will.dea...@arm.com>
Cc: Michael S. Tsirkin <m...@redhat.com>
Cc: Robin Murphy <robin.mur...@arm.com>
Cc: Jean-Philippe Brucker <jean-phili...@linaro.org>
Cc: Eric Auger <eric.au...@redhat.com>
Cc: Alex Williamson <alex.william...@redhat.com>
Cc: Kevin Tian <kevin.t...@intel.com>
Cc: Jacob Pan <jacob.jun....@linux.intel.com>
Cc: Liu Yi L <yi.l....@intel.com>
Cc: Lorenzo Pieralisi <lorenzo.pieral...@arm.com>
Cc: Shameerali Kolothum Thodi <shameerali.kolothum.th...@huawei.com>
---
 drivers/iommu/virtio-iommu.c | 102 ++++++++++++++++++++++++++++++++++-
 1 file changed, 101 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
index 2bfdd5734844..12d73321dbf4 100644
--- a/drivers/iommu/virtio-iommu.c
+++ b/drivers/iommu/virtio-iommu.c
@@ -78,6 +78,17 @@ struct viommu_endpoint {
        struct viommu_dev               *viommu;
        struct viommu_domain            *vdomain;
        struct list_head                resv_regions;
+
+       /* properties of the physical IOMMU */
+       u64                             pgsize_mask;
+       u64                             input_start;
+       u64                             input_end;
+       u8                              output_bits;
+       u8                              pasid_bits;
+       /* Preferred PASID table format */
+       void                            *pstf;
+       /* Preferred page table format */
+       void                            *pgtf;
 };
 
 struct viommu_request {
@@ -457,6 +468,72 @@ static int viommu_add_resv_mem(struct viommu_endpoint 
*vdev,
        return 0;
 }
 
+static int viommu_add_pgsize_mask(struct viommu_endpoint *vdev,
+                                 struct virtio_iommu_probe_page_size_mask 
*prop,
+                                 size_t len)
+{
+       if (len < sizeof(*prop))
+               return -EINVAL;
+       vdev->pgsize_mask = le64_to_cpu(prop->mask);
+       return 0;
+}
+
+static int viommu_add_input_range(struct viommu_endpoint *vdev,
+                                 struct virtio_iommu_probe_input_range *prop,
+                                 size_t len)
+{
+       if (len < sizeof(*prop))
+               return -EINVAL;
+       vdev->input_start       = le64_to_cpu(prop->start);
+       vdev->input_end         = le64_to_cpu(prop->end);
+       return 0;
+}
+
+static int viommu_add_output_size(struct viommu_endpoint *vdev,
+                                 struct virtio_iommu_probe_output_size *prop,
+                                 size_t len)
+{
+       if (len < sizeof(*prop))
+               return -EINVAL;
+       vdev->output_bits = prop->bits;
+       return 0;
+}
+
+static int viommu_add_pasid_size(struct viommu_endpoint *vdev,
+                                struct virtio_iommu_probe_pasid_size *prop,
+                                size_t len)
+{
+       if (len < sizeof(*prop))
+               return -EINVAL;
+       vdev->pasid_bits = prop->bits;
+       return 0;
+}
+
+static int viommu_add_pgtf(struct viommu_endpoint *vdev, void *pgtf, size_t 
len)
+{
+       /* Select the first page table format available */
+       if (len < sizeof(struct virtio_iommu_probe_table_format) || vdev->pgtf)
+               return -EINVAL;
+
+       vdev->pgtf = kmemdup(pgtf, len, GFP_KERNEL);
+       if (!vdev->pgtf)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int viommu_add_pstf(struct viommu_endpoint *vdev, void *pstf, size_t 
len)
+{
+       if (len < sizeof(struct virtio_iommu_probe_table_format) || vdev->pstf)
+               return -EINVAL;
+
+       vdev->pstf = kmemdup(pstf, len, GFP_KERNEL);
+       if (!vdev->pstf)
+               return -ENOMEM;
+
+       return 0;
+}
+
 static int viommu_probe_endpoint(struct viommu_dev *viommu, struct device *dev)
 {
        int ret;
@@ -493,11 +570,30 @@ static int viommu_probe_endpoint(struct viommu_dev 
*viommu, struct device *dev)
 
        while (type != VIRTIO_IOMMU_PROBE_T_NONE &&
               cur < viommu->probe_size) {
+               void *value = prop;
                len = le16_to_cpu(prop->length) + sizeof(*prop);
 
                switch (type) {
                case VIRTIO_IOMMU_PROBE_T_RESV_MEM:
-                       ret = viommu_add_resv_mem(vdev, (void *)prop, len);
+                       ret = viommu_add_resv_mem(vdev, value, len);
+                       break;
+               case VIRTIO_IOMMU_PROBE_T_PAGE_SIZE_MASK:
+                       ret = viommu_add_pgsize_mask(vdev, value, len);
+                       break;
+               case VIRTIO_IOMMU_PROBE_T_INPUT_RANGE:
+                       ret = viommu_add_input_range(vdev, value, len);
+                       break;
+               case VIRTIO_IOMMU_PROBE_T_OUTPUT_SIZE:
+                       ret = viommu_add_output_size(vdev, value, len);
+                       break;
+               case VIRTIO_IOMMU_PROBE_T_PASID_SIZE:
+                       ret = viommu_add_pasid_size(vdev, value, len);
+                       break;
+               case VIRTIO_IOMMU_PROBE_T_PAGE_TABLE_FMT:
+                       ret = viommu_add_pgtf(vdev, value, len);
+                       break;
+               case VIRTIO_IOMMU_PROBE_T_PASID_TABLE_FMT:
+                       ret = viommu_add_pstf(vdev, value, len);
                        break;
                default:
                        dev_err(dev, "unknown viommu prop 0x%x\n", type);
@@ -899,6 +995,8 @@ static struct iommu_device *viommu_probe_device(struct 
device *dev)
 
 err_free_dev:
        generic_iommu_put_resv_regions(dev, &vdev->resv_regions);
+       kfree(vdev->pstf);
+       kfree(vdev->pgtf);
        kfree(vdev);
 
        return ERR_PTR(ret);
@@ -915,6 +1013,8 @@ static void viommu_release_device(struct device *dev)
        vdev = dev_iommu_priv_get(dev);
 
        generic_iommu_put_resv_regions(dev, &vdev->resv_regions);
+       kfree(vdev->pstf);
+       kfree(vdev->pgtf);
        kfree(vdev);
 }
 
-- 
2.17.1

Reply via email to