0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <linux/kthread.h>
0025 #include <linux/module.h>
0026 #include <linux/sched.h>
0027 #include <linux/slab.h>
0028 #include <linux/wait.h>
0029
0030 #include <drm/gpu_scheduler.h>
0031
0032 static struct kmem_cache *sched_fence_slab;
0033
0034 static int __init drm_sched_fence_slab_init(void)
0035 {
0036 sched_fence_slab = kmem_cache_create(
0037 "drm_sched_fence", sizeof(struct drm_sched_fence), 0,
0038 SLAB_HWCACHE_ALIGN, NULL);
0039 if (!sched_fence_slab)
0040 return -ENOMEM;
0041
0042 return 0;
0043 }
0044
0045 static void __exit drm_sched_fence_slab_fini(void)
0046 {
0047 rcu_barrier();
0048 kmem_cache_destroy(sched_fence_slab);
0049 }
0050
0051 void drm_sched_fence_scheduled(struct drm_sched_fence *fence)
0052 {
0053 dma_fence_signal(&fence->scheduled);
0054 }
0055
0056 void drm_sched_fence_finished(struct drm_sched_fence *fence)
0057 {
0058 dma_fence_signal(&fence->finished);
0059 }
0060
0061 static const char *drm_sched_fence_get_driver_name(struct dma_fence *fence)
0062 {
0063 return "drm_sched";
0064 }
0065
0066 static const char *drm_sched_fence_get_timeline_name(struct dma_fence *f)
0067 {
0068 struct drm_sched_fence *fence = to_drm_sched_fence(f);
0069 return (const char *)fence->sched->name;
0070 }
0071
0072 static void drm_sched_fence_free_rcu(struct rcu_head *rcu)
0073 {
0074 struct dma_fence *f = container_of(rcu, struct dma_fence, rcu);
0075 struct drm_sched_fence *fence = to_drm_sched_fence(f);
0076
0077 if (!WARN_ON_ONCE(!fence))
0078 kmem_cache_free(sched_fence_slab, fence);
0079 }
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 void drm_sched_fence_free(struct drm_sched_fence *fence)
0090 {
0091
0092 if (!WARN_ON_ONCE(fence->sched))
0093 kmem_cache_free(sched_fence_slab, fence);
0094 }
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 static void drm_sched_fence_release_scheduled(struct dma_fence *f)
0105 {
0106 struct drm_sched_fence *fence = to_drm_sched_fence(f);
0107
0108 dma_fence_put(fence->parent);
0109 call_rcu(&fence->finished.rcu, drm_sched_fence_free_rcu);
0110 }
0111
0112
0113
0114
0115
0116
0117
0118
0119 static void drm_sched_fence_release_finished(struct dma_fence *f)
0120 {
0121 struct drm_sched_fence *fence = to_drm_sched_fence(f);
0122
0123 dma_fence_put(&fence->scheduled);
0124 }
0125
0126 static const struct dma_fence_ops drm_sched_fence_ops_scheduled = {
0127 .get_driver_name = drm_sched_fence_get_driver_name,
0128 .get_timeline_name = drm_sched_fence_get_timeline_name,
0129 .release = drm_sched_fence_release_scheduled,
0130 };
0131
0132 static const struct dma_fence_ops drm_sched_fence_ops_finished = {
0133 .get_driver_name = drm_sched_fence_get_driver_name,
0134 .get_timeline_name = drm_sched_fence_get_timeline_name,
0135 .release = drm_sched_fence_release_finished,
0136 };
0137
0138 struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f)
0139 {
0140 if (f->ops == &drm_sched_fence_ops_scheduled)
0141 return container_of(f, struct drm_sched_fence, scheduled);
0142
0143 if (f->ops == &drm_sched_fence_ops_finished)
0144 return container_of(f, struct drm_sched_fence, finished);
0145
0146 return NULL;
0147 }
0148 EXPORT_SYMBOL(to_drm_sched_fence);
0149
0150 struct drm_sched_fence *drm_sched_fence_alloc(struct drm_sched_entity *entity,
0151 void *owner)
0152 {
0153 struct drm_sched_fence *fence = NULL;
0154
0155 fence = kmem_cache_zalloc(sched_fence_slab, GFP_KERNEL);
0156 if (fence == NULL)
0157 return NULL;
0158
0159 fence->owner = owner;
0160 spin_lock_init(&fence->lock);
0161
0162 return fence;
0163 }
0164
0165 void drm_sched_fence_init(struct drm_sched_fence *fence,
0166 struct drm_sched_entity *entity)
0167 {
0168 unsigned seq;
0169
0170 fence->sched = entity->rq->sched;
0171 seq = atomic_inc_return(&entity->fence_seq);
0172 dma_fence_init(&fence->scheduled, &drm_sched_fence_ops_scheduled,
0173 &fence->lock, entity->fence_context, seq);
0174 dma_fence_init(&fence->finished, &drm_sched_fence_ops_finished,
0175 &fence->lock, entity->fence_context + 1, seq);
0176 }
0177
0178 module_init(drm_sched_fence_slab_init);
0179 module_exit(drm_sched_fence_slab_fini);
0180
0181 MODULE_DESCRIPTION("DRM GPU scheduler");
0182 MODULE_LICENSE("GPL and additional rights");