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 17 static 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 31 static 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 42 static 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 55 static 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 63 static 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 89 out: 90 *map = lbo->map; 91 92 return 0; 93 } 94 95 static 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 113 static 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 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, 138 }; 139 140 struct 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 174 struct drm_gem_object * 175 lsdc_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 200 int 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 249 int 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 265 void 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 273 int 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