1f6ffbd4fSLucas Stach // SPDX-License-Identifier: GPL-2.0 2a8c21a54SThe etnaviv authors /* 3f6ffbd4fSLucas Stach * Copyright (C) 2015-2018 Etnaviv Project 4a8c21a54SThe etnaviv authors */ 5a8c21a54SThe etnaviv authors 6a8c21a54SThe etnaviv authors #include <linux/component.h> 76eae41feSSam Ravnborg #include <linux/dma-mapping.h> 82e737e52SLucas Stach #include <linux/module.h> 9a8c21a54SThe etnaviv authors #include <linux/of_platform.h> 106eae41feSSam Ravnborg #include <linux/uaccess.h> 116eae41feSSam Ravnborg 126eae41feSSam Ravnborg #include <drm/drm_debugfs.h> 136eae41feSSam Ravnborg #include <drm/drm_drv.h> 146eae41feSSam Ravnborg #include <drm/drm_file.h> 156eae41feSSam Ravnborg #include <drm/drm_ioctl.h> 1697ac0e47SRussell King #include <drm/drm_of.h> 176eae41feSSam Ravnborg #include <drm/drm_prime.h> 18a8c21a54SThe etnaviv authors 19ea1f5729SLucas Stach #include "etnaviv_cmdbuf.h" 20a8c21a54SThe etnaviv authors #include "etnaviv_drv.h" 21a8c21a54SThe etnaviv authors #include "etnaviv_gpu.h" 22a8c21a54SThe etnaviv authors #include "etnaviv_gem.h" 23a8c21a54SThe etnaviv authors #include "etnaviv_mmu.h" 249e2c2e27SChristian Gmeiner #include "etnaviv_perfmon.h" 25a8c21a54SThe etnaviv authors 26a8c21a54SThe etnaviv authors /* 27a8c21a54SThe etnaviv authors * DRM operations: 28a8c21a54SThe etnaviv authors */ 29a8c21a54SThe etnaviv authors 30a8c21a54SThe etnaviv authors 31a8c21a54SThe etnaviv authors static void load_gpu(struct drm_device *dev) 32a8c21a54SThe etnaviv authors { 33a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 34a8c21a54SThe etnaviv authors unsigned int i; 35a8c21a54SThe etnaviv authors 36a8c21a54SThe etnaviv authors for (i = 0; i < ETNA_MAX_PIPES; i++) { 37a8c21a54SThe etnaviv authors struct etnaviv_gpu *g = priv->gpu[i]; 38a8c21a54SThe etnaviv authors 39a8c21a54SThe etnaviv authors if (g) { 40a8c21a54SThe etnaviv authors int ret; 41a8c21a54SThe etnaviv authors 42a8c21a54SThe etnaviv authors ret = etnaviv_gpu_init(g); 43c1c77b0eSLucas Stach if (ret) 44a8c21a54SThe etnaviv authors priv->gpu[i] = NULL; 45a8c21a54SThe etnaviv authors } 46a8c21a54SThe etnaviv authors } 47a8c21a54SThe etnaviv authors } 48a8c21a54SThe etnaviv authors 49a8c21a54SThe etnaviv authors static int etnaviv_open(struct drm_device *dev, struct drm_file *file) 50a8c21a54SThe etnaviv authors { 51e93b6deeSLucas Stach struct etnaviv_drm_private *priv = dev->dev_private; 52a8c21a54SThe etnaviv authors struct etnaviv_file_private *ctx; 5317e4660aSLucas Stach int ret, i; 54a8c21a54SThe etnaviv authors 55a8c21a54SThe etnaviv authors ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 56a8c21a54SThe etnaviv authors if (!ctx) 57a8c21a54SThe etnaviv authors return -ENOMEM; 58a8c21a54SThe etnaviv authors 5917e4660aSLucas Stach ctx->mmu = etnaviv_iommu_context_init(priv->mmu_global, 6017e4660aSLucas Stach priv->cmdbuf_suballoc); 6117e4660aSLucas Stach if (!ctx->mmu) { 6217e4660aSLucas Stach ret = -ENOMEM; 6317e4660aSLucas Stach goto out_free; 6417e4660aSLucas Stach } 6517e4660aSLucas Stach 66e93b6deeSLucas Stach for (i = 0; i < ETNA_MAX_PIPES; i++) { 67e93b6deeSLucas Stach struct etnaviv_gpu *gpu = priv->gpu[i]; 68b3ac1766SNirmoy Das struct drm_gpu_scheduler *sched; 69e93b6deeSLucas Stach 70e93b6deeSLucas Stach if (gpu) { 71b3ac1766SNirmoy Das sched = &gpu->sched; 72aa16b6c6SNayan Deshmukh drm_sched_entity_init(&ctx->sched_entity[i], 73b3ac1766SNirmoy Das DRM_SCHED_PRIORITY_NORMAL, &sched, 74b3ac1766SNirmoy Das 1, NULL); 75e93b6deeSLucas Stach } 76e93b6deeSLucas Stach } 77e93b6deeSLucas Stach 78a8c21a54SThe etnaviv authors file->driver_priv = ctx; 79a8c21a54SThe etnaviv authors 80a8c21a54SThe etnaviv authors return 0; 8117e4660aSLucas Stach 8217e4660aSLucas Stach out_free: 8317e4660aSLucas Stach kfree(ctx); 8417e4660aSLucas Stach return ret; 85a8c21a54SThe etnaviv authors } 86a8c21a54SThe etnaviv authors 87fda8fa5bSDaniel Vetter static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) 88a8c21a54SThe etnaviv authors { 89a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 90a8c21a54SThe etnaviv authors struct etnaviv_file_private *ctx = file->driver_priv; 91a8c21a54SThe etnaviv authors unsigned int i; 92a8c21a54SThe etnaviv authors 93a8c21a54SThe etnaviv authors for (i = 0; i < ETNA_MAX_PIPES; i++) { 94a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu = priv->gpu[i]; 95a8c21a54SThe etnaviv authors 96801c7a1eSLucas Stach if (gpu) 97cdc50176SNayan Deshmukh drm_sched_entity_destroy(&ctx->sched_entity[i]); 98a8c21a54SThe etnaviv authors } 99a8c21a54SThe etnaviv authors 10017e4660aSLucas Stach etnaviv_iommu_context_put(ctx->mmu); 10117e4660aSLucas Stach 102a8c21a54SThe etnaviv authors kfree(ctx); 103a8c21a54SThe etnaviv authors } 104a8c21a54SThe etnaviv authors 105a8c21a54SThe etnaviv authors /* 106a8c21a54SThe etnaviv authors * DRM debugfs: 107a8c21a54SThe etnaviv authors */ 108a8c21a54SThe etnaviv authors 109a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS 110a8c21a54SThe etnaviv authors static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m) 111a8c21a54SThe etnaviv authors { 112a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 113a8c21a54SThe etnaviv authors 114a8c21a54SThe etnaviv authors etnaviv_gem_describe_objects(priv, m); 115a8c21a54SThe etnaviv authors 116a8c21a54SThe etnaviv authors return 0; 117a8c21a54SThe etnaviv authors } 118a8c21a54SThe etnaviv authors 119a8c21a54SThe etnaviv authors static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m) 120a8c21a54SThe etnaviv authors { 121b5c3714fSDaniel Vetter struct drm_printer p = drm_seq_file_printer(m); 122a8c21a54SThe etnaviv authors 123a8c21a54SThe etnaviv authors read_lock(&dev->vma_offset_manager->vm_lock); 124b5c3714fSDaniel Vetter drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p); 125a8c21a54SThe etnaviv authors read_unlock(&dev->vma_offset_manager->vm_lock); 126a8c21a54SThe etnaviv authors 127b5c3714fSDaniel Vetter return 0; 128a8c21a54SThe etnaviv authors } 129a8c21a54SThe etnaviv authors 130a8c21a54SThe etnaviv authors static int etnaviv_mmu_show(struct etnaviv_gpu *gpu, struct seq_file *m) 131a8c21a54SThe etnaviv authors { 132b5c3714fSDaniel Vetter struct drm_printer p = drm_seq_file_printer(m); 13317e4660aSLucas Stach struct etnaviv_iommu_context *mmu_context; 134b5c3714fSDaniel Vetter 135a8c21a54SThe etnaviv authors seq_printf(m, "Active Objects (%s):\n", dev_name(gpu->dev)); 136a8c21a54SThe etnaviv authors 13717e4660aSLucas Stach /* 13817e4660aSLucas Stach * Lock the GPU to avoid a MMU context switch just now and elevate 13917e4660aSLucas Stach * the refcount of the current context to avoid it disappearing from 14017e4660aSLucas Stach * under our feet. 14117e4660aSLucas Stach */ 14217e4660aSLucas Stach mutex_lock(&gpu->lock); 14317e4660aSLucas Stach mmu_context = gpu->mmu_context; 14417e4660aSLucas Stach if (mmu_context) 14517e4660aSLucas Stach etnaviv_iommu_context_get(mmu_context); 14617e4660aSLucas Stach mutex_unlock(&gpu->lock); 14717e4660aSLucas Stach 14817e4660aSLucas Stach if (!mmu_context) 14917e4660aSLucas Stach return 0; 15017e4660aSLucas Stach 15117e4660aSLucas Stach mutex_lock(&mmu_context->lock); 15217e4660aSLucas Stach drm_mm_print(&mmu_context->mm, &p); 15317e4660aSLucas Stach mutex_unlock(&mmu_context->lock); 15417e4660aSLucas Stach 15517e4660aSLucas Stach etnaviv_iommu_context_put(mmu_context); 156a8c21a54SThe etnaviv authors 157a8c21a54SThe etnaviv authors return 0; 158a8c21a54SThe etnaviv authors } 159a8c21a54SThe etnaviv authors 160a8c21a54SThe etnaviv authors static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m) 161a8c21a54SThe etnaviv authors { 1622f9225dbSLucas Stach struct etnaviv_cmdbuf *buf = &gpu->buffer; 163a8c21a54SThe etnaviv authors u32 size = buf->size; 164a8c21a54SThe etnaviv authors u32 *ptr = buf->vaddr; 165a8c21a54SThe etnaviv authors u32 i; 166a8c21a54SThe etnaviv authors 167a8c21a54SThe etnaviv authors seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n", 1689912b4dbSLucas Stach buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf), 1699912b4dbSLucas Stach size - buf->user_size); 170a8c21a54SThe etnaviv authors 171a8c21a54SThe etnaviv authors for (i = 0; i < size / 4; i++) { 172a8c21a54SThe etnaviv authors if (i && !(i % 4)) 173a8c21a54SThe etnaviv authors seq_puts(m, "\n"); 174a8c21a54SThe etnaviv authors if (i % 4 == 0) 175a8c21a54SThe etnaviv authors seq_printf(m, "\t0x%p: ", ptr + i); 176a8c21a54SThe etnaviv authors seq_printf(m, "%08x ", *(ptr + i)); 177a8c21a54SThe etnaviv authors } 178a8c21a54SThe etnaviv authors seq_puts(m, "\n"); 179a8c21a54SThe etnaviv authors } 180a8c21a54SThe etnaviv authors 181a8c21a54SThe etnaviv authors static int etnaviv_ring_show(struct etnaviv_gpu *gpu, struct seq_file *m) 182a8c21a54SThe etnaviv authors { 183a8c21a54SThe etnaviv authors seq_printf(m, "Ring Buffer (%s): ", dev_name(gpu->dev)); 184a8c21a54SThe etnaviv authors 185a8c21a54SThe etnaviv authors mutex_lock(&gpu->lock); 186a8c21a54SThe etnaviv authors etnaviv_buffer_dump(gpu, m); 187a8c21a54SThe etnaviv authors mutex_unlock(&gpu->lock); 188a8c21a54SThe etnaviv authors 189a8c21a54SThe etnaviv authors return 0; 190a8c21a54SThe etnaviv authors } 191a8c21a54SThe etnaviv authors 192a8c21a54SThe etnaviv authors static int show_unlocked(struct seq_file *m, void *arg) 193a8c21a54SThe etnaviv authors { 194a8c21a54SThe etnaviv authors struct drm_info_node *node = (struct drm_info_node *) m->private; 195a8c21a54SThe etnaviv authors struct drm_device *dev = node->minor->dev; 196a8c21a54SThe etnaviv authors int (*show)(struct drm_device *dev, struct seq_file *m) = 197a8c21a54SThe etnaviv authors node->info_ent->data; 198a8c21a54SThe etnaviv authors 199a8c21a54SThe etnaviv authors return show(dev, m); 200a8c21a54SThe etnaviv authors } 201a8c21a54SThe etnaviv authors 202a8c21a54SThe etnaviv authors static int show_each_gpu(struct seq_file *m, void *arg) 203a8c21a54SThe etnaviv authors { 204a8c21a54SThe etnaviv authors struct drm_info_node *node = (struct drm_info_node *) m->private; 205a8c21a54SThe etnaviv authors struct drm_device *dev = node->minor->dev; 206a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 207a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 208a8c21a54SThe etnaviv authors int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) = 209a8c21a54SThe etnaviv authors node->info_ent->data; 210a8c21a54SThe etnaviv authors unsigned int i; 211a8c21a54SThe etnaviv authors int ret = 0; 212a8c21a54SThe etnaviv authors 213a8c21a54SThe etnaviv authors for (i = 0; i < ETNA_MAX_PIPES; i++) { 214a8c21a54SThe etnaviv authors gpu = priv->gpu[i]; 215a8c21a54SThe etnaviv authors if (!gpu) 216a8c21a54SThe etnaviv authors continue; 217a8c21a54SThe etnaviv authors 218a8c21a54SThe etnaviv authors ret = show(gpu, m); 219a8c21a54SThe etnaviv authors if (ret < 0) 220a8c21a54SThe etnaviv authors break; 221a8c21a54SThe etnaviv authors } 222a8c21a54SThe etnaviv authors 223a8c21a54SThe etnaviv authors return ret; 224a8c21a54SThe etnaviv authors } 225a8c21a54SThe etnaviv authors 226a8c21a54SThe etnaviv authors static struct drm_info_list etnaviv_debugfs_list[] = { 227a8c21a54SThe etnaviv authors {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs}, 228a8c21a54SThe etnaviv authors {"gem", show_unlocked, 0, etnaviv_gem_show}, 229a8c21a54SThe etnaviv authors { "mm", show_unlocked, 0, etnaviv_mm_show }, 230a8c21a54SThe etnaviv authors {"mmu", show_each_gpu, 0, etnaviv_mmu_show}, 231a8c21a54SThe etnaviv authors {"ring", show_each_gpu, 0, etnaviv_ring_show}, 232a8c21a54SThe etnaviv authors }; 233a8c21a54SThe etnaviv authors 2347ce84471SWambui Karuga static void etnaviv_debugfs_init(struct drm_minor *minor) 235a8c21a54SThe etnaviv authors { 23614b46195SWambui Karuga drm_debugfs_create_files(etnaviv_debugfs_list, 237a8c21a54SThe etnaviv authors ARRAY_SIZE(etnaviv_debugfs_list), 238a8c21a54SThe etnaviv authors minor->debugfs_root, minor); 239a8c21a54SThe etnaviv authors } 240a8c21a54SThe etnaviv authors #endif 241a8c21a54SThe etnaviv authors 242a8c21a54SThe etnaviv authors /* 243a8c21a54SThe etnaviv authors * DRM ioctls: 244a8c21a54SThe etnaviv authors */ 245a8c21a54SThe etnaviv authors 246a8c21a54SThe etnaviv authors static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data, 247a8c21a54SThe etnaviv authors struct drm_file *file) 248a8c21a54SThe etnaviv authors { 249a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 250a8c21a54SThe etnaviv authors struct drm_etnaviv_param *args = data; 251a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 252a8c21a54SThe etnaviv authors 253a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 254a8c21a54SThe etnaviv authors return -EINVAL; 255a8c21a54SThe etnaviv authors 256a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 257a8c21a54SThe etnaviv authors if (!gpu) 258a8c21a54SThe etnaviv authors return -ENXIO; 259a8c21a54SThe etnaviv authors 260a8c21a54SThe etnaviv authors return etnaviv_gpu_get_param(gpu, args->param, &args->value); 261a8c21a54SThe etnaviv authors } 262a8c21a54SThe etnaviv authors 263a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data, 264a8c21a54SThe etnaviv authors struct drm_file *file) 265a8c21a54SThe etnaviv authors { 266a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_new *args = data; 267a8c21a54SThe etnaviv authors 268a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED | 269a8c21a54SThe etnaviv authors ETNA_BO_FORCE_MMU)) 270a8c21a54SThe etnaviv authors return -EINVAL; 271a8c21a54SThe etnaviv authors 272a8c21a54SThe etnaviv authors return etnaviv_gem_new_handle(dev, file, args->size, 273a8c21a54SThe etnaviv authors args->flags, &args->handle); 274a8c21a54SThe etnaviv authors } 275a8c21a54SThe etnaviv authors 276a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, 277a8c21a54SThe etnaviv authors struct drm_file *file) 278a8c21a54SThe etnaviv authors { 279a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_cpu_prep *args = data; 280a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 281a8c21a54SThe etnaviv authors int ret; 282a8c21a54SThe etnaviv authors 283a8c21a54SThe etnaviv authors if (args->op & ~(ETNA_PREP_READ | ETNA_PREP_WRITE | ETNA_PREP_NOSYNC)) 284a8c21a54SThe etnaviv authors return -EINVAL; 285a8c21a54SThe etnaviv authors 286a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 287a8c21a54SThe etnaviv authors if (!obj) 288a8c21a54SThe etnaviv authors return -ENOENT; 289a8c21a54SThe etnaviv authors 29038c4a4cfSArnd Bergmann ret = etnaviv_gem_cpu_prep(obj, args->op, &args->timeout); 291a8c21a54SThe etnaviv authors 2926780bf32SEmil Velikov drm_gem_object_put(obj); 293a8c21a54SThe etnaviv authors 294a8c21a54SThe etnaviv authors return ret; 295a8c21a54SThe etnaviv authors } 296a8c21a54SThe etnaviv authors 297a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, 298a8c21a54SThe etnaviv authors struct drm_file *file) 299a8c21a54SThe etnaviv authors { 300a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_cpu_fini *args = data; 301a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 302a8c21a54SThe etnaviv authors int ret; 303a8c21a54SThe etnaviv authors 304a8c21a54SThe etnaviv authors if (args->flags) 305a8c21a54SThe etnaviv authors return -EINVAL; 306a8c21a54SThe etnaviv authors 307a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 308a8c21a54SThe etnaviv authors if (!obj) 309a8c21a54SThe etnaviv authors return -ENOENT; 310a8c21a54SThe etnaviv authors 311a8c21a54SThe etnaviv authors ret = etnaviv_gem_cpu_fini(obj); 312a8c21a54SThe etnaviv authors 3136780bf32SEmil Velikov drm_gem_object_put(obj); 314a8c21a54SThe etnaviv authors 315a8c21a54SThe etnaviv authors return ret; 316a8c21a54SThe etnaviv authors } 317a8c21a54SThe etnaviv authors 318a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data, 319a8c21a54SThe etnaviv authors struct drm_file *file) 320a8c21a54SThe etnaviv authors { 321a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_info *args = data; 322a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 323a8c21a54SThe etnaviv authors int ret; 324a8c21a54SThe etnaviv authors 325a8c21a54SThe etnaviv authors if (args->pad) 326a8c21a54SThe etnaviv authors return -EINVAL; 327a8c21a54SThe etnaviv authors 328a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 329a8c21a54SThe etnaviv authors if (!obj) 330a8c21a54SThe etnaviv authors return -ENOENT; 331a8c21a54SThe etnaviv authors 332a8c21a54SThe etnaviv authors ret = etnaviv_gem_mmap_offset(obj, &args->offset); 3336780bf32SEmil Velikov drm_gem_object_put(obj); 334a8c21a54SThe etnaviv authors 335a8c21a54SThe etnaviv authors return ret; 336a8c21a54SThe etnaviv authors } 337a8c21a54SThe etnaviv authors 338a8c21a54SThe etnaviv authors static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data, 339a8c21a54SThe etnaviv authors struct drm_file *file) 340a8c21a54SThe etnaviv authors { 341a8c21a54SThe etnaviv authors struct drm_etnaviv_wait_fence *args = data; 342a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 34338c4a4cfSArnd Bergmann struct drm_etnaviv_timespec *timeout = &args->timeout; 344a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 345a8c21a54SThe etnaviv authors 346a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_WAIT_NONBLOCK)) 347a8c21a54SThe etnaviv authors return -EINVAL; 348a8c21a54SThe etnaviv authors 349a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 350a8c21a54SThe etnaviv authors return -EINVAL; 351a8c21a54SThe etnaviv authors 352a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 353a8c21a54SThe etnaviv authors if (!gpu) 354a8c21a54SThe etnaviv authors return -ENXIO; 355a8c21a54SThe etnaviv authors 356a8c21a54SThe etnaviv authors if (args->flags & ETNA_WAIT_NONBLOCK) 357a8c21a54SThe etnaviv authors timeout = NULL; 358a8c21a54SThe etnaviv authors 359a8c21a54SThe etnaviv authors return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence, 360a8c21a54SThe etnaviv authors timeout); 361a8c21a54SThe etnaviv authors } 362a8c21a54SThe etnaviv authors 363a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data, 364a8c21a54SThe etnaviv authors struct drm_file *file) 365a8c21a54SThe etnaviv authors { 366a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_userptr *args = data; 367a8c21a54SThe etnaviv authors 368a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) || 369a8c21a54SThe etnaviv authors args->flags == 0) 370a8c21a54SThe etnaviv authors return -EINVAL; 371a8c21a54SThe etnaviv authors 372a8c21a54SThe etnaviv authors if (offset_in_page(args->user_ptr | args->user_size) || 373a8c21a54SThe etnaviv authors (uintptr_t)args->user_ptr != args->user_ptr || 374a8c21a54SThe etnaviv authors (u32)args->user_size != args->user_size || 375a8c21a54SThe etnaviv authors args->user_ptr & ~PAGE_MASK) 376a8c21a54SThe etnaviv authors return -EINVAL; 377a8c21a54SThe etnaviv authors 37896d4f267SLinus Torvalds if (!access_ok((void __user *)(unsigned long)args->user_ptr, 379a8c21a54SThe etnaviv authors args->user_size)) 380a8c21a54SThe etnaviv authors return -EFAULT; 381a8c21a54SThe etnaviv authors 382a8c21a54SThe etnaviv authors return etnaviv_gem_new_userptr(dev, file, args->user_ptr, 383a8c21a54SThe etnaviv authors args->user_size, args->flags, 384a8c21a54SThe etnaviv authors &args->handle); 385a8c21a54SThe etnaviv authors } 386a8c21a54SThe etnaviv authors 387a8c21a54SThe etnaviv authors static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data, 388a8c21a54SThe etnaviv authors struct drm_file *file) 389a8c21a54SThe etnaviv authors { 390a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = dev->dev_private; 391a8c21a54SThe etnaviv authors struct drm_etnaviv_gem_wait *args = data; 39238c4a4cfSArnd Bergmann struct drm_etnaviv_timespec *timeout = &args->timeout; 393a8c21a54SThe etnaviv authors struct drm_gem_object *obj; 394a8c21a54SThe etnaviv authors struct etnaviv_gpu *gpu; 395a8c21a54SThe etnaviv authors int ret; 396a8c21a54SThe etnaviv authors 397a8c21a54SThe etnaviv authors if (args->flags & ~(ETNA_WAIT_NONBLOCK)) 398a8c21a54SThe etnaviv authors return -EINVAL; 399a8c21a54SThe etnaviv authors 400a8c21a54SThe etnaviv authors if (args->pipe >= ETNA_MAX_PIPES) 401a8c21a54SThe etnaviv authors return -EINVAL; 402a8c21a54SThe etnaviv authors 403a8c21a54SThe etnaviv authors gpu = priv->gpu[args->pipe]; 404a8c21a54SThe etnaviv authors if (!gpu) 405a8c21a54SThe etnaviv authors return -ENXIO; 406a8c21a54SThe etnaviv authors 407a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file, args->handle); 408a8c21a54SThe etnaviv authors if (!obj) 409a8c21a54SThe etnaviv authors return -ENOENT; 410a8c21a54SThe etnaviv authors 411a8c21a54SThe etnaviv authors if (args->flags & ETNA_WAIT_NONBLOCK) 412a8c21a54SThe etnaviv authors timeout = NULL; 413a8c21a54SThe etnaviv authors 414a8c21a54SThe etnaviv authors ret = etnaviv_gem_wait_bo(gpu, obj, timeout); 415a8c21a54SThe etnaviv authors 4166780bf32SEmil Velikov drm_gem_object_put(obj); 417a8c21a54SThe etnaviv authors 418a8c21a54SThe etnaviv authors return ret; 419a8c21a54SThe etnaviv authors } 420a8c21a54SThe etnaviv authors 4219e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data, 4229e2c2e27SChristian Gmeiner struct drm_file *file) 4239e2c2e27SChristian Gmeiner { 4249e2c2e27SChristian Gmeiner struct etnaviv_drm_private *priv = dev->dev_private; 4259e2c2e27SChristian Gmeiner struct drm_etnaviv_pm_domain *args = data; 4269e2c2e27SChristian Gmeiner struct etnaviv_gpu *gpu; 4279e2c2e27SChristian Gmeiner 4289e2c2e27SChristian Gmeiner if (args->pipe >= ETNA_MAX_PIPES) 4299e2c2e27SChristian Gmeiner return -EINVAL; 4309e2c2e27SChristian Gmeiner 4319e2c2e27SChristian Gmeiner gpu = priv->gpu[args->pipe]; 4329e2c2e27SChristian Gmeiner if (!gpu) 4339e2c2e27SChristian Gmeiner return -ENXIO; 4349e2c2e27SChristian Gmeiner 4359e2c2e27SChristian Gmeiner return etnaviv_pm_query_dom(gpu, args); 4369e2c2e27SChristian Gmeiner } 4379e2c2e27SChristian Gmeiner 4389e2c2e27SChristian Gmeiner static int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data, 4399e2c2e27SChristian Gmeiner struct drm_file *file) 4409e2c2e27SChristian Gmeiner { 4419e2c2e27SChristian Gmeiner struct etnaviv_drm_private *priv = dev->dev_private; 4429e2c2e27SChristian Gmeiner struct drm_etnaviv_pm_signal *args = data; 4439e2c2e27SChristian Gmeiner struct etnaviv_gpu *gpu; 4449e2c2e27SChristian Gmeiner 4459e2c2e27SChristian Gmeiner if (args->pipe >= ETNA_MAX_PIPES) 4469e2c2e27SChristian Gmeiner return -EINVAL; 4479e2c2e27SChristian Gmeiner 4489e2c2e27SChristian Gmeiner gpu = priv->gpu[args->pipe]; 4499e2c2e27SChristian Gmeiner if (!gpu) 4509e2c2e27SChristian Gmeiner return -ENXIO; 4519e2c2e27SChristian Gmeiner 4529e2c2e27SChristian Gmeiner return etnaviv_pm_query_sig(gpu, args); 4539e2c2e27SChristian Gmeiner } 4549e2c2e27SChristian Gmeiner 455a8c21a54SThe etnaviv authors static const struct drm_ioctl_desc etnaviv_ioctls[] = { 456a8c21a54SThe etnaviv authors #define ETNA_IOCTL(n, func, flags) \ 457a8c21a54SThe etnaviv authors DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags) 458b8602f9aSEmil Velikov ETNA_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), 459b8602f9aSEmil Velikov ETNA_IOCTL(GEM_NEW, gem_new, DRM_RENDER_ALLOW), 460b8602f9aSEmil Velikov ETNA_IOCTL(GEM_INFO, gem_info, DRM_RENDER_ALLOW), 461b8602f9aSEmil Velikov ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, DRM_RENDER_ALLOW), 462b8602f9aSEmil Velikov ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, DRM_RENDER_ALLOW), 463b8602f9aSEmil Velikov ETNA_IOCTL(GEM_SUBMIT, gem_submit, DRM_RENDER_ALLOW), 464b8602f9aSEmil Velikov ETNA_IOCTL(WAIT_FENCE, wait_fence, DRM_RENDER_ALLOW), 465b8602f9aSEmil Velikov ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_RENDER_ALLOW), 466b8602f9aSEmil Velikov ETNA_IOCTL(GEM_WAIT, gem_wait, DRM_RENDER_ALLOW), 467b8602f9aSEmil Velikov ETNA_IOCTL(PM_QUERY_DOM, pm_query_dom, DRM_RENDER_ALLOW), 468b8602f9aSEmil Velikov ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW), 469a8c21a54SThe etnaviv authors }; 470a8c21a54SThe etnaviv authors 47181fd23e2SThomas Zimmermann DEFINE_DRM_GEM_FOPS(fops); 472a8c21a54SThe etnaviv authors 47370a59dd8SDaniel Vetter static const struct drm_driver etnaviv_drm_driver = { 4740424fdafSDaniel Vetter .driver_features = DRIVER_GEM | DRIVER_RENDER, 475a8c21a54SThe etnaviv authors .open = etnaviv_open, 476fda8fa5bSDaniel Vetter .postclose = etnaviv_postclose, 477a8c21a54SThe etnaviv authors .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 478a8c21a54SThe etnaviv authors .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 479a8c21a54SThe etnaviv authors .gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table, 48081fd23e2SThomas Zimmermann .gem_prime_mmap = drm_gem_prime_mmap, 481a8c21a54SThe etnaviv authors #ifdef CONFIG_DEBUG_FS 482a8c21a54SThe etnaviv authors .debugfs_init = etnaviv_debugfs_init, 483a8c21a54SThe etnaviv authors #endif 484a8c21a54SThe etnaviv authors .ioctls = etnaviv_ioctls, 485a8c21a54SThe etnaviv authors .num_ioctls = DRM_ETNAVIV_NUM_IOCTLS, 486a8c21a54SThe etnaviv authors .fops = &fops, 487a8c21a54SThe etnaviv authors .name = "etnaviv", 488a8c21a54SThe etnaviv authors .desc = "etnaviv DRM", 489a8c21a54SThe etnaviv authors .date = "20151214", 490a8c21a54SThe etnaviv authors .major = 1, 491088880ddSLucas Stach .minor = 3, 492a8c21a54SThe etnaviv authors }; 493a8c21a54SThe etnaviv authors 494a8c21a54SThe etnaviv authors /* 495a8c21a54SThe etnaviv authors * Platform driver: 496a8c21a54SThe etnaviv authors */ 497a8c21a54SThe etnaviv authors static int etnaviv_bind(struct device *dev) 498a8c21a54SThe etnaviv authors { 499a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv; 500a8c21a54SThe etnaviv authors struct drm_device *drm; 501a8c21a54SThe etnaviv authors int ret; 502a8c21a54SThe etnaviv authors 503a8c21a54SThe etnaviv authors drm = drm_dev_alloc(&etnaviv_drm_driver, dev); 5040f288605STom Gundersen if (IS_ERR(drm)) 5050f288605STom Gundersen return PTR_ERR(drm); 506a8c21a54SThe etnaviv authors 507a8c21a54SThe etnaviv authors priv = kzalloc(sizeof(*priv), GFP_KERNEL); 508a8c21a54SThe etnaviv authors if (!priv) { 509a8c21a54SThe etnaviv authors dev_err(dev, "failed to allocate private data\n"); 510a8c21a54SThe etnaviv authors ret = -ENOMEM; 51199e29449SThomas Zimmermann goto out_put; 512a8c21a54SThe etnaviv authors } 513a8c21a54SThe etnaviv authors drm->dev_private = priv; 514a8c21a54SThe etnaviv authors 5151262cc88SRussell King dma_set_max_seg_size(dev, SZ_2G); 5161262cc88SRussell King 517a8c21a54SThe etnaviv authors mutex_init(&priv->gem_lock); 518a8c21a54SThe etnaviv authors INIT_LIST_HEAD(&priv->gem_list); 519a8c21a54SThe etnaviv authors priv->num_gpus = 0; 520b72af445SLucas Stach priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN; 521a8c21a54SThe etnaviv authors 522bffe5db8SLucas Stach priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev); 523bffe5db8SLucas Stach if (IS_ERR(priv->cmdbuf_suballoc)) { 524bffe5db8SLucas Stach dev_err(drm->dev, "Failed to create cmdbuf suballocator\n"); 525bffe5db8SLucas Stach ret = PTR_ERR(priv->cmdbuf_suballoc); 526bffe5db8SLucas Stach goto out_free_priv; 527bffe5db8SLucas Stach } 528bffe5db8SLucas Stach 529a8c21a54SThe etnaviv authors dev_set_drvdata(dev, drm); 530a8c21a54SThe etnaviv authors 531a8c21a54SThe etnaviv authors ret = component_bind_all(dev, drm); 532a8c21a54SThe etnaviv authors if (ret < 0) 533bffe5db8SLucas Stach goto out_destroy_suballoc; 534a8c21a54SThe etnaviv authors 535a8c21a54SThe etnaviv authors load_gpu(drm); 536a8c21a54SThe etnaviv authors 537a8c21a54SThe etnaviv authors ret = drm_dev_register(drm, 0); 538a8c21a54SThe etnaviv authors if (ret) 539bffe5db8SLucas Stach goto out_unbind; 540a8c21a54SThe etnaviv authors 541a8c21a54SThe etnaviv authors return 0; 542a8c21a54SThe etnaviv authors 543bffe5db8SLucas Stach out_unbind: 544a8c21a54SThe etnaviv authors component_unbind_all(dev, drm); 545bffe5db8SLucas Stach out_destroy_suballoc: 546bffe5db8SLucas Stach etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 547bffe5db8SLucas Stach out_free_priv: 548a8c21a54SThe etnaviv authors kfree(priv); 54999e29449SThomas Zimmermann out_put: 55099e29449SThomas Zimmermann drm_dev_put(drm); 551a8c21a54SThe etnaviv authors 552a8c21a54SThe etnaviv authors return ret; 553a8c21a54SThe etnaviv authors } 554a8c21a54SThe etnaviv authors 555a8c21a54SThe etnaviv authors static void etnaviv_unbind(struct device *dev) 556a8c21a54SThe etnaviv authors { 557a8c21a54SThe etnaviv authors struct drm_device *drm = dev_get_drvdata(dev); 558a8c21a54SThe etnaviv authors struct etnaviv_drm_private *priv = drm->dev_private; 559a8c21a54SThe etnaviv authors 560a8c21a54SThe etnaviv authors drm_dev_unregister(drm); 561a8c21a54SThe etnaviv authors 562a8c21a54SThe etnaviv authors component_unbind_all(dev, drm); 563a8c21a54SThe etnaviv authors 564bffe5db8SLucas Stach etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 565bffe5db8SLucas Stach 566a8c21a54SThe etnaviv authors drm->dev_private = NULL; 567a8c21a54SThe etnaviv authors kfree(priv); 568a8c21a54SThe etnaviv authors 56999e29449SThomas Zimmermann drm_dev_put(drm); 570a8c21a54SThe etnaviv authors } 571a8c21a54SThe etnaviv authors 572a8c21a54SThe etnaviv authors static const struct component_master_ops etnaviv_master_ops = { 573a8c21a54SThe etnaviv authors .bind = etnaviv_bind, 574a8c21a54SThe etnaviv authors .unbind = etnaviv_unbind, 575a8c21a54SThe etnaviv authors }; 576a8c21a54SThe etnaviv authors 577a8c21a54SThe etnaviv authors static int compare_of(struct device *dev, void *data) 578a8c21a54SThe etnaviv authors { 579a8c21a54SThe etnaviv authors struct device_node *np = data; 580a8c21a54SThe etnaviv authors 581a8c21a54SThe etnaviv authors return dev->of_node == np; 582a8c21a54SThe etnaviv authors } 583a8c21a54SThe etnaviv authors 584a8c21a54SThe etnaviv authors static int compare_str(struct device *dev, void *data) 585a8c21a54SThe etnaviv authors { 586a8c21a54SThe etnaviv authors return !strcmp(dev_name(dev), data); 587a8c21a54SThe etnaviv authors } 588a8c21a54SThe etnaviv authors 589a8c21a54SThe etnaviv authors static int etnaviv_pdev_probe(struct platform_device *pdev) 590a8c21a54SThe etnaviv authors { 591a8c21a54SThe etnaviv authors struct device *dev = &pdev->dev; 592*0ea057a9SMichael Walle struct device_node *first_node = NULL; 593a8c21a54SThe etnaviv authors struct component_match *match = NULL; 594a8c21a54SThe etnaviv authors 595246774d1SLucas Stach if (!dev->platform_data) { 596a8c21a54SThe etnaviv authors struct device_node *core_node; 597a8c21a54SThe etnaviv authors 598246774d1SLucas Stach for_each_compatible_node(core_node, NULL, "vivante,gc") { 599246774d1SLucas Stach if (!of_device_is_available(core_node)) 600246774d1SLucas Stach continue; 601a8c21a54SThe etnaviv authors 602*0ea057a9SMichael Walle if (!first_node) 603*0ea057a9SMichael Walle first_node = core_node; 604*0ea057a9SMichael Walle 60597ac0e47SRussell King drm_of_component_match_add(&pdev->dev, &match, 60697ac0e47SRussell King compare_of, core_node); 607a8c21a54SThe etnaviv authors } 608246774d1SLucas Stach } else { 609a8c21a54SThe etnaviv authors char **names = dev->platform_data; 610a8c21a54SThe etnaviv authors unsigned i; 611a8c21a54SThe etnaviv authors 612a8c21a54SThe etnaviv authors for (i = 0; names[i]; i++) 613a8c21a54SThe etnaviv authors component_match_add(dev, &match, compare_str, names[i]); 614a8c21a54SThe etnaviv authors } 615a8c21a54SThe etnaviv authors 616*0ea057a9SMichael Walle /* 617*0ea057a9SMichael Walle * Apply the same DMA configuration to the virtual etnaviv 618*0ea057a9SMichael Walle * device as the GPU we found. This assumes that all Vivante 619*0ea057a9SMichael Walle * GPUs in the system share the same DMA constraints. 620*0ea057a9SMichael Walle */ 621*0ea057a9SMichael Walle if (first_node) 622*0ea057a9SMichael Walle of_dma_configure(&pdev->dev, first_node, true); 623*0ea057a9SMichael Walle 624a8c21a54SThe etnaviv authors return component_master_add_with_match(dev, &etnaviv_master_ops, match); 625a8c21a54SThe etnaviv authors } 626a8c21a54SThe etnaviv authors 627a8c21a54SThe etnaviv authors static int etnaviv_pdev_remove(struct platform_device *pdev) 628a8c21a54SThe etnaviv authors { 629a8c21a54SThe etnaviv authors component_master_del(&pdev->dev, &etnaviv_master_ops); 630a8c21a54SThe etnaviv authors 631a8c21a54SThe etnaviv authors return 0; 632a8c21a54SThe etnaviv authors } 633a8c21a54SThe etnaviv authors 634a8c21a54SThe etnaviv authors static struct platform_driver etnaviv_platform_driver = { 635a8c21a54SThe etnaviv authors .probe = etnaviv_pdev_probe, 636a8c21a54SThe etnaviv authors .remove = etnaviv_pdev_remove, 637a8c21a54SThe etnaviv authors .driver = { 638a8c21a54SThe etnaviv authors .name = "etnaviv", 639a8c21a54SThe etnaviv authors }, 640a8c21a54SThe etnaviv authors }; 641a8c21a54SThe etnaviv authors 64245a0faabSFabio Estevam static struct platform_device *etnaviv_drm; 64345a0faabSFabio Estevam 644a8c21a54SThe etnaviv authors static int __init etnaviv_init(void) 645a8c21a54SThe etnaviv authors { 64645a0faabSFabio Estevam struct platform_device *pdev; 647a8c21a54SThe etnaviv authors int ret; 648246774d1SLucas Stach struct device_node *np; 649a8c21a54SThe etnaviv authors 650a8c21a54SThe etnaviv authors etnaviv_validate_init(); 651a8c21a54SThe etnaviv authors 652a8c21a54SThe etnaviv authors ret = platform_driver_register(&etnaviv_gpu_driver); 653a8c21a54SThe etnaviv authors if (ret != 0) 654a8c21a54SThe etnaviv authors return ret; 655a8c21a54SThe etnaviv authors 656a8c21a54SThe etnaviv authors ret = platform_driver_register(&etnaviv_platform_driver); 657a8c21a54SThe etnaviv authors if (ret != 0) 65845a0faabSFabio Estevam goto unregister_gpu_driver; 659a8c21a54SThe etnaviv authors 660246774d1SLucas Stach /* 661246774d1SLucas Stach * If the DT contains at least one available GPU device, instantiate 662246774d1SLucas Stach * the DRM platform device. 663246774d1SLucas Stach */ 664246774d1SLucas Stach for_each_compatible_node(np, NULL, "vivante,gc") { 665246774d1SLucas Stach if (!of_device_is_available(np)) 666246774d1SLucas Stach continue; 6671a866306SLucas Stach 6683c7e0cccSMichael Walle pdev = platform_device_alloc("etnaviv", PLATFORM_DEVID_NONE); 6691a866306SLucas Stach if (!pdev) { 6701a866306SLucas Stach ret = -ENOMEM; 67145a0faabSFabio Estevam of_node_put(np); 67245a0faabSFabio Estevam goto unregister_platform_driver; 67345a0faabSFabio Estevam } 6741a866306SLucas Stach pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40); 6751a866306SLucas Stach pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; 6761a866306SLucas Stach 6771a866306SLucas Stach ret = platform_device_add(pdev); 6781a866306SLucas Stach if (ret) { 6791a866306SLucas Stach platform_device_put(pdev); 6801a866306SLucas Stach of_node_put(np); 6811a866306SLucas Stach goto unregister_platform_driver; 6821a866306SLucas Stach } 6831a866306SLucas Stach 68445a0faabSFabio Estevam etnaviv_drm = pdev; 685246774d1SLucas Stach of_node_put(np); 686246774d1SLucas Stach break; 687246774d1SLucas Stach } 688246774d1SLucas Stach 68945a0faabSFabio Estevam return 0; 69045a0faabSFabio Estevam 69145a0faabSFabio Estevam unregister_platform_driver: 69245a0faabSFabio Estevam platform_driver_unregister(&etnaviv_platform_driver); 69345a0faabSFabio Estevam unregister_gpu_driver: 69445a0faabSFabio Estevam platform_driver_unregister(&etnaviv_gpu_driver); 695a8c21a54SThe etnaviv authors return ret; 696a8c21a54SThe etnaviv authors } 697a8c21a54SThe etnaviv authors module_init(etnaviv_init); 698a8c21a54SThe etnaviv authors 699a8c21a54SThe etnaviv authors static void __exit etnaviv_exit(void) 700a8c21a54SThe etnaviv authors { 701bf6ba3aeSFabio Estevam platform_device_unregister(etnaviv_drm); 702a8c21a54SThe etnaviv authors platform_driver_unregister(&etnaviv_platform_driver); 703bf6ba3aeSFabio Estevam platform_driver_unregister(&etnaviv_gpu_driver); 704a8c21a54SThe etnaviv authors } 705a8c21a54SThe etnaviv authors module_exit(etnaviv_exit); 706a8c21a54SThe etnaviv authors 707a8c21a54SThe etnaviv authors MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>"); 7084f39467eSRussell King MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>"); 709a8c21a54SThe etnaviv authors MODULE_AUTHOR("Lucas Stach <l.stach@pengutronix.de>"); 710a8c21a54SThe etnaviv authors MODULE_DESCRIPTION("etnaviv DRM Driver"); 711a8c21a54SThe etnaviv authors MODULE_LICENSE("GPL v2"); 712a8c21a54SThe etnaviv authors MODULE_ALIAS("platform:etnaviv"); 713