diff options
Diffstat (limited to 'drivers/gpu/drm/vc4/vc4_bo.c')
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_bo.c | 142 |
1 files changed, 134 insertions, 8 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 3f6704cf6608..487f96412d35 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -6,7 +6,8 @@ * published by the Free Software Foundation. */ -/* DOC: VC4 GEM BO management support. +/** + * DOC: VC4 GEM BO management support * * The VC4 GPU architecture (both scanout and rendering) has direct * access to system memory with no MMU in between. To support it, we @@ -18,6 +19,8 @@ * rendering can return quickly. */ +#include <linux/dma-buf.h> + #include "vc4_drv.h" #include "uapi/drm/vc4_drm.h" @@ -87,6 +90,9 @@ static void vc4_bo_destroy(struct vc4_bo *bo) vc4->bo_stats.num_allocated--; vc4->bo_stats.size_allocated -= obj->size; + + reservation_object_fini(&bo->_resv); + drm_gem_cma_free_object(obj); } @@ -186,6 +192,8 @@ out: /** * vc4_gem_create_object - Implementation of driver->gem_create_object. + * @dev: DRM device + * @size: Size in bytes of the memory the object will reference * * This lets the CMA helpers allocate object structs for us, and keep * our BO stats correct. @@ -203,26 +211,29 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) vc4->bo_stats.num_allocated++; vc4->bo_stats.size_allocated += size; mutex_unlock(&vc4->bo_lock); + bo->resv = &bo->_resv; + reservation_object_init(bo->resv); return &bo->base.base; } struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, - bool from_cache) + bool allow_unzeroed) { size_t size = roundup(unaligned_size, PAGE_SIZE); struct vc4_dev *vc4 = to_vc4_dev(dev); struct drm_gem_cma_object *cma_obj; + struct vc4_bo *bo; if (size == 0) return ERR_PTR(-EINVAL); /* First, try to get a vc4_bo from the kernel BO cache. */ - if (from_cache) { - struct vc4_bo *bo = vc4_bo_get_from_cache(dev, size); - - if (bo) - return bo; + bo = vc4_bo_get_from_cache(dev, size); + if (bo) { + if (!allow_unzeroed) + memset(bo->base.vaddr, 0, bo->base.base.size); + return bo; } cma_obj = drm_gem_cma_create(dev, size); @@ -240,7 +251,6 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, return ERR_PTR(-ENOMEM); } } - return to_vc4_bo(&cma_obj->base); } @@ -313,6 +323,14 @@ void vc4_free_object(struct drm_gem_object *gem_bo) goto out; } + /* If this object was partially constructed but CMA allocation + * had failed, just free it. + */ + if (!bo->base.vaddr) { + vc4_bo_destroy(bo); + goto out; + } + cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size); if (!cache_list) { vc4_bo_destroy(bo); @@ -325,6 +343,7 @@ void vc4_free_object(struct drm_gem_object *gem_bo) bo->validated_shader = NULL; } + bo->t_format = false; bo->free_time = jiffies; list_add(&bo->size_head, cache_list); list_add(&bo->unref_head, &vc4->bo_cache.time_list); @@ -357,6 +376,13 @@ static void vc4_bo_cache_time_timer(unsigned long data) schedule_work(&vc4->bo_cache.time_work); } +struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj) +{ + struct vc4_bo *bo = to_vc4_bo(obj); + + return bo->resv; +} + struct dma_buf * vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) { @@ -428,6 +454,24 @@ void *vc4_prime_vmap(struct drm_gem_object *obj) return drm_gem_cma_prime_vmap(obj); } +struct drm_gem_object * +vc4_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt) +{ + struct drm_gem_object *obj; + struct vc4_bo *bo; + + obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt); + if (IS_ERR(obj)) + return obj; + + bo = to_vc4_bo(obj); + bo->resv = attach->dmabuf->resv; + + return obj; +} + int vc4_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -525,6 +569,88 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, return ret; } +/** + * vc4_set_tiling_ioctl() - Sets the tiling modifier for a BO. + * @dev: DRM device + * @data: ioctl argument + * @file_priv: DRM file for this fd + * + * The tiling state of the BO decides the default modifier of an fb if + * no specific modifier was set by userspace, and the return value of + * vc4_get_tiling_ioctl() (so that userspace can treat a BO it + * received from dmabuf as the same tiling format as the producer + * used). + */ +int vc4_set_tiling_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vc4_set_tiling *args = data; + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + bool t_format; + + if (args->flags != 0) + return -EINVAL; + + switch (args->modifier) { + case DRM_FORMAT_MOD_NONE: + t_format = false; + break; + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: + t_format = true; + break; + default: + return -EINVAL; + } + + gem_obj = drm_gem_object_lookup(file_priv, args->handle); + if (!gem_obj) { + DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); + return -ENOENT; + } + bo = to_vc4_bo(gem_obj); + bo->t_format = t_format; + + drm_gem_object_unreference_unlocked(gem_obj); + + return 0; +} + +/** + * vc4_get_tiling_ioctl() - Gets the tiling modifier for a BO. + * @dev: DRM device + * @data: ioctl argument + * @file_priv: DRM file for this fd + * + * Returns the tiling modifier for a BO as set by vc4_set_tiling_ioctl(). + */ +int vc4_get_tiling_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vc4_get_tiling *args = data; + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + + if (args->flags != 0 || args->modifier != 0) + return -EINVAL; + + gem_obj = drm_gem_object_lookup(file_priv, args->handle); + if (!gem_obj) { + DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); + return -ENOENT; + } + bo = to_vc4_bo(gem_obj); + + if (bo->t_format) + args->modifier = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED; + else + args->modifier = DRM_FORMAT_MOD_NONE; + + drm_gem_object_unreference_unlocked(gem_obj); + + return 0; +} + void vc4_bo_cache_init(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); |