Skip to content

Commit a5a91e5

Browse files
hegdevasantjoergroedel
authored andcommitted
iommu/amd: Add SVA domain support
- Allocate SVA domain and setup mmu notifier. In free path unregister mmu notifier and free protection domain. - Add mmu notifier callback function. It will retrieve SVA protection domain and invalidates IO/TLB. Signed-off-by: Vasant Hegde <vasant.hegde@amd.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/20240418103400.6229-16-vasant.hegde@amd.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
1 parent 80af5a4 commit a5a91e5

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

drivers/iommu/amd/amd_iommu.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ extern enum io_pgtable_fmt amd_iommu_pgtable;
4545
extern int amd_iommu_gpt_level;
4646

4747
/* Protection domain ops */
48+
struct protection_domain *protection_domain_alloc(unsigned int type);
49+
void protection_domain_free(struct protection_domain *domain);
50+
struct iommu_domain *amd_iommu_domain_alloc_sva(struct device *dev,
51+
struct mm_struct *mm);
52+
void amd_iommu_domain_free(struct iommu_domain *dom);
4853
int iommu_sva_set_dev_pasid(struct iommu_domain *domain,
4954
struct device *dev, ioasid_t pasid);
5055
void amd_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid);

drivers/iommu/amd/amd_iommu_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,7 @@ struct protection_domain {
586586
unsigned dev_cnt; /* devices assigned to this domain */
587587
unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
588588

589+
struct mmu_notifier mn; /* mmu notifier for the SVA domain */
589590
struct list_head dev_data_list; /* List of pdom_dev_data */
590591
};
591592

drivers/iommu/amd/iommu.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,7 +2280,7 @@ static void cleanup_domain(struct protection_domain *domain)
22802280
WARN_ON(domain->dev_cnt != 0);
22812281
}
22822282

2283-
static void protection_domain_free(struct protection_domain *domain)
2283+
void protection_domain_free(struct protection_domain *domain)
22842284
{
22852285
if (!domain)
22862286
return;
@@ -2323,7 +2323,7 @@ static int protection_domain_init_v2(struct protection_domain *pdom)
23232323
return 0;
23242324
}
23252325

