@@ -3147,6 +3147,121 @@ static void arm_smmu_disable_iopf(struct arm_smmu_master *master,
31473147 iopf_queue_remove_device (master -> smmu -> evtq .iopf , master -> dev );
31483148}
31493149
3150+ static struct arm_smmu_inv *
3151+ arm_smmu_master_build_inv (struct arm_smmu_master * master ,
3152+ enum arm_smmu_inv_type type , u32 id , ioasid_t ssid ,
3153+ size_t pgsize )
3154+ {
3155+ struct arm_smmu_invs * build_invs = master -> build_invs ;
3156+ struct arm_smmu_inv * cur , inv = {
3157+ .smmu = master -> smmu ,
3158+ .type = type ,
3159+ .id = id ,
3160+ .pgsize = pgsize ,
3161+ };
3162+
3163+ if (WARN_ON (build_invs -> num_invs >= build_invs -> max_invs ))
3164+ return NULL ;
3165+ cur = & build_invs -> inv [build_invs -> num_invs ];
3166+ build_invs -> num_invs ++ ;
3167+
3168+ * cur = inv ;
3169+ switch (type ) {
3170+ case INV_TYPE_S1_ASID :
3171+ /*
3172+ * For S1 page tables the driver always uses VMID=0, and the
3173+ * invalidation logic for this type will set it as well.
3174+ */
3175+ if (master -> smmu -> features & ARM_SMMU_FEAT_E2H ) {
3176+ cur -> size_opcode = CMDQ_OP_TLBI_EL2_VA ;
3177+ cur -> nsize_opcode = CMDQ_OP_TLBI_EL2_ASID ;
3178+ } else {
3179+ cur -> size_opcode = CMDQ_OP_TLBI_NH_VA ;
3180+ cur -> nsize_opcode = CMDQ_OP_TLBI_NH_ASID ;
3181+ }
3182+ break ;
3183+ case INV_TYPE_S2_VMID :
3184+ cur -> size_opcode = CMDQ_OP_TLBI_S2_IPA ;
3185+ cur -> nsize_opcode = CMDQ_OP_TLBI_S12_VMALL ;
3186+ break ;
3187+ case INV_TYPE_S2_VMID_S1_CLEAR :
3188+ cur -> size_opcode = cur -> nsize_opcode = CMDQ_OP_TLBI_NH_ALL ;
3189+ break ;
3190+ case INV_TYPE_ATS :
3191+ case INV_TYPE_ATS_FULL :
3192+ cur -> size_opcode = cur -> nsize_opcode = CMDQ_OP_ATC_INV ;
3193+ cur -> ssid = ssid ;
3194+ break ;
3195+ }
3196+
3197+ return cur ;
3198+ }
3199+
3200+ /*
3201+ * Use the preallocated scratch array at master->build_invs, to build a to_merge
3202+ * or to_unref array, to pass into a following arm_smmu_invs_merge/unref() call.
3203+ *
3204+ * Do not free the returned invs array. It is reused, and will be overwritten by
3205+ * the next arm_smmu_master_build_invs() call.
3206+ */
3207+ static struct arm_smmu_invs *
3208+ arm_smmu_master_build_invs (struct arm_smmu_master * master , bool ats_enabled ,
3209+ ioasid_t ssid , struct arm_smmu_domain * smmu_domain )
3210+ {
3211+ const bool nesting = smmu_domain -> nest_parent ;
3212+ size_t pgsize = 0 , i ;
3213+
3214+ iommu_group_mutex_assert (master -> dev );
3215+
3216+ master -> build_invs -> num_invs = 0 ;
3217+
3218+ /* Range-based invalidation requires the leaf pgsize for calculation */
3219+ if (master -> smmu -> features & ARM_SMMU_FEAT_RANGE_INV )
3220+ pgsize = __ffs (smmu_domain -> domain .pgsize_bitmap );
3221+
3222+ switch (smmu_domain -> stage ) {
3223+ case ARM_SMMU_DOMAIN_SVA :
3224+ case ARM_SMMU_DOMAIN_S1 :
3225+ if (!arm_smmu_master_build_inv (master , INV_TYPE_S1_ASID ,
3226+ smmu_domain -> cd .asid ,
3227+ IOMMU_NO_PASID , pgsize ))
3228+ return NULL ;
3229+ break ;
3230+ case ARM_SMMU_DOMAIN_S2 :
3231+ if (!arm_smmu_master_build_inv (master , INV_TYPE_S2_VMID ,
3232+ smmu_domain -> s2_cfg .vmid ,
3233+ IOMMU_NO_PASID , pgsize ))
3234+ return NULL ;
3235+ break ;
3236+ default :
3237+ WARN_ON (true);
3238+ return NULL ;
3239+ }
3240+
3241+ /* All the nested S1 ASIDs have to be flushed when S2 parent changes */
3242+ if (nesting ) {
3243+ if (!arm_smmu_master_build_inv (
3244+ master , INV_TYPE_S2_VMID_S1_CLEAR ,
3245+ smmu_domain -> s2_cfg .vmid , IOMMU_NO_PASID , 0 ))
3246+ return NULL ;
3247+ }
3248+
3249+ for (i = 0 ; ats_enabled && i < master -> num_streams ; i ++ ) {
3250+ /*
3251+ * If an S2 used as a nesting parent is changed we have no
3252+ * option but to completely flush the ATC.
3253+ */
3254+ if (!arm_smmu_master_build_inv (
3255+ master , nesting ? INV_TYPE_ATS_FULL : INV_TYPE_ATS ,
3256+ master -> streams [i ].id , ssid , 0 ))
3257+ return NULL ;
3258+ }
3259+
3260+ /* Note this build_invs must have been sorted */
3261+
3262+ return master -> build_invs ;
3263+ }
3264+
31503265static void arm_smmu_remove_master_domain (struct arm_smmu_master * master ,
31513266 struct iommu_domain * domain ,
31523267 ioasid_t ssid )
@@ -3176,6 +3291,135 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
31763291 kfree (master_domain );
31773292}
31783293
3294+ /*
3295+ * During attachment, the updates of the two domain->invs arrays are sequenced:
3296+ * 1. new domain updates its invs array, merging master->build_invs
3297+ * 2. new domain starts to include the master during its invalidation
3298+ * 3. master updates its STE switching from the old domain to the new domain
3299+ * 4. old domain still includes the master during its invalidation
3300+ * 5. old domain updates its invs array, unreferencing master->build_invs
3301+ *
3302+ * For 1 and 5, prepare the two updated arrays in advance, handling any changes
3303+ * that can possibly failure. So the actual update of either 1 or 5 won't fail.
3304+ * arm_smmu_asid_lock ensures that the old invs in the domains are intact while
3305+ * we are sequencing to update them.
3306+ */
3307+ static int arm_smmu_attach_prepare_invs (struct arm_smmu_attach_state * state ,
3308+ struct iommu_domain * new_domain )
3309+ {
3310+ struct arm_smmu_domain * old_smmu_domain =
3311+ to_smmu_domain_devices (state -> old_domain );
3312+ struct arm_smmu_domain * new_smmu_domain =
3313+ to_smmu_domain_devices (new_domain );
3314+ struct arm_smmu_master * master = state -> master ;
3315+ ioasid_t ssid = state -> ssid ;
3316+
3317+ /*
3318+ * At this point a NULL domain indicates the domain doesn't use the
3319+ * IOTLB, see to_smmu_domain_devices().
3320+ */
3321+ if (new_smmu_domain ) {
3322+ struct arm_smmu_inv_state * invst = & state -> new_domain_invst ;
3323+ struct arm_smmu_invs * build_invs ;
3324+
3325+ invst -> invs_ptr = & new_smmu_domain -> invs ;
3326+ invst -> old_invs = rcu_dereference_protected (
3327+ new_smmu_domain -> invs ,
3328+ lockdep_is_held (& arm_smmu_asid_lock ));
3329+ build_invs = arm_smmu_master_build_invs (
3330+ master , state -> ats_enabled , ssid , new_smmu_domain );
3331+ if (!build_invs )
3332+ return - EINVAL ;
3333+
3334+ invst -> new_invs =
3335+ arm_smmu_invs_merge (invst -> old_invs , build_invs );
3336+ if (IS_ERR (invst -> new_invs ))
3337+ return PTR_ERR (invst -> new_invs );
3338+ }
3339+
3340+ if (old_smmu_domain ) {
3341+ struct arm_smmu_inv_state * invst = & state -> old_domain_invst ;
3342+
3343+ invst -> invs_ptr = & old_smmu_domain -> invs ;
3344+ /* A re-attach case might have a different ats_enabled state */
3345+ if (new_smmu_domain == old_smmu_domain )
3346+ invst -> old_invs = state -> new_domain_invst .new_invs ;
3347+ else
3348+ invst -> old_invs = rcu_dereference_protected (
3349+ old_smmu_domain -> invs ,
3350+ lockdep_is_held (& arm_smmu_asid_lock ));
3351+ /* For old_smmu_domain, new_invs points to master->build_invs */
3352+ invst -> new_invs = arm_smmu_master_build_invs (
3353+ master , master -> ats_enabled , ssid , old_smmu_domain );
3354+ }
3355+
3356+ return 0 ;
3357+ }
3358+
3359+ /* Must be installed before arm_smmu_install_ste_for_dev() */
3360+ static void
3361+ arm_smmu_install_new_domain_invs (struct arm_smmu_attach_state * state )
3362+ {
3363+ struct arm_smmu_inv_state * invst = & state -> new_domain_invst ;
3364+
3365+ if (!invst -> invs_ptr )
3366+ return ;
3367+
3368+ rcu_assign_pointer (* invst -> invs_ptr , invst -> new_invs );
3369+ kfree_rcu (invst -> old_invs , rcu );
3370+ }
3371+
3372+ static void arm_smmu_inv_flush_iotlb_tag (struct arm_smmu_inv * inv )
3373+ {
3374+ struct arm_smmu_cmdq_ent cmd = {};
3375+
3376+ switch (inv -> type ) {
3377+ case INV_TYPE_S1_ASID :
3378+ cmd .tlbi .asid = inv -> id ;
3379+ break ;
3380+ case INV_TYPE_S2_VMID :
3381+ /* S2_VMID using nsize_opcode covers S2_VMID_S1_CLEAR */
3382+ cmd .tlbi .vmid = inv -> id ;
3383+ break ;
3384+ default :
3385+ return ;
3386+ }
3387+
3388+ cmd .opcode = inv -> nsize_opcode ;
3389+ arm_smmu_cmdq_issue_cmd_with_sync (inv -> smmu , & cmd );
3390+ }
3391+
3392+ /* Should be installed after arm_smmu_install_ste_for_dev() */
3393+ static void
3394+ arm_smmu_install_old_domain_invs (struct arm_smmu_attach_state * state )
3395+ {
3396+ struct arm_smmu_inv_state * invst = & state -> old_domain_invst ;
3397+ struct arm_smmu_invs * old_invs = invst -> old_invs ;
3398+ struct arm_smmu_invs * new_invs ;
3399+
3400+ lockdep_assert_held (& arm_smmu_asid_lock );
3401+
3402+ if (!invst -> invs_ptr )
3403+ return ;
3404+
3405+ arm_smmu_invs_unref (old_invs , invst -> new_invs );
3406+ /*
3407+ * When an IOTLB tag (the first entry in invs->new_invs) is no longer used,
3408+ * it means the ASID or VMID will no longer be invalidated by map/unmap and
3409+ * must be cleaned right now. The rule is that any ASID/VMID not in an invs
3410+ * array must be left cleared in the IOTLB.
3411+ */
3412+ if (!READ_ONCE (invst -> new_invs -> inv [0 ].users ))
3413+ arm_smmu_inv_flush_iotlb_tag (& invst -> new_invs -> inv [0 ]);
3414+
3415+ new_invs = arm_smmu_invs_purge (old_invs );
3416+ if (!new_invs )
3417+ return ;
3418+
3419+ rcu_assign_pointer (* invst -> invs_ptr , new_invs );
3420+ kfree_rcu (old_invs , rcu );
3421+ }
3422+
31793423/*
31803424 * Start the sequence to attach a domain to a master. The sequence contains three
31813425 * steps:
@@ -3233,12 +3477,16 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
32333477 arm_smmu_ats_supported (master );
32343478 }
32353479
3480+ ret = arm_smmu_attach_prepare_invs (state , new_domain );
3481+ if (ret )
3482+ return ret ;
3483+
32363484 if (smmu_domain ) {
32373485 if (new_domain -> type == IOMMU_DOMAIN_NESTED ) {
32383486 ret = arm_smmu_attach_prepare_vmaster (
32393487 state , to_smmu_nested_domain (new_domain ));
32403488 if (ret )
3241- return ret ;
3489+ goto err_unprepare_invs ;
32423490 }
32433491
32443492 master_domain = kzalloc_obj (* master_domain );
@@ -3286,6 +3534,8 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
32863534 atomic_inc (& smmu_domain -> nr_ats_masters );
32873535 list_add (& master_domain -> devices_elm , & smmu_domain -> devices );
32883536 spin_unlock_irqrestore (& smmu_domain -> devices_lock , flags );
3537+
3538+ arm_smmu_install_new_domain_invs (state );
32893539 }
32903540
32913541 if (!state -> ats_enabled && master -> ats_enabled ) {
@@ -3305,6 +3555,8 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
33053555 kfree (master_domain );
33063556err_free_vmaster :
33073557 kfree (state -> vmaster );
3558+ err_unprepare_invs :
3559+ kfree (state -> new_domain_invst .new_invs );
33083560 return ret ;
33093561}
33103562
@@ -3336,6 +3588,7 @@ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)
33363588 }
33373589
33383590 arm_smmu_remove_master_domain (master , state -> old_domain , state -> ssid );
3591+ arm_smmu_install_old_domain_invs (state );
33393592 master -> ats_enabled = state -> ats_enabled ;
33403593}
33413594
@@ -3518,12 +3771,19 @@ static int arm_smmu_blocking_set_dev_pasid(struct iommu_domain *new_domain,
35183771{
35193772 struct arm_smmu_domain * smmu_domain = to_smmu_domain (old_domain );
35203773 struct arm_smmu_master * master = dev_iommu_priv_get (dev );
3774+ struct arm_smmu_attach_state state = {
3775+ .master = master ,
3776+ .old_domain = old_domain ,
3777+ .ssid = pasid ,
3778+ };
35213779
35223780 mutex_lock (& arm_smmu_asid_lock );
3781+ arm_smmu_attach_prepare_invs (& state , NULL );
35233782 arm_smmu_clear_cd (master , pasid );
35243783 if (master -> ats_enabled )
35253784 arm_smmu_atc_inv_master (master , pasid );
35263785 arm_smmu_remove_master_domain (master , & smmu_domain -> domain , pasid );
3786+ arm_smmu_install_old_domain_invs (& state );
35273787 mutex_unlock (& arm_smmu_asid_lock );
35283788
35293789 /*
0 commit comments