18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2011 Red Hat Inc. 38c2ecf20Sopenharmony_ci * All Rights Reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the 78c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 88c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 98c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 108c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 118c2ecf20Sopenharmony_ci * the following conditions: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 148c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 158c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 168c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 178c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 188c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 198c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 228c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 238c2ecf20Sopenharmony_ci * of the Software. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * Authors: 288c2ecf20Sopenharmony_ci * Jerome Glisse <glisse@freedesktop.org> 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci/* Algorithm: 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * We store the last allocated bo in "hole", we always try to allocate 338c2ecf20Sopenharmony_ci * after the last allocated bo. Principle is that in a linear GPU ring 348c2ecf20Sopenharmony_ci * progression was is after last is the oldest bo we allocated and thus 358c2ecf20Sopenharmony_ci * the first one that should no longer be in use by the GPU. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * If it's not the case we skip over the bo after last to the closest 388c2ecf20Sopenharmony_ci * done bo if such one exist. If none exist and we are not asked to 398c2ecf20Sopenharmony_ci * block we report failure to allocate. 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * If we are asked to block we wait on all the oldest fence of all 428c2ecf20Sopenharmony_ci * rings. We just wait for any of those fence to complete. 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include "radeon.h" 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void radeon_sa_bo_remove_locked(struct radeon_sa_bo *sa_bo); 488c2ecf20Sopenharmony_cistatic void radeon_sa_bo_try_free(struct radeon_sa_manager *sa_manager); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciint radeon_sa_bo_manager_init(struct radeon_device *rdev, 518c2ecf20Sopenharmony_ci struct radeon_sa_manager *sa_manager, 528c2ecf20Sopenharmony_ci unsigned size, u32 align, u32 domain, u32 flags) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci int i, r; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci init_waitqueue_head(&sa_manager->wq); 578c2ecf20Sopenharmony_ci sa_manager->bo = NULL; 588c2ecf20Sopenharmony_ci sa_manager->size = size; 598c2ecf20Sopenharmony_ci sa_manager->domain = domain; 608c2ecf20Sopenharmony_ci sa_manager->align = align; 618c2ecf20Sopenharmony_ci sa_manager->hole = &sa_manager->olist; 628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sa_manager->olist); 638c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sa_manager->flist[i]); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci r = radeon_bo_create(rdev, size, align, true, 688c2ecf20Sopenharmony_ci domain, flags, NULL, NULL, &sa_manager->bo); 698c2ecf20Sopenharmony_ci if (r) { 708c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r); 718c2ecf20Sopenharmony_ci return r; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return r; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_civoid radeon_sa_bo_manager_fini(struct radeon_device *rdev, 788c2ecf20Sopenharmony_ci struct radeon_sa_manager *sa_manager) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct radeon_sa_bo *sa_bo, *tmp; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (!list_empty(&sa_manager->olist)) { 838c2ecf20Sopenharmony_ci sa_manager->hole = &sa_manager->olist, 848c2ecf20Sopenharmony_ci radeon_sa_bo_try_free(sa_manager); 858c2ecf20Sopenharmony_ci if (!list_empty(&sa_manager->olist)) { 868c2ecf20Sopenharmony_ci dev_err(rdev->dev, "sa_manager is not empty, clearing anyway\n"); 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci list_for_each_entry_safe(sa_bo, tmp, &sa_manager->olist, olist) { 908c2ecf20Sopenharmony_ci radeon_sa_bo_remove_locked(sa_bo); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci radeon_bo_unref(&sa_manager->bo); 938c2ecf20Sopenharmony_ci sa_manager->size = 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint radeon_sa_bo_manager_start(struct radeon_device *rdev, 978c2ecf20Sopenharmony_ci struct radeon_sa_manager *sa_manager) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci int r; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (sa_manager->bo == NULL) { 1028c2ecf20Sopenharmony_ci dev_err(rdev->dev, "no bo for sa manager\n"); 1038c2ecf20Sopenharmony_ci return -EINVAL; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* map the buffer */ 1078c2ecf20Sopenharmony_ci r = radeon_bo_reserve(sa_manager->bo, false); 1088c2ecf20Sopenharmony_ci if (r) { 1098c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(%d) failed to reserve manager bo\n", r); 1108c2ecf20Sopenharmony_ci return r; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci r = radeon_bo_pin(sa_manager->bo, sa_manager->domain, &sa_manager->gpu_addr); 1138c2ecf20Sopenharmony_ci if (r) { 1148c2ecf20Sopenharmony_ci radeon_bo_unreserve(sa_manager->bo); 1158c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(%d) failed to pin manager bo\n", r); 1168c2ecf20Sopenharmony_ci return r; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci r = radeon_bo_kmap(sa_manager->bo, &sa_manager->cpu_ptr); 1198c2ecf20Sopenharmony_ci radeon_bo_unreserve(sa_manager->bo); 1208c2ecf20Sopenharmony_ci return r; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciint radeon_sa_bo_manager_suspend(struct radeon_device *rdev, 1248c2ecf20Sopenharmony_ci struct radeon_sa_manager *sa_manager) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci int r; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (sa_manager->bo == NULL) { 1298c2ecf20Sopenharmony_ci dev_err(rdev->dev, "no bo for sa manager\n"); 1308c2ecf20Sopenharmony_ci return -EINVAL; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci r = radeon_bo_reserve(sa_manager->bo, false); 1348c2ecf20Sopenharmony_ci if (!r) { 1358c2ecf20Sopenharmony_ci radeon_bo_kunmap(sa_manager->bo); 1368c2ecf20Sopenharmony_ci radeon_bo_unpin(sa_manager->bo); 1378c2ecf20Sopenharmony_ci radeon_bo_unreserve(sa_manager->bo); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci return r; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void radeon_sa_bo_remove_locked(struct radeon_sa_bo *sa_bo) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct radeon_sa_manager *sa_manager = sa_bo->manager; 1458c2ecf20Sopenharmony_ci if (sa_manager->hole == &sa_bo->olist) { 1468c2ecf20Sopenharmony_ci sa_manager->hole = sa_bo->olist.prev; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci list_del_init(&sa_bo->olist); 1498c2ecf20Sopenharmony_ci list_del_init(&sa_bo->flist); 1508c2ecf20Sopenharmony_ci radeon_fence_unref(&sa_bo->fence); 1518c2ecf20Sopenharmony_ci kfree(sa_bo); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic void radeon_sa_bo_try_free(struct radeon_sa_manager *sa_manager) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct radeon_sa_bo *sa_bo, *tmp; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (sa_manager->hole->next == &sa_manager->olist) 1598c2ecf20Sopenharmony_ci return; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci sa_bo = list_entry(sa_manager->hole->next, struct radeon_sa_bo, olist); 1628c2ecf20Sopenharmony_ci list_for_each_entry_safe_from(sa_bo, tmp, &sa_manager->olist, olist) { 1638c2ecf20Sopenharmony_ci if (sa_bo->fence == NULL || !radeon_fence_signaled(sa_bo->fence)) { 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci radeon_sa_bo_remove_locked(sa_bo); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline unsigned radeon_sa_bo_hole_soffset(struct radeon_sa_manager *sa_manager) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct list_head *hole = sa_manager->hole; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (hole != &sa_manager->olist) { 1758c2ecf20Sopenharmony_ci return list_entry(hole, struct radeon_sa_bo, olist)->eoffset; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic inline unsigned radeon_sa_bo_hole_eoffset(struct radeon_sa_manager *sa_manager) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct list_head *hole = sa_manager->hole; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (hole->next != &sa_manager->olist) { 1858c2ecf20Sopenharmony_ci return list_entry(hole->next, struct radeon_sa_bo, olist)->soffset; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci return sa_manager->size; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic bool radeon_sa_bo_try_alloc(struct radeon_sa_manager *sa_manager, 1918c2ecf20Sopenharmony_ci struct radeon_sa_bo *sa_bo, 1928c2ecf20Sopenharmony_ci unsigned size, unsigned align) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci unsigned soffset, eoffset, wasted; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci soffset = radeon_sa_bo_hole_soffset(sa_manager); 1978c2ecf20Sopenharmony_ci eoffset = radeon_sa_bo_hole_eoffset(sa_manager); 1988c2ecf20Sopenharmony_ci wasted = (align - (soffset % align)) % align; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if ((eoffset - soffset) >= (size + wasted)) { 2018c2ecf20Sopenharmony_ci soffset += wasted; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci sa_bo->manager = sa_manager; 2048c2ecf20Sopenharmony_ci sa_bo->soffset = soffset; 2058c2ecf20Sopenharmony_ci sa_bo->eoffset = soffset + size; 2068c2ecf20Sopenharmony_ci list_add(&sa_bo->olist, sa_manager->hole); 2078c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sa_bo->flist); 2088c2ecf20Sopenharmony_ci sa_manager->hole = &sa_bo->olist; 2098c2ecf20Sopenharmony_ci return true; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci return false; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/** 2158c2ecf20Sopenharmony_ci * radeon_sa_event - Check if we can stop waiting 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * @sa_manager: pointer to the sa_manager 2188c2ecf20Sopenharmony_ci * @size: number of bytes we want to allocate 2198c2ecf20Sopenharmony_ci * @align: alignment we need to match 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * Check if either there is a fence we can wait for or 2228c2ecf20Sopenharmony_ci * enough free memory to satisfy the allocation directly 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_cistatic bool radeon_sa_event(struct radeon_sa_manager *sa_manager, 2258c2ecf20Sopenharmony_ci unsigned size, unsigned align) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci unsigned soffset, eoffset, wasted; 2288c2ecf20Sopenharmony_ci int i; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 2318c2ecf20Sopenharmony_ci if (!list_empty(&sa_manager->flist[i])) { 2328c2ecf20Sopenharmony_ci return true; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci soffset = radeon_sa_bo_hole_soffset(sa_manager); 2378c2ecf20Sopenharmony_ci eoffset = radeon_sa_bo_hole_eoffset(sa_manager); 2388c2ecf20Sopenharmony_ci wasted = (align - (soffset % align)) % align; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if ((eoffset - soffset) >= (size + wasted)) { 2418c2ecf20Sopenharmony_ci return true; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return false; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager, 2488c2ecf20Sopenharmony_ci struct radeon_fence **fences, 2498c2ecf20Sopenharmony_ci unsigned *tries) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct radeon_sa_bo *best_bo = NULL; 2528c2ecf20Sopenharmony_ci unsigned i, soffset, best, tmp; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* if hole points to the end of the buffer */ 2558c2ecf20Sopenharmony_ci if (sa_manager->hole->next == &sa_manager->olist) { 2568c2ecf20Sopenharmony_ci /* try again with its beginning */ 2578c2ecf20Sopenharmony_ci sa_manager->hole = &sa_manager->olist; 2588c2ecf20Sopenharmony_ci return true; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci soffset = radeon_sa_bo_hole_soffset(sa_manager); 2628c2ecf20Sopenharmony_ci /* to handle wrap around we add sa_manager->size */ 2638c2ecf20Sopenharmony_ci best = sa_manager->size * 2; 2648c2ecf20Sopenharmony_ci /* go over all fence list and try to find the closest sa_bo 2658c2ecf20Sopenharmony_ci * of the current last 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 2688c2ecf20Sopenharmony_ci struct radeon_sa_bo *sa_bo; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (list_empty(&sa_manager->flist[i])) { 2718c2ecf20Sopenharmony_ci continue; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci sa_bo = list_first_entry(&sa_manager->flist[i], 2758c2ecf20Sopenharmony_ci struct radeon_sa_bo, flist); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (!radeon_fence_signaled(sa_bo->fence)) { 2788c2ecf20Sopenharmony_ci fences[i] = sa_bo->fence; 2798c2ecf20Sopenharmony_ci continue; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* limit the number of tries each ring gets */ 2838c2ecf20Sopenharmony_ci if (tries[i] > 2) { 2848c2ecf20Sopenharmony_ci continue; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci tmp = sa_bo->soffset; 2888c2ecf20Sopenharmony_ci if (tmp < soffset) { 2898c2ecf20Sopenharmony_ci /* wrap around, pretend it's after */ 2908c2ecf20Sopenharmony_ci tmp += sa_manager->size; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci tmp -= soffset; 2938c2ecf20Sopenharmony_ci if (tmp < best) { 2948c2ecf20Sopenharmony_ci /* this sa bo is the closest one */ 2958c2ecf20Sopenharmony_ci best = tmp; 2968c2ecf20Sopenharmony_ci best_bo = sa_bo; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (best_bo) { 3018c2ecf20Sopenharmony_ci ++tries[best_bo->fence->ring]; 3028c2ecf20Sopenharmony_ci sa_manager->hole = best_bo->olist.prev; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* we knew that this one is signaled, 3058c2ecf20Sopenharmony_ci so it's save to remote it */ 3068c2ecf20Sopenharmony_ci radeon_sa_bo_remove_locked(best_bo); 3078c2ecf20Sopenharmony_ci return true; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci return false; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ciint radeon_sa_bo_new(struct radeon_device *rdev, 3138c2ecf20Sopenharmony_ci struct radeon_sa_manager *sa_manager, 3148c2ecf20Sopenharmony_ci struct radeon_sa_bo **sa_bo, 3158c2ecf20Sopenharmony_ci unsigned size, unsigned align) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct radeon_fence *fences[RADEON_NUM_RINGS]; 3188c2ecf20Sopenharmony_ci unsigned tries[RADEON_NUM_RINGS]; 3198c2ecf20Sopenharmony_ci int i, r; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci BUG_ON(align > sa_manager->align); 3228c2ecf20Sopenharmony_ci BUG_ON(size > sa_manager->size); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci *sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL); 3258c2ecf20Sopenharmony_ci if ((*sa_bo) == NULL) { 3268c2ecf20Sopenharmony_ci return -ENOMEM; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci (*sa_bo)->manager = sa_manager; 3298c2ecf20Sopenharmony_ci (*sa_bo)->fence = NULL; 3308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&(*sa_bo)->olist); 3318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&(*sa_bo)->flist); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci spin_lock(&sa_manager->wq.lock); 3348c2ecf20Sopenharmony_ci do { 3358c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 3368c2ecf20Sopenharmony_ci fences[i] = NULL; 3378c2ecf20Sopenharmony_ci tries[i] = 0; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci do { 3418c2ecf20Sopenharmony_ci radeon_sa_bo_try_free(sa_manager); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (radeon_sa_bo_try_alloc(sa_manager, *sa_bo, 3448c2ecf20Sopenharmony_ci size, align)) { 3458c2ecf20Sopenharmony_ci spin_unlock(&sa_manager->wq.lock); 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* see if we can skip over some allocations */ 3508c2ecf20Sopenharmony_ci } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) 3538c2ecf20Sopenharmony_ci radeon_fence_ref(fences[i]); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci spin_unlock(&sa_manager->wq.lock); 3568c2ecf20Sopenharmony_ci r = radeon_fence_wait_any(rdev, fences, false); 3578c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) 3588c2ecf20Sopenharmony_ci radeon_fence_unref(&fences[i]); 3598c2ecf20Sopenharmony_ci spin_lock(&sa_manager->wq.lock); 3608c2ecf20Sopenharmony_ci /* if we have nothing to wait for block */ 3618c2ecf20Sopenharmony_ci if (r == -ENOENT) { 3628c2ecf20Sopenharmony_ci r = wait_event_interruptible_locked( 3638c2ecf20Sopenharmony_ci sa_manager->wq, 3648c2ecf20Sopenharmony_ci radeon_sa_event(sa_manager, size, align) 3658c2ecf20Sopenharmony_ci ); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci } while (!r); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci spin_unlock(&sa_manager->wq.lock); 3718c2ecf20Sopenharmony_ci kfree(*sa_bo); 3728c2ecf20Sopenharmony_ci *sa_bo = NULL; 3738c2ecf20Sopenharmony_ci return r; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_civoid radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo **sa_bo, 3778c2ecf20Sopenharmony_ci struct radeon_fence *fence) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct radeon_sa_manager *sa_manager; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (sa_bo == NULL || *sa_bo == NULL) { 3828c2ecf20Sopenharmony_ci return; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci sa_manager = (*sa_bo)->manager; 3868c2ecf20Sopenharmony_ci spin_lock(&sa_manager->wq.lock); 3878c2ecf20Sopenharmony_ci if (fence && !radeon_fence_signaled(fence)) { 3888c2ecf20Sopenharmony_ci (*sa_bo)->fence = radeon_fence_ref(fence); 3898c2ecf20Sopenharmony_ci list_add_tail(&(*sa_bo)->flist, 3908c2ecf20Sopenharmony_ci &sa_manager->flist[fence->ring]); 3918c2ecf20Sopenharmony_ci } else { 3928c2ecf20Sopenharmony_ci radeon_sa_bo_remove_locked(*sa_bo); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci wake_up_all_locked(&sa_manager->wq); 3958c2ecf20Sopenharmony_ci spin_unlock(&sa_manager->wq.lock); 3968c2ecf20Sopenharmony_ci *sa_bo = NULL; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 4008c2ecf20Sopenharmony_civoid radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager, 4018c2ecf20Sopenharmony_ci struct seq_file *m) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct radeon_sa_bo *i; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci spin_lock(&sa_manager->wq.lock); 4068c2ecf20Sopenharmony_ci list_for_each_entry(i, &sa_manager->olist, olist) { 4078c2ecf20Sopenharmony_ci uint64_t soffset = i->soffset + sa_manager->gpu_addr; 4088c2ecf20Sopenharmony_ci uint64_t eoffset = i->eoffset + sa_manager->gpu_addr; 4098c2ecf20Sopenharmony_ci if (&i->olist == sa_manager->hole) { 4108c2ecf20Sopenharmony_ci seq_printf(m, ">"); 4118c2ecf20Sopenharmony_ci } else { 4128c2ecf20Sopenharmony_ci seq_printf(m, " "); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci seq_printf(m, "[0x%010llx 0x%010llx] size %8lld", 4158c2ecf20Sopenharmony_ci soffset, eoffset, eoffset - soffset); 4168c2ecf20Sopenharmony_ci if (i->fence) { 4178c2ecf20Sopenharmony_ci seq_printf(m, " protected by 0x%016llx on ring %d", 4188c2ecf20Sopenharmony_ci i->fence->seq, i->fence->ring); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci seq_printf(m, "\n"); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci spin_unlock(&sa_manager->wq.lock); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci#endif 425