etnaviv_bo.c revision 49ef06a4
11.105Sskrll/* 21.1Sichiro * Copyright (C) 2014 Etnaviv Project 31.1Sichiro * 41.1Sichiro * Permission is hereby granted, free of charge, to any person obtaining a 51.1Sichiro * copy of this software and associated documentation files (the "Software"), 61.77Snonaka * to deal in the Software without restriction, including without limitation 71.1Sichiro * the rights to use, copy, modify, merge, publish, distribute, sublicense, 81.19Satatat * and/or sell copies of the Software, and to permit persons to whom the 91.19Satatat * Software is furnished to do so, subject to the following conditions: 101.105Sskrll * 111.1Sichiro * The above copyright notice and this permission notice (including the next 121.1Sichiro * paragraph) shall be included in all copies or substantial portions of the 131.1Sichiro * Software. 141.1Sichiro * 151.1Sichiro * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161.1Sichiro * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 171.79Stsutsui * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 181.79Stsutsui * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191.1Sichiro * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 201.1Sichiro * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 211.1Sichiro * SOFTWARE. 221.1Sichiro * 231.61Speter * Authors: 241.1Sichiro * Christian Gmeiner <christian.gmeiner@gmail.com> 251.1Sichiro */ 261.1Sichiro 271.1Sichiro#include "etnaviv_priv.h" 281.1Sichiro#include "etnaviv_drmif.h" 291.1Sichiro 301.1Sichirodrm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; 311.1Sichirodrm_private void bo_del(struct etna_bo *bo); 321.1Sichiro 331.1Sichiro/* set buffer name, and add to table, call w/ table_lock held: */ 341.1Sichirostatic void set_name(struct etna_bo *bo, uint32_t name) 351.63Sichiro{ 361.1Sichiro bo->name = name; 371.1Sichiro /* add ourself into the name table: */ 381.1Sichiro drmHashInsert(bo->dev->name_table, name, bo); 391.1Sichiro} 401.1Sichiro 411.1Sichiro/* Called under table_lock */ 421.63Sichirodrm_private void bo_del(struct etna_bo *bo) 431.1Sichiro{ 441.63Sichiro if (bo->map) 451.46Schristos drm_munmap(bo->map, bo->size); 461.63Sichiro 471.54Speter if (bo->name) 481.1Sichiro drmHashDelete(bo->dev->name_table, bo->name); 491.1Sichiro 501.82Sbouyer if (bo->handle) { 511.82Sbouyer drmHashDelete(bo->dev->handle_table, bo->handle); 521.83Swiz drmCloseBufferHandle(bo->dev->fd, bo->handle); 531.85Sdholland } 541.48Stsutsui 551.1Sichiro free(bo); 561.1Sichiro} 571.1Sichiro 581.1Sichiro/* lookup a buffer from it's handle, call w/ table_lock held: */ 591.1Sichirostatic struct etna_bo *lookup_bo(void *tbl, uint32_t handle) 601.1Sichiro{ 611.1Sichiro struct etna_bo *bo = NULL; 621.63Sichiro 631.1Sichiro if (!drmHashLookup(tbl, handle, (void **)&bo)) { 641.63Sichiro /* found, incr refcnt and return: */ 651.63Sichiro bo = etna_bo_ref(bo); 661.1Sichiro 671.1Sichiro /* don't break the bucket if this bo was found in one */ 681.1Sichiro list_delinit(&bo->list); 691.1Sichiro } 701.10Sabs 711.1Sichiro return bo; 721.1Sichiro} 731.1Sichiro 741.101Smrg/* allocate a new buffer object, call w/ table_lock held */ 751.101Smrgstatic struct etna_bo *bo_from_handle(struct etna_device *dev, 761.1Sichiro uint32_t size, uint32_t handle, uint32_t flags) 771.1Sichiro{ 781.1Sichiro struct etna_bo *bo = calloc(sizeof(*bo), 1); 791.1Sichiro 801.1Sichiro if (!bo) { 811.1Sichiro drmCloseBufferHandle(dev->fd, handle); 821.1Sichiro return NULL; 831.1Sichiro } 841.1Sichiro 851.22Stoshii bo->dev = etna_device_ref(dev); 861.15Slukem bo->size = size; 871.1Sichiro bo->handle = handle; 881.1Sichiro bo->flags = flags; 891.1Sichiro atomic_set(&bo->refcnt, 1); 901.1Sichiro list_inithead(&bo->list); 911.1Sichiro /* add ourselves to the handle table: */ 921.1Sichiro drmHashInsert(dev->handle_table, handle, bo); 931.28Slukem 941.13Sjdolecek return bo; 951.35Satatat} 961.1Sichiro 971.4Stoshii/* allocate a new (un-tiled) buffer object */ 981.4Stoshiidrm_public struct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size, 991.103Ssevan uint32_t flags) 1001.103Ssevan{ 1011.103Ssevan struct etna_bo *bo; 1021.103Ssevan int ret; 1031.103Ssevan struct drm_etnaviv_gem_new req = { 1041.1Sichiro .flags = flags, 1051.1Sichiro }; 1061.12Slukem 1071.55Speter bo = etna_bo_cache_alloc(&dev->bo_cache, &size, flags); 1081.47Speter if (bo) 1091.105Sskrll return bo; 1101.99Ssevan 1111.99Ssevan req.size = size; 1121.1Sichiro ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GEM_NEW, 1131.1Sichiro &req, sizeof(req)); 1141.99Ssevan if (ret) 1151.1Sichiro return NULL; 1161.1Sichiro 1171.2Sichiro pthread_mutex_lock(&table_lock); 1181.1Sichiro bo = bo_from_handle(dev, size, req.handle, flags); 1191.1Sichiro bo->reuse = 1; 1201.1Sichiro pthread_mutex_unlock(&table_lock); 1211.1Sichiro 1221.34Swiz return bo; 1231.1Sichiro} 1241.1Sichiro 1251.1Sichirodrm_public struct etna_bo *etna_bo_ref(struct etna_bo *bo) 1261.1Sichiro{ 1271.1Sichiro atomic_inc(&bo->refcnt); 1281.12Slukem 1291.58Speter return bo; 1301.1Sichiro} 1311.53Speter 1321.12Slukem/* get buffer info */ 1331.1Sichirostatic int get_buffer_info(struct etna_bo *bo) 1341.61Speter{ 1351.4Stoshii int ret; 1361.4Stoshii struct drm_etnaviv_gem_info req = { 1371.4Stoshii .handle = bo->handle, 1381.4Stoshii }; 1391.4Stoshii 1401.4Stoshii ret = drmCommandWriteRead(bo->dev->fd, DRM_ETNAVIV_GEM_INFO, 1411.4Stoshii &req, sizeof(req)); 1421.4Stoshii if (ret) { 1431.4Stoshii return ret; 1441.63Sichiro } 1451.63Sichiro 1461.63Sichiro /* really all we need for now is mmap offset */ 1471.63Sichiro bo->offset = req.offset; 1481.63Sichiro 1491.63Sichiro return 0; 1501.63Sichiro} 1511.63Sichiro 1521.63Sichiro/* import a buffer object from DRI2 name */ 1531.63Sichirodrm_public struct etna_bo *etna_bo_from_name(struct etna_device *dev, 1541.63Sichiro uint32_t name) 1551.63Sichiro{ 1561.63Sichiro struct etna_bo *bo; 1571.63Sichiro struct drm_gem_open req = { 1581.63Sichiro .name = name, 1591.63Sichiro }; 1601.63Sichiro 1611.63Sichiro pthread_mutex_lock(&table_lock); 1621.63Sichiro 1631.63Sichiro /* check name table first, to see if bo is already open: */ 1641.4Stoshii bo = lookup_bo(dev->name_table, name); 1651.4Stoshii if (bo) 1661.33Slukem goto out_unlock; 1671.32Sbouyer 1681.4Stoshii if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { 1691.4Stoshii ERROR_MSG("gem-open failed: %s", strerror(errno)); 1701.9Stoshii goto out_unlock; 1711.9Stoshii } 1721.9Stoshii 1731.63Sichiro bo = lookup_bo(dev->handle_table, req.handle); 1741.9Stoshii if (bo) 1751.9Stoshii goto out_unlock; 1761.4Stoshii 1771.9Stoshii bo = bo_from_handle(dev, req.size, req.handle, 0); 1781.63Sichiro if (bo) 1791.4Stoshii set_name(bo, name); 1801.63Sichiro 1811.63Sichiroout_unlock: 1821.63Sichiro pthread_mutex_unlock(&table_lock); 1831.63Sichiro 1841.63Sichiro return bo; 1851.63Sichiro} 1861.23Smanu 1871.63Sichiro/* import a buffer from dmabuf fd, does not take ownership of the 1881.63Sichiro * fd so caller should close() the fd when it is otherwise done 1891.63Sichiro * with it (even if it is still using the 'struct etna_bo *') 1901.63Sichiro */ 1911.65Skiyoharadrm_public struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd) 1921.63Sichiro{ 1931.63Sichiro struct etna_bo *bo; 1941.67Skiyohara int ret, size; 1951.63Sichiro uint32_t handle; 1961.65Skiyohara 1971.64Skiyohara /* take the lock before calling drmPrimeFDToHandle to avoid 1981.63Sichiro * racing against etna_bo_del, which might invalidate the 1991.63Sichiro * returned handle. 2001.63Sichiro */ 2011.63Sichiro pthread_mutex_lock(&table_lock); 2021.63Sichiro 2031.63Sichiro ret = drmPrimeFDToHandle(dev->fd, fd, &handle); 2041.63Sichiro if (ret) { 2051.63Sichiro pthread_mutex_unlock(&table_lock); 2061.63Sichiro return NULL; 2071.63Sichiro } 2081.63Sichiro 2091.63Sichiro bo = lookup_bo(dev->handle_table, handle); 2101.78Splunky if (bo) 2111.78Splunky goto out_unlock; 2121.78Splunky 2131.78Splunky /* lseek() to get bo size */ 2141.63Sichiro size = lseek(fd, 0, SEEK_END); 2151.63Sichiro lseek(fd, 0, SEEK_CUR); 2161.63Sichiro 2171.50Speter bo = bo_from_handle(dev, size, handle, 0); 2181.8Stoshii 2191.8Stoshiiout_unlock: 2201.8Stoshii pthread_mutex_unlock(&table_lock); 2211.26Smanu 2221.87Sabs return bo; 2231.26Smanu} 2241.50Speter 2251.50Speter/* destroy a buffer object */ 2261.50Speterdrm_public void etna_bo_del(struct etna_bo *bo) 2271.50Speter{ 2281.50Speter struct etna_device *dev = bo->dev; 2291.50Speter 2301.50Speter if (!bo) 2311.50Speter return; 2321.50Speter 2331.50Speter if (!atomic_dec_and_test(&bo->refcnt)) 2341.8Stoshii return; 2351.53Speter 2361.5Stoshii pthread_mutex_lock(&table_lock); 2371.5Stoshii 2381.5Stoshii if (bo->reuse && (etna_bo_cache_free(&dev->bo_cache, bo) == 0)) 2391.53Speter goto out; 2401.53Speter 2411.8Stoshii bo_del(bo); 2421.1Sichiro etna_device_del_locked(dev); 2431.53Speterout: 2441.53Speter pthread_mutex_unlock(&table_lock); 2451.53Speter} 2461.53Speter 2471.53Speter/* get the global flink/DRI2 buffer name */ 2481.53Speterdrm_public int etna_bo_get_name(struct etna_bo *bo, uint32_t *name) 2491.53Speter{ 2501.53Speter if (!bo->name) { 2511.61Speter struct drm_gem_flink req = { 2521.53Speter .handle = bo->handle, 2531.53Speter }; 2541.53Speter int ret; 2551.53Speter 2561.53Speter ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); 2571.53Speter if (ret) { 2581.53Speter return ret; 2591.53Speter } 2601.53Speter 2611.53Speter pthread_mutex_lock(&table_lock); 2621.91Schristos set_name(bo, req.name); 2631.103Ssevan pthread_mutex_unlock(&table_lock); 2641.51Srpaulo bo->reuse = 0; 2651.52Scube } 2661.52Scube 2671.52Scube *name = bo->name; 2681.52Scube 2691.102Smaxv return 0; 2701.52Scube} 2711.52Scube 2721.57Spaveldrm_public uint32_t etna_bo_handle(struct etna_bo *bo) 2731.47Speter{ 2741.1Sichiro return bo->handle; 2751.1Sichiro} 2761.52Scube 2771.91Schristos/* caller owns the dmabuf fd that is returned and is responsible 2781.91Schristos * to close() it when done 2791.92Schristos */ 2801.1Sichirodrm_public int etna_bo_dmabuf(struct etna_bo *bo) 2811.76Spooka{ 2821.1Sichiro int ret, prime_fd; 2831.12Slukem 2841.12Slukem ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, 2851.1Sichiro &prime_fd); 2861.80Shannken if (ret) { 2871.21Slukem ERROR_MSG("failed to get dmabuf fd: %d", ret); 2881.47Speter return ret; 2891.67Skiyohara } 2901.64Skiyohara 2911.103Ssevan bo->reuse = 0; 2921.103Ssevan 293 return prime_fd; 294} 295 296drm_public uint32_t etna_bo_size(struct etna_bo *bo) 297{ 298 return bo->size; 299} 300 301drm_public void *etna_bo_map(struct etna_bo *bo) 302{ 303 if (!bo->map) { 304 if (!bo->offset) { 305 get_buffer_info(bo); 306 } 307 308 bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, 309 MAP_SHARED, bo->dev->fd, bo->offset); 310 if (bo->map == MAP_FAILED) { 311 ERROR_MSG("mmap failed: %s", strerror(errno)); 312 bo->map = NULL; 313 } 314 } 315 316 return bo->map; 317} 318 319drm_public int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op) 320{ 321 struct drm_etnaviv_gem_cpu_prep req = { 322 .handle = bo->handle, 323 .op = op, 324 }; 325 326 get_abs_timeout(&req.timeout, 5000000000); 327 328 return drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_PREP, 329 &req, sizeof(req)); 330} 331 332drm_public void etna_bo_cpu_fini(struct etna_bo *bo) 333{ 334 struct drm_etnaviv_gem_cpu_fini req = { 335 .handle = bo->handle, 336 }; 337 338 drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_FINI, 339 &req, sizeof(req)); 340} 341