2326-
static struct protection_domain *protection_domain_alloc(unsigned int type)
2326+
struct protection_domain *protection_domain_alloc(unsigned int type)
23272327
{
23282328
struct io_pgtable_ops *pgtbl_ops;
23292329
struct protection_domain *domain;
@@ -2346,6 +2346,7 @@ static struct protection_domain *protection_domain_alloc(unsigned int type)
23462346
switch (type) {
23472347
/* No need to allocate io pgtable ops in passthrough mode */
23482348
case IOMMU_DOMAIN_IDENTITY:
2349+
case IOMMU_DOMAIN_SVA:
23492350
return domain;
23502351
case IOMMU_DOMAIN_DMA:
23512352
pgtable = amd_iommu_pgtable;
@@ -2465,7 +2466,7 @@ amd_iommu_domain_alloc_user(struct device *dev, u32 flags,
24652466
return do_iommu_domain_alloc(type, dev, flags);
24662467
}
24672468

2468-
static void amd_iommu_domain_free(struct iommu_domain *dom)
2469+
void amd_iommu_domain_free(struct iommu_domain *dom)
24692470
{
24702471
struct protection_domain *domain;
24712472
unsigned long flags;
@@ -2833,6 +2834,7 @@ static int amd_iommu_dev_enable_feature(struct device *dev,
28332834

28342835
switch (feat) {
28352836
case IOMMU_DEV_FEAT_IOPF:
2837+
case IOMMU_DEV_FEAT_SVA:
28362838
break;
28372839
default:
28382840
ret = -EINVAL;
@@ -2848,6 +2850,7 @@ static int amd_iommu_dev_disable_feature(struct device *dev,
28482850

28492851
switch (feat) {
28502852
case IOMMU_DEV_FEAT_IOPF:
2853+
case IOMMU_DEV_FEAT_SVA:
28512854
break;
28522855
default:
28532856
ret = -EINVAL;
@@ -2860,6 +2863,7 @@ const struct iommu_ops amd_iommu_ops = {
28602863
.capable = amd_iommu_capable,
28612864
.domain_alloc = amd_iommu_domain_alloc,
28622865
.domain_alloc_user = amd_iommu_domain_alloc_user,
2866+
.domain_alloc_sva = amd_iommu_domain_alloc_sva,
28632867
.probe_device = amd_iommu_probe_device,
28642868
.release_device = amd_iommu_release_device,
28652869
.probe_finalize = amd_iommu_probe_finalize,

drivers/iommu/amd/pasid.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,49 @@ static void remove_pdom_dev_pasid(struct protection_domain *pdom,
5656
}
5757
}
5858

59+
static void sva_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
60+
struct mm_struct *mm,
61+
unsigned long start, unsigned long end)
62+
{
63+
struct pdom_dev_data *pdom_dev_data;
64+
struct protection_domain *sva_pdom;
65+
unsigned long flags;
66+
67+
sva_pdom = container_of(mn, struct protection_domain, mn);
68+
69+
spin_lock_irqsave(&sva_pdom->lock, flags);
70+
71+
for_each_pdom_dev_data(pdom_dev_data, sva_pdom) {
72+
amd_iommu_dev_flush_pasid_pages(pdom_dev_data->dev_data,
73+
pdom_dev_data->pasid,
74+
start, end - start);
75+
}
76+
77+
spin_unlock_irqrestore(&sva_pdom->lock, flags);
78+
}
79+
80+
static void sva_mn_release(struct mmu_notifier *mn, struct mm_struct *mm)
81+
{
82+
struct pdom_dev_data *pdom_dev_data, *next;
83+
struct protection_domain *sva_pdom;
84+
unsigned long flags;
85+
86+
sva_pdom = container_of(mn, struct protection_domain, mn);
87+
88+
spin_lock_irqsave(&sva_pdom->lock, flags);
89+
90+
/* Assume dev_data_list contains same PASID with different devices */
91+
for_each_pdom_dev_data_safe(pdom_dev_data, next, sva_pdom)
92+
remove_dev_pasid(pdom_dev_data);
93+
94+
spin_unlock_irqrestore(&sva_pdom->lock, flags);
95+
}
96+
97+
static const struct mmu_notifier_ops sva_mn = {
98+
.arch_invalidate_secondary_tlbs = sva_arch_invalidate_secondary_tlbs,
99+
.release = sva_mn_release,
100+
};
101+
59102
int iommu_sva_set_dev_pasid(struct iommu_domain *domain,
60103
struct device *dev, ioasid_t pasid)
61104
{
@@ -120,3 +163,40 @@ void amd_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
120163

121164
spin_unlock_irqrestore(&sva_pdom->lock, flags);
122165
}
166+
167+
static void iommu_sva_domain_free(struct iommu_domain *domain)
168+
{
169+
struct protection_domain *sva_pdom = to_pdomain(domain);
170+
171+
if (sva_pdom->mn.ops)
172+
mmu_notifier_unregister(&sva_pdom->mn, domain->mm);
173+
174+
amd_iommu_domain_free(domain);
175+
}
176+
177+
static const struct iommu_domain_ops amd_sva_domain_ops = {
178+
.set_dev_pasid = iommu_sva_set_dev_pasid,
179+
.free = iommu_sva_domain_free
180+
};
181+
182+
struct iommu_domain *amd_iommu_domain_alloc_sva(struct device *dev,
183+
struct mm_struct *mm)
184+
{
185+
struct protection_domain *pdom;
186+
int ret;
187+
188+
pdom = protection_domain_alloc(IOMMU_DOMAIN_SVA);
189+
if (!pdom)
190+
return ERR_PTR(-ENOMEM);
191+
192+
pdom->domain.ops = &amd_sva_domain_ops;
193+
pdom->mn.ops = &sva_mn;
194+
195+
ret = mmu_notifier_register(&pdom->mn, mm);
196+
if (ret) {
197+
protection_domain_free(pdom);
198+
return ERR_PTR(ret);
199+
}
200+
201+
return &pdom->domain;
202+
}

0 commit comments

Comments
 (0)