18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2008 Ben Skeggs. 38c2ecf20Sopenharmony_ci * All Rights Reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining 68c2ecf20Sopenharmony_ci * a 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, sublicense, 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 above copyright notice and this permission notice (including the 148c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial 158c2ecf20Sopenharmony_ci * portions of the Software. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 188c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 198c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 208c2ecf20Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 218c2ecf20Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 228c2ecf20Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 238c2ecf20Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "nouveau_drv.h" 288c2ecf20Sopenharmony_ci#include "nouveau_dma.h" 298c2ecf20Sopenharmony_ci#include "nouveau_fence.h" 308c2ecf20Sopenharmony_ci#include "nouveau_abi16.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "nouveau_ttm.h" 338c2ecf20Sopenharmony_ci#include "nouveau_gem.h" 348c2ecf20Sopenharmony_ci#include "nouveau_mem.h" 358c2ecf20Sopenharmony_ci#include "nouveau_vmm.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <nvif/class.h> 388c2ecf20Sopenharmony_ci#include <nvif/push206e.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_civoid 418c2ecf20Sopenharmony_cinouveau_gem_object_del(struct drm_gem_object *gem) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo = nouveau_gem_object(gem); 448c2ecf20Sopenharmony_ci struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); 458c2ecf20Sopenharmony_ci struct device *dev = drm->dev->dev; 468c2ecf20Sopenharmony_ci int ret; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 498c2ecf20Sopenharmony_ci if (WARN_ON(ret < 0 && ret != -EACCES)) { 508c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 518c2ecf20Sopenharmony_ci return; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (gem->import_attach) 558c2ecf20Sopenharmony_ci drm_prime_gem_destroy(gem, nvbo->bo.sg); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci ttm_bo_put(&nvbo->bo); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 608c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciint 648c2ecf20Sopenharmony_cinouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct nouveau_cli *cli = nouveau_cli(file_priv); 678c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo = nouveau_gem_object(gem); 688c2ecf20Sopenharmony_ci struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); 698c2ecf20Sopenharmony_ci struct device *dev = drm->dev->dev; 708c2ecf20Sopenharmony_ci struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : &cli->vmm; 718c2ecf20Sopenharmony_ci struct nouveau_vma *vma; 728c2ecf20Sopenharmony_ci int ret; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50) 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL); 788c2ecf20Sopenharmony_ci if (ret) 798c2ecf20Sopenharmony_ci return ret; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 828c2ecf20Sopenharmony_ci if (ret < 0 && ret != -EACCES) { 838c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 848c2ecf20Sopenharmony_ci goto out; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci ret = nouveau_vma_new(nvbo, vmm, &vma); 888c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 898c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 908c2ecf20Sopenharmony_ciout: 918c2ecf20Sopenharmony_ci ttm_bo_unreserve(&nvbo->bo); 928c2ecf20Sopenharmony_ci return ret; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct nouveau_gem_object_unmap { 968c2ecf20Sopenharmony_ci struct nouveau_cli_work work; 978c2ecf20Sopenharmony_ci struct nouveau_vma *vma; 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void 1018c2ecf20Sopenharmony_cinouveau_gem_object_delete(struct nouveau_vma *vma) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci nouveau_fence_unref(&vma->fence); 1048c2ecf20Sopenharmony_ci nouveau_vma_del(&vma); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void 1088c2ecf20Sopenharmony_cinouveau_gem_object_delete_work(struct nouveau_cli_work *w) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct nouveau_gem_object_unmap *work = 1118c2ecf20Sopenharmony_ci container_of(w, typeof(*work), work); 1128c2ecf20Sopenharmony_ci nouveau_gem_object_delete(work->vma); 1138c2ecf20Sopenharmony_ci kfree(work); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void 1178c2ecf20Sopenharmony_cinouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct dma_fence *fence = vma->fence ? &vma->fence->base : NULL; 1208c2ecf20Sopenharmony_ci struct nouveau_gem_object_unmap *work; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci list_del_init(&vma->head); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (!fence) { 1258c2ecf20Sopenharmony_ci nouveau_gem_object_delete(vma); 1268c2ecf20Sopenharmony_ci return; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (!(work = kmalloc(sizeof(*work), GFP_KERNEL))) { 1308c2ecf20Sopenharmony_ci WARN_ON(dma_fence_wait_timeout(fence, false, 2 * HZ) <= 0); 1318c2ecf20Sopenharmony_ci nouveau_gem_object_delete(vma); 1328c2ecf20Sopenharmony_ci return; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci work->work.func = nouveau_gem_object_delete_work; 1368c2ecf20Sopenharmony_ci work->vma = vma; 1378c2ecf20Sopenharmony_ci nouveau_cli_work_queue(vma->vmm->cli, fence, &work->work); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_civoid 1418c2ecf20Sopenharmony_cinouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct nouveau_cli *cli = nouveau_cli(file_priv); 1448c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo = nouveau_gem_object(gem); 1458c2ecf20Sopenharmony_ci struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); 1468c2ecf20Sopenharmony_ci struct device *dev = drm->dev->dev; 1478c2ecf20Sopenharmony_ci struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : & cli->vmm; 1488c2ecf20Sopenharmony_ci struct nouveau_vma *vma; 1498c2ecf20Sopenharmony_ci int ret; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50) 1528c2ecf20Sopenharmony_ci return; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL); 1558c2ecf20Sopenharmony_ci if (ret) 1568c2ecf20Sopenharmony_ci return; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci vma = nouveau_vma_find(nvbo, vmm); 1598c2ecf20Sopenharmony_ci if (vma) { 1608c2ecf20Sopenharmony_ci if (--vma->refs == 0) { 1618c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 1628c2ecf20Sopenharmony_ci if (!WARN_ON(ret < 0 && ret != -EACCES)) { 1638c2ecf20Sopenharmony_ci nouveau_gem_object_unmap(nvbo, vma); 1648c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci ttm_bo_unreserve(&nvbo->bo); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciint 1738c2ecf20Sopenharmony_cinouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain, 1748c2ecf20Sopenharmony_ci uint32_t tile_mode, uint32_t tile_flags, 1758c2ecf20Sopenharmony_ci struct nouveau_bo **pnvbo) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct nouveau_drm *drm = cli->drm; 1788c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (!(domain & (NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART))) 1828c2ecf20Sopenharmony_ci domain |= NOUVEAU_GEM_DOMAIN_CPU; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci nvbo = nouveau_bo_alloc(cli, &size, &align, domain, tile_mode, 1858c2ecf20Sopenharmony_ci tile_flags); 1868c2ecf20Sopenharmony_ci if (IS_ERR(nvbo)) 1878c2ecf20Sopenharmony_ci return PTR_ERR(nvbo); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Initialize the embedded gem-object. We return a single gem-reference 1908c2ecf20Sopenharmony_ci * to the caller, instead of a normal nouveau_bo ttm reference. */ 1918c2ecf20Sopenharmony_ci ret = drm_gem_object_init(drm->dev, &nvbo->bo.base, size); 1928c2ecf20Sopenharmony_ci if (ret) { 1938c2ecf20Sopenharmony_ci drm_gem_object_release(&nvbo->bo.base); 1948c2ecf20Sopenharmony_ci kfree(nvbo); 1958c2ecf20Sopenharmony_ci return ret; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci ret = nouveau_bo_init(nvbo, size, align, domain, NULL, NULL); 1998c2ecf20Sopenharmony_ci if (ret) 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* we restrict allowed domains on nv50+ to only the types 2038c2ecf20Sopenharmony_ci * that were requested at creation time. not possibly on 2048c2ecf20Sopenharmony_ci * earlier chips without busting the ABI. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | 2078c2ecf20Sopenharmony_ci NOUVEAU_GEM_DOMAIN_GART; 2088c2ecf20Sopenharmony_ci if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) 2098c2ecf20Sopenharmony_ci nvbo->valid_domains &= domain; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci nvbo->bo.persistent_swap_storage = nvbo->bo.base.filp; 2128c2ecf20Sopenharmony_ci *pnvbo = nvbo; 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int 2178c2ecf20Sopenharmony_cinouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, 2188c2ecf20Sopenharmony_ci struct drm_nouveau_gem_info *rep) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct nouveau_cli *cli = nouveau_cli(file_priv); 2218c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo = nouveau_gem_object(gem); 2228c2ecf20Sopenharmony_ci struct nouveau_vmm *vmm = cli->svm.cli ? &cli->svm : &cli->vmm; 2238c2ecf20Sopenharmony_ci struct nouveau_vma *vma; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (is_power_of_2(nvbo->valid_domains)) 2268c2ecf20Sopenharmony_ci rep->domain = nvbo->valid_domains; 2278c2ecf20Sopenharmony_ci else if (nvbo->bo.mem.mem_type == TTM_PL_TT) 2288c2ecf20Sopenharmony_ci rep->domain = NOUVEAU_GEM_DOMAIN_GART; 2298c2ecf20Sopenharmony_ci else 2308c2ecf20Sopenharmony_ci rep->domain = NOUVEAU_GEM_DOMAIN_VRAM; 2318c2ecf20Sopenharmony_ci rep->offset = nvbo->offset; 2328c2ecf20Sopenharmony_ci if (vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) { 2338c2ecf20Sopenharmony_ci vma = nouveau_vma_find(nvbo, vmm); 2348c2ecf20Sopenharmony_ci if (!vma) 2358c2ecf20Sopenharmony_ci return -EINVAL; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci rep->offset = vma->addr; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT; 2418c2ecf20Sopenharmony_ci rep->map_handle = drm_vma_node_offset_addr(&nvbo->bo.base.vma_node); 2428c2ecf20Sopenharmony_ci rep->tile_mode = nvbo->mode; 2438c2ecf20Sopenharmony_ci rep->tile_flags = nvbo->contig ? 0 : NOUVEAU_GEM_TILE_NONCONTIG; 2448c2ecf20Sopenharmony_ci if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) 2458c2ecf20Sopenharmony_ci rep->tile_flags |= nvbo->kind << 8; 2468c2ecf20Sopenharmony_ci else 2478c2ecf20Sopenharmony_ci if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) 2488c2ecf20Sopenharmony_ci rep->tile_flags |= nvbo->kind << 8 | nvbo->comp << 16; 2498c2ecf20Sopenharmony_ci else 2508c2ecf20Sopenharmony_ci rep->tile_flags |= nvbo->zeta; 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciint 2558c2ecf20Sopenharmony_cinouveau_gem_ioctl_new(struct drm_device *dev, void *data, 2568c2ecf20Sopenharmony_ci struct drm_file *file_priv) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct nouveau_cli *cli = nouveau_cli(file_priv); 2598c2ecf20Sopenharmony_ci struct drm_nouveau_gem_new *req = data; 2608c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo = NULL; 2618c2ecf20Sopenharmony_ci int ret = 0; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ret = nouveau_gem_new(cli, req->info.size, req->align, 2648c2ecf20Sopenharmony_ci req->info.domain, req->info.tile_mode, 2658c2ecf20Sopenharmony_ci req->info.tile_flags, &nvbo); 2668c2ecf20Sopenharmony_ci if (ret) 2678c2ecf20Sopenharmony_ci return ret; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ret = drm_gem_handle_create(file_priv, &nvbo->bo.base, 2708c2ecf20Sopenharmony_ci &req->info.handle); 2718c2ecf20Sopenharmony_ci if (ret == 0) { 2728c2ecf20Sopenharmony_ci ret = nouveau_gem_info(file_priv, &nvbo->bo.base, &req->info); 2738c2ecf20Sopenharmony_ci if (ret) 2748c2ecf20Sopenharmony_ci drm_gem_handle_delete(file_priv, req->info.handle); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* drop reference from allocate - handle holds it now */ 2788c2ecf20Sopenharmony_ci drm_gem_object_put(&nvbo->bo.base); 2798c2ecf20Sopenharmony_ci return ret; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int 2838c2ecf20Sopenharmony_cinouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains, 2848c2ecf20Sopenharmony_ci uint32_t write_domains, uint32_t valid_domains) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo = nouveau_gem_object(gem); 2878c2ecf20Sopenharmony_ci struct ttm_buffer_object *bo = &nvbo->bo; 2888c2ecf20Sopenharmony_ci uint32_t domains = valid_domains & nvbo->valid_domains & 2898c2ecf20Sopenharmony_ci (write_domains ? write_domains : read_domains); 2908c2ecf20Sopenharmony_ci uint32_t pref_domains = 0;; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (!domains) 2938c2ecf20Sopenharmony_ci return -EINVAL; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci valid_domains &= ~(NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if ((domains & NOUVEAU_GEM_DOMAIN_VRAM) && 2988c2ecf20Sopenharmony_ci bo->mem.mem_type == TTM_PL_VRAM) 2998c2ecf20Sopenharmony_ci pref_domains |= NOUVEAU_GEM_DOMAIN_VRAM; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci else if ((domains & NOUVEAU_GEM_DOMAIN_GART) && 3028c2ecf20Sopenharmony_ci bo->mem.mem_type == TTM_PL_TT) 3038c2ecf20Sopenharmony_ci pref_domains |= NOUVEAU_GEM_DOMAIN_GART; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci else if (domains & NOUVEAU_GEM_DOMAIN_VRAM) 3068c2ecf20Sopenharmony_ci pref_domains |= NOUVEAU_GEM_DOMAIN_VRAM; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci pref_domains |= NOUVEAU_GEM_DOMAIN_GART; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci nouveau_bo_placement_set(nvbo, pref_domains, valid_domains); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistruct validate_op { 3178c2ecf20Sopenharmony_ci struct list_head list; 3188c2ecf20Sopenharmony_ci struct ww_acquire_ctx ticket; 3198c2ecf20Sopenharmony_ci}; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic void 3228c2ecf20Sopenharmony_civalidate_fini_no_ticket(struct validate_op *op, struct nouveau_channel *chan, 3238c2ecf20Sopenharmony_ci struct nouveau_fence *fence, 3248c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *pbbo) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 3278c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *b; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci while (!list_empty(&op->list)) { 3308c2ecf20Sopenharmony_ci nvbo = list_entry(op->list.next, struct nouveau_bo, entry); 3318c2ecf20Sopenharmony_ci b = &pbbo[nvbo->pbbo_index]; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (likely(fence)) { 3348c2ecf20Sopenharmony_ci nouveau_bo_fence(nvbo, fence, !!b->write_domains); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (chan->vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) { 3378c2ecf20Sopenharmony_ci struct nouveau_vma *vma = 3388c2ecf20Sopenharmony_ci (void *)(unsigned long)b->user_priv; 3398c2ecf20Sopenharmony_ci nouveau_fence_unref(&vma->fence); 3408c2ecf20Sopenharmony_ci dma_fence_get(&fence->base); 3418c2ecf20Sopenharmony_ci vma->fence = fence; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (unlikely(nvbo->validate_mapped)) { 3468c2ecf20Sopenharmony_ci ttm_bo_kunmap(&nvbo->kmap); 3478c2ecf20Sopenharmony_ci nvbo->validate_mapped = false; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci list_del(&nvbo->entry); 3518c2ecf20Sopenharmony_ci nvbo->reserved_by = NULL; 3528c2ecf20Sopenharmony_ci ttm_bo_unreserve(&nvbo->bo); 3538c2ecf20Sopenharmony_ci drm_gem_object_put(&nvbo->bo.base); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic void 3588c2ecf20Sopenharmony_civalidate_fini(struct validate_op *op, struct nouveau_channel *chan, 3598c2ecf20Sopenharmony_ci struct nouveau_fence *fence, 3608c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *pbbo) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci validate_fini_no_ticket(op, chan, fence, pbbo); 3638c2ecf20Sopenharmony_ci ww_acquire_fini(&op->ticket); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int 3678c2ecf20Sopenharmony_civalidate_init(struct nouveau_channel *chan, struct drm_file *file_priv, 3688c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *pbbo, 3698c2ecf20Sopenharmony_ci int nr_buffers, struct validate_op *op) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct nouveau_cli *cli = nouveau_cli(file_priv); 3728c2ecf20Sopenharmony_ci int trycnt = 0; 3738c2ecf20Sopenharmony_ci int ret = -EINVAL, i; 3748c2ecf20Sopenharmony_ci struct nouveau_bo *res_bo = NULL; 3758c2ecf20Sopenharmony_ci LIST_HEAD(gart_list); 3768c2ecf20Sopenharmony_ci LIST_HEAD(vram_list); 3778c2ecf20Sopenharmony_ci LIST_HEAD(both_list); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ww_acquire_init(&op->ticket, &reservation_ww_class); 3808c2ecf20Sopenharmony_ciretry: 3818c2ecf20Sopenharmony_ci if (++trycnt > 100000) { 3828c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "%s failed and gave up.\n", __func__); 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci for (i = 0; i < nr_buffers; i++) { 3878c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[i]; 3888c2ecf20Sopenharmony_ci struct drm_gem_object *gem; 3898c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci gem = drm_gem_object_lookup(file_priv, b->handle); 3928c2ecf20Sopenharmony_ci if (!gem) { 3938c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "Unknown handle 0x%08x\n", b->handle); 3948c2ecf20Sopenharmony_ci ret = -ENOENT; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci nvbo = nouveau_gem_object(gem); 3988c2ecf20Sopenharmony_ci if (nvbo == res_bo) { 3998c2ecf20Sopenharmony_ci res_bo = NULL; 4008c2ecf20Sopenharmony_ci drm_gem_object_put(gem); 4018c2ecf20Sopenharmony_ci continue; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (nvbo->reserved_by && nvbo->reserved_by == file_priv) { 4058c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "multiple instances of buffer %d on " 4068c2ecf20Sopenharmony_ci "validation list\n", b->handle); 4078c2ecf20Sopenharmony_ci drm_gem_object_put(gem); 4088c2ecf20Sopenharmony_ci ret = -EINVAL; 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci ret = ttm_bo_reserve(&nvbo->bo, true, false, &op->ticket); 4138c2ecf20Sopenharmony_ci if (ret) { 4148c2ecf20Sopenharmony_ci list_splice_tail_init(&vram_list, &op->list); 4158c2ecf20Sopenharmony_ci list_splice_tail_init(&gart_list, &op->list); 4168c2ecf20Sopenharmony_ci list_splice_tail_init(&both_list, &op->list); 4178c2ecf20Sopenharmony_ci validate_fini_no_ticket(op, chan, NULL, NULL); 4188c2ecf20Sopenharmony_ci if (unlikely(ret == -EDEADLK)) { 4198c2ecf20Sopenharmony_ci ret = ttm_bo_reserve_slowpath(&nvbo->bo, true, 4208c2ecf20Sopenharmony_ci &op->ticket); 4218c2ecf20Sopenharmony_ci if (!ret) 4228c2ecf20Sopenharmony_ci res_bo = nvbo; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci if (unlikely(ret)) { 4258c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 4268c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "fail reserve\n"); 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (chan->vmm->vmm.object.oclass >= NVIF_CLASS_VMM_NV50) { 4328c2ecf20Sopenharmony_ci struct nouveau_vmm *vmm = chan->vmm; 4338c2ecf20Sopenharmony_ci struct nouveau_vma *vma = nouveau_vma_find(nvbo, vmm); 4348c2ecf20Sopenharmony_ci if (!vma) { 4358c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "vma not found!\n"); 4368c2ecf20Sopenharmony_ci ret = -EINVAL; 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci b->user_priv = (uint64_t)(unsigned long)vma; 4418c2ecf20Sopenharmony_ci } else { 4428c2ecf20Sopenharmony_ci b->user_priv = (uint64_t)(unsigned long)nvbo; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci nvbo->reserved_by = file_priv; 4468c2ecf20Sopenharmony_ci nvbo->pbbo_index = i; 4478c2ecf20Sopenharmony_ci if ((b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) && 4488c2ecf20Sopenharmony_ci (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART)) 4498c2ecf20Sopenharmony_ci list_add_tail(&nvbo->entry, &both_list); 4508c2ecf20Sopenharmony_ci else 4518c2ecf20Sopenharmony_ci if (b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) 4528c2ecf20Sopenharmony_ci list_add_tail(&nvbo->entry, &vram_list); 4538c2ecf20Sopenharmony_ci else 4548c2ecf20Sopenharmony_ci if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART) 4558c2ecf20Sopenharmony_ci list_add_tail(&nvbo->entry, &gart_list); 4568c2ecf20Sopenharmony_ci else { 4578c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "invalid valid domains: 0x%08x\n", 4588c2ecf20Sopenharmony_ci b->valid_domains); 4598c2ecf20Sopenharmony_ci list_add_tail(&nvbo->entry, &both_list); 4608c2ecf20Sopenharmony_ci ret = -EINVAL; 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci if (nvbo == res_bo) 4648c2ecf20Sopenharmony_ci goto retry; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci ww_acquire_done(&op->ticket); 4688c2ecf20Sopenharmony_ci list_splice_tail(&vram_list, &op->list); 4698c2ecf20Sopenharmony_ci list_splice_tail(&gart_list, &op->list); 4708c2ecf20Sopenharmony_ci list_splice_tail(&both_list, &op->list); 4718c2ecf20Sopenharmony_ci if (ret) 4728c2ecf20Sopenharmony_ci validate_fini(op, chan, NULL, NULL); 4738c2ecf20Sopenharmony_ci return ret; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic int 4788c2ecf20Sopenharmony_civalidate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, 4798c2ecf20Sopenharmony_ci struct list_head *list, struct drm_nouveau_gem_pushbuf_bo *pbbo) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct nouveau_drm *drm = chan->drm; 4828c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 4838c2ecf20Sopenharmony_ci int ret, relocs = 0; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci list_for_each_entry(nvbo, list, entry) { 4868c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci ret = nouveau_gem_set_domain(&nvbo->bo.base, b->read_domains, 4898c2ecf20Sopenharmony_ci b->write_domains, 4908c2ecf20Sopenharmony_ci b->valid_domains); 4918c2ecf20Sopenharmony_ci if (unlikely(ret)) { 4928c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "fail set_domain\n"); 4938c2ecf20Sopenharmony_ci return ret; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ret = nouveau_bo_validate(nvbo, true, false); 4978c2ecf20Sopenharmony_ci if (unlikely(ret)) { 4988c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 4998c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "fail ttm_validate\n"); 5008c2ecf20Sopenharmony_ci return ret; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci ret = nouveau_fence_sync(nvbo, chan, !!b->write_domains, true); 5048c2ecf20Sopenharmony_ci if (unlikely(ret)) { 5058c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 5068c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "fail post-validate sync\n"); 5078c2ecf20Sopenharmony_ci return ret; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) { 5118c2ecf20Sopenharmony_ci if (nvbo->offset == b->presumed.offset && 5128c2ecf20Sopenharmony_ci ((nvbo->bo.mem.mem_type == TTM_PL_VRAM && 5138c2ecf20Sopenharmony_ci b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) || 5148c2ecf20Sopenharmony_ci (nvbo->bo.mem.mem_type == TTM_PL_TT && 5158c2ecf20Sopenharmony_ci b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART))) 5168c2ecf20Sopenharmony_ci continue; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (nvbo->bo.mem.mem_type == TTM_PL_TT) 5198c2ecf20Sopenharmony_ci b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART; 5208c2ecf20Sopenharmony_ci else 5218c2ecf20Sopenharmony_ci b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM; 5228c2ecf20Sopenharmony_ci b->presumed.offset = nvbo->offset; 5238c2ecf20Sopenharmony_ci b->presumed.valid = 0; 5248c2ecf20Sopenharmony_ci relocs++; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci return relocs; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int 5328c2ecf20Sopenharmony_cinouveau_gem_pushbuf_validate(struct nouveau_channel *chan, 5338c2ecf20Sopenharmony_ci struct drm_file *file_priv, 5348c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *pbbo, 5358c2ecf20Sopenharmony_ci int nr_buffers, 5368c2ecf20Sopenharmony_ci struct validate_op *op, bool *apply_relocs) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct nouveau_cli *cli = nouveau_cli(file_priv); 5398c2ecf20Sopenharmony_ci int ret; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&op->list); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (nr_buffers == 0) 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); 5478c2ecf20Sopenharmony_ci if (unlikely(ret)) { 5488c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 5498c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "validate_init\n"); 5508c2ecf20Sopenharmony_ci return ret; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci ret = validate_list(chan, cli, &op->list, pbbo); 5548c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) { 5558c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 5568c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "validating bo list\n"); 5578c2ecf20Sopenharmony_ci validate_fini(op, chan, NULL, NULL); 5588c2ecf20Sopenharmony_ci return ret; 5598c2ecf20Sopenharmony_ci } else if (ret > 0) { 5608c2ecf20Sopenharmony_ci *apply_relocs = true; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic inline void 5678c2ecf20Sopenharmony_ciu_free(void *addr) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci kvfree(addr); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic inline void * 5738c2ecf20Sopenharmony_ciu_memcpya(uint64_t user, unsigned nmemb, unsigned size) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci void *mem; 5768c2ecf20Sopenharmony_ci void __user *userptr = (void __force __user *)(uintptr_t)user; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci size *= nmemb; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci mem = kvmalloc(size, GFP_KERNEL); 5818c2ecf20Sopenharmony_ci if (!mem) 5828c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (copy_from_user(mem, userptr, size)) { 5858c2ecf20Sopenharmony_ci u_free(mem); 5868c2ecf20Sopenharmony_ci return ERR_PTR(-EFAULT); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return mem; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic int 5938c2ecf20Sopenharmony_cinouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, 5948c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf *req, 5958c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_reloc *reloc, 5968c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *bo) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci int ret = 0; 5998c2ecf20Sopenharmony_ci unsigned i; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci for (i = 0; i < req->nr_relocs; i++) { 6028c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_reloc *r = &reloc[i]; 6038c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *b; 6048c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 6058c2ecf20Sopenharmony_ci uint32_t data; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (unlikely(r->bo_index >= req->nr_buffers)) { 6088c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "reloc bo index invalid\n"); 6098c2ecf20Sopenharmony_ci ret = -EINVAL; 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci b = &bo[r->bo_index]; 6148c2ecf20Sopenharmony_ci if (b->presumed.valid) 6158c2ecf20Sopenharmony_ci continue; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (unlikely(r->reloc_bo_index >= req->nr_buffers)) { 6188c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "reloc container bo index invalid\n"); 6198c2ecf20Sopenharmony_ci ret = -EINVAL; 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci nvbo = (void *)(unsigned long)bo[r->reloc_bo_index].user_priv; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (unlikely(r->reloc_bo_offset + 4 > 6258c2ecf20Sopenharmony_ci nvbo->bo.mem.num_pages << PAGE_SHIFT)) { 6268c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "reloc outside of bo\n"); 6278c2ecf20Sopenharmony_ci ret = -EINVAL; 6288c2ecf20Sopenharmony_ci break; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (!nvbo->kmap.virtual) { 6328c2ecf20Sopenharmony_ci ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, 6338c2ecf20Sopenharmony_ci &nvbo->kmap); 6348c2ecf20Sopenharmony_ci if (ret) { 6358c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "failed kmap for reloc\n"); 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci nvbo->validate_mapped = true; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (r->flags & NOUVEAU_GEM_RELOC_LOW) 6428c2ecf20Sopenharmony_ci data = b->presumed.offset + r->data; 6438c2ecf20Sopenharmony_ci else 6448c2ecf20Sopenharmony_ci if (r->flags & NOUVEAU_GEM_RELOC_HIGH) 6458c2ecf20Sopenharmony_ci data = (b->presumed.offset + r->data) >> 32; 6468c2ecf20Sopenharmony_ci else 6478c2ecf20Sopenharmony_ci data = r->data; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (r->flags & NOUVEAU_GEM_RELOC_OR) { 6508c2ecf20Sopenharmony_ci if (b->presumed.domain == NOUVEAU_GEM_DOMAIN_GART) 6518c2ecf20Sopenharmony_ci data |= r->tor; 6528c2ecf20Sopenharmony_ci else 6538c2ecf20Sopenharmony_ci data |= r->vor; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci ret = ttm_bo_wait(&nvbo->bo, false, false); 6578c2ecf20Sopenharmony_ci if (ret) { 6588c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "reloc wait_idle failed: %d\n", ret); 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data); 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return ret; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ciint 6698c2ecf20Sopenharmony_cinouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, 6708c2ecf20Sopenharmony_ci struct drm_file *file_priv) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv); 6738c2ecf20Sopenharmony_ci struct nouveau_cli *cli = nouveau_cli(file_priv); 6748c2ecf20Sopenharmony_ci struct nouveau_abi16_chan *temp; 6758c2ecf20Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 6768c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf *req = data; 6778c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_push *push; 6788c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; 6798c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo *bo; 6808c2ecf20Sopenharmony_ci struct nouveau_channel *chan = NULL; 6818c2ecf20Sopenharmony_ci struct validate_op op; 6828c2ecf20Sopenharmony_ci struct nouveau_fence *fence = NULL; 6838c2ecf20Sopenharmony_ci int i, j, ret = 0; 6848c2ecf20Sopenharmony_ci bool do_reloc = false, sync = false; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (unlikely(!abi16)) 6878c2ecf20Sopenharmony_ci return -ENOMEM; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci list_for_each_entry(temp, &abi16->channels, head) { 6908c2ecf20Sopenharmony_ci if (temp->chan->chid == req->channel) { 6918c2ecf20Sopenharmony_ci chan = temp->chan; 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (!chan) 6978c2ecf20Sopenharmony_ci return nouveau_abi16_put(abi16, -ENOENT); 6988c2ecf20Sopenharmony_ci if (unlikely(atomic_read(&chan->killed))) 6998c2ecf20Sopenharmony_ci return nouveau_abi16_put(abi16, -ENODEV); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci sync = req->vram_available & NOUVEAU_GEM_PUSHBUF_SYNC; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci req->vram_available = drm->gem.vram_available; 7048c2ecf20Sopenharmony_ci req->gart_available = drm->gem.gart_available; 7058c2ecf20Sopenharmony_ci if (unlikely(req->nr_push == 0)) 7068c2ecf20Sopenharmony_ci goto out_next; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) { 7098c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n", 7108c2ecf20Sopenharmony_ci req->nr_push, NOUVEAU_GEM_MAX_PUSH); 7118c2ecf20Sopenharmony_ci return nouveau_abi16_put(abi16, -EINVAL); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) { 7158c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "pushbuf bo count exceeds limit: %d max %d\n", 7168c2ecf20Sopenharmony_ci req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS); 7178c2ecf20Sopenharmony_ci return nouveau_abi16_put(abi16, -EINVAL); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) { 7218c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "pushbuf reloc count exceeds limit: %d max %d\n", 7228c2ecf20Sopenharmony_ci req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS); 7238c2ecf20Sopenharmony_ci return nouveau_abi16_put(abi16, -EINVAL); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci push = u_memcpya(req->push, req->nr_push, sizeof(*push)); 7278c2ecf20Sopenharmony_ci if (IS_ERR(push)) 7288c2ecf20Sopenharmony_ci return nouveau_abi16_put(abi16, PTR_ERR(push)); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); 7318c2ecf20Sopenharmony_ci if (IS_ERR(bo)) { 7328c2ecf20Sopenharmony_ci u_free(push); 7338c2ecf20Sopenharmony_ci return nouveau_abi16_put(abi16, PTR_ERR(bo)); 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Ensure all push buffers are on validate list */ 7378c2ecf20Sopenharmony_ci for (i = 0; i < req->nr_push; i++) { 7388c2ecf20Sopenharmony_ci if (push[i].bo_index >= req->nr_buffers) { 7398c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "push %d buffer not in list\n", i); 7408c2ecf20Sopenharmony_ci ret = -EINVAL; 7418c2ecf20Sopenharmony_ci goto out_prevalid; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Validate buffer list */ 7468c2ecf20Sopenharmony_cirevalidate: 7478c2ecf20Sopenharmony_ci ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, 7488c2ecf20Sopenharmony_ci req->nr_buffers, &op, &do_reloc); 7498c2ecf20Sopenharmony_ci if (ret) { 7508c2ecf20Sopenharmony_ci if (ret != -ERESTARTSYS) 7518c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "validate: %d\n", ret); 7528c2ecf20Sopenharmony_ci goto out_prevalid; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* Apply any relocations that are required */ 7568c2ecf20Sopenharmony_ci if (do_reloc) { 7578c2ecf20Sopenharmony_ci if (!reloc) { 7588c2ecf20Sopenharmony_ci validate_fini(&op, chan, NULL, bo); 7598c2ecf20Sopenharmony_ci reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc)); 7608c2ecf20Sopenharmony_ci if (IS_ERR(reloc)) { 7618c2ecf20Sopenharmony_ci ret = PTR_ERR(reloc); 7628c2ecf20Sopenharmony_ci goto out_prevalid; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci goto revalidate; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci ret = nouveau_gem_pushbuf_reloc_apply(cli, req, reloc, bo); 7698c2ecf20Sopenharmony_ci if (ret) { 7708c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "reloc apply: %d\n", ret); 7718c2ecf20Sopenharmony_ci goto out; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (chan->dma.ib_max) { 7768c2ecf20Sopenharmony_ci ret = nouveau_dma_wait(chan, req->nr_push + 1, 16); 7778c2ecf20Sopenharmony_ci if (ret) { 7788c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "nv50cal_space: %d\n", ret); 7798c2ecf20Sopenharmony_ci goto out; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci for (i = 0; i < req->nr_push; i++) { 7838c2ecf20Sopenharmony_ci struct nouveau_vma *vma = (void *)(unsigned long) 7848c2ecf20Sopenharmony_ci bo[push[i].bo_index].user_priv; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci nv50_dma_push(chan, vma->addr + push[i].offset, 7878c2ecf20Sopenharmony_ci push[i].length); 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci } else 7908c2ecf20Sopenharmony_ci if (drm->client.device.info.chipset >= 0x25) { 7918c2ecf20Sopenharmony_ci ret = PUSH_WAIT(chan->chan.push, req->nr_push * 2); 7928c2ecf20Sopenharmony_ci if (ret) { 7938c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "cal_space: %d\n", ret); 7948c2ecf20Sopenharmony_ci goto out; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci for (i = 0; i < req->nr_push; i++) { 7988c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo = (void *)(unsigned long) 7998c2ecf20Sopenharmony_ci bo[push[i].bo_index].user_priv; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci PUSH_CALL(chan->chan.push, nvbo->offset + push[i].offset); 8028c2ecf20Sopenharmony_ci PUSH_DATA(chan->chan.push, 0); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci } else { 8058c2ecf20Sopenharmony_ci ret = PUSH_WAIT(chan->chan.push, req->nr_push * (2 + NOUVEAU_DMA_SKIPS)); 8068c2ecf20Sopenharmony_ci if (ret) { 8078c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "jmp_space: %d\n", ret); 8088c2ecf20Sopenharmony_ci goto out; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci for (i = 0; i < req->nr_push; i++) { 8128c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo = (void *)(unsigned long) 8138c2ecf20Sopenharmony_ci bo[push[i].bo_index].user_priv; 8148c2ecf20Sopenharmony_ci uint32_t cmd; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci cmd = chan->push.addr + ((chan->dma.cur + 2) << 2); 8178c2ecf20Sopenharmony_ci cmd |= 0x20000000; 8188c2ecf20Sopenharmony_ci if (unlikely(cmd != req->suffix0)) { 8198c2ecf20Sopenharmony_ci if (!nvbo->kmap.virtual) { 8208c2ecf20Sopenharmony_ci ret = ttm_bo_kmap(&nvbo->bo, 0, 8218c2ecf20Sopenharmony_ci nvbo->bo.mem. 8228c2ecf20Sopenharmony_ci num_pages, 8238c2ecf20Sopenharmony_ci &nvbo->kmap); 8248c2ecf20Sopenharmony_ci if (ret) { 8258c2ecf20Sopenharmony_ci WIND_RING(chan); 8268c2ecf20Sopenharmony_ci goto out; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci nvbo->validate_mapped = true; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci nouveau_bo_wr32(nvbo, (push[i].offset + 8328c2ecf20Sopenharmony_ci push[i].length - 8) / 4, cmd); 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci PUSH_JUMP(chan->chan.push, nvbo->offset + push[i].offset); 8368c2ecf20Sopenharmony_ci PUSH_DATA(chan->chan.push, 0); 8378c2ecf20Sopenharmony_ci for (j = 0; j < NOUVEAU_DMA_SKIPS; j++) 8388c2ecf20Sopenharmony_ci PUSH_DATA(chan->chan.push, 0); 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci ret = nouveau_fence_new(chan, false, &fence); 8438c2ecf20Sopenharmony_ci if (ret) { 8448c2ecf20Sopenharmony_ci NV_PRINTK(err, cli, "error fencing pushbuf: %d\n", ret); 8458c2ecf20Sopenharmony_ci WIND_RING(chan); 8468c2ecf20Sopenharmony_ci goto out; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (sync) { 8508c2ecf20Sopenharmony_ci if (!(ret = nouveau_fence_wait(fence, false, false))) { 8518c2ecf20Sopenharmony_ci if ((ret = dma_fence_get_status(&fence->base)) == 1) 8528c2ecf20Sopenharmony_ci ret = 0; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ciout: 8578c2ecf20Sopenharmony_ci validate_fini(&op, chan, fence, bo); 8588c2ecf20Sopenharmony_ci nouveau_fence_unref(&fence); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (do_reloc) { 8618c2ecf20Sopenharmony_ci struct drm_nouveau_gem_pushbuf_bo __user *upbbo = 8628c2ecf20Sopenharmony_ci u64_to_user_ptr(req->buffers); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci for (i = 0; i < req->nr_buffers; i++) { 8658c2ecf20Sopenharmony_ci if (bo[i].presumed.valid) 8668c2ecf20Sopenharmony_ci continue; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (copy_to_user(&upbbo[i].presumed, &bo[i].presumed, 8698c2ecf20Sopenharmony_ci sizeof(bo[i].presumed))) { 8708c2ecf20Sopenharmony_ci ret = -EFAULT; 8718c2ecf20Sopenharmony_ci break; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ciout_prevalid: 8768c2ecf20Sopenharmony_ci if (!IS_ERR(reloc)) 8778c2ecf20Sopenharmony_ci u_free(reloc); 8788c2ecf20Sopenharmony_ci u_free(bo); 8798c2ecf20Sopenharmony_ci u_free(push); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ciout_next: 8828c2ecf20Sopenharmony_ci if (chan->dma.ib_max) { 8838c2ecf20Sopenharmony_ci req->suffix0 = 0x00000000; 8848c2ecf20Sopenharmony_ci req->suffix1 = 0x00000000; 8858c2ecf20Sopenharmony_ci } else 8868c2ecf20Sopenharmony_ci if (drm->client.device.info.chipset >= 0x25) { 8878c2ecf20Sopenharmony_ci req->suffix0 = 0x00020000; 8888c2ecf20Sopenharmony_ci req->suffix1 = 0x00000000; 8898c2ecf20Sopenharmony_ci } else { 8908c2ecf20Sopenharmony_ci req->suffix0 = 0x20000000 | 8918c2ecf20Sopenharmony_ci (chan->push.addr + ((chan->dma.cur + 2) << 2)); 8928c2ecf20Sopenharmony_ci req->suffix1 = 0x00000000; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return nouveau_abi16_put(abi16, ret); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ciint 8998c2ecf20Sopenharmony_cinouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, 9008c2ecf20Sopenharmony_ci struct drm_file *file_priv) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci struct drm_nouveau_gem_cpu_prep *req = data; 9038c2ecf20Sopenharmony_ci struct drm_gem_object *gem; 9048c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 9058c2ecf20Sopenharmony_ci bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); 9068c2ecf20Sopenharmony_ci bool write = !!(req->flags & NOUVEAU_GEM_CPU_PREP_WRITE); 9078c2ecf20Sopenharmony_ci long lret; 9088c2ecf20Sopenharmony_ci int ret; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci gem = drm_gem_object_lookup(file_priv, req->handle); 9118c2ecf20Sopenharmony_ci if (!gem) 9128c2ecf20Sopenharmony_ci return -ENOENT; 9138c2ecf20Sopenharmony_ci nvbo = nouveau_gem_object(gem); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci lret = dma_resv_wait_timeout_rcu(nvbo->bo.base.resv, write, true, 9168c2ecf20Sopenharmony_ci no_wait ? 0 : 30 * HZ); 9178c2ecf20Sopenharmony_ci if (!lret) 9188c2ecf20Sopenharmony_ci ret = -EBUSY; 9198c2ecf20Sopenharmony_ci else if (lret > 0) 9208c2ecf20Sopenharmony_ci ret = 0; 9218c2ecf20Sopenharmony_ci else 9228c2ecf20Sopenharmony_ci ret = lret; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci nouveau_bo_sync_for_cpu(nvbo); 9258c2ecf20Sopenharmony_ci drm_gem_object_put(gem); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci return ret; 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ciint 9318c2ecf20Sopenharmony_cinouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, 9328c2ecf20Sopenharmony_ci struct drm_file *file_priv) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci struct drm_nouveau_gem_cpu_fini *req = data; 9358c2ecf20Sopenharmony_ci struct drm_gem_object *gem; 9368c2ecf20Sopenharmony_ci struct nouveau_bo *nvbo; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci gem = drm_gem_object_lookup(file_priv, req->handle); 9398c2ecf20Sopenharmony_ci if (!gem) 9408c2ecf20Sopenharmony_ci return -ENOENT; 9418c2ecf20Sopenharmony_ci nvbo = nouveau_gem_object(gem); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci nouveau_bo_sync_for_device(nvbo); 9448c2ecf20Sopenharmony_ci drm_gem_object_put(gem); 9458c2ecf20Sopenharmony_ci return 0; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ciint 9498c2ecf20Sopenharmony_cinouveau_gem_ioctl_info(struct drm_device *dev, void *data, 9508c2ecf20Sopenharmony_ci struct drm_file *file_priv) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct drm_nouveau_gem_info *req = data; 9538c2ecf20Sopenharmony_ci struct drm_gem_object *gem; 9548c2ecf20Sopenharmony_ci int ret; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci gem = drm_gem_object_lookup(file_priv, req->handle); 9578c2ecf20Sopenharmony_ci if (!gem) 9588c2ecf20Sopenharmony_ci return -ENOENT; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci ret = nouveau_gem_info(file_priv, gem, req); 9618c2ecf20Sopenharmony_ci drm_gem_object_put(gem); 9628c2ecf20Sopenharmony_ci return ret; 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 965