]> www.infradead.org Git - linux-platform-drivers-x86.git/commitdiff
iommu/amd: Adopt IO page table framework for AMD IOMMU v1 page table
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Tue, 15 Dec 2020 07:37:05 +0000 (01:37 -0600)
committerJoerg Roedel <jroedel@suse.de>
Thu, 28 Jan 2021 15:51:18 +0000 (16:51 +0100)
Switch to using IO page table framework for AMD IOMMU v1 page table.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Link: https://lore.kernel.org/r/20201215073705.123786-14-suravee.suthikulpanit@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/amd_iommu.h
drivers/iommu/amd/init.c
drivers/iommu/amd/iommu.c

index 3770b1a4d51c78415b513123cefe70669ebb5bac..91452e0ff0725357f3c61ab42eecc76ac3f615fb 100644 (file)
@@ -36,6 +36,7 @@ extern void amd_iommu_disable(void);
 extern int amd_iommu_reenable(int);
 extern int amd_iommu_enable_faulting(void);
 extern int amd_iommu_guest_ir;
+extern enum io_pgtable_fmt amd_iommu_pgtable;
 
 /* IOMMUv2 specific functions */
 struct iommu_domain;
index 1804c3e3b6ac6a072b5abc6262ed66a6e90d9933..5a6c511e91d1b40eab3501c68e6d42edb9f937ea 100644 (file)
@@ -147,6 +147,8 @@ struct ivmd_header {
 bool amd_iommu_dump;
 bool amd_iommu_irq_remap __read_mostly;
 
+enum io_pgtable_fmt amd_iommu_pgtable = AMD_IOMMU_V1;
+
 int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC;
 static int amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE;
 
index 256d38ad6afb0fa6f5ebc5c6cca625e038998225..a69a8b573e40d004ffaac632b9be88ed1c58b71b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/irqdomain.h>
 #include <linux/percpu.h>
 #include <linux/iova.h>
+#include <linux/io-pgtable.h>
 #include <asm/irq_remapping.h>
 #include <asm/io_apic.h>
 #include <asm/apic.h>
@@ -1900,7 +1901,7 @@ static void protection_domain_free(struct protection_domain *domain)
        kfree(domain);
 }
 
-static int protection_domain_init(struct protection_domain *domain, int mode)
+static int protection_domain_init_v1(struct protection_domain *domain, int mode)
 {
        u64 *pt_root = NULL;
 
@@ -1923,34 +1924,55 @@ static int protection_domain_init(struct protection_domain *domain, int mode)
        return 0;
 }
 
-static struct protection_domain *protection_domain_alloc(int mode)
+static struct protection_domain *protection_domain_alloc(unsigned int type)
 {
+       struct io_pgtable_ops *pgtbl_ops;
        struct protection_domain *domain;
+       int pgtable = amd_iommu_pgtable;
+       int mode = DEFAULT_PGTABLE_LEVEL;
+       int ret;
 
        domain = kzalloc(sizeof(*domain), GFP_KERNEL);
        if (!domain)
                return NULL;
 
-       if (protection_domain_init(domain, mode))
+       /*
+        * Force IOMMU v1 page table when iommu=pt and
+        * when allocating domain for pass-through devices.
+        */
+       if (type == IOMMU_DOMAIN_IDENTITY) {
+               pgtable = AMD_IOMMU_V1;
+               mode = PAGE_MODE_NONE;
+       } else if (type == IOMMU_DOMAIN_UNMANAGED) {
+               pgtable = AMD_IOMMU_V1;
+       }
+
+       switch (pgtable) {
+       case AMD_IOMMU_V1:
+               ret = protection_domain_init_v1(domain, mode);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       if (ret)
                goto out_err;
 
-       return domain;
+       pgtbl_ops = alloc_io_pgtable_ops(pgtable, &domain->iop.pgtbl_cfg, domain);
+       if (!pgtbl_ops)
+               goto out_err;
 
+       return domain;
 out_err:
        kfree(domain);
-
        return NULL;
 }
 
 static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 {
        struct protection_domain *domain;
-       int mode = DEFAULT_PGTABLE_LEVEL;
-
-       if (type == IOMMU_DOMAIN_IDENTITY)
-               mode = PAGE_MODE_NONE;
 
-       domain = protection_domain_alloc(mode);
+       domain = protection_domain_alloc(type);
        if (!domain)
                return NULL;
 
@@ -2069,7 +2091,8 @@ static int amd_iommu_map(struct iommu_domain *dom, unsigned long iova,
        int prot = 0;
        int ret = -EINVAL;
 
-       if (domain->iop.mode == PAGE_MODE_NONE)
+       if ((amd_iommu_pgtable == AMD_IOMMU_V1) &&
+           (domain->iop.mode == PAGE_MODE_NONE))
                return -EINVAL;
 
        if (iommu_prot & IOMMU_READ)
@@ -2092,7 +2115,8 @@ static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
        struct protection_domain *domain = to_pdomain(dom);
        struct io_pgtable_ops *ops = &domain->iop.iop.ops;
 
-       if (domain->iop.mode == PAGE_MODE_NONE)
+       if ((amd_iommu_pgtable == AMD_IOMMU_V1) &&
+           (domain->iop.mode == PAGE_MODE_NONE))
                return 0;
 
        return (ops->unmap) ? ops->unmap(ops, iova, page_size, gather) : 0;