diff mbox series

[RFC,v1,07/15] iommu/virtio: Add table format probing

Message ID 20210115121342.15093-8-vivek.gautam@arm.com (mailing list archive)
State New, archived
Headers show
Series iommu/virtio: Nested stage support with Arm | expand

Commit Message

Vivek Kumar Gautam Jan. 15, 2021, 12:13 p.m. UTC
From: Jean-Philippe Brucker <jean-philippe.brucker@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.brucker@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.gautam@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Jean-Philippe Brucker <jean-philippe@linaro.org>
Cc: Eric Auger <eric.auger@redhat.com>
Cc: Alex Williamson <alex.williamson@redhat.com>
Cc: Kevin Tian <kevin.tian@intel.com>
Cc: Jacob Pan <jacob.jun.pan@linux.intel.com>
Cc: Liu Yi L <yi.l.liu@intel.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com>
---
 drivers/iommu/virtio-iommu.c | 102 ++++++++++++++++++++++++++++++++++-
 1 file changed, 101 insertions(+), 1 deletion(-)
diff mbox series

Patch

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);
 }