@@ -92,16 +92,10 @@ int xe_gt_tlb_invalidation_init(struct xe_gt *gt)
92
92
}
93
93
94
94
static 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 )
96
97
{
97
98
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
- };
105
99
int seqno ;
106
100
int ret ;
107
101
bool queue_work ;
@@ -125,7 +119,7 @@ static int send_tlb_invalidation(struct xe_guc *guc,
125
119
TLB_INVALIDATION_SEQNO_MAX ;
126
120
if (!gt -> tlb_invalidation .seqno )
127
121
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 ,
129
123
G2H_LEN_DW_TLB_INVALIDATE , 1 );
130
124
if (!ret && fence ) {
131
125
fence -> invalidation_time = ktime_get ();
@@ -146,18 +140,83 @@ static int send_tlb_invalidation(struct xe_guc *guc,
146
140
* @gt: graphics tile
147
141
* @fence: invalidation fence which will be signal on TLB invalidation
148
142
* completion, can be NULL
143
+ * @vma: VMA to invalidate
149
144
*
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.
153
149
*
154
150
* Return: Seqno which can be passed to xe_gt_tlb_invalidation_wait on success,
155
151
* negative error code on error.
156
152
*/
157
153
int 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 )
159
156
{
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 );
161
220
}
162
221
163
222
static bool tlb_invalidation_seqno_past (struct xe_gt * gt , int seqno )
0 commit comments