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

When PASID isn't supported, we can still register one set of tables.
Add support to register Arm LPAE based page table.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.bruc...@arm.com>
[Vivek: Clean-ups to add right tcr definitions and accomodate
        with parent patches]
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      | 131 +++++++++++++++++++++++++-----
 include/uapi/linux/virtio_iommu.h |  30 +++++++
 2 files changed, 139 insertions(+), 22 deletions(-)

diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
index b5222da1dc74..9cc3d35125e9 100644
--- a/drivers/iommu/virtio-iommu.c
+++ b/drivers/iommu/virtio-iommu.c
@@ -135,6 +135,13 @@ struct viommu_event {
 #define to_viommu_domain(domain)       \
        container_of(domain, struct viommu_domain, domain)
 
+#define VIRTIO_FIELD_PREP(_mask, _shift, _val)                 \
+       ({                                                      \
+               (((_val) << VIRTIO_IOMMU_PGTF_ARM_ ## _shift) & \
+                (VIRTIO_IOMMU_PGTF_ARM_ ## _mask <<            \
+                 VIRTIO_IOMMU_PGTF_ARM_ ## _shift));           \
+       })
+
 static int viommu_get_req_errno(void *buf, size_t len)
 {
        struct virtio_iommu_req_tail *tail = buf + len - sizeof(*tail);
@@ -897,6 +904,76 @@ static int viommu_simple_attach(struct viommu_domain 
*vdomain,
        return ret;
 }
 
+static int viommu_config_arm_pgt(struct viommu_endpoint *vdev,
+                                struct io_pgtable_cfg *cfg,
+                                struct virtio_iommu_req_attach_pgt_arm *req,
+                                u64 *asid)
+{
+       int id;
+       struct virtio_iommu_probe_table_format *pgtf = (void *)vdev->pgtf;
+       typeof(&cfg->arm_lpae_s1_cfg.tcr) tcr = &cfg->arm_lpae_s1_cfg.tcr;
+       u64 __tcr;
+
+       if (pgtf->asid_bits != 8 && pgtf->asid_bits != 16)
+               return -EINVAL;
+
+       id = ida_simple_get(&asid_ida, 1, 1 << pgtf->asid_bits, GFP_KERNEL);
+       if (id < 0)
+               return -ENOMEM;
+
+       __tcr = VIRTIO_FIELD_PREP(T0SZ_MASK, T0SZ_SHIFT, tcr->tsz) |
+               VIRTIO_FIELD_PREP(IRGN0_MASK, IRGN0_SHIFT, tcr->irgn) |
+               VIRTIO_FIELD_PREP(ORGN0_MASK, ORGN0_SHIFT, tcr->orgn) |
+               VIRTIO_FIELD_PREP(SH0_MASK, SH0_SHIFT, tcr->sh) |
+               VIRTIO_FIELD_PREP(TG0_MASK, TG0_SHIFT, tcr->tg) |
+               VIRTIO_IOMMU_PGTF_ARM_EPD1 | VIRTIO_IOMMU_PGTF_ARM_HPD0 |
+               VIRTIO_IOMMU_PGTF_ARM_HPD1;
+
+       req->format     = cpu_to_le16(VIRTIO_IOMMU_FOMRAT_PGTF_ARM_LPAE);
+       req->ttbr       = cpu_to_le64(cfg->arm_lpae_s1_cfg.ttbr);
+       req->tcr        = cpu_to_le64(__tcr);
+       req->mair       = cpu_to_le64(cfg->arm_lpae_s1_cfg.mair);
+       req->asid       = cpu_to_le16(id);
+
+       *asid = id;
+       return 0;
+}
+
+static int viommu_attach_pgtable(struct viommu_endpoint *vdev,
+                                struct viommu_domain *vdomain,
+                                enum io_pgtable_fmt fmt,
+                                struct io_pgtable_cfg *cfg,
+                                u64 *asid)
+{
+       int ret;
+       int i, eid;
+
+       struct virtio_iommu_req_attach_table req = {
+               .head.type      = VIRTIO_IOMMU_T_ATTACH_TABLE,
+               .domain         = cpu_to_le32(vdomain->id),
+       };
+
+       switch (fmt) {
+       case ARM_64_LPAE_S1:
+               ret = viommu_config_arm_pgt(vdev, cfg, (void *)&req, asid);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       vdev_for_each_id(i, eid, vdev) {
+               req.endpoint = cpu_to_le32(eid);
+               ret = viommu_send_req_sync(vdomain->viommu, &req, sizeof(req));
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int viommu_teardown_pgtable(struct viommu_domain *vdomain)
 {
        struct iommu_vendor_psdtable_cfg *pst_cfg;
@@ -972,32 +1049,42 @@ static int viommu_setup_pgtable(struct viommu_endpoint 
*vdev,
        if (!ops)
                return -ENOMEM;
 
-       pst_cfg = &tbl->cfg;
-       cfgi = &pst_cfg->vendor.cfg;
-       id = ida_simple_get(&asid_ida, 1, 1 << desc->asid_bits, GFP_KERNEL);
-       if (id < 0) {
-               ret = id;
-               goto err_free_pgtable;
-       }
+       if (!tbl) {
+               /* No PASID support, send attach_table */
+               ret = viommu_attach_pgtable(vdev, vdomain, fmt, &cfg,
+                                           &vdomain->mm.archid);
+               if (ret)
+                       goto err_free_pgtable;
+       } else {
+               pst_cfg = &tbl->cfg;
+               cfgi = &pst_cfg->vendor.cfg;
+               id = ida_simple_get(&asid_ida, 1, 1 << desc->asid_bits, 
GFP_KERNEL);
+               if (id < 0) {
+                       ret = id;
+                       goto err_free_pgtable;
+               }
 
-       asid = id;
-       ret = iommu_psdtable_prepare(tbl, pst_cfg, &cfg, asid);
-       if (ret)
-               goto err_free_asid;
+               asid = id;
+               ret = iommu_psdtable_prepare(tbl, pst_cfg, &cfg, asid);
+               if (ret)
+                       goto err_free_asid;
 
-       /*
-        * Strange to setup an op here?
-        * cd-lib is the actual user of sync op, and therefore the platform
-        * drivers should assign this sync/maintenance ops as per need.
-        */
-       tbl->ops->sync = viommu_flush_pasid;
+               /*
+                * Strange to setup an op here?
+                * cd-lib is the actual user of sync op, and therefore the
+                * cd-lib consumer drivers should assign this sync/maintenance
+                * ops as per need.
+                */
+               tbl->ops->sync = viommu_flush_pasid;
 
-       /* Right now only PASID 0 supported ?? */
-       ret = iommu_psdtable_write(tbl, pst_cfg, 0, &cfgi->s1_cfg->cd);
-       if (ret)
-               goto err_free_asid;
+               /* Right now only PASID 0 supported */
+               ret = iommu_psdtable_write(tbl, pst_cfg, 0, &cfgi->s1_cfg->cd);
+               if (ret)
+                       goto err_free_asid;
+
+               vdomain->mm.ops = ops;
+       }
 
-       vdomain->mm.ops = ops;
        dev_dbg(vdev->dev, "using page table format 0x%x\n", fmt);
 
        return 0;
diff --git a/include/uapi/linux/virtio_iommu.h 
b/include/uapi/linux/virtio_iommu.h
index 3481e4a3dd24..608c8d642e1f 100644
--- a/include/uapi/linux/virtio_iommu.h
+++ b/include/uapi/linux/virtio_iommu.h
@@ -116,6 +116,36 @@ struct virtio_iommu_req_attach_pst_arm {
        struct virtio_iommu_req_tail            tail;
 };
 
+/* TCR_EL1 fields from Arm LPAE format */
+#define VIRTIO_IOMMU_PGTF_ARM_HPD1             (1ULL << 42)
+#define VIRTIO_IOMMU_PGTF_ARM_HPD0             (1ULL << 41)
+#define VIRTIO_IOMMU_PGTF_ARM_EPD1             (1 << 23)
+
+#define VIRTIO_IOMMU_PGTF_ARM_TG0_SHIFT                14
+#define VIRTIO_IOMMU_PGTF_ARM_TG0_MASK         0x3
+#define VIRTIO_IOMMU_PGTF_ARM_SH0_SHIFT                12
+#define VIRTIO_IOMMU_PGTF_ARM_SH0_MASK         0x3
+#define VIRTIO_IOMMU_PGTF_ARM_ORGN0_SHIFT      10
+#define VIRTIO_IOMMU_PGTF_ARM_ORGN0_MASK       0x3
+#define VIRTIO_IOMMU_PGTF_ARM_IRGN0_SHIFT      8
+#define VIRTIO_IOMMU_PGTF_ARM_IRGN0_MASK       0x3
+#define VIRTIO_IOMMU_PGTF_ARM_T0SZ_SHIFT       0
+#define VIRTIO_IOMMU_PGTF_ARM_T0SZ_MASK                0x3f
+
+/* Arm LPAE Page Table Descriptor */
+struct virtio_iommu_req_attach_pgt_arm {
+       struct virtio_iommu_req_head            head;
+       __le32                                  domain;
+       __le32                                  endpoint;
+       __le16                                  format;
+       __le16                                  asid;
+       __le64                                  tcr;
+       __le64                                  ttbr;
+       __le64                                  mair;
+       __u8                                    reserved[28];
+       struct virtio_iommu_req_tail            tail;
+};
+
 #define VIRTIO_IOMMU_MAP_F_READ                        (1 << 0)
 #define VIRTIO_IOMMU_MAP_F_WRITE               (1 << 1)
 #define VIRTIO_IOMMU_MAP_F_MMIO                        (1 << 2)
-- 
2.17.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to