@@ -2595,23 +2595,19 @@ static void arm_smmu_tlb_inv_context(void *cookie)
25952595 arm_smmu_atc_inv_domain (smmu_domain , 0 , 0 );
25962596}
25972597
2598- static void __arm_smmu_tlb_inv_range (struct arm_smmu_cmdq_ent * cmd ,
2599- unsigned long iova , size_t size ,
2600- size_t granule ,
2601- struct arm_smmu_domain * smmu_domain )
2598+ static void arm_smmu_cmdq_batch_add_range (struct arm_smmu_device * smmu ,
2599+ struct arm_smmu_cmdq_batch * cmds ,
2600+ struct arm_smmu_cmdq_ent * cmd ,
2601+ unsigned long iova , size_t size ,
2602+ size_t granule , size_t pgsize )
26022603{
2603- struct arm_smmu_device * smmu = smmu_domain -> smmu ;
2604- unsigned long end = iova + size , num_pages = 0 , tg = 0 ;
2604+ unsigned long end = iova + size , num_pages = 0 , tg = pgsize ;
26052605 size_t inv_range = granule ;
2606- struct arm_smmu_cmdq_batch cmds ;
26072606
26082607 if (!size )
26092608 return ;
26102609
26112610 if (smmu -> features & ARM_SMMU_FEAT_RANGE_INV ) {
2612- /* Get the leaf page size */
2613- tg = __ffs (smmu_domain -> domain .pgsize_bitmap );
2614-
26152611 num_pages = size >> tg ;
26162612
26172613 /* Convert page size of 12,14,16 (log2) to 1,2,3 */
@@ -2631,8 +2627,6 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
26312627 num_pages ++ ;
26322628 }
26332629
2634- arm_smmu_cmdq_batch_init (smmu , & cmds , cmd );
2635-
26362630 while (iova < end ) {
26372631 if (smmu -> features & ARM_SMMU_FEAT_RANGE_INV ) {
26382632 /*
@@ -2660,9 +2654,26 @@ static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
26602654 }
26612655
26622656 cmd -> tlbi .addr = iova ;
2663- arm_smmu_cmdq_batch_add (smmu , & cmds , cmd );
2657+ arm_smmu_cmdq_batch_add (smmu , cmds , cmd );
26642658 iova += inv_range ;
26652659 }
2660+ }
2661+
2662+ static void __arm_smmu_tlb_inv_range (struct arm_smmu_cmdq_ent * cmd ,
2663+ unsigned long iova , size_t size ,
2664+ size_t granule ,
2665+ struct arm_smmu_domain * smmu_domain )
2666+ {
2667+ struct arm_smmu_device * smmu = smmu_domain -> smmu ;
2668+ struct arm_smmu_cmdq_batch cmds ;
2669+ size_t pgsize ;
2670+
2671+ /* Get the leaf page size */
2672+ pgsize = __ffs (smmu_domain -> domain .pgsize_bitmap );
2673+
2674+ arm_smmu_cmdq_batch_init (smmu , & cmds , cmd );
2675+ arm_smmu_cmdq_batch_add_range (smmu , & cmds , cmd , iova , size , granule ,
2676+ pgsize );
26662677 arm_smmu_cmdq_batch_submit (smmu , & cmds );
26672678}
26682679
@@ -2718,6 +2729,194 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
27182729 __arm_smmu_tlb_inv_range (& cmd , iova , size , granule , smmu_domain );
27192730}
27202731
2732+ static bool arm_smmu_inv_size_too_big (struct arm_smmu_device * smmu , size_t size ,
2733+ size_t granule )
2734+ {
2735+ size_t max_tlbi_ops ;
2736+
2737+ /* 0 size means invalidate all */
2738+ if (!size || size == SIZE_MAX )
2739+ return true;
2740+
2741+ if (smmu -> features & ARM_SMMU_FEAT_RANGE_INV )
2742+ return false;
2743+
2744+ /*
2745+ * Borrowed from the MAX_TLBI_OPS in arch/arm64/include/asm/tlbflush.h,
2746+ * this is used as a threshold to replace "size_opcode" commands with a
2747+ * single "nsize_opcode" command, when SMMU doesn't implement the range
2748+ * invalidation feature, where there can be too many per-granule TLBIs,
2749+ * resulting in a soft lockup.
2750+ */
2751+ max_tlbi_ops = 1 << (ilog2 (granule ) - 3 );
2752+ return size >= max_tlbi_ops * granule ;
2753+ }
2754+
2755+ /* Used by non INV_TYPE_ATS* invalidations */
2756+ static void arm_smmu_inv_to_cmdq_batch (struct arm_smmu_inv * inv ,
2757+ struct arm_smmu_cmdq_batch * cmds ,
2758+ struct arm_smmu_cmdq_ent * cmd ,
2759+ unsigned long iova , size_t size ,
2760+ unsigned int granule )
2761+ {
2762+ if (arm_smmu_inv_size_too_big (inv -> smmu , size , granule )) {
2763+ cmd -> opcode = inv -> nsize_opcode ;
2764+ arm_smmu_cmdq_batch_add (inv -> smmu , cmds , cmd );
2765+ return ;
2766+ }
2767+
2768+ cmd -> opcode = inv -> size_opcode ;
2769+ arm_smmu_cmdq_batch_add_range (inv -> smmu , cmds , cmd , iova , size , granule ,
2770+ inv -> pgsize );
2771+ }
2772+
2773+ static inline bool arm_smmu_invs_end_batch (struct arm_smmu_inv * cur ,
2774+ struct arm_smmu_inv * next )
2775+ {
2776+ /* Changing smmu means changing command queue */
2777+ if (cur -> smmu != next -> smmu )
2778+ return true;
2779+ /* The batch for S2 TLBI must be done before nested S1 ASIDs */
2780+ if (cur -> type != INV_TYPE_S2_VMID_S1_CLEAR &&
2781+ next -> type == INV_TYPE_S2_VMID_S1_CLEAR )
2782+ return true;
2783+ /* ATS must be after a sync of the S1/S2 invalidations */
2784+ if (!arm_smmu_inv_is_ats (cur ) && arm_smmu_inv_is_ats (next ))
2785+ return true;
2786+ return false;
2787+ }
2788+
2789+ static void __arm_smmu_domain_inv_range (struct arm_smmu_invs * invs ,
2790+ unsigned long iova , size_t size ,
2791+ unsigned int granule , bool leaf )
2792+ {
2793+ struct arm_smmu_cmdq_batch cmds = {};
2794+ struct arm_smmu_inv * cur ;
2795+ struct arm_smmu_inv * end ;
2796+
2797+ cur = invs -> inv ;
2798+ end = cur + READ_ONCE (invs -> num_invs );
2799+ /* Skip any leading entry marked as a trash */
2800+ for (; cur != end ; cur ++ )
2801+ if (READ_ONCE (cur -> users ))
2802+ break ;
2803+ while (cur != end ) {
2804+ struct arm_smmu_device * smmu = cur -> smmu ;
2805+ struct arm_smmu_cmdq_ent cmd = {
2806+ /*
2807+ * Pick size_opcode to run arm_smmu_get_cmdq(). This can
2808+ * be changed to nsize_opcode, which would result in the
2809+ * same CMDQ pointer.
2810+ */
2811+ .opcode = cur -> size_opcode ,
2812+ };
2813+ struct arm_smmu_inv * next ;
2814+
2815+ if (!cmds .num )
2816+ arm_smmu_cmdq_batch_init (smmu , & cmds , & cmd );
2817+
2818+ switch (cur -> type ) {
2819+ case INV_TYPE_S1_ASID :
2820+ cmd .tlbi .asid = cur -> id ;
2821+ cmd .tlbi .leaf = leaf ;
2822+ arm_smmu_inv_to_cmdq_batch (cur , & cmds , & cmd , iova , size ,
2823+ granule );
2824+ break ;
2825+ case INV_TYPE_S2_VMID :
2826+ cmd .tlbi .vmid = cur -> id ;
2827+ cmd .tlbi .leaf = leaf ;
2828+ arm_smmu_inv_to_cmdq_batch (cur , & cmds , & cmd , iova , size ,
2829+ granule );
2830+ break ;
2831+ case INV_TYPE_S2_VMID_S1_CLEAR :
2832+ /* CMDQ_OP_TLBI_S12_VMALL already flushed S1 entries */
2833+ if (arm_smmu_inv_size_too_big (cur -> smmu , size , granule ))
2834+ continue ;
2835+ cmd .tlbi .vmid = cur -> id ;
2836+ arm_smmu_cmdq_batch_add (smmu , & cmds , & cmd );
2837+ break ;
2838+ case INV_TYPE_ATS :
2839+ arm_smmu_atc_inv_to_cmd (cur -> ssid , iova , size , & cmd );
2840+ cmd .atc .sid = cur -> id ;
2841+ arm_smmu_cmdq_batch_add (smmu , & cmds , & cmd );
2842+ break ;
2843+ case INV_TYPE_ATS_FULL :
2844+ arm_smmu_atc_inv_to_cmd (IOMMU_NO_PASID , 0 , 0 , & cmd );
2845+ cmd .atc .sid = cur -> id ;
2846+ arm_smmu_cmdq_batch_add (smmu , & cmds , & cmd );
2847+ break ;
2848+ default :
2849+ WARN_ON_ONCE (1 );
2850+ continue ;
2851+ }
2852+
2853+ /* Skip any trash entry in-between */
2854+ for (next = cur + 1 ; next != end ; next ++ )
2855+ if (READ_ONCE (next -> users ))
2856+ break ;
2857+
2858+ if (cmds .num &&
2859+ (next == end || arm_smmu_invs_end_batch (cur , next ))) {
2860+ arm_smmu_cmdq_batch_submit (smmu , & cmds );
2861+ cmds .num = 0 ;
2862+ }
2863+ cur = next ;
2864+ }
2865+ }
2866+
2867+ void arm_smmu_domain_inv_range (struct arm_smmu_domain * smmu_domain ,
2868+ unsigned long iova , size_t size ,
2869+ unsigned int granule , bool leaf )
2870+ {
2871+ struct arm_smmu_invs * invs ;
2872+
2873+ /*
2874+ * An invalidation request must follow some IOPTE change and then load
2875+ * an invalidation array. In the meantime, a domain attachment mutates
2876+ * the array and then stores an STE/CD asking SMMU HW to acquire those
2877+ * changed IOPTEs.
2878+ *
2879+ * When running alone, a domain attachment relies on the dma_wmb() in
2880+ * arm_smmu_write_entry() used by arm_smmu_install_ste_for_dev().
2881+ *
2882+ * But in a race, these two can be interdependent, making it a special
2883+ * case requiring an additional smp_mb() for the write->read ordering.
2884+ * Pairing with the dma_wmb() in arm_smmu_install_ste_for_dev(), this
2885+ * makes sure that IOPTE update prior to this point is visable to SMMU
2886+ * hardware before we load the updated invalidation array.
2887+ *
2888+ * [CPU0] | [CPU1]
2889+ * change IOPTE on new domain: |
2890+ * arm_smmu_domain_inv_range() { | arm_smmu_install_new_domain_invs()
2891+ * smp_mb(); // ensures IOPTE | arm_smmu_install_ste_for_dev {
2892+ * // seen by SMMU | dma_wmb(); // ensures invs update
2893+ * // load the updated invs | // before updating STE
2894+ * invs = rcu_dereference(); | STE = TTB0;
2895+ * ... | ...
2896+ * } | }
2897+ */
2898+ smp_mb ();
2899+
2900+ rcu_read_lock ();
2901+ invs = rcu_dereference (smmu_domain -> invs );
2902+
2903+ /*
2904+ * Avoid locking unless ATS is being used. No ATC invalidation can be
2905+ * going on after a domain is detached.
2906+ */
2907+ if (invs -> has_ats ) {
2908+ unsigned long flags ;
2909+
2910+ read_lock_irqsave (& invs -> rwlock , flags );
2911+ __arm_smmu_domain_inv_range (invs , iova , size , granule , leaf );
2912+ read_unlock_irqrestore (& invs -> rwlock , flags );
2913+ } else {
2914+ __arm_smmu_domain_inv_range (invs , iova , size , granule , leaf );
2915+ }
2916+
2917+ rcu_read_unlock ();
2918+ }
2919+
27212920static void arm_smmu_tlb_inv_page_nosync (struct iommu_iotlb_gather * gather ,
27222921 unsigned long iova , size_t granule ,
27232922 void * cookie )
0 commit comments