@@ -92,16 +92,10 @@ int xe_gt_tlb_invalidation_init(struct xe_gt *gt)
9292}
9393
9494static int send_tlb_invalidation (struct xe_guc * guc ,
95- struct xe_gt_tlb_invalidation_fence * fence )
95+ struct xe_gt_tlb_invalidation_fence * fence ,
96+ u32 * action , int len )
9697{
9798 struct xe_gt * gt = guc_to_gt (guc );
98- u32 action [] = {
99- XE_GUC_ACTION_TLB_INVALIDATION ,
100- 0 ,
101- XE_GUC_TLB_INVAL_FULL << XE_GUC_TLB_INVAL_TYPE_SHIFT |
102- XE_GUC_TLB_INVAL_MODE_HEAVY << XE_GUC_TLB_INVAL_MODE_SHIFT |
103- XE_GUC_TLB_INVAL_FLUSH_CACHE ,
104- };
10599 int seqno ;
106100 int ret ;
107101 bool queue_work ;
@@ -125,7 +119,7 @@ static int send_tlb_invalidation(struct xe_guc *guc,
125119 TLB_INVALIDATION_SEQNO_MAX ;
126120 if (!gt -> tlb_invalidation .seqno )
127121 gt -> tlb_invalidation .seqno = 1 ;
128- ret = xe_guc_ct_send_locked (& guc -> ct , action , ARRAY_SIZE ( action ) ,
122+ ret = xe_guc_ct_send_locked (& guc -> ct , action , len ,
129123 G2H_LEN_DW_TLB_INVALIDATE , 1 );
130124 if (!ret && fence ) {
131125 fence -> invalidation_time = ktime_get ();
@@ -146,18 +140,83 @@ static int send_tlb_invalidation(struct xe_guc *guc,
146140 * @gt: graphics tile
147141 * @fence: invalidation fence which will be signal on TLB invalidation
148142 * completion, can be NULL
143+ * @vma: VMA to invalidate
149144 *
150- * Issue a full TLB invalidation on the GT. Completion of TLB is asynchronous
151- * and caller can either use the invalidation fence or seqno +
152- * xe_gt_tlb_invalidation_wait to wait for completion.
145+ * Issue a range based TLB invalidation if supported, if not fallback to a full
146+ * TLB invalidation. Completion of TLB is asynchronous and caller can either use
147+ * the invalidation fence or seqno + xe_gt_tlb_invalidation_wait to wait for
148+ * completion.
153149 *
154150 * Return: Seqno which can be passed to xe_gt_tlb_invalidation_wait on success,
155151 * negative error code on error.
156152 */
157153int xe_gt_tlb_invalidation (struct xe_gt * gt ,
158- struct xe_gt_tlb_invalidation_fence * fence )
154+ struct xe_gt_tlb_invalidation_fence * fence ,
155+ struct xe_vma * vma )
159156{
160- return send_tlb_invalidation (& gt -> uc .guc , fence );
157+ struct xe_device * xe = gt_to_xe (gt );
158+ #define MAX_TLB_INVALIDATION_LEN 7
159+ u32 action [MAX_TLB_INVALIDATION_LEN ];
160+ int len = 0 ;
161+
162+ XE_BUG_ON (!vma );
163+
164+ if (!xe -> info .has_range_tlb_invalidation ) {
165+ action [len ++ ] = XE_GUC_ACTION_TLB_INVALIDATION ;
166+ action [len ++ ] = 0 ; /* seqno, replaced in send_tlb_invalidation */
167+ #define MAKE_INVAL_OP (type ) ((type << XE_GUC_TLB_INVAL_TYPE_SHIFT) | \
168+ XE_GUC_TLB_INVAL_MODE_HEAVY << XE_GUC_TLB_INVAL_MODE_SHIFT | \
169+ XE_GUC_TLB_INVAL_FLUSH_CACHE)
170+ action [len ++ ] = MAKE_INVAL_OP (XE_GUC_TLB_INVAL_FULL );
171+ } else {
172+ u64 start = vma -> start ;
173+ u64 length = vma -> end - vma -> start + 1 ;
174+ u64 align , end ;
175+
176+ if (length < SZ_4K )
177+ length = SZ_4K ;
178+
179+ /*
180+ * We need to invalidate a higher granularity if start address
181+ * is not aligned to length. When start is not aligned with
182+ * length we need to find the length large enough to create an
183+ * address mask covering the required range.
184+ */
185+ align = roundup_pow_of_two (length );
186+ start = ALIGN_DOWN (vma -> start , align );
187+ end = ALIGN (vma -> start + length , align );
188+ length = align ;
189+ while (start + length < end ) {
190+ length <<= 1 ;
191+ start = ALIGN_DOWN (vma -> start , length );
192+ }
193+
194+ /*
195+ * Minimum invalidation size for a 2MB page that the hardware
196+ * expects is 16MB
197+ */
198+ if (length >= SZ_2M ) {
199+ length = max_t (u64 , SZ_16M , length );
200+ start = ALIGN_DOWN (vma -> start , length );
201+ }
202+
203+ XE_BUG_ON (length < SZ_4K );
204+ XE_BUG_ON (!is_power_of_2 (length ));
205+ XE_BUG_ON (length & GENMASK (ilog2 (SZ_16M ) - 1 , ilog2 (SZ_2M ) + 1 ));
206+ XE_BUG_ON (!IS_ALIGNED (start , length ));
207+
208+ action [len ++ ] = XE_GUC_ACTION_TLB_INVALIDATION ;
209+ action [len ++ ] = 0 ; /* seqno, replaced in send_tlb_invalidation */
210+ action [len ++ ] = MAKE_INVAL_OP (XE_GUC_TLB_INVAL_PAGE_SELECTIVE );
211+ action [len ++ ] = vma -> vm -> usm .asid ;
212+ action [len ++ ] = lower_32_bits (start );
213+ action [len ++ ] = upper_32_bits (start );
214+ action [len ++ ] = ilog2 (length ) - ilog2 (SZ_4K );
215+ }
216+
217+ XE_BUG_ON (len > MAX_TLB_INVALIDATION_LEN );
218+
219+ return send_tlb_invalidation (& gt -> uc .guc , fence , action , len );
161220}
162221
163222static bool tlb_invalidation_seqno_past (struct xe_gt * gt , int seqno )
0 commit comments