drm_private int drm_tegra_bo_free(struct drm_tegra_bo *bo) { struct drm_tegra *drm = bo->drm; struct drm_gem_close args; void *map_cached; int err; DBG_BO(bo, "\n"); #ifndef NDEBUG if (drm->debug_bo) { drm->debug_bos_allocated--; drm->debug_bos_total_size -= bo->debug_size; } #endif drm_tegra_bo_unmap_guards(bo); if (bo->map) { if (RUNNING_ON_VALGRIND) VG_BO_UNMMAP(bo); else munmap(bo->map, bo->offset + bo->size); } else if (bo->map_cached) { map_cached = drm_tegra_bo_cache_map(bo); if (!RUNNING_ON_VALGRIND) munmap(map_cached, bo->offset + bo->size); } else { goto vg_free; } #ifndef NDEBUG if (drm->debug_bo) { drm->debug_bos_mapped--; drm->debug_bos_total_pages -= bo->debug_size / 4096; } #endif vg_free: VG_BO_FREE(bo); if (bo->name) drmHashDelete(drm->name_table, bo->name); drmHashDelete(drm->handle_table, bo->handle); memset(&args, 0, sizeof(args)); args.handle = bo->handle; err = drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &args); if (err < 0) err = -errno; free(bo); DBG_BO_STATS(drm); return err; }
/* Called under table_lock */ drm_private void bo_del(struct fd_bo *bo) { VG_BO_FREE(bo); if (bo->map) drm_munmap(bo->map, bo->size); /* TODO probably bo's in bucket list get removed from * handle table?? */ if (bo->handle) { struct drm_gem_close req = { .handle = bo->handle, }; drmHashDelete(bo->dev->handle_table, bo->handle); if (bo->name) drmHashDelete(bo->dev->name_table, bo->name); drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); } bo->funcs->destroy(bo); } int fd_bo_get_name(struct fd_bo *bo, uint32_t *name) { if (!bo->name) { struct drm_gem_flink req = { .handle = bo->handle, }; int ret; ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); if (ret) { return ret; } pthread_mutex_lock(&table_lock); set_name(bo, req.name); pthread_mutex_unlock(&table_lock); bo->bo_reuse = FALSE; } *name = bo->name; return 0; } uint32_t fd_bo_handle(struct fd_bo *bo) { return bo->handle; } int fd_bo_dmabuf(struct fd_bo *bo) { int ret, prime_fd; ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, &prime_fd); if (ret) { ERROR_MSG("failed to get dmabuf fd: %d", ret); return ret; } bo->bo_reuse = FALSE; return prime_fd; } uint32_t fd_bo_size(struct fd_bo *bo) { return bo->size; } void * fd_bo_map(struct fd_bo *bo) { if (!bo->map) { uint64_t offset; int ret; ret = bo->funcs->offset(bo, &offset); if (ret) { return NULL; } bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->dev->fd, offset); if (bo->map == MAP_FAILED) { ERROR_MSG("mmap failed: %s", strerror(errno)); bo->map = NULL; } } return bo->map; } /* a bit odd to take the pipe as an arg, but it's a, umm, quirk of kgsl.. */ int fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) { return bo->funcs->cpu_prep(bo, pipe, op); } void fd_bo_cpu_fini(struct fd_bo *bo) { bo->funcs->cpu_fini(bo); }