xref: /linux/drivers/iommu/iommufd/hwpt_noiommu.c (revision 85e0d1de369cdf827dae8c759f40696de81b7ca7)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
4  */
5 #include <linux/generic_pt/iommu.h>
6 #include <linux/iommu.h>
7 #include "../iommu-pages.h"
8 #include "iommufd_private.h"
9 
10 static const struct iommu_domain_ops noiommu_amdv1_ops;
11 
12 struct noiommu_domain {
13 	union {
14 		struct iommu_domain domain;
15 		struct pt_iommu_amdv1 amdv1;
16 	};
17 	spinlock_t lock;
18 };
19 PT_IOMMU_CHECK_DOMAIN(struct noiommu_domain, amdv1.iommu, domain);
20 
21 static void noiommu_change_top(struct pt_iommu *iommu_table,
22 			       phys_addr_t top_paddr, unsigned int top_level)
23 {
24 }
25 
26 static spinlock_t *noiommu_get_top_lock(struct pt_iommu *iommupt)
27 {
28 	struct noiommu_domain *domain =
29 		container_of(iommupt, struct noiommu_domain, amdv1.iommu);
30 
31 	return &domain->lock;
32 }
33 
34 static const struct pt_iommu_driver_ops noiommu_driver_ops = {
35 	.get_top_lock = noiommu_get_top_lock,
36 	.change_top = noiommu_change_top,
37 };
38 
39 static struct iommu_domain *
40 noiommu_alloc_paging_flags(struct device *dev, u32 flags,
41 			   const struct iommu_user_data *user_data)
42 {
43 	struct pt_iommu_amdv1_cfg cfg = {};
44 	struct noiommu_domain *dom;
45 	int rc;
46 
47 	if (flags || user_data)
48 		return ERR_PTR(-EOPNOTSUPP);
49 
50 	cfg.common.hw_max_vasz_lg2 = 64;
51 	cfg.common.hw_max_oasz_lg2 = 52;
52 	cfg.starting_level = 2;
53 	cfg.common.features =
54 		(BIT(PT_FEAT_DYNAMIC_TOP) | BIT(PT_FEAT_AMDV1_ENCRYPT_TABLES) |
55 		 BIT(PT_FEAT_AMDV1_FORCE_COHERENCE));
56 
57 	dom = kzalloc(sizeof(*dom), GFP_KERNEL);
58 	if (!dom)
59 		return ERR_PTR(-ENOMEM);
60 
61 	spin_lock_init(&dom->lock);
62 	dom->amdv1.iommu.nid = NUMA_NO_NODE;
63 	dom->amdv1.iommu.driver_ops = &noiommu_driver_ops;
64 	dom->domain.ops = &noiommu_amdv1_ops;
65 
66 	/* Use SW-only page table which is based on AMDV1 */
67 	rc = pt_iommu_amdv1_init(&dom->amdv1, &cfg, GFP_KERNEL);
68 	if (rc) {
69 		kfree(dom);
70 		return ERR_PTR(rc);
71 	}
72 
73 	return &dom->domain;
74 }
75 
76 static void noiommu_domain_free(struct iommu_domain *iommu_domain)
77 {
78 	struct noiommu_domain *domain =
79 		container_of(iommu_domain, struct noiommu_domain, domain);
80 
81 	pt_iommu_deinit(&domain->amdv1.iommu);
82 	kfree(domain);
83 }
84 
85 static void noiommu_iotlb_sync(struct iommu_domain *domain,
86 			       struct iommu_iotlb_gather *gather)
87 {
88 	iommu_put_pages_list(&gather->freelist);
89 }
90 
91 /*
92  * Domain ops for iommufd no-IOMMU mode. Uses AMDV1 format as a
93  * SW-only IOPT because it has the best multi-page size options
94  * of all the formats. IOVAs serve only for IOVA-to-PA lookups,
95  * not for hardware DMA translation.
96  */
97 static const struct iommu_domain_ops noiommu_amdv1_ops = {
98 	IOMMU_PT_DOMAIN_OPS(amdv1),
99 	.iotlb_sync = noiommu_iotlb_sync,
100 	.free = noiommu_domain_free,
101 };
102 
103 const struct iommu_ops iommufd_noiommu_ops = {
104 	.domain_alloc_paging_flags = noiommu_alloc_paging_flags,
105 };
106