drivers/gpu/drm/xe/xe_svm.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/xe/xe_svm.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/xe/xe_svm.c
Extension
.c
Size
56492 bytes
Lines
2050
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (xe_pt_zap_ptes_range(tile, vm, range)) {
			/*
			 * WRITE_ONCE pairs with READ_ONCE in
			 * xe_vm_has_valid_gpu_mapping()
			 */
			WRITE_ONCE(range->tile_invalidated,
				   range->tile_invalidated | BIT(id));

			if (!(tile_mask & BIT(id))) {
				xe_svm_tlb_inval_count_stats_incr(tile->primary_gt);
				if (tile->media_gt)
					xe_svm_tlb_inval_count_stats_incr(tile->media_gt);
				tile_mask |= BIT(id);
			}
		}

	return tile_mask;
}

static void
xe_svm_range_notifier_event_end(struct xe_vm *vm, struct drm_gpusvm_range *r,
				const struct mmu_notifier_range *mmu_range)
{
	struct drm_gpusvm_ctx ctx = { .in_notifier = true, };

	xe_svm_assert_in_notifier(vm);

	drm_gpusvm_range_unmap_pages(&vm->svm.gpusvm, r, &ctx);
	if (!xe_vm_is_closed(vm) && mmu_range->event == MMU_NOTIFY_UNMAP)
		xe_svm_garbage_collector_add_range(vm, to_xe_range(r),
						   mmu_range);
}

static void xe_svm_tlb_inval_us_stats_incr(struct xe_gt *gt, ktime_t start)
{
	s64 us_delta = xe_gt_stats_ktime_us_delta(start);

	xe_gt_stats_incr(gt, XE_GT_STATS_ID_SVM_TLB_INVAL_US, us_delta);
}

static void xe_svm_invalidate(struct drm_gpusvm *gpusvm,
			      struct drm_gpusvm_notifier *notifier,
			      const struct mmu_notifier_range *mmu_range)
{
	struct xe_vm *vm = gpusvm_to_vm(gpusvm);
	struct xe_tlb_inval_batch batch;
	struct xe_device *xe = vm->xe;
	struct drm_gpusvm_range *r, *first;
	struct xe_tile *tile;
	ktime_t start = xe_gt_stats_ktime_get();
	u64 adj_start = mmu_range->start, adj_end = mmu_range->end;
	u8 tile_mask = 0, id;
	long err;

	xe_svm_assert_in_notifier(vm);

	vm_dbg(&gpusvm_to_vm(gpusvm)->xe->drm,
	       "INVALIDATE: asid=%u, gpusvm=%p, seqno=%lu, start=0x%016lx, end=0x%016lx, event=%d",
	       vm->usm.asid, gpusvm, notifier->notifier.invalidate_seq,
	       mmu_range->start, mmu_range->end, mmu_range->event);

	/* Adjust invalidation to notifier boundaries */
	adj_start = max(drm_gpusvm_notifier_start(notifier), adj_start);
	adj_end = min(drm_gpusvm_notifier_end(notifier), adj_end);

	first = drm_gpusvm_range_find(notifier, adj_start, adj_end);
	if (!first)
		return;

	/*
	 * PTs may be getting destroyed so not safe to touch these but PT should
	 * be invalidated at this point in time. Regardless we still need to
	 * ensure any dma mappings are unmapped in the here.
	 */
	if (xe_vm_is_closed(vm))
		goto range_notifier_event_end;

	/*
	 * XXX: Less than ideal to always wait on VM's resv slots if an
	 * invalidation is not required. Could walk range list twice to figure
	 * out if an invalidations is need, but also not ideal.
	 */
	err = dma_resv_wait_timeout(xe_vm_resv(vm),
				    DMA_RESV_USAGE_BOOKKEEP,
				    false, MAX_SCHEDULE_TIMEOUT);
	XE_WARN_ON(err <= 0);

	r = first;
	drm_gpusvm_for_each_range(r, notifier, adj_start, adj_end)
		tile_mask |= xe_svm_range_notifier_event_begin(vm, r, mmu_range,

Annotation

Implementation Notes