aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/msm_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/msm_drv.c')
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c246
1 files changed, 245 insertions, 1 deletions
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index b5ae0dbe1eb8..864c9773636b 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -16,6 +16,7 @@
16 */ 16 */
17 17
18#include "msm_drv.h" 18#include "msm_drv.h"
19#include "msm_gpu.h"
19 20
20#include <mach/iommu.h> 21#include <mach/iommu.h>
21 22
@@ -135,6 +136,7 @@ static int msm_unload(struct drm_device *dev)
135{ 136{
136 struct msm_drm_private *priv = dev->dev_private; 137 struct msm_drm_private *priv = dev->dev_private;
137 struct msm_kms *kms = priv->kms; 138 struct msm_kms *kms = priv->kms;
139 struct msm_gpu *gpu = priv->gpu;
138 140
139 drm_kms_helper_poll_fini(dev); 141 drm_kms_helper_poll_fini(dev);
140 drm_mode_config_cleanup(dev); 142 drm_mode_config_cleanup(dev);
@@ -152,6 +154,12 @@ static int msm_unload(struct drm_device *dev)
152 kms->funcs->destroy(kms); 154 kms->funcs->destroy(kms);
153 } 155 }
154 156
157 if (gpu) {
158 mutex_lock(&dev->struct_mutex);
159 gpu->funcs->pm_suspend(gpu);
160 gpu->funcs->destroy(gpu);
161 mutex_unlock(&dev->struct_mutex);
162 }
155 163
156 dev->dev_private = NULL; 164 dev->dev_private = NULL;
157 165
@@ -176,6 +184,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
176 dev->dev_private = priv; 184 dev->dev_private = priv;
177 185
178 priv->wq = alloc_ordered_workqueue("msm", 0); 186 priv->wq = alloc_ordered_workqueue("msm", 0);
187 init_waitqueue_head(&priv->fence_event);
179 188
180 INIT_LIST_HEAD(&priv->inactive_list); 189 INIT_LIST_HEAD(&priv->inactive_list);
181 190
@@ -240,12 +249,70 @@ fail:
240 return ret; 249 return ret;
241} 250}
242 251
252static void load_gpu(struct drm_device *dev)
253{
254 struct msm_drm_private *priv = dev->dev_private;
255 struct msm_gpu *gpu;
256
257 if (priv->gpu)
258 return;
259
260 mutex_lock(&dev->struct_mutex);
261 gpu = a3xx_gpu_init(dev);
262 if (IS_ERR(gpu)) {
263 dev_warn(dev->dev, "failed to load a3xx gpu\n");
264 gpu = NULL;
265 /* not fatal */
266 }
267 mutex_unlock(&dev->struct_mutex);
268
269 if (gpu) {
270 int ret;
271 gpu->funcs->pm_resume(gpu);
272 ret = gpu->funcs->hw_init(gpu);
273 if (ret) {
274 dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
275 gpu->funcs->destroy(gpu);
276 gpu = NULL;
277 }
278 }
279
280 priv->gpu = gpu;
281}
282
283static int msm_open(struct drm_device *dev, struct drm_file *file)
284{
285 struct msm_file_private *ctx;
286
287 /* For now, load gpu on open.. to avoid the requirement of having
288 * firmware in the initrd.
289 */
290 load_gpu(dev);
291
292 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
293 if (!ctx)
294 return -ENOMEM;
295
296 file->driver_priv = ctx;
297
298 return 0;
299}
300
243static void msm_preclose(struct drm_device *dev, struct drm_file *file) 301static void msm_preclose(struct drm_device *dev, struct drm_file *file)
244{ 302{
245 struct msm_drm_private *priv = dev->dev_private; 303 struct msm_drm_private *priv = dev->dev_private;
304 struct msm_file_private *ctx = file->driver_priv;
246 struct msm_kms *kms = priv->kms; 305 struct msm_kms *kms = priv->kms;
306
247 if (kms) 307 if (kms)
248 kms->funcs->preclose(kms, file); 308 kms->funcs->preclose(kms, file);
309
310 mutex_lock(&dev->struct_mutex);
311 if (ctx == priv->lastctx)
312 priv->lastctx = NULL;
313 mutex_unlock(&dev->struct_mutex);
314
315 kfree(ctx);
249} 316}
250 317
251static void msm_lastclose(struct drm_device *dev) 318static void msm_lastclose(struct drm_device *dev)
@@ -316,11 +383,30 @@ static void msm_disable_vblank(struct drm_device *dev, int crtc_id)
316 */ 383 */
317 384
318#ifdef CONFIG_DEBUG_FS 385#ifdef CONFIG_DEBUG_FS
386static int msm_gpu_show(struct drm_device *dev, struct seq_file *m)
387{
388 struct msm_drm_private *priv = dev->dev_private;
389 struct msm_gpu *gpu = priv->gpu;
390
391 if (gpu) {
392 seq_printf(m, "%s Status:\n", gpu->name);
393 gpu->funcs->show(gpu, m);
394 }
395
396 return 0;
397}
398
319static int msm_gem_show(struct drm_device *dev, struct seq_file *m) 399static int msm_gem_show(struct drm_device *dev, struct seq_file *m)
320{ 400{
321 struct msm_drm_private *priv = dev->dev_private; 401 struct msm_drm_private *priv = dev->dev_private;
402 struct msm_gpu *gpu = priv->gpu;
403
404 if (gpu) {
405 seq_printf(m, "Active Objects (%s):\n", gpu->name);
406 msm_gem_describe_objects(&gpu->active_list, m);
407 }
322 408
323 seq_printf(m, "All Objects:\n"); 409 seq_printf(m, "Inactive Objects:\n");
324 msm_gem_describe_objects(&priv->inactive_list, m); 410 msm_gem_describe_objects(&priv->inactive_list, m);
325 411
326 return 0; 412 return 0;
@@ -375,6 +461,7 @@ static int show_locked(struct seq_file *m, void *arg)
375} 461}
376 462
377static struct drm_info_list msm_debugfs_list[] = { 463static struct drm_info_list msm_debugfs_list[] = {
464 {"gpu", show_locked, 0, msm_gpu_show},
378 {"gem", show_locked, 0, msm_gem_show}, 465 {"gem", show_locked, 0, msm_gem_show},
379 { "mm", show_locked, 0, msm_mm_show }, 466 { "mm", show_locked, 0, msm_mm_show },
380 { "fb", show_locked, 0, msm_fb_show }, 467 { "fb", show_locked, 0, msm_fb_show },
@@ -404,6 +491,158 @@ static void msm_debugfs_cleanup(struct drm_minor *minor)
404} 491}
405#endif 492#endif
406 493
494/*
495 * Fences:
496 */
497
498int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
499 struct timespec *timeout)
500{
501 struct msm_drm_private *priv = dev->dev_private;
502 unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
503 unsigned long start_jiffies = jiffies;
504 unsigned long remaining_jiffies;
505 int ret;
506
507 if (time_after(start_jiffies, timeout_jiffies))
508 remaining_jiffies = 0;
509 else
510 remaining_jiffies = timeout_jiffies - start_jiffies;
511
512 ret = wait_event_interruptible_timeout(priv->fence_event,
513 priv->completed_fence >= fence,
514 remaining_jiffies);
515 if (ret == 0) {
516 DBG("timeout waiting for fence: %u (completed: %u)",
517 fence, priv->completed_fence);
518 ret = -ETIMEDOUT;
519 } else if (ret != -ERESTARTSYS) {
520 ret = 0;
521 }
522
523 return ret;
524}
525
526/* call under struct_mutex */
527void msm_update_fence(struct drm_device *dev, uint32_t fence)
528{
529 struct msm_drm_private *priv = dev->dev_private;
530
531 if (fence > priv->completed_fence) {
532 priv->completed_fence = fence;
533 wake_up_all(&priv->fence_event);
534 }
535}
536
537/*
538 * DRM ioctls:
539 */
540
541static int msm_ioctl_get_param(struct drm_device *dev, void *data,
542 struct drm_file *file)
543{
544 struct msm_drm_private *priv = dev->dev_private;
545 struct drm_msm_param *args = data;
546 struct msm_gpu *gpu;
547
548 /* for now, we just have 3d pipe.. eventually this would need to
549 * be more clever to dispatch to appropriate gpu module:
550 */
551 if (args->pipe != MSM_PIPE_3D0)
552 return -EINVAL;
553
554 gpu = priv->gpu;
555
556 if (!gpu)
557 return -ENXIO;
558
559 return gpu->funcs->get_param(gpu, args->param, &args->value);
560}
561
562static int msm_ioctl_gem_new(struct drm_device *dev, void *data,
563 struct drm_file *file)
564{
565 struct drm_msm_gem_new *args = data;
566 return msm_gem_new_handle(dev, file, args->size,
567 args->flags, &args->handle);
568}
569
570#define TS(t) ((struct timespec){ .tv_sec = (t).tv_sec, .tv_nsec = (t).tv_nsec })
571
572static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
573 struct drm_file *file)
574{
575 struct drm_msm_gem_cpu_prep *args = data;
576 struct drm_gem_object *obj;
577 int ret;
578
579 obj = drm_gem_object_lookup(dev, file, args->handle);
580 if (!obj)
581 return -ENOENT;
582
583 ret = msm_gem_cpu_prep(obj, args->op, &TS(args->timeout));
584
585 drm_gem_object_unreference_unlocked(obj);
586
587 return ret;
588}
589
590static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
591 struct drm_file *file)
592{
593 struct drm_msm_gem_cpu_fini *args = data;
594 struct drm_gem_object *obj;
595 int ret;
596
597 obj = drm_gem_object_lookup(dev, file, args->handle);
598 if (!obj)
599 return -ENOENT;
600
601 ret = msm_gem_cpu_fini(obj);
602
603 drm_gem_object_unreference_unlocked(obj);
604
605 return ret;
606}
607
608static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
609 struct drm_file *file)
610{
611 struct drm_msm_gem_info *args = data;
612 struct drm_gem_object *obj;
613 int ret = 0;
614
615 if (args->pad)
616 return -EINVAL;
617
618 obj = drm_gem_object_lookup(dev, file, args->handle);
619 if (!obj)
620 return -ENOENT;
621
622 args->offset = msm_gem_mmap_offset(obj);
623
624 drm_gem_object_unreference_unlocked(obj);
625
626 return ret;
627}
628
629static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
630 struct drm_file *file)
631{
632 struct drm_msm_wait_fence *args = data;
633 return msm_wait_fence_interruptable(dev, args->fence, &TS(args->timeout));
634}
635
636static const struct drm_ioctl_desc msm_ioctls[] = {
637 DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_UNLOCKED|DRM_AUTH),
638 DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH),
639 DRM_IOCTL_DEF_DRV(MSM_GEM_INFO, msm_ioctl_gem_info, DRM_UNLOCKED|DRM_AUTH),
640 DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH),
641 DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH),
642 DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT, msm_ioctl_gem_submit, DRM_UNLOCKED|DRM_AUTH),
643 DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_UNLOCKED|DRM_AUTH),
644};
645
407static const struct vm_operations_struct vm_ops = { 646static const struct vm_operations_struct vm_ops = {
408 .fault = msm_gem_fault, 647 .fault = msm_gem_fault,
409 .open = drm_gem_vm_open, 648 .open = drm_gem_vm_open,
@@ -428,6 +667,7 @@ static struct drm_driver msm_driver = {
428 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, 667 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
429 .load = msm_load, 668 .load = msm_load,
430 .unload = msm_unload, 669 .unload = msm_unload,
670 .open = msm_open,
431 .preclose = msm_preclose, 671 .preclose = msm_preclose,
432 .lastclose = msm_lastclose, 672 .lastclose = msm_lastclose,
433 .irq_handler = msm_irq, 673 .irq_handler = msm_irq,
@@ -446,6 +686,8 @@ static struct drm_driver msm_driver = {
446 .debugfs_init = msm_debugfs_init, 686 .debugfs_init = msm_debugfs_init,
447 .debugfs_cleanup = msm_debugfs_cleanup, 687 .debugfs_cleanup = msm_debugfs_cleanup,
448#endif 688#endif
689 .ioctls = msm_ioctls,
690 .num_ioctls = DRM_MSM_NUM_IOCTLS,
449 .fops = &fops, 691 .fops = &fops,
450 .name = "msm", 692 .name = "msm",
451 .desc = "MSM Snapdragon DRM", 693 .desc = "MSM Snapdragon DRM",
@@ -514,6 +756,7 @@ static int __init msm_drm_register(void)
514{ 756{
515 DBG("init"); 757 DBG("init");
516 hdmi_register(); 758 hdmi_register();
759 a3xx_register();
517 return platform_driver_register(&msm_platform_driver); 760 return platform_driver_register(&msm_platform_driver);
518} 761}
519 762
@@ -522,6 +765,7 @@ static void __exit msm_drm_unregister(void)
522 DBG("fini"); 765 DBG("fini");
523 platform_driver_unregister(&msm_platform_driver); 766 platform_driver_unregister(&msm_platform_driver);
524 hdmi_unregister(); 767 hdmi_unregister();
768 a3xx_unregister();
525} 769}
526 770
527module_init(msm_drm_register); 771module_init(msm_drm_register);