Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe/pf: Invalidate LMTT during LMEM unprovisioning

Invalidate LMTT immediately after removing VF's LMTT page tables
and clearing root PTE in the LMTT PD to avoid any invalid access
by the hardware (and VF) due to stale data.

Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Michał Winiarski <michal.winiarski@intel.com>
Cc: Piotr Piórkowski <piotr.piorkowski@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Link: https://lore.kernel.org/r/20250711193316.1920-6-michal.wajdeczko@intel.com

+94
+4
drivers/gpu/drm/xe/xe_device.h
··· 131 131 for ((id__) = 0; (id__) < (xe__)->info.tile_count * (xe__)->info.max_gt_per_tile; (id__)++) \ 132 132 for_each_if((gt__) = xe_device_get_gt((xe__), (id__))) 133 133 134 + #define for_each_gt_on_tile(gt__, tile__, id__) \ 135 + for_each_gt((gt__), (tile__)->xe, (id__)) \ 136 + for_each_if((gt__)->tile == (tile__)) 137 + 134 138 static inline struct xe_force_wake *gt_to_fw(struct xe_gt *gt) 135 139 { 136 140 return &gt->pm.fw;
+34
drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c
··· 330 330 return 0; 331 331 } 332 332 333 + static int send_tlb_invalidation_all(struct xe_gt *gt, 334 + struct xe_gt_tlb_invalidation_fence *fence) 335 + { 336 + u32 action[] = { 337 + XE_GUC_ACTION_TLB_INVALIDATION_ALL, 338 + 0, /* seqno, replaced in send_tlb_invalidation */ 339 + MAKE_INVAL_OP(XE_GUC_TLB_INVAL_FULL), 340 + }; 341 + 342 + return send_tlb_invalidation(&gt->uc.guc, fence, action, ARRAY_SIZE(action)); 343 + } 344 + 345 + /** 346 + * xe_gt_tlb_invalidation_all - Invalidate all TLBs across PF and all VFs. 347 + * @gt: the &xe_gt structure 348 + * @fence: the &xe_gt_tlb_invalidation_fence to be signaled on completion 349 + * 350 + * Send a request to invalidate all TLBs across PF and all VFs. 351 + * 352 + * Return: 0 on success, negative error code on error 353 + */ 354 + int xe_gt_tlb_invalidation_all(struct xe_gt *gt, struct xe_gt_tlb_invalidation_fence *fence) 355 + { 356 + int err; 357 + 358 + xe_gt_assert(gt, gt == fence->gt); 359 + 360 + err = send_tlb_invalidation_all(gt, fence); 361 + if (err) 362 + xe_gt_err(gt, "TLB invalidation request failed (%pe)", ERR_PTR(err)); 363 + 364 + return err; 365 + } 366 + 333 367 /* 334 368 * Ensure that roundup_pow_of_two(length) doesn't overflow. 335 369 * Note that roundup_pow_of_two() operates on unsigned long,
+1
drivers/gpu/drm/xe/xe_gt_tlb_invalidation.h
··· 20 20 void xe_gt_tlb_invalidation_reset(struct xe_gt *gt); 21 21 int xe_gt_tlb_invalidation_ggtt(struct xe_gt *gt); 22 22 void xe_gt_tlb_invalidation_vm(struct xe_gt *gt, struct xe_vm *vm); 23 + int xe_gt_tlb_invalidation_all(struct xe_gt *gt, struct xe_gt_tlb_invalidation_fence *fence); 23 24 int xe_gt_tlb_invalidation_range(struct xe_gt *gt, 24 25 struct xe_gt_tlb_invalidation_fence *fence, 25 26 u64 start, u64 end, u32 asid);
+54
drivers/gpu/drm/xe/xe_lmtt.c
··· 11 11 12 12 #include "xe_assert.h" 13 13 #include "xe_bo.h" 14 + #include "xe_gt_tlb_invalidation.h" 14 15 #include "xe_lmtt.h" 15 16 #include "xe_map.h" 16 17 #include "xe_mmio.h" ··· 223 222 lmtt_setup_dir_ptr(lmtt); 224 223 } 225 224 225 + static int lmtt_invalidate_hw(struct xe_lmtt *lmtt) 226 + { 227 + struct xe_gt_tlb_invalidation_fence fences[XE_MAX_GT_PER_TILE]; 228 + struct xe_gt_tlb_invalidation_fence *fence = fences; 229 + struct xe_tile *tile = lmtt_to_tile(lmtt); 230 + struct xe_gt *gt; 231 + int result = 0; 232 + int err; 233 + u8 id; 234 + 235 + for_each_gt_on_tile(gt, tile, id) { 236 + xe_gt_tlb_invalidation_fence_init(gt, fence, true); 237 + err = xe_gt_tlb_invalidation_all(gt, fence); 238 + result = result ?: err; 239 + fence++; 240 + } 241 + 242 + lmtt_debug(lmtt, "num_fences=%d err=%d\n", (int)(fence - fences), result); 243 + 244 + /* 245 + * It is fine to wait for all fences, even for those which covers the 246 + * invalidation request that failed, as such fence should be already 247 + * marked as signaled. 248 + */ 249 + fence = fences; 250 + for_each_gt_on_tile(gt, tile, id) 251 + xe_gt_tlb_invalidation_fence_wait(fence++); 252 + 253 + return result; 254 + } 255 + 256 + /** 257 + * xe_lmtt_invalidate_hw - Invalidate LMTT hardware. 258 + * @lmtt: the &xe_lmtt to invalidate 259 + * 260 + * Send requests to all GuCs on this tile to invalidate all TLBs. 261 + * 262 + * This function should be called only when running as a PF driver. 263 + */ 264 + void xe_lmtt_invalidate_hw(struct xe_lmtt *lmtt) 265 + { 266 + struct xe_device *xe = lmtt_to_xe(lmtt); 267 + int err; 268 + 269 + lmtt_assert(lmtt, IS_SRIOV_PF(xe)); 270 + 271 + err = lmtt_invalidate_hw(lmtt); 272 + if (err) 273 + xe_sriov_warn(xe, "LMTT%u invalidation failed (%pe)", 274 + lmtt_to_tile(lmtt)->id, ERR_PTR(err)); 275 + } 276 + 226 277 static void lmtt_write_pte(struct xe_lmtt *lmtt, struct xe_lmtt_pt *pt, 227 278 u64 pte, unsigned int idx) 228 279 { ··· 329 276 return; 330 277 331 278 lmtt_write_pte(lmtt, pd, LMTT_PTE_INVALID, vfid); 279 + lmtt_invalidate_hw(lmtt); 332 280 333 281 lmtt_assert(lmtt, pd->level > 0); 334 282 lmtt_assert(lmtt, pt->level == pd->level - 1);
+1
drivers/gpu/drm/xe/xe_lmtt.h
··· 15 15 #ifdef CONFIG_PCI_IOV 16 16 int xe_lmtt_init(struct xe_lmtt *lmtt); 17 17 void xe_lmtt_init_hw(struct xe_lmtt *lmtt); 18 + void xe_lmtt_invalidate_hw(struct xe_lmtt *lmtt); 18 19 int xe_lmtt_prepare_pages(struct xe_lmtt *lmtt, unsigned int vfid, u64 range); 19 20 int xe_lmtt_populate_pages(struct xe_lmtt *lmtt, unsigned int vfid, struct xe_bo *bo, u64 offset); 20 21 void xe_lmtt_drop_pages(struct xe_lmtt *lmtt, unsigned int vfid);