Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2015 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
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  * drm_sched_fence_free - free up an uninitialized fence
0083  *
0084  * @fence: fence to free
0085  *
0086  * Free up the fence memory. Should only be used if drm_sched_fence_init()
0087  * has not been called yet.
0088  */
0089 void drm_sched_fence_free(struct drm_sched_fence *fence)
0090 {
0091     /* This function should not be called if the fence has been initialized. */
0092     if (!WARN_ON_ONCE(fence->sched))
0093         kmem_cache_free(sched_fence_slab, fence);
0094 }
0095 
0096 /**
0097  * drm_sched_fence_release_scheduled - callback that fence can be freed
0098  *
0099  * @f: fence
0100  *
0101  * This function is called when the reference count becomes zero.
0102  * It just RCU schedules freeing up the fence.
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  * drm_sched_fence_release_finished - drop extra reference
0114  *
0115  * @f: fence
0116  *
0117  * Drop the extra reference from the scheduled fence to the base fence.
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");