drivers/gpu/drm/xe/xe_guc_tlb_inval.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/xe/xe_guc_tlb_inval.c
Extension
.c
Size
11352 bytes
Lines
414
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->info.platform == XE_PVC || GRAPHICS_VER(xe) >= 20) {
			xe_mmio_write32(mmio, PVC_GUC_TLB_INV_DESC1,
					PVC_GUC_TLB_INV_DESC1_INVALIDATE);
			xe_mmio_write32(mmio, PVC_GUC_TLB_INV_DESC0,
					PVC_GUC_TLB_INV_DESC0_VALID);
		} else {
			xe_mmio_write32(mmio, GUC_TLB_INV_CR,
					GUC_TLB_INV_CR_INVALIDATE);
		}
	}

	return -ECANCELED;
}

static int send_page_reclaim(struct xe_guc *guc, u32 seqno,
			     u64 gpu_addr)
{
	struct xe_gt *gt = guc_to_gt(guc);
	u32 action[] = {
		XE_GUC_ACTION_PAGE_RECLAMATION,
		seqno,
		lower_32_bits(gpu_addr),
		upper_32_bits(gpu_addr),
	};

	xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_ISSUED_COUNT, 1);

	return xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action),
			      G2H_LEN_DW_PAGE_RECLAMATION, 1);
}

static u64 normalize_invalidation_range(struct xe_gt *gt, u64 *start, u64 *end)
{
	u64 orig_start = *start;
	u64 length = *end - *start;
	u64 align;

	if (length < SZ_4K)
		length = SZ_4K;

	align = roundup_pow_of_two(length);
	*start = ALIGN_DOWN(*start, align);
	*end = ALIGN(*end, align);
	length = align;
	while (*start + length < *end) {
		length <<= 1;
		*start = ALIGN_DOWN(orig_start, length);
	}

	if (length >= SZ_2M) {
		length = max_t(u64, SZ_16M, length);
		*start = ALIGN_DOWN(orig_start, length);
	}

	xe_gt_assert(gt, length >= SZ_4K);
	xe_gt_assert(gt, is_power_of_2(length));
	xe_gt_assert(gt, !(length & GENMASK(ilog2(SZ_16M) - 1,
					    ilog2(SZ_2M) + 1)));
	xe_gt_assert(gt, IS_ALIGNED(*start, length));

	return length;
}

/*
 * Ensure that roundup_pow_of_two(length) doesn't overflow.
 * Note that roundup_pow_of_two() operates on unsigned long,
 * not on u64.
 */
#define MAX_RANGE_TLB_INVALIDATION_LENGTH (rounddown_pow_of_two(ULONG_MAX))

static int send_tlb_inval_ppgtt(struct xe_guc *guc, u32 seqno, u64 start,
				u64 end, u32 id, u32 type,
				struct drm_suballoc *prl_sa)
{
#define MAX_TLB_INVALIDATION_LEN	7
	struct xe_gt *gt = guc_to_gt(guc);
	struct xe_device *xe = guc_to_xe(guc);
	u32 action[MAX_TLB_INVALIDATION_LEN];
	u64 length = end - start;
	int len = 0, err;

	xe_gt_assert(gt, (type == XE_GUC_TLB_INVAL_PAGE_SELECTIVE &&
			  !xe->info.has_ctx_tlb_inval) ||
		     (type == XE_GUC_TLB_INVAL_PAGE_SELECTIVE_CTX &&
		      xe->info.has_ctx_tlb_inval));

	action[len++] = XE_GUC_ACTION_TLB_INVALIDATION;
	action[len++] = !prl_sa ? seqno : TLB_INVALIDATION_SEQNO_INVALID;
	if (!gt_to_xe(gt)->info.has_range_tlb_inval ||
	    length > MAX_RANGE_TLB_INVALIDATION_LENGTH) {

Annotation

Implementation Notes