1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2023 Loongson Technology Corporation Limited
6 #include <linux/dma-buf.h>
8 #include <drm/drm_debugfs.h>
9 #include <drm/drm_file.h>
10 #include <drm/drm_gem.h>
11 #include <drm/drm_prime.h>
17 static int lsdc_gem_prime_pin(struct drm_gem_object *obj)
19 struct lsdc_bo *lbo = gem_to_lsdc_bo(obj);
22 dma_resv_assert_held(obj->resv);
24 ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_GTT, NULL);
31 static void lsdc_gem_prime_unpin(struct drm_gem_object *obj)
33 struct lsdc_bo *lbo = gem_to_lsdc_bo(obj);
35 dma_resv_assert_held(obj->resv);
38 if (lbo->sharing_count)
42 static struct sg_table *lsdc_gem_prime_get_sg_table(struct drm_gem_object *obj)
44 struct ttm_buffer_object *tbo = to_ttm_bo(obj);
45 struct ttm_tt *tt = tbo->ttm;
48 drm_err(obj->dev, "sharing a buffer without backing memory\n");
49 return ERR_PTR(-ENOMEM);
52 return drm_prime_pages_to_sg(obj->dev, tt->pages, tt->num_pages);
55 static void lsdc_gem_object_free(struct drm_gem_object *obj)
57 struct ttm_buffer_object *tbo = to_ttm_bo(obj);
63 static int lsdc_gem_object_vmap(struct drm_gem_object *obj, struct iosys_map *map)
65 struct ttm_buffer_object *tbo = to_ttm_bo(obj);
66 struct lsdc_bo *lbo = to_lsdc_bo(tbo);
69 if (lbo->vmap_count > 0) {
74 ret = lsdc_bo_pin(lbo, 0, NULL);
76 drm_err(obj->dev, "pin %p for vmap failed\n", lbo);
80 ret = ttm_bo_vmap(tbo, &lbo->map);
82 drm_err(obj->dev, "ttm bo vmap failed\n");
95 static void lsdc_gem_object_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
97 struct ttm_buffer_object *tbo = to_ttm_bo(obj);
98 struct lsdc_bo *lbo = to_lsdc_bo(tbo);
100 if (unlikely(!lbo->vmap_count)) {
101 drm_warn(obj->dev, "%p is not mapped\n", lbo);
106 if (lbo->vmap_count == 0) {
107 ttm_bo_vunmap(tbo, &lbo->map);
113 static int lsdc_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
115 struct ttm_buffer_object *tbo = to_ttm_bo(obj);
118 ret = ttm_bo_mmap_obj(vma, tbo);
120 drm_warn(obj->dev, "mmap %p failed\n", tbo);
124 drm_gem_object_put(obj);
129 static 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,
140 struct drm_gem_object *lsdc_gem_object_create(struct drm_device *ddev,
145 struct dma_resv *resv)
147 struct lsdc_device *ldev = to_lsdc(ddev);
148 struct drm_gem_object *gobj;
152 lbo = lsdc_bo_create(ddev, domain, size, kerenl, sg, resv);
159 /* VRAM is filled with random data */
163 gobj = &lbo->tbo.base;
164 gobj->funcs = &lsdc_gem_object_funcs;
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);
174 struct drm_gem_object *
175 lsdc_prime_import_sg_table(struct drm_device *ddev,
176 struct dma_buf_attachment *attach,
179 struct dma_resv *resv = attach->dmabuf->resv;
180 u64 size = attach->dmabuf->size;
181 struct drm_gem_object *gobj;
184 dma_resv_lock(resv, NULL);
185 gobj = lsdc_gem_object_create(ddev, LSDC_GEM_DOMAIN_GTT, size, false,
187 dma_resv_unlock(resv);
190 drm_err(ddev, "Failed to import sg table\n");
194 lbo = gem_to_lsdc_bo(gobj);
195 lbo->sharing_count = 1;
200 int lsdc_dumb_create(struct drm_file *file, struct drm_device *ddev,
201 struct drm_mode_create_dumb *args)
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;
212 if (!args->width || !args->height)
215 if (args->bpp != 32 && args->bpp != 16)
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);
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);
229 gobj = lsdc_gem_object_create(ddev, domain, size, false, NULL, NULL);
231 drm_err(ddev, "Failed to create gem object\n");
232 return PTR_ERR(gobj);
235 ret = drm_gem_handle_create(file, gobj, &handle);
237 /* drop reference from allocate, handle holds it now */
238 drm_gem_object_put(gobj);
244 args->handle = handle;
249 int lsdc_dumb_map_offset(struct drm_file *filp, struct drm_device *ddev,
250 u32 handle, uint64_t *offset)
252 struct drm_gem_object *gobj;
254 gobj = drm_gem_object_lookup(filp, handle);
258 *offset = drm_vma_node_offset_addr(&gobj->vma_node);
260 drm_gem_object_put(gobj);
265 void lsdc_gem_init(struct drm_device *ddev)
267 struct lsdc_device *ldev = to_lsdc(ddev);
269 mutex_init(&ldev->gem.mutex);
270 INIT_LIST_HEAD(&ldev->gem.objects);
273 int lsdc_show_buffer_object(struct seq_file *m, void *arg)
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);
281 mutex_lock(&ldev->gem.mutex);
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;
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));
296 mutex_unlock(&ldev->gem.mutex);
298 seq_printf(m, "Pinned BO size: VRAM: %zuKiB, GTT: %zu KiB\n",
299 ldev->vram_pinned_size >> 10, ldev->gtt_pinned_size >> 10);