Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) 2023 Loongson Technology Corporation Limited
  4 */
  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}