1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include <linux/slab.h> 7 8 #include <drm/gpu_scheduler.h> 9 10 #include "xe_dep_job_types.h" 11 #include "xe_dep_scheduler.h" 12 #include "xe_device_types.h" 13 14 /** 15 * DOC: Xe Dependency Scheduler 16 * 17 * The Xe dependency scheduler is a simple wrapper built around the DRM 18 * scheduler to execute jobs once their dependencies are resolved (i.e., all 19 * input fences specified as dependencies are signaled). The jobs that are 20 * executed contain virtual functions to run (execute) and free the job, 21 * allowing a single dependency scheduler to handle jobs performing different 22 * operations. 23 * 24 * Example use cases include deferred resource freeing, TLB invalidations after 25 * bind jobs, etc. 26 */ 27 28 /** struct xe_dep_scheduler - Generic Xe dependency scheduler */ 29 struct xe_dep_scheduler { 30 /** @sched: DRM GPU scheduler */ 31 struct drm_gpu_scheduler sched; 32 /** @entity: DRM scheduler entity */ 33 struct drm_sched_entity entity; 34 /** @rcu: For safe freeing of exported dma fences */ 35 struct rcu_head rcu; 36 }; 37 38 static struct dma_fence *xe_dep_scheduler_run_job(struct drm_sched_job *drm_job) 39 { 40 struct xe_dep_job *dep_job = 41 container_of(drm_job, typeof(*dep_job), drm); 42 43 return dep_job->ops->run_job(dep_job); 44 } 45 46 static void xe_dep_scheduler_free_job(struct drm_sched_job *drm_job) 47 { 48 struct xe_dep_job *dep_job = 49 container_of(drm_job, typeof(*dep_job), drm); 50 51 dep_job->ops->free_job(dep_job); 52 } 53 54 static const struct drm_sched_backend_ops sched_ops = { 55 .run_job = xe_dep_scheduler_run_job, 56 .free_job = xe_dep_scheduler_free_job, 57 }; 58 59 /** 60 * xe_dep_scheduler_create() - Generic Xe dependency scheduler create 61 * @xe: Xe device 62 * @submit_wq: Submit workqueue struct (can be NULL) 63 * @name: Name of dependency scheduler 64 * @job_limit: Max dependency jobs that can be scheduled 65 * 66 * Create a generic Xe dependency scheduler and initialize internal DRM 67 * scheduler objects. 68 * 69 * Return: Generic Xe dependency scheduler object on success, ERR_PTR failure 70 */ 71 struct xe_dep_scheduler * 72 xe_dep_scheduler_create(struct xe_device *xe, 73 struct workqueue_struct *submit_wq, 74 const char *name, u32 job_limit) 75 { 76 struct xe_dep_scheduler *dep_scheduler; 77 struct drm_gpu_scheduler *sched; 78 const struct drm_sched_init_args args = { 79 .ops = &sched_ops, 80 .submit_wq = submit_wq, 81 .num_rqs = 1, 82 .credit_limit = job_limit, 83 .timeout = MAX_SCHEDULE_TIMEOUT, 84 .name = name, 85 .dev = xe->drm.dev, 86 }; 87 int err; 88 89 dep_scheduler = kzalloc(sizeof(*dep_scheduler), GFP_KERNEL); 90 if (!dep_scheduler) 91 return ERR_PTR(-ENOMEM); 92 93 err = drm_sched_init(&dep_scheduler->sched, &args); 94 if (err) 95 goto err_free; 96 97 sched = &dep_scheduler->sched; 98 err = drm_sched_entity_init(&dep_scheduler->entity, 0, &sched, 1, NULL); 99 if (err) 100 goto err_sched; 101 102 init_rcu_head(&dep_scheduler->rcu); 103 104 return dep_scheduler; 105 106 err_sched: 107 drm_sched_fini(&dep_scheduler->sched); 108 err_free: 109 kfree(dep_scheduler); 110 111 return ERR_PTR(err); 112 } 113 114 /** 115 * xe_dep_scheduler_fini() - Generic Xe dependency scheduler finalize 116 * @dep_scheduler: Generic Xe dependency scheduler object 117 * 118 * Finalize internal DRM scheduler objects and free generic Xe dependency 119 * scheduler object 120 */ 121 void xe_dep_scheduler_fini(struct xe_dep_scheduler *dep_scheduler) 122 { 123 drm_sched_entity_fini(&dep_scheduler->entity); 124 drm_sched_fini(&dep_scheduler->sched); 125 /* 126 * RCU free due sched being exported via DRM scheduler fences 127 * (timeline name). 128 */ 129 kfree_rcu(dep_scheduler, rcu); 130 } 131 132 /** 133 * xe_dep_scheduler_entity() - Retrieve a generic Xe dependency scheduler 134 * DRM scheduler entity 135 * @dep_scheduler: Generic Xe dependency scheduler object 136 * 137 * Return: The generic Xe dependency scheduler's DRM scheduler entity 138 */ 139 struct drm_sched_entity * 140 xe_dep_scheduler_entity(struct xe_dep_scheduler *dep_scheduler) 141 { 142 return &dep_scheduler->entity; 143 } 144