Skip to content

Commit 85f2fb6

Browse files
jgunthorpewilldeacon
authored andcommitted
iommu/arm-smmu-v3: Start building a generic PASID layer
Add arm_smmu_set_pasid()/arm_smmu_remove_pasid() which are to be used by callers that already constructed the arm_smmu_cd they wish to program. These functions will encapsulate the shared logic to setup a CD entry that will be shared by SVA and S1 domain cases. Prior fixes had already moved most of this logic up into __arm_smmu_sva_bind(), move it to it's final home. Following patches will relieve some of the remaining SVA restrictions: - The RID domain is a S1 domain and has already setup the STE to point to the CD table - The programmed PASID is the mm_get_enqcmd_pasid() - Nothing changes while SVA is running (sva_enable) SVA invalidation will still iterate over the S1 domain's master list, later patches will resolve that. Tested-by: Nicolin Chen <[email protected]> Tested-by: Shameer Kolothum <[email protected]> Reviewed-by: Nicolin Chen <[email protected]> Reviewed-by: Jerry Snitselaar <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 678d79b commit 85f2fb6

File tree

3 files changed

+67
-31
lines changed

3 files changed

+67
-31
lines changed

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -417,29 +417,27 @@ static void arm_smmu_mmu_notifier_put(struct arm_smmu_mmu_notifier *smmu_mn)
417417
arm_smmu_free_shared_cd(cd);
418418
}
419419

420-
static int __arm_smmu_sva_bind(struct device *dev, ioasid_t pasid,
421-
struct mm_struct *mm)
420+
static struct arm_smmu_bond *__arm_smmu_sva_bind(struct device *dev,
421+
struct mm_struct *mm)
422422
{
423423
int ret;
424-
struct arm_smmu_cd target;
425-
struct arm_smmu_cd *cdptr;
426424
struct arm_smmu_bond *bond;
427425
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
428426
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
429427
struct arm_smmu_domain *smmu_domain;
430428

431429
if (!(domain->type & __IOMMU_DOMAIN_PAGING))
432-
return -ENODEV;
430+
return ERR_PTR(-ENODEV);
433431
smmu_domain = to_smmu_domain(domain);
434432
if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1)
435-
return -ENODEV;
433+
return ERR_PTR(-ENODEV);
436434

437435
if (!master || !master->sva_enabled)
438-
return -ENODEV;
436+
return ERR_PTR(-ENODEV);
439437

440438
bond = kzalloc(sizeof(*bond), GFP_KERNEL);
441439
if (!bond)
442-
return -ENOMEM;
440+
return ERR_PTR(-ENOMEM);
443441

444442
bond->mm = mm;
445443

@@ -449,22 +447,12 @@ static int __arm_smmu_sva_bind(struct device *dev, ioasid_t pasid,
449447
goto err_free_bond;
450448
}
451449

452-
cdptr = arm_smmu_alloc_cd_ptr(master, mm_get_enqcmd_pasid(mm));
453-
if (!cdptr) {
454-
ret = -ENOMEM;
455-
goto err_put_notifier;
456-
}
457-
arm_smmu_make_sva_cd(&target, master, mm, bond->smmu_mn->cd->asid);
458-
arm_smmu_write_cd_entry(master, pasid, cdptr, &target);
459-
460450
list_add(&bond->list, &master->bonds);
461-
return 0;
451+
return bond;
462452

463-
err_put_notifier:
464-
arm_smmu_mmu_notifier_put(bond->smmu_mn);
465453
err_free_bond:
466454
kfree(bond);
467-
return ret;
455+
return ERR_PTR(ret);
468456
}
469457

