1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */ 3 4 #include <linux/module.h> 5 #include <linux/of_platform.h> 6 #include <linux/uaccess.h> 7 #include <linux/slab.h> 8 #include <drm/drm_ioctl.h> 9 #include <drm/drm_drv.h> 10 #include <drm/drm_prime.h> 11 #include <drm/lima_drm.h> 12 13 #include "lima_drv.h" 14 #include "lima_gem.h" 15 #include "lima_vm.h" 16 17 int lima_sched_timeout_ms; 18 19 MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms"); 20 module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); 21 22 static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) 23 { 24 struct drm_lima_get_param *args = data; 25 struct lima_device *ldev = to_lima_dev(dev); 26 27 if (args->pad) 28 return -EINVAL; 29 30 switch (args->param) { 31 case DRM_LIMA_PARAM_GPU_ID: 32 switch (ldev->id) { 33 case lima_gpu_mali400: 34 args->value = DRM_LIMA_PARAM_GPU_ID_MALI400; 35 break; 36 case lima_gpu_mali450: 37 args->value = DRM_LIMA_PARAM_GPU_ID_MALI450; 38 break; 39 default: 40 args->value = DRM_LIMA_PARAM_GPU_ID_UNKNOWN; 41 break; 42 } 43 break; 44 45 case DRM_LIMA_PARAM_NUM_PP: 46 args->value = ldev->pipe[lima_pipe_pp].num_processor; 47 break; 48 49 case DRM_LIMA_PARAM_GP_VERSION: 50 args->value = ldev->gp_version; 51 break; 52 53 case DRM_LIMA_PARAM_PP_VERSION: 54 args->value = ldev->pp_version; 55 break; 56 57 default: 58 return -EINVAL; 59 } 60 61 return 0; 62 } 63 64 static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_file *file) 65 { 66 struct drm_lima_gem_create *args = data; 67 68 if (args->pad) 69 return -EINVAL; 70 71 if (args->flags) 72 return -EINVAL; 73 74 if (args->size == 0) 75 return -EINVAL; 76 77 return lima_gem_create_handle(dev, file, args->size, args->flags, &args->handle); 78 } 79 80 static int lima_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file) 81 { 82 struct drm_lima_gem_info *args = data; 83 84 return lima_gem_get_info(file, args->handle, &args->va, &args->offset); 85 } 86 87 static int lima_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file) 88 { 89 struct drm_lima_gem_submit *args = data; 90 struct lima_device *ldev = to_lima_dev(dev); 91 struct lima_drm_priv *priv = file->driver_priv; 92 struct drm_lima_gem_submit_bo *bos; 93 struct lima_sched_pipe *pipe; 94 struct lima_sched_task *task; 95 struct lima_ctx *ctx; 96 struct lima_submit submit = {0}; 97 size_t size; 98 int err = 0; 99 100 if (args->pipe >= lima_pipe_num || args->nr_bos == 0) 101 return -EINVAL; 102 103 if (args->flags & ~(LIMA_SUBMIT_FLAG_EXPLICIT_FENCE)) 104 return -EINVAL; 105 106 pipe = ldev->pipe + args->pipe; 107 if (args->frame_size != pipe->frame_size) 108 return -EINVAL; 109 110 bos = kvcalloc(args->nr_bos, sizeof(*submit.bos) + sizeof(*submit.lbos), GFP_KERNEL); 111 if (!bos) 112 return -ENOMEM; 113 114 size = args->nr_bos * sizeof(*submit.bos); 115 if (copy_from_user(bos, u64_to_user_ptr(args->bos), size)) { 116 err = -EFAULT; 117 goto out0; 118 } 119 120 task = kmem_cache_zalloc(pipe->task_slab, GFP_KERNEL); 121 if (!task) { 122 err = -ENOMEM; 123 goto out0; 124 } 125 126 task->frame = task + 1; 127 if (copy_from_user(task->frame, u64_to_user_ptr(args->frame), args->frame_size)) { 128 err = -EFAULT; 129 goto out1; 130 } 131 132 err = pipe->task_validate(pipe, task); 133 if (err) 134 goto out1; 135 136 ctx = lima_ctx_get(&priv->ctx_mgr, args->ctx); 137 if (!ctx) { 138 err = -ENOENT; 139 goto out1; 140 } 141 142 submit.pipe = args->pipe; 143 submit.bos = bos; 144 submit.lbos = (void *)bos + size; 145 submit.nr_bos = args->nr_bos; 146 submit.task = task; 147 submit.ctx = ctx; 148 submit.flags = args->flags; 149 submit.in_sync[0] = args->in_sync[0]; 150 submit.in_sync[1] = args->in_sync[1]; 151 submit.out_sync = args->out_sync; 152 153 err = lima_gem_submit(file, &submit); 154 155 lima_ctx_put(ctx); 156 out1: 157 if (err) 158 kmem_cache_free(pipe->task_slab, task); 159 out0: 160 kvfree(bos); 161 return err; 162 } 163 164 static int lima_ioctl_gem_wait(struct drm_device *dev, void *data, struct drm_file *file) 165 { 166 struct drm_lima_gem_wait *args = data; 167 168 if (args->op & ~(LIMA_GEM_WAIT_READ|LIMA_GEM_WAIT_WRITE)) 169 return -EINVAL; 170 171 return lima_gem_wait(file, args->handle, args->op, args->timeout_ns); 172 } 173 174 static int lima_ioctl_ctx_create(struct drm_device *dev, void *data, struct drm_file *file) 175 { 176 struct drm_lima_ctx_create *args = data; 177 struct lima_drm_priv *priv = file->driver_priv; 178 struct lima_device *ldev = to_lima_dev(dev); 179 180 if (args->_pad) 181 return -EINVAL; 182 183 return lima_ctx_create(ldev, &priv->ctx_mgr, &args->id); 184 } 185 186 static int lima_ioctl_ctx_free(struct drm_device *dev, void *data, struct drm_file *file) 187 { 188 struct drm_lima_ctx_create *args = data; 189 struct lima_drm_priv *priv = file->driver_priv; 190 191 if (args->_pad) 192 return -EINVAL; 193 194 return lima_ctx_free(&priv->ctx_mgr, args->id); 195 } 196 197 static int lima_drm_driver_open(struct drm_device *dev, struct drm_file *file) 198 { 199 int err; 200 struct lima_drm_priv *priv; 201 struct lima_device *ldev = to_lima_dev(dev); 202 203 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 204 if (!priv) 205 return -ENOMEM; 206 207 priv->vm = lima_vm_create(ldev); 208 if (!priv->vm) { 209 err = -ENOMEM; 210 goto err_out0; 211 } 212 213 lima_ctx_mgr_init(&priv->ctx_mgr); 214 215 file->driver_priv = priv; 216 return 0; 217 218 err_out0: 219 kfree(priv); 220 return err; 221 } 222 223 static void lima_drm_driver_postclose(struct drm_device *dev, struct drm_file *file) 224 { 225 struct lima_drm_priv *priv = file->driver_priv; 226 227 lima_ctx_mgr_fini(&priv->ctx_mgr); 228 lima_vm_put(priv->vm); 229 kfree(priv); 230 } 231 232 static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = { 233 DRM_IOCTL_DEF_DRV(LIMA_GET_PARAM, lima_ioctl_get_param, DRM_RENDER_ALLOW), 234 DRM_IOCTL_DEF_DRV(LIMA_GEM_CREATE, lima_ioctl_gem_create, DRM_RENDER_ALLOW), 235 DRM_IOCTL_DEF_DRV(LIMA_GEM_INFO, lima_ioctl_gem_info, DRM_RENDER_ALLOW), 236 DRM_IOCTL_DEF_DRV(LIMA_GEM_SUBMIT, lima_ioctl_gem_submit, DRM_RENDER_ALLOW), 237 DRM_IOCTL_DEF_DRV(LIMA_GEM_WAIT, lima_ioctl_gem_wait, DRM_RENDER_ALLOW), 238 DRM_IOCTL_DEF_DRV(LIMA_CTX_CREATE, lima_ioctl_ctx_create, DRM_RENDER_ALLOW), 239 DRM_IOCTL_DEF_DRV(LIMA_CTX_FREE, lima_ioctl_ctx_free, DRM_RENDER_ALLOW), 240 }; 241 242 DEFINE_DRM_GEM_FOPS(lima_drm_driver_fops); 243 244 static struct drm_driver lima_drm_driver = { 245 .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, 246 .open = lima_drm_driver_open, 247 .postclose = lima_drm_driver_postclose, 248 .ioctls = lima_drm_driver_ioctls, 249 .num_ioctls = ARRAY_SIZE(lima_drm_driver_ioctls), 250 .fops = &lima_drm_driver_fops, 251 .name = "lima", 252 .desc = "lima DRM", 253 .date = "20190217", 254 .major = 1, 255 .minor = 0, 256 .patchlevel = 0, 257 258 .gem_create_object = lima_gem_create_object, 259 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 260 .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, 261 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 262 .gem_prime_mmap = drm_gem_prime_mmap, 263 }; 264 265 static int lima_pdev_probe(struct platform_device *pdev) 266 { 267 struct lima_device *ldev; 268 struct drm_device *ddev; 269 int err; 270 271 err = lima_sched_slab_init(); 272 if (err) 273 return err; 274 275 ldev = devm_kzalloc(&pdev->dev, sizeof(*ldev), GFP_KERNEL); 276 if (!ldev) { 277 err = -ENOMEM; 278 goto err_out0; 279 } 280 281 ldev->pdev = pdev; 282 ldev->dev = &pdev->dev; 283 ldev->id = (enum lima_gpu_id)of_device_get_match_data(&pdev->dev); 284 285 platform_set_drvdata(pdev, ldev); 286 287 /* Allocate and initialize the DRM device. */ 288 ddev = drm_dev_alloc(&lima_drm_driver, &pdev->dev); 289 if (IS_ERR(ddev)) 290 return PTR_ERR(ddev); 291 292 ddev->dev_private = ldev; 293 ldev->ddev = ddev; 294 295 err = lima_device_init(ldev); 296 if (err) 297 goto err_out1; 298 299 /* 300 * Register the DRM device with the core and the connectors with 301 * sysfs. 302 */ 303 err = drm_dev_register(ddev, 0); 304 if (err < 0) 305 goto err_out2; 306 307 return 0; 308 309 err_out2: 310 lima_device_fini(ldev); 311 err_out1: 312 drm_dev_put(ddev); 313 err_out0: 314 lima_sched_slab_fini(); 315 return err; 316 } 317 318 static int lima_pdev_remove(struct platform_device *pdev) 319 { 320 struct lima_device *ldev = platform_get_drvdata(pdev); 321 struct drm_device *ddev = ldev->ddev; 322 323 drm_dev_unregister(ddev); 324 lima_device_fini(ldev); 325 drm_dev_put(ddev); 326 lima_sched_slab_fini(); 327 return 0; 328 } 329 330 static const struct of_device_id dt_match[] = { 331 { .compatible = "arm,mali-400", .data = (void *)lima_gpu_mali400 }, 332 { .compatible = "arm,mali-450", .data = (void *)lima_gpu_mali450 }, 333 {} 334 }; 335 MODULE_DEVICE_TABLE(of, dt_match); 336 337 static struct platform_driver lima_platform_driver = { 338 .probe = lima_pdev_probe, 339 .remove = lima_pdev_remove, 340 .driver = { 341 .name = "lima", 342 .of_match_table = dt_match, 343 }, 344 }; 345 346 static int __init lima_init(void) 347 { 348 return platform_driver_register(&lima_platform_driver); 349 } 350 module_init(lima_init); 351 352 static void __exit lima_exit(void) 353 { 354 platform_driver_unregister(&lima_platform_driver); 355 } 356 module_exit(lima_exit); 357 358 MODULE_AUTHOR("Lima Project Developers"); 359 MODULE_DESCRIPTION("Lima DRM Driver"); 360 MODULE_LICENSE("GPL v2"); 361