303 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2023 Loongson Technology Corporation Limited4 */5 6#include <linux/dma-buf.h>7 8#include <drm/drm_debugfs.h>9#include <drm/drm_file.h>10#include <drm/drm_gem.h>11#include <drm/drm_prime.h>12 13#include "lsdc_drv.h"14#include "lsdc_gem.h"15#include "lsdc_ttm.h"16 17static int lsdc_gem_prime_pin(struct drm_gem_object *obj)18{19 struct lsdc_bo *lbo = gem_to_lsdc_bo(obj);20 int ret;21 22 dma_resv_assert_held(obj->resv);23 24 ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_GTT, NULL);25 if (likely(ret == 0))26 lbo->sharing_count++;27 28 return ret;29}30 31static void lsdc_gem_prime_unpin(struct drm_gem_object *obj)32{33 struct lsdc_bo *lbo = gem_to_lsdc_bo(obj);34 35 dma_resv_assert_held(obj->resv);36 37 lsdc_bo_unpin(lbo);38 if (lbo->sharing_count)39 lbo->sharing_count--;40}41 42static struct sg_table *lsdc_gem_prime_get_sg_table(struct drm_gem_object *obj)43{44 struct ttm_buffer_object *tbo = to_ttm_bo(obj);45 struct ttm_tt *tt = tbo->ttm;46 47 if (!tt) {48 drm_err(obj->dev, "sharing a buffer without backing memory\n");49 return ERR_PTR(-ENOMEM);50 }51 52 return drm_prime_pages_to_sg(obj->dev, tt->pages, tt->num_pages);53}54 55static void lsdc_gem_object_free(struct drm_gem_object *obj)56{57 struct ttm_buffer_object *tbo = to_ttm_bo(obj);58 59 if (tbo)60 ttm_bo_put(tbo);61}62 63static int lsdc_gem_object_vmap(struct drm_gem_object *obj, struct iosys_map *map)64{65 struct ttm_buffer_object *tbo = to_ttm_bo(obj);66 struct lsdc_bo *lbo = to_lsdc_bo(tbo);67 int ret;68 69 if (lbo->vmap_count > 0) {70 ++lbo->vmap_count;71 goto out;72 }73 74 ret = lsdc_bo_pin(lbo, 0, NULL);75 if (unlikely(ret)) {76 drm_err(obj->dev, "pin %p for vmap failed\n", lbo);77 return ret;78 }79 80 ret = ttm_bo_vmap(tbo, &lbo->map);81 if (ret) {82 drm_err(obj->dev, "ttm bo vmap failed\n");83 lsdc_bo_unpin(lbo);84 return ret;85 }86 87 lbo->vmap_count = 1;88 89out:90 *map = lbo->map;91 92 return 0;93}94 95static void lsdc_gem_object_vunmap(struct drm_gem_object *obj, struct iosys_map *map)96{97 struct ttm_buffer_object *tbo = to_ttm_bo(obj);98 struct lsdc_bo *lbo = to_lsdc_bo(tbo);99 100 if (unlikely(!lbo->vmap_count)) {101 drm_warn(obj->dev, "%p is not mapped\n", lbo);102 return;103 }104 105 --lbo->vmap_count;106 if (lbo->vmap_count == 0) {107 ttm_bo_vunmap(tbo, &lbo->map);108 109 lsdc_bo_unpin(lbo);110 }111}112 113static int lsdc_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)114{115 struct ttm_buffer_object *tbo = to_ttm_bo(obj);116 int ret;117 118 ret = ttm_bo_mmap_obj(vma, tbo);119 if (unlikely(ret)) {120 drm_warn(obj->dev, "mmap %p failed\n", tbo);121 return ret;122 }123 124 drm_gem_object_put(obj);125 126 return 0;127}128 129static const struct drm_gem_object_funcs lsdc_gem_object_funcs = {130 .free = lsdc_gem_object_free,131 .export = drm_gem_prime_export,132 .pin = lsdc_gem_prime_pin,133 .unpin = lsdc_gem_prime_unpin,134 .get_sg_table = lsdc_gem_prime_get_sg_table,135 .vmap = lsdc_gem_object_vmap,136 .vunmap = lsdc_gem_object_vunmap,137 .mmap = lsdc_gem_object_mmap,138};139 140struct drm_gem_object *lsdc_gem_object_create(struct drm_device *ddev,141 u32 domain,142 size_t size,143 bool kerenl,144 struct sg_table *sg,145 struct dma_resv *resv)146{147 struct lsdc_device *ldev = to_lsdc(ddev);148 struct drm_gem_object *gobj;149 struct lsdc_bo *lbo;150 int ret;151 152 lbo = lsdc_bo_create(ddev, domain, size, kerenl, sg, resv);153 if (IS_ERR(lbo)) {154 ret = PTR_ERR(lbo);155 return ERR_PTR(ret);156 }157 158 if (!sg) {159 /* VRAM is filled with random data */160 lsdc_bo_clear(lbo);161 }162 163 gobj = &lbo->tbo.base;164 gobj->funcs = &lsdc_gem_object_funcs;165 166 /* tracking the BOs we created */167 mutex_lock(&ldev->gem.mutex);168 list_add_tail(&lbo->list, &ldev->gem.objects);169 mutex_unlock(&ldev->gem.mutex);170 171 return gobj;172}173 174struct drm_gem_object *175lsdc_prime_import_sg_table(struct drm_device *ddev,176 struct dma_buf_attachment *attach,177 struct sg_table *sg)178{179 struct dma_resv *resv = attach->dmabuf->resv;180 u64 size = attach->dmabuf->size;181 struct drm_gem_object *gobj;182 struct lsdc_bo *lbo;183 184 dma_resv_lock(resv, NULL);185 gobj = lsdc_gem_object_create(ddev, LSDC_GEM_DOMAIN_GTT, size, false,186 sg, resv);187 dma_resv_unlock(resv);188 189 if (IS_ERR(gobj)) {190 drm_err(ddev, "Failed to import sg table\n");191 return gobj;192 }193 194 lbo = gem_to_lsdc_bo(gobj);195 lbo->sharing_count = 1;196 197 return gobj;198}199 200int lsdc_dumb_create(struct drm_file *file, struct drm_device *ddev,201 struct drm_mode_create_dumb *args)202{203 struct lsdc_device *ldev = to_lsdc(ddev);204 const struct lsdc_desc *descp = ldev->descp;205 u32 domain = LSDC_GEM_DOMAIN_VRAM;206 struct drm_gem_object *gobj;207 size_t size;208 u32 pitch;209 u32 handle;210 int ret;211 212 if (!args->width || !args->height)213 return -EINVAL;214 215 if (args->bpp != 32 && args->bpp != 16)216 return -EINVAL;217 218 pitch = args->width * args->bpp / 8;219 pitch = ALIGN(pitch, descp->pitch_align);220 size = pitch * args->height;221 size = ALIGN(size, PAGE_SIZE);222 223 /* Maximum single bo size allowed is the half vram size available */224 if (size > ldev->vram_size / 2) {225 drm_err(ddev, "Requesting(%zuMiB) failed\n", size >> 20);226 return -ENOMEM;227 }228 229 gobj = lsdc_gem_object_create(ddev, domain, size, false, NULL, NULL);230 if (IS_ERR(gobj)) {231 drm_err(ddev, "Failed to create gem object\n");232 return PTR_ERR(gobj);233 }234 235 ret = drm_gem_handle_create(file, gobj, &handle);236 237 /* drop reference from allocate, handle holds it now */238 drm_gem_object_put(gobj);239 if (ret)240 return ret;241 242 args->pitch = pitch;243 args->size = size;244 args->handle = handle;245 246 return 0;247}248 249int lsdc_dumb_map_offset(struct drm_file *filp, struct drm_device *ddev,250 u32 handle, uint64_t *offset)251{252 struct drm_gem_object *gobj;253 254 gobj = drm_gem_object_lookup(filp, handle);255 if (!gobj)256 return -ENOENT;257 258 *offset = drm_vma_node_offset_addr(&gobj->vma_node);259 260 drm_gem_object_put(gobj);261 262 return 0;263}264 265void lsdc_gem_init(struct drm_device *ddev)266{267 struct lsdc_device *ldev = to_lsdc(ddev);268 269 mutex_init(&ldev->gem.mutex);270 INIT_LIST_HEAD(&ldev->gem.objects);271}272 273int lsdc_show_buffer_object(struct seq_file *m, void *arg)274{275 struct drm_info_node *node = (struct drm_info_node *)m->private;276 struct drm_device *ddev = node->minor->dev;277 struct lsdc_device *ldev = to_lsdc(ddev);278 struct lsdc_bo *lbo;279 unsigned int i;280 281 mutex_lock(&ldev->gem.mutex);282 283 i = 0;284 285 list_for_each_entry(lbo, &ldev->gem.objects, list) {286 struct ttm_buffer_object *tbo = &lbo->tbo;287 struct ttm_resource *resource = tbo->resource;288 289 seq_printf(m, "bo[%04u][%p]: size: %8zuKiB %s offset: %8llx\n",290 i, lbo, lsdc_bo_size(lbo) >> 10,291 lsdc_mem_type_to_str(resource->mem_type),292 lsdc_bo_gpu_offset(lbo));293 i++;294 }295 296 mutex_unlock(&ldev->gem.mutex);297 298 seq_printf(m, "Pinned BO size: VRAM: %zuKiB, GTT: %zu KiB\n",299 ldev->vram_pinned_size >> 10, ldev->gtt_pinned_size >> 10);300 301 return 0;302}303