diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_gem.c')
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gem.c | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 07d8cdd6bb2e..017411a0bf45 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -10,8 +10,10 @@ #include <linux/shmem_fs.h> #include <linux/dma-buf.h> +#include <drm/drm_dumb_buffers.h> #include <drm/drm_prime.h> #include <drm/drm_file.h> +#include <drm/drm_fourcc.h> #include <trace/events/gpu_mem.h> @@ -698,8 +700,32 @@ void msm_gem_unpin_iova(struct drm_gem_object *obj, struct drm_gpuvm *vm) int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - args->pitch = align_pitch(args->width, args->bpp); - args->size = PAGE_ALIGN(args->pitch * args->height); + u32 fourcc; + u64 pitch_align; + int ret; + + /* + * Adreno needs pitch aligned to 32 pixels. Compute the number + * of bytes for a block of 32 pixels at the given color format. + * Use the result as pitch alignment. + */ + fourcc = drm_driver_color_mode_format(dev, args->bpp); + if (fourcc != DRM_FORMAT_INVALID) { + const struct drm_format_info *info; + + info = drm_format_info(fourcc); + if (!info) + return -EINVAL; + pitch_align = drm_format_info_min_pitch(info, 0, 32); + } else { + pitch_align = round_up(args->width, 32) * DIV_ROUND_UP(args->bpp, SZ_8); + } + if (!pitch_align || pitch_align > U32_MAX) + return -EINVAL; + ret = drm_mode_size_dumb(dev, args, pitch_align, 0); + if (ret) + return ret; + return msm_gem_new_handle(dev, file, args->size, MSM_BO_SCANOUT | MSM_BO_WC, &args->handle, "dumb"); } @@ -1120,12 +1146,16 @@ static void msm_gem_free_object(struct drm_gem_object *obj) put_pages(obj); } - if (obj->resv != &obj->_resv) { + /* + * In error paths, we could end up here before msm_gem_new_handle() + * has changed obj->resv to point to the shared resv. In this case, + * we don't want to drop a ref to the shared r_obj that we haven't + * taken yet. + */ + if ((msm_obj->flags & MSM_BO_NO_SHARE) && (obj->resv != &obj->_resv)) { struct drm_gem_object *r_obj = container_of(obj->resv, struct drm_gem_object, _resv); - WARN_ON(!(msm_obj->flags & MSM_BO_NO_SHARE)); - /* Drop reference we hold to shared resv obj: */ drm_gem_object_put(r_obj); } |
