10856cab1SChristian König /* 20856cab1SChristian König * Copyright 2015 Advanced Micro Devices, Inc. 30856cab1SChristian König * 40856cab1SChristian König * Permission is hereby granted, free of charge, to any person obtaining a 50856cab1SChristian König * copy of this software and associated documentation files (the "Software"), 60856cab1SChristian König * to deal in the Software without restriction, including without limitation 70856cab1SChristian König * the rights to use, copy, modify, merge, publish, distribute, sublicense, 80856cab1SChristian König * and/or sell copies of the Software, and to permit persons to whom the 90856cab1SChristian König * Software is furnished to do so, subject to the following conditions: 100856cab1SChristian König * 110856cab1SChristian König * The above copyright notice and this permission notice shall be included in 120856cab1SChristian König * all copies or substantial portions of the Software. 130856cab1SChristian König * 140856cab1SChristian König * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 150856cab1SChristian König * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 160856cab1SChristian König * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 170856cab1SChristian König * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 180856cab1SChristian König * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 190856cab1SChristian König * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 200856cab1SChristian König * OTHER DEALINGS IN THE SOFTWARE. 210856cab1SChristian König * 220856cab1SChristian König * 230856cab1SChristian König */ 240856cab1SChristian König #include <linux/kthread.h> 250856cab1SChristian König #include <linux/wait.h> 260856cab1SChristian König #include <linux/sched.h> 270856cab1SChristian König #include <drm/drmP.h> 280856cab1SChristian König #include "amdgpu.h" 290856cab1SChristian König #include "amdgpu_trace.h" 300856cab1SChristian König 311b1f42d8SLucas Stach static void amdgpu_job_timedout(struct drm_sched_job *s_job) 320de2479cSMonk Liu { 333320b8d2SChristian König struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched); 343320b8d2SChristian König struct amdgpu_job *job = to_amdgpu_job(s_job); 350e51a772SChristian König 36f024e883SChristian König DRM_ERROR("ring %s timeout, signaled seq=%u, emitted seq=%u\n", 373320b8d2SChristian König job->base.sched->name, atomic_read(&ring->fence_drv.last_seq), 383320b8d2SChristian König ring->fence_drv.sync_seq); 394fbf87e2SMonk Liu 40a1917b73SChristian König amdgpu_device_gpu_recover(ring->adev, job, false); 410de2479cSMonk Liu } 420de2479cSMonk Liu 430856cab1SChristian König int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, 44c5637837SMonk Liu struct amdgpu_job **job, struct amdgpu_vm *vm) 450856cab1SChristian König { 460856cab1SChristian König size_t size = sizeof(struct amdgpu_job); 470856cab1SChristian König 480856cab1SChristian König if (num_ibs == 0) 490856cab1SChristian König return -EINVAL; 500856cab1SChristian König 510856cab1SChristian König size += sizeof(struct amdgpu_ib) * num_ibs; 520856cab1SChristian König 530856cab1SChristian König *job = kzalloc(size, GFP_KERNEL); 540856cab1SChristian König if (!*job) 550856cab1SChristian König return -ENOMEM; 560856cab1SChristian König 57a1917b73SChristian König /* 58a1917b73SChristian König * Initialize the scheduler to at least some ring so that we always 59a1917b73SChristian König * have a pointer to adev. 60a1917b73SChristian König */ 61a1917b73SChristian König (*job)->base.sched = &adev->rings[0]->sched; 62c5637837SMonk Liu (*job)->vm = vm; 630856cab1SChristian König (*job)->ibs = (void *)&(*job)[1]; 640856cab1SChristian König (*job)->num_ibs = num_ibs; 650856cab1SChristian König 66e86f9ceeSChristian König amdgpu_sync_create(&(*job)->sync); 67df83d1ebSChunming Zhou amdgpu_sync_create(&(*job)->sched_sync); 68c70b78a7SMonk Liu (*job)->vram_lost_counter = atomic_read(&adev->vram_lost_counter); 69e86f9ceeSChristian König 700856cab1SChristian König return 0; 710856cab1SChristian König } 720856cab1SChristian König 730856cab1SChristian König int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, 740856cab1SChristian König struct amdgpu_job **job) 750856cab1SChristian König { 760856cab1SChristian König int r; 770856cab1SChristian König 78c5637837SMonk Liu r = amdgpu_job_alloc(adev, 1, job, NULL); 790856cab1SChristian König if (r) 800856cab1SChristian König return r; 810856cab1SChristian König 820856cab1SChristian König r = amdgpu_ib_get(adev, NULL, size, &(*job)->ibs[0]); 830856cab1SChristian König if (r) 840856cab1SChristian König kfree(*job); 85df264f9eSChristian König else 86df264f9eSChristian König (*job)->vm_pd_addr = adev->gart.table_addr; 870856cab1SChristian König 880856cab1SChristian König return r; 890856cab1SChristian König } 900856cab1SChristian König 91a5fb4ec2SChristian König void amdgpu_job_free_resources(struct amdgpu_job *job) 920856cab1SChristian König { 93a1917b73SChristian König struct amdgpu_ring *ring = to_amdgpu_ring(job->base.sched); 94f54d1867SChris Wilson struct dma_fence *f; 951ab0d211SChristian König unsigned i; 961ab0d211SChristian König 97676d8c24SMonk Liu /* use sched fence if available */ 986fc13675SChristian König f = job->base.s_fence ? &job->base.s_fence->finished : job->fence; 990856cab1SChristian König 1000856cab1SChristian König for (i = 0; i < job->num_ibs; ++i) 101a1917b73SChristian König amdgpu_ib_free(ring->adev, &job->ibs[i], f); 1020856cab1SChristian König } 1030856cab1SChristian König 1041b1f42d8SLucas Stach static void amdgpu_job_free_cb(struct drm_sched_job *s_job) 105b6723c8dSMonk Liu { 1063320b8d2SChristian König struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched); 1073320b8d2SChristian König struct amdgpu_job *job = to_amdgpu_job(s_job); 108c5f74f78SChristian König 1093320b8d2SChristian König amdgpu_ring_priority_put(ring, s_job->s_priority); 110f54d1867SChris Wilson dma_fence_put(job->fence); 111a79a5bdcSChristian König amdgpu_sync_free(&job->sync); 112df83d1ebSChunming Zhou amdgpu_sync_free(&job->sched_sync); 113b6723c8dSMonk Liu kfree(job); 114b6723c8dSMonk Liu } 115b6723c8dSMonk Liu 1161e24e31fSChristian König void amdgpu_job_free(struct amdgpu_job *job) 1171e24e31fSChristian König { 1181e24e31fSChristian König amdgpu_job_free_resources(job); 119a79a5bdcSChristian König 120f54d1867SChris Wilson dma_fence_put(job->fence); 121a79a5bdcSChristian König amdgpu_sync_free(&job->sync); 122df83d1ebSChunming Zhou amdgpu_sync_free(&job->sched_sync); 1231e24e31fSChristian König kfree(job); 1241e24e31fSChristian König } 1251e24e31fSChristian König 1260e28b10fSChristian König int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, 1270e28b10fSChristian König void *owner, struct dma_fence **f) 1280856cab1SChristian König { 129b5286801SChristian König enum drm_sched_priority priority; 130b5286801SChristian König struct amdgpu_ring *ring; 131e686941aSMonk Liu int r; 1320856cab1SChristian König 133e686941aSMonk Liu if (!f) 134e686941aSMonk Liu return -EINVAL; 135e686941aSMonk Liu 136cdc50176SNayan Deshmukh r = drm_sched_job_init(&job->base, entity, owner); 137e686941aSMonk Liu if (r) 138e686941aSMonk Liu return r; 1390856cab1SChristian König 1400856cab1SChristian König job->owner = owner; 141f54d1867SChris Wilson *f = dma_fence_get(&job->base.s_fence->finished); 142a5fb4ec2SChristian König amdgpu_job_free_resources(job); 143b5286801SChristian König priority = job->base.s_priority; 1441b1f42d8SLucas Stach drm_sched_entity_push_job(&job->base, entity); 1450856cab1SChristian König 146*068c3304SNayan Deshmukh ring = to_amdgpu_ring(entity->rq->sched); 147b5286801SChristian König amdgpu_ring_priority_get(ring, priority); 148b5286801SChristian König 1490856cab1SChristian König return 0; 1500856cab1SChristian König } 1510856cab1SChristian König 152ee913fd9SChristian König int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, 153ee913fd9SChristian König struct dma_fence **fence) 154ee913fd9SChristian König { 155ee913fd9SChristian König int r; 156ee913fd9SChristian König 157ee913fd9SChristian König job->base.sched = &ring->sched; 158ee913fd9SChristian König r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, NULL, fence); 159ee913fd9SChristian König job->fence = dma_fence_get(*fence); 160ee913fd9SChristian König if (r) 161ee913fd9SChristian König return r; 162ee913fd9SChristian König 163ee913fd9SChristian König amdgpu_job_free(job); 164ee913fd9SChristian König return 0; 165ee913fd9SChristian König } 166ee913fd9SChristian König 1671b1f42d8SLucas Stach static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, 1681b1f42d8SLucas Stach struct drm_sched_entity *s_entity) 1690856cab1SChristian König { 170*068c3304SNayan Deshmukh struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->rq->sched); 1710856cab1SChristian König struct amdgpu_job *job = to_amdgpu_job(sched_job); 172c5637837SMonk Liu struct amdgpu_vm *vm = job->vm; 173f024e883SChristian König struct dma_fence *fence; 174cebb52b7SAndrey Grodzovsky bool explicit = false; 175df83d1ebSChunming Zhou int r; 1760856cab1SChristian König 177f024e883SChristian König fence = amdgpu_sync_get_fence(&job->sync, &explicit); 178cebb52b7SAndrey Grodzovsky if (fence && explicit) { 1791b1f42d8SLucas Stach if (drm_sched_dependency_optimized(fence, s_entity)) { 180a1917b73SChristian König r = amdgpu_sync_fence(ring->adev, &job->sched_sync, 181a1917b73SChristian König fence, false); 182a340c7bcSChunming Zhou if (r) 183f024e883SChristian König DRM_ERROR("Error adding fence (%d)\n", r); 184a340c7bcSChunming Zhou } 185cebb52b7SAndrey Grodzovsky } 186cebb52b7SAndrey Grodzovsky 187c4f46f22SChristian König while (fence == NULL && vm && !job->vmid) { 188620f774fSChristian König r = amdgpu_vmid_grab(vm, ring, &job->sync, 1896fc13675SChristian König &job->base.s_fence->finished, 190fd53be30SChunming Zhou job); 1910856cab1SChristian König if (r) 1920856cab1SChristian König DRM_ERROR("Error getting VM ID (%d)\n", r); 1930856cab1SChristian König 194cebb52b7SAndrey Grodzovsky fence = amdgpu_sync_get_fence(&job->sync, NULL); 1950856cab1SChristian König } 1960856cab1SChristian König 1970856cab1SChristian König return fence; 1980856cab1SChristian König } 1990856cab1SChristian König 2001b1f42d8SLucas Stach static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) 2010856cab1SChristian König { 2023320b8d2SChristian König struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched); 20348f05f29SMonk Liu struct dma_fence *fence = NULL, *finished; 2040856cab1SChristian König struct amdgpu_job *job; 2050856cab1SChristian König int r; 2060856cab1SChristian König 2070856cab1SChristian König job = to_amdgpu_job(sched_job); 20848f05f29SMonk Liu finished = &job->base.s_fence->finished; 209e86f9ceeSChristian König 2101fbb2e92SChristian König BUG_ON(amdgpu_sync_peek_fence(&job->sync, NULL)); 211e86f9ceeSChristian König 2120856cab1SChristian König trace_amdgpu_sched_run_job(job); 21348f05f29SMonk Liu 214a1917b73SChristian König if (job->vram_lost_counter != atomic_read(&ring->adev->vram_lost_counter)) 21548f05f29SMonk Liu dma_fence_set_error(finished, -ECANCELED);/* skip IB as well if VRAM lost */ 21648f05f29SMonk Liu 21748f05f29SMonk Liu if (finished->error < 0) { 21848f05f29SMonk Liu DRM_INFO("Skip scheduling IBs!\n"); 21914e47f93SChristian König } else { 2203320b8d2SChristian König r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, job, 22114e47f93SChristian König &fence); 22222a77cf6SChristian König if (r) 2230856cab1SChristian König DRM_ERROR("Error scheduling IBs (%d)\n", r); 22415d73ce6SChunming Zhou } 225c7c5fbcdSChunming Zhou /* if gpu reset, hw fence will be replaced here */ 226f54d1867SChris Wilson dma_fence_put(job->fence); 227f54d1867SChris Wilson job->fence = dma_fence_get(fence); 228b2ff0e8aSAndres Rodriguez 22922a77cf6SChristian König amdgpu_job_free_resources(job); 2300856cab1SChristian König return fence; 2310856cab1SChristian König } 2320856cab1SChristian König 2331b1f42d8SLucas Stach const struct drm_sched_backend_ops amdgpu_sched_ops = { 2340856cab1SChristian König .dependency = amdgpu_job_dependency, 2350856cab1SChristian König .run_job = amdgpu_job_run, 2360e51a772SChristian König .timedout_job = amdgpu_job_timedout, 237c5f74f78SChristian König .free_job = amdgpu_job_free_cb 2380856cab1SChristian König }; 239