470458
bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
@@ -611,10 +599,9 @@ void arm_smmu_sva_remove_dev_pasid(struct iommu_domain *domain,
611599
struct arm_smmu_bond *bond = NULL, *t;
612600
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
613601

614-
mutex_lock(&sva_lock);
615-
616-
arm_smmu_clear_cd(master, id);
602+
arm_smmu_remove_pasid(master, to_smmu_domain(domain), id);
617603

604+
mutex_lock(&sva_lock);
618605
list_for_each_entry(t, &master->bonds, list) {
619606
if (t->mm == mm) {
620607
bond = t;
@@ -633,17 +620,33 @@ void arm_smmu_sva_remove_dev_pasid(struct iommu_domain *domain,
633620
static int arm_smmu_sva_set_dev_pasid(struct iommu_domain *domain,
634621
struct device *dev, ioasid_t id)
635622
{
636-
int ret = 0;
623+
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
637624
struct mm_struct *mm = domain->mm;
625+
struct arm_smmu_bond *bond;
626+
struct arm_smmu_cd target;
627+
int ret;
638628

639629
if (mm_get_enqcmd_pasid(mm) != id)
640630
return -EINVAL;
641631

642632
mutex_lock(&sva_lock);
643-
ret = __arm_smmu_sva_bind(dev, id, mm);
644-
mutex_unlock(&sva_lock);
633+
bond = __arm_smmu_sva_bind(dev, mm);
634+
if (IS_ERR(bond)) {
635+
mutex_unlock(&sva_lock);
636+
return PTR_ERR(bond);
637+
}
645638

646-
return ret;
639+
arm_smmu_make_sva_cd(&target, master, mm, bond->smmu_mn->cd->asid);
640+
ret = arm_smmu_set_pasid(master, NULL, id, &target);
641+
if (ret) {
642+
list_del(&bond->list);
643+
arm_smmu_mmu_notifier_put(bond->smmu_mn);
644+
kfree(bond);
645+
mutex_unlock(&sva_lock);
646+
return ret;
647+
}
648+
mutex_unlock(&sva_lock);
649+
return 0;
647650
}
648651

649652
static void arm_smmu_sva_domain_free(struct iommu_domain *domain)

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,8 +1211,8 @@ struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
12111211
return &l1_desc->l2ptr[ssid % CTXDESC_L2_ENTRIES];
12121212
}
12131213

1214-
struct arm_smmu_cd *arm_smmu_alloc_cd_ptr(struct arm_smmu_master *master,
1215-
u32 ssid)
1214+
static struct arm_smmu_cd *arm_smmu_alloc_cd_ptr(struct arm_smmu_master *master,
1215+
u32 ssid)
12161216
{
12171217
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
12181218
struct arm_smmu_device *smmu = master->smmu;
@@ -2412,6 +2412,10 @@ static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
24122412
int i, j;
24132413
struct arm_smmu_device *smmu = master->smmu;
24142414

2415+
master->cd_table.in_ste =
2416+
FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(target->data[0])) ==
2417+
STRTAB_STE_0_CFG_S1_TRANS;
2418+
24152419
for (i = 0; i < master->num_streams; ++i) {
24162420
u32 sid = master->streams[i].id;
24172421
struct arm_smmu_ste *step =
@@ -2632,6 +2636,30 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
26322636
return 0;
26332637
}
26342638

2639+
int arm_smmu_set_pasid(struct arm_smmu_master *master,
2640+
struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
2641+
const struct arm_smmu_cd *cd)
2642+
{
2643+
struct arm_smmu_cd *cdptr;
2644+
2645+
/* The core code validates pasid */
2646+
2647+
if (!master->cd_table.in_ste)
2648+
return -ENODEV;
2649+
2650+
cdptr = arm_smmu_alloc_cd_ptr(master, pasid);
2651+
if (!cdptr)
2652+
return -ENOMEM;
2653+
arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
2654+
return 0;
2655+
}
2656+
2657+
void arm_smmu_remove_pasid(struct arm_smmu_master *master,
2658+
struct arm_smmu_domain *smmu_domain, ioasid_t pasid)
2659+
{
2660+
arm_smmu_clear_cd(master, pasid);
2661+
}
2662+
26352663
static int arm_smmu_attach_dev_ste(struct device *dev,
26362664
struct arm_smmu_ste *ste)
26372665
{

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ struct arm_smmu_ctx_desc_cfg {
602602
dma_addr_t cdtab_dma;
603603
struct arm_smmu_l1_ctx_desc *l1_desc;
604604
unsigned int num_l1_ents;
605+
u8 in_ste;
605606
u8 s1fmt;
606607
/* log2 of the maximum number of CDs supported by this table */
607608
u8 s1cdmax;
@@ -777,15 +778,19 @@ extern struct mutex arm_smmu_asid_lock;
777778
void arm_smmu_clear_cd(struct arm_smmu_master *master, ioasid_t ssid);
778779
struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
779780
u32 ssid);
780-
struct arm_smmu_cd *arm_smmu_alloc_cd_ptr(struct arm_smmu_master *master,
781-
u32 ssid);
782781
void arm_smmu_make_s1_cd(struct arm_smmu_cd *target,
783782
struct arm_smmu_master *master,
784783
struct arm_smmu_domain *smmu_domain);
785784
void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
786785
struct arm_smmu_cd *cdptr,
787786
const struct arm_smmu_cd *target);
788787

788+
int arm_smmu_set_pasid(struct arm_smmu_master *master,
789+
struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
790+
const struct arm_smmu_cd *cd);
791+
void arm_smmu_remove_pasid(struct arm_smmu_master *master,
792+
struct arm_smmu_domain *smmu_domain, ioasid_t pasid);
793+
789794
void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
790795
void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
791796
size_t granule, bool leaf,

0 commit comments

Comments
 (0)