/* Frees older cached buffers. Called under table_lock */ drm_private void drm_tegra_bo_cache_cleanup(struct drm_tegra *drm, time_t time) { struct drm_tegra_bo_cache *cache = &drm->bo_cache; time_t delta; int i; if (cache->time == time) return; for (i = 0; i < cache->num_buckets; i++) { struct drm_tegra_bo_bucket *bucket = &cache->cache_bucket[i]; struct drm_tegra_bo *bo; if (time && !bucket_free_up(drm, bucket, false)) continue; while (!DRMLISTEMPTY(&bucket->list)) { bo = DRMLISTENTRY(struct drm_tegra_bo, bucket->list.next, bo_list); delta = time - bo->free_time; /* keep things in cache for at least 1 second: */ if (time && delta <= 1) break; /* keep things in cache longer if not much */ if (time && delta < 60 && bucket->num_entries < 5) break; VG_BO_OBTAIN(bo); DRMLISTDEL(&bo->bo_list); drm_tegra_bo_free(bo); #ifndef NDEBUG if (drm->debug_bo) drm->debug_bos_cached--; #endif bucket->num_entries--; } } cache->time = time; }
drm_public int drm_tegra_bo_unref(struct drm_tegra_bo *bo) { int err = 0; if (!bo) return -EINVAL; DBG_BO(bo, "\n"); if (!atomic_dec_and_test(&bo->ref)) return 0; drm_tegra_bo_check_guards(bo); pthread_mutex_lock(&table_lock); if (!bo->reuse || drm_tegra_bo_cache_free(bo)) err = drm_tegra_bo_free(bo); pthread_mutex_unlock(&table_lock); return err; }
drm_public int drm_tegra_bo_from_dmabuf(struct drm_tegra_bo **bop, struct drm_tegra *drm, int fd, uint32_t flags) { struct drm_tegra_bo *dup; struct drm_tegra_bo *bo; uint32_t handle; uint32_t size; int err; if (!drm || !bop) return -EINVAL; pthread_mutex_lock(&table_lock); bo = calloc(1, sizeof(*bo)); if (!bo) { err = -ENOMEM; goto unlock; } err = drmPrimeFDToHandle(drm->fd, fd, &handle); if (err) { free(bo); bo = NULL; goto unlock; } /* check handle table to see if BO is already open */ dup = lookup_bo(drm->handle_table, handle); if (dup) { DBG_BO(dup, "success reused\n"); free(bo); bo = dup; goto unlock; } errno = 0; /* lseek() to get bo size */ size = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_CUR); /* store lseek() error number */ err = -errno; atomic_set(&bo->ref, 1); bo->handle = handle; bo->flags = flags; bo->size = size; bo->drm = drm; VG_BO_ALLOC(bo); /* add ourself into the handle table: */ drmHashInsert(drm->handle_table, handle, bo); /* handle lseek() error */ if (err) { VDBG_BO(bo, "lseek failed %d (%s)\n", err, strerror(-err)); drm_tegra_bo_free(bo); bo = NULL; } else { DBG_BO(bo, "success\n"); } unlock: pthread_mutex_unlock(&table_lock); *bop = bo; return err; }
void drm_tegra_bo_unref(struct drm_tegra_bo *bo) { if (bo && atomic_dec_and_test(&bo->ref)) drm_tegra_bo_free(bo); }