1*15366239SMatthew Brost // SPDX-License-Identifier: MIT 2*15366239SMatthew Brost /* 3*15366239SMatthew Brost * Copyright © 2025 Intel Corporation 4*15366239SMatthew Brost */ 5*15366239SMatthew Brost 6*15366239SMatthew Brost #include "xe_assert.h" 7*15366239SMatthew Brost #include "xe_dep_job_types.h" 8*15366239SMatthew Brost #include "xe_dep_scheduler.h" 9*15366239SMatthew Brost #include "xe_exec_queue.h" 10*15366239SMatthew Brost #include "xe_gt_types.h" 11*15366239SMatthew Brost #include "xe_tlb_inval.h" 12*15366239SMatthew Brost #include "xe_tlb_inval_job.h" 13*15366239SMatthew Brost #include "xe_migrate.h" 14*15366239SMatthew Brost #include "xe_pm.h" 15*15366239SMatthew Brost 16*15366239SMatthew Brost /** struct xe_tlb_inval_job - TLB invalidation job */ 17*15366239SMatthew Brost struct xe_tlb_inval_job { 18*15366239SMatthew Brost /** @dep: base generic dependency Xe job */ 19*15366239SMatthew Brost struct xe_dep_job dep; 20*15366239SMatthew Brost /** @tlb_inval: TLB invalidation client */ 21*15366239SMatthew Brost struct xe_tlb_inval *tlb_inval; 22*15366239SMatthew Brost /** @q: exec queue issuing the invalidate */ 23*15366239SMatthew Brost struct xe_exec_queue *q; 24*15366239SMatthew Brost /** @refcount: ref count of this job */ 25*15366239SMatthew Brost struct kref refcount; 26*15366239SMatthew Brost /** 27*15366239SMatthew Brost * @fence: dma fence to indicate completion. 1 way relationship - job 28*15366239SMatthew Brost * can safely reference fence, fence cannot safely reference job. 29*15366239SMatthew Brost */ 30*15366239SMatthew Brost struct dma_fence *fence; 31*15366239SMatthew Brost /** @start: Start address to invalidate */ 32*15366239SMatthew Brost u64 start; 33*15366239SMatthew Brost /** @end: End address to invalidate */ 34*15366239SMatthew Brost u64 end; 35*15366239SMatthew Brost /** @asid: Address space ID to invalidate */ 36*15366239SMatthew Brost u32 asid; 37*15366239SMatthew Brost /** @fence_armed: Fence has been armed */ 38*15366239SMatthew Brost bool fence_armed; 39*15366239SMatthew Brost }; 40*15366239SMatthew Brost 41*15366239SMatthew Brost static struct dma_fence *xe_tlb_inval_job_run(struct xe_dep_job *dep_job) 42*15366239SMatthew Brost { 43*15366239SMatthew Brost struct xe_tlb_inval_job *job = 44*15366239SMatthew Brost container_of(dep_job, typeof(*job), dep); 45*15366239SMatthew Brost struct xe_tlb_inval_fence *ifence = 46*15366239SMatthew Brost container_of(job->fence, typeof(*ifence), base); 47*15366239SMatthew Brost 48*15366239SMatthew Brost xe_tlb_inval_range(job->tlb_inval, ifence, job->start, 49*15366239SMatthew Brost job->end, job->asid); 50*15366239SMatthew Brost 51*15366239SMatthew Brost return job->fence; 52*15366239SMatthew Brost } 53*15366239SMatthew Brost 54*15366239SMatthew Brost static void xe_tlb_inval_job_free(struct xe_dep_job *dep_job) 55*15366239SMatthew Brost { 56*15366239SMatthew Brost struct xe_tlb_inval_job *job = 57*15366239SMatthew Brost container_of(dep_job, typeof(*job), dep); 58*15366239SMatthew Brost 59*15366239SMatthew Brost /* Pairs with get in xe_tlb_inval_job_push */ 60*15366239SMatthew Brost xe_tlb_inval_job_put(job); 61*15366239SMatthew Brost } 62*15366239SMatthew Brost 63*15366239SMatthew Brost static const struct xe_dep_job_ops dep_job_ops = { 64*15366239SMatthew Brost .run_job = xe_tlb_inval_job_run, 65*15366239SMatthew Brost .free_job = xe_tlb_inval_job_free, 66*15366239SMatthew Brost }; 67*15366239SMatthew Brost 68*15366239SMatthew Brost /** 69*15366239SMatthew Brost * xe_tlb_inval_job_create() - TLB invalidation job create 70*15366239SMatthew Brost * @q: exec queue issuing the invalidate 71*15366239SMatthew Brost * @tlb_inval: TLB invalidation client 72*15366239SMatthew Brost * @dep_scheduler: Dependency scheduler for job 73*15366239SMatthew Brost * @start: Start address to invalidate 74*15366239SMatthew Brost * @end: End address to invalidate 75*15366239SMatthew Brost * @asid: Address space ID to invalidate 76*15366239SMatthew Brost * 77*15366239SMatthew Brost * Create a TLB invalidation job and initialize internal fields. The caller is 78*15366239SMatthew Brost * responsible for releasing the creation reference. 79*15366239SMatthew Brost * 80*15366239SMatthew Brost * Return: TLB invalidation job object on success, ERR_PTR failure 81*15366239SMatthew Brost */ 82*15366239SMatthew Brost struct xe_tlb_inval_job * 83*15366239SMatthew Brost xe_tlb_inval_job_create(struct xe_exec_queue *q, struct xe_tlb_inval *tlb_inval, 84*15366239SMatthew Brost struct xe_dep_scheduler *dep_scheduler, u64 start, 85*15366239SMatthew Brost u64 end, u32 asid) 86*15366239SMatthew Brost { 87*15366239SMatthew Brost struct xe_tlb_inval_job *job; 88*15366239SMatthew Brost struct drm_sched_entity *entity = 89*15366239SMatthew Brost xe_dep_scheduler_entity(dep_scheduler); 90*15366239SMatthew Brost struct xe_tlb_inval_fence *ifence; 91*15366239SMatthew Brost int err; 92*15366239SMatthew Brost 93*15366239SMatthew Brost job = kmalloc(sizeof(*job), GFP_KERNEL); 94*15366239SMatthew Brost if (!job) 95*15366239SMatthew Brost return ERR_PTR(-ENOMEM); 96*15366239SMatthew Brost 97*15366239SMatthew Brost job->q = q; 98*15366239SMatthew Brost job->tlb_inval = tlb_inval; 99*15366239SMatthew Brost job->start = start; 100*15366239SMatthew Brost job->end = end; 101*15366239SMatthew Brost job->asid = asid; 102*15366239SMatthew Brost job->fence_armed = false; 103*15366239SMatthew Brost job->dep.ops = &dep_job_ops; 104*15366239SMatthew Brost kref_init(&job->refcount); 105*15366239SMatthew Brost xe_exec_queue_get(q); /* Pairs with put in xe_tlb_inval_job_destroy */ 106*15366239SMatthew Brost 107*15366239SMatthew Brost ifence = kmalloc(sizeof(*ifence), GFP_KERNEL); 108*15366239SMatthew Brost if (!ifence) { 109*15366239SMatthew Brost err = -ENOMEM; 110*15366239SMatthew Brost goto err_job; 111*15366239SMatthew Brost } 112*15366239SMatthew Brost job->fence = &ifence->base; 113*15366239SMatthew Brost 114*15366239SMatthew Brost err = drm_sched_job_init(&job->dep.drm, entity, 1, NULL, 115*15366239SMatthew Brost q->xef ? q->xef->drm->client_id : 0); 116*15366239SMatthew Brost if (err) 117*15366239SMatthew Brost goto err_fence; 118*15366239SMatthew Brost 119*15366239SMatthew Brost /* Pairs with put in xe_tlb_inval_job_destroy */ 120*15366239SMatthew Brost xe_pm_runtime_get_noresume(gt_to_xe(q->gt)); 121*15366239SMatthew Brost 122*15366239SMatthew Brost return job; 123*15366239SMatthew Brost 124*15366239SMatthew Brost err_fence: 125*15366239SMatthew Brost kfree(ifence); 126*15366239SMatthew Brost err_job: 127*15366239SMatthew Brost xe_exec_queue_put(q); 128*15366239SMatthew Brost kfree(job); 129*15366239SMatthew Brost 130*15366239SMatthew Brost return ERR_PTR(err); 131*15366239SMatthew Brost } 132*15366239SMatthew Brost 133*15366239SMatthew Brost static void xe_tlb_inval_job_destroy(struct kref *ref) 134*15366239SMatthew Brost { 135*15366239SMatthew Brost struct xe_tlb_inval_job *job = container_of(ref, typeof(*job), 136*15366239SMatthew Brost refcount); 137*15366239SMatthew Brost struct xe_tlb_inval_fence *ifence = 138*15366239SMatthew Brost container_of(job->fence, typeof(*ifence), base); 139*15366239SMatthew Brost struct xe_exec_queue *q = job->q; 140*15366239SMatthew Brost struct xe_device *xe = gt_to_xe(q->gt); 141*15366239SMatthew Brost 142*15366239SMatthew Brost if (!job->fence_armed) 143*15366239SMatthew Brost kfree(ifence); 144*15366239SMatthew Brost else 145*15366239SMatthew Brost /* Ref from xe_tlb_inval_fence_init */ 146*15366239SMatthew Brost dma_fence_put(job->fence); 147*15366239SMatthew Brost 148*15366239SMatthew Brost drm_sched_job_cleanup(&job->dep.drm); 149*15366239SMatthew Brost kfree(job); 150*15366239SMatthew Brost xe_exec_queue_put(q); /* Pairs with get from xe_tlb_inval_job_create */ 151*15366239SMatthew Brost xe_pm_runtime_put(xe); /* Pairs with get from xe_tlb_inval_job_create */ 152*15366239SMatthew Brost } 153*15366239SMatthew Brost 154*15366239SMatthew Brost /** 155*15366239SMatthew Brost * xe_tlb_inval_alloc_dep() - TLB invalidation job alloc dependency 156*15366239SMatthew Brost * @job: TLB invalidation job to alloc dependency for 157*15366239SMatthew Brost * 158*15366239SMatthew Brost * Allocate storage for a dependency in the TLB invalidation fence. This 159*15366239SMatthew Brost * function should be called at most once per job and must be paired with 160*15366239SMatthew Brost * xe_tlb_inval_job_push being called with a real fence. 161*15366239SMatthew Brost * 162*15366239SMatthew Brost * Return: 0 on success, -errno on failure 163*15366239SMatthew Brost */ 164*15366239SMatthew Brost int xe_tlb_inval_job_alloc_dep(struct xe_tlb_inval_job *job) 165*15366239SMatthew Brost { 166*15366239SMatthew Brost xe_assert(gt_to_xe(job->q->gt), !xa_load(&job->dep.drm.dependencies, 0)); 167*15366239SMatthew Brost might_alloc(GFP_KERNEL); 168*15366239SMatthew Brost 169*15366239SMatthew Brost return drm_sched_job_add_dependency(&job->dep.drm, 170*15366239SMatthew Brost dma_fence_get_stub()); 171*15366239SMatthew Brost } 172*15366239SMatthew Brost 173*15366239SMatthew Brost /** 174*15366239SMatthew Brost * xe_tlb_inval_job_push() - TLB invalidation job push 175*15366239SMatthew Brost * @job: TLB invalidation job to push 176*15366239SMatthew Brost * @m: The migration object being used 177*15366239SMatthew Brost * @fence: Dependency for TLB invalidation job 178*15366239SMatthew Brost * 179*15366239SMatthew Brost * Pushes a TLB invalidation job for execution, using @fence as a dependency. 180*15366239SMatthew Brost * Storage for @fence must be preallocated with xe_tlb_inval_job_alloc_dep 181*15366239SMatthew Brost * prior to this call if @fence is not signaled. Takes a reference to the job’s 182*15366239SMatthew Brost * finished fence, which the caller is responsible for releasing, and return it 183*15366239SMatthew Brost * to the caller. This function is safe to be called in the path of reclaim. 184*15366239SMatthew Brost * 185*15366239SMatthew Brost * Return: Job's finished fence on success, cannot fail 186*15366239SMatthew Brost */ 187*15366239SMatthew Brost struct dma_fence *xe_tlb_inval_job_push(struct xe_tlb_inval_job *job, 188*15366239SMatthew Brost struct xe_migrate *m, 189*15366239SMatthew Brost struct dma_fence *fence) 190*15366239SMatthew Brost { 191*15366239SMatthew Brost struct xe_tlb_inval_fence *ifence = 192*15366239SMatthew Brost container_of(job->fence, typeof(*ifence), base); 193*15366239SMatthew Brost 194*15366239SMatthew Brost if (!dma_fence_is_signaled(fence)) { 195*15366239SMatthew Brost void *ptr; 196*15366239SMatthew Brost 197*15366239SMatthew Brost /* 198*15366239SMatthew Brost * Can be in path of reclaim, hence the preallocation of fence 199*15366239SMatthew Brost * storage in xe_tlb_inval_job_alloc_dep. Verify caller did 200*15366239SMatthew Brost * this correctly. 201*15366239SMatthew Brost */ 202*15366239SMatthew Brost xe_assert(gt_to_xe(job->q->gt), 203*15366239SMatthew Brost xa_load(&job->dep.drm.dependencies, 0) == 204*15366239SMatthew Brost dma_fence_get_stub()); 205*15366239SMatthew Brost 206*15366239SMatthew Brost dma_fence_get(fence); /* ref released once dependency processed by scheduler */ 207*15366239SMatthew Brost ptr = xa_store(&job->dep.drm.dependencies, 0, fence, 208*15366239SMatthew Brost GFP_ATOMIC); 209*15366239SMatthew Brost xe_assert(gt_to_xe(job->q->gt), !xa_is_err(ptr)); 210*15366239SMatthew Brost } 211*15366239SMatthew Brost 212*15366239SMatthew Brost xe_tlb_inval_job_get(job); /* Pairs with put in free_job */ 213*15366239SMatthew Brost job->fence_armed = true; 214*15366239SMatthew Brost 215*15366239SMatthew Brost /* 216*15366239SMatthew Brost * We need the migration lock to protect the job's seqno and the spsc 217*15366239SMatthew Brost * queue, only taken on migration queue, user queues protected dma-resv 218*15366239SMatthew Brost * VM lock. 219*15366239SMatthew Brost */ 220*15366239SMatthew Brost xe_migrate_job_lock(m, job->q); 221*15366239SMatthew Brost 222*15366239SMatthew Brost /* Creation ref pairs with put in xe_tlb_inval_job_destroy */ 223*15366239SMatthew Brost xe_tlb_inval_fence_init(job->tlb_inval, ifence, false); 224*15366239SMatthew Brost dma_fence_get(job->fence); /* Pairs with put in DRM scheduler */ 225*15366239SMatthew Brost 226*15366239SMatthew Brost drm_sched_job_arm(&job->dep.drm); 227*15366239SMatthew Brost /* 228*15366239SMatthew Brost * caller ref, get must be done before job push as it could immediately 229*15366239SMatthew Brost * signal and free. 230*15366239SMatthew Brost */ 231*15366239SMatthew Brost dma_fence_get(&job->dep.drm.s_fence->finished); 232*15366239SMatthew Brost drm_sched_entity_push_job(&job->dep.drm); 233*15366239SMatthew Brost 234*15366239SMatthew Brost xe_migrate_job_unlock(m, job->q); 235*15366239SMatthew Brost 236*15366239SMatthew Brost /* 237*15366239SMatthew Brost * Not using job->fence, as it has its own dma-fence context, which does 238*15366239SMatthew Brost * not allow TLB invalidation fences on the same queue, GT tuple to 239*15366239SMatthew Brost * be squashed in dma-resv/DRM scheduler. Instead, we use the DRM scheduler 240*15366239SMatthew Brost * context and job's finished fence, which enables squashing. 241*15366239SMatthew Brost */ 242*15366239SMatthew Brost return &job->dep.drm.s_fence->finished; 243*15366239SMatthew Brost } 244*15366239SMatthew Brost 245*15366239SMatthew Brost /** 246*15366239SMatthew Brost * xe_tlb_inval_job_get() - Get a reference to TLB invalidation job 247*15366239SMatthew Brost * @job: TLB invalidation job object 248*15366239SMatthew Brost * 249*15366239SMatthew Brost * Increment the TLB invalidation job's reference count 250*15366239SMatthew Brost */ 251*15366239SMatthew Brost void xe_tlb_inval_job_get(struct xe_tlb_inval_job *job) 252*15366239SMatthew Brost { 253*15366239SMatthew Brost kref_get(&job->refcount); 254*15366239SMatthew Brost } 255*15366239SMatthew Brost 256*15366239SMatthew Brost /** 257*15366239SMatthew Brost * xe_tlb_inval_job_put() - Put a reference to TLB invalidation job 258*15366239SMatthew Brost * @job: TLB invalidation job object 259*15366239SMatthew Brost * 260*15366239SMatthew Brost * Decrement the TLB invalidation job's reference count, call 261*15366239SMatthew Brost * xe_tlb_inval_job_destroy when reference count == 0. Skips decrement if 262*15366239SMatthew Brost * input @job is NULL or IS_ERR. 263*15366239SMatthew Brost */ 264*15366239SMatthew Brost void xe_tlb_inval_job_put(struct xe_tlb_inval_job *job) 265*15366239SMatthew Brost { 266*15366239SMatthew Brost if (!IS_ERR_OR_NULL(job)) 267*15366239SMatthew Brost kref_put(&job->refcount, xe_tlb_inval_job_destroy); 268*15366239SMatthew Brost } 269