Skip to content

Commit 1fbe8fa

Browse files
hegdevasantkeryell
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 <[email protected]>
1 parent 006b77f commit 1fbe8fa

File tree

4 files changed

+97
-3
lines changed

4 files changed

+97
-3
lines changed

drivers/iommu/amd/amd_iommu.h

+5
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

+1
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ struct protection_domain {
588588
unsigned dev_cnt; /* devices assigned to this domain */
589589
unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
590590

591+
struct mmu_notifier mn; /* mmu notifier for the SVA domain */
591592
struct list_head pasid_list; /* List of pdom_pasid_data */
592593
};
593594

drivers/iommu/amd/iommu.c

+7-3
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

+84
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,53 @@ static void remove_pdom_dev_pasid(struct protection_domain *pdom,
120120
}
121121
}
122122

123+
static void sva_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
124+
struct mm_struct *mm,
125+
unsigned long start, unsigned long end)
126+
{
127+
struct pdom_pasid_data *pasid_data;
128+
struct protection_domain *sva_pdom;
129+
struct iommu_dev_data *dev_data;
130+
unsigned long flags;
131+
132+
sva_pdom = container_of(mn, struct protection_domain, mn);
133+
134+
spin_lock_irqsave(&sva_pdom->lock, flags);
135+
136+
list_for_each_entry(pasid_data, &sva_pdom->pasid_list, pdom_link) {
137+
dev_data = pasid_data->dev_data;
138+
139+
amd_iommu_dev_flush_pasid_pages(dev_data, pasid_data->pasid,
140+
start, end - start);
141+
}
142+
143+
spin_unlock_irqrestore(&sva_pdom->lock, flags);
144+
}
145+
146+
static void sva_mn_release(struct mmu_notifier *mn, struct mm_struct *mm)
147+
{
148+
struct pdom_pasid_data *pasid_data, *next;
149+
struct protection_domain *sva_pdom;
150+
unsigned long flags;
151+
152+
sva_pdom = container_of(mn, struct protection_domain, mn);
153+
154+
spin_lock_irqsave(&sva_pdom->lock, flags);
155+
156+
/* Assume pasid_list contains same PASID with different devices */
157+
list_for_each_entry_safe(pasid_data, next,
158+
&sva_pdom->pasid_list, pdom_link) {
159+
remove_dev_pasid(pasid_data);
160+
}
161+
162+
spin_unlock_irqrestore(&sva_pdom->lock, flags);
163+
}
164+
165+
static const struct mmu_notifier_ops sva_mn = {
166+
.arch_invalidate_secondary_tlbs = sva_arch_invalidate_secondary_tlbs,
167+
.release = sva_mn_release,
168+
};
169+
123170
int iommu_sva_set_dev_pasid(struct iommu_domain *domain,
124171
struct device *dev, ioasid_t pasid)
125172
{
@@ -191,3 +238,40 @@ void amd_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
191238

192239
spin_unlock_irqrestore(&sva_pdom->lock, flags);
193240
}
241+
242+
static void iommu_sva_domain_free(struct iommu_domain *domain)
243+
{
244+
struct protection_domain *sva_pdom = to_pdomain(domain);
245+
246+
if (sva_pdom->mn.ops)
247+
mmu_notifier_unregister(&sva_pdom->mn, domain->mm);
248+
249+
amd_iommu_domain_free(domain);
250+
}
251+
252+
static const struct iommu_domain_ops amd_sva_domain_ops = {
253+
.set_dev_pasid = iommu_sva_set_dev_pasid,
254+
.free = iommu_sva_domain_free
255+
};
256+
257+
struct iommu_domain *amd_iommu_domain_alloc_sva(struct device *dev,
258+
struct mm_struct *mm)
259+
{
260+
struct protection_domain *pdom;
261+
int ret;
262+
263+
pdom = protection_domain_alloc(IOMMU_DOMAIN_SVA);
264+
if (!pdom)
265+
return ERR_PTR(-ENOMEM);
266+
267+
pdom->domain.ops = &amd_sva_domain_ops;
268+
pdom->mn.ops = &sva_mn;
269+
270+
ret = mmu_notifier_register(&pdom->mn, mm);
271+
if (ret) {
272+
protection_domain_free(pdom);
273+
return ERR_PTR(ret);
274+
}
275+
276+
return &pdom->domain;
277+
}

0 commit comments

Comments
 (0)