diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 98 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 95 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_stub.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_cp.c | 45 |
5 files changed, 198 insertions, 43 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 251bc0e3b5ec..8ac7fbf6b2b7 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -257,6 +257,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
257 | 257 | ||
258 | INIT_LIST_HEAD(&priv->lhead); | 258 | INIT_LIST_HEAD(&priv->lhead); |
259 | INIT_LIST_HEAD(&priv->fbs); | 259 | INIT_LIST_HEAD(&priv->fbs); |
260 | INIT_LIST_HEAD(&priv->event_list); | ||
261 | init_waitqueue_head(&priv->event_wait); | ||
262 | priv->event_space = 4096; /* set aside 4k for event buffer */ | ||
260 | 263 | ||
261 | if (dev->driver->driver_features & DRIVER_GEM) | 264 | if (dev->driver->driver_features & DRIVER_GEM) |
262 | drm_gem_open(dev, priv); | 265 | drm_gem_open(dev, priv); |
@@ -413,6 +416,30 @@ static void drm_master_release(struct drm_device *dev, struct file *filp) | |||
413 | } | 416 | } |
414 | } | 417 | } |
415 | 418 | ||
419 | static void drm_events_release(struct drm_file *file_priv) | ||
420 | { | ||
421 | struct drm_device *dev = file_priv->minor->dev; | ||
422 | struct drm_pending_event *e, *et; | ||
423 | struct drm_pending_vblank_event *v, *vt; | ||
424 | unsigned long flags; | ||
425 | |||
426 | spin_lock_irqsave(&dev->event_lock, flags); | ||
427 | |||
428 | /* Remove pending flips */ | ||
429 | list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link) | ||
430 | if (v->base.file_priv == file_priv) { | ||
431 | list_del(&v->base.link); | ||
432 | drm_vblank_put(dev, v->pipe); | ||
433 | v->base.destroy(&v->base); | ||
434 | } | ||
435 | |||
436 | /* Remove unconsumed events */ | ||
437 | list_for_each_entry_safe(e, et, &file_priv->event_list, link) | ||
438 | e->destroy(e); | ||
439 | |||
440 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
441 | } | ||
442 | |||
416 | /** | 443 | /** |
417 | * Release file. | 444 | * Release file. |
418 | * | 445 | * |
@@ -451,6 +478,8 @@ int drm_release(struct inode *inode, struct file *filp) | |||
451 | if (file_priv->minor->master) | 478 | if (file_priv->minor->master) |
452 | drm_master_release(dev, filp); | 479 | drm_master_release(dev, filp); |
453 | 480 | ||
481 | drm_events_release(file_priv); | ||
482 | |||
454 | if (dev->driver->driver_features & DRIVER_GEM) | 483 | if (dev->driver->driver_features & DRIVER_GEM) |
455 | drm_gem_release(dev, file_priv); | 484 | drm_gem_release(dev, file_priv); |
456 | 485 | ||
@@ -544,9 +573,74 @@ int drm_release(struct inode *inode, struct file *filp) | |||
544 | } | 573 | } |
545 | EXPORT_SYMBOL(drm_release); | 574 | EXPORT_SYMBOL(drm_release); |
546 | 575 | ||
547 | /** No-op. */ | 576 | static bool |
577 | drm_dequeue_event(struct drm_file *file_priv, | ||
578 | size_t total, size_t max, struct drm_pending_event **out) | ||
579 | { | ||
580 | struct drm_device *dev = file_priv->minor->dev; | ||
581 | struct drm_pending_event *e; | ||
582 | unsigned long flags; | ||
583 | bool ret = false; | ||
584 | |||
585 | spin_lock_irqsave(&dev->event_lock, flags); | ||
586 | |||
587 | *out = NULL; | ||
588 | if (list_empty(&file_priv->event_list)) | ||
589 | goto out; | ||
590 | e = list_first_entry(&file_priv->event_list, | ||
591 | struct drm_pending_event, link); | ||
592 | if (e->event->length + total > max) | ||
593 | goto out; | ||
594 | |||
595 | file_priv->event_space += e->event->length; | ||
596 | list_del(&e->link); | ||
597 | *out = e; | ||
598 | ret = true; | ||
599 | |||
600 | out: | ||
601 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
602 | return ret; | ||
603 | } | ||
604 | |||
605 | ssize_t drm_read(struct file *filp, char __user *buffer, | ||
606 | size_t count, loff_t *offset) | ||
607 | { | ||
608 | struct drm_file *file_priv = filp->private_data; | ||
609 | struct drm_pending_event *e; | ||
610 | size_t total; | ||
611 | ssize_t ret; | ||
612 | |||
613 | ret = wait_event_interruptible(file_priv->event_wait, | ||
614 | !list_empty(&file_priv->event_list)); | ||
615 | if (ret < 0) | ||
616 | return ret; | ||
617 | |||
618 | total = 0; | ||
619 | while (drm_dequeue_event(file_priv, total, count, &e)) { | ||
620 | if (copy_to_user(buffer + total, | ||
621 | e->event, e->event->length)) { | ||
622 | total = -EFAULT; | ||
623 | break; | ||
624 | } | ||
625 | |||
626 | total += e->event->length; | ||
627 | e->destroy(e); | ||
628 | } | ||
629 | |||
630 | return total; | ||
631 | } | ||
632 | EXPORT_SYMBOL(drm_read); | ||
633 | |||
548 | unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) | 634 | unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) |
549 | { | 635 | { |
550 | return 0; | 636 | struct drm_file *file_priv = filp->private_data; |
637 | unsigned int mask = 0; | ||
638 | |||
639 | poll_wait(filp, &file_priv->event_wait, wait); | ||
640 | |||
641 | if (!list_empty(&file_priv->event_list)) | ||
642 | mask |= POLLIN | POLLRDNORM; | ||
643 | |||
644 | return mask; | ||
551 | } | 645 | } |
552 | EXPORT_SYMBOL(drm_poll); | 646 | EXPORT_SYMBOL(drm_poll); |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f85aaf21e783..d9af7964f81c 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -523,6 +523,62 @@ out: | |||
523 | return ret; | 523 | return ret; |
524 | } | 524 | } |
525 | 525 | ||
526 | static int drm_queue_vblank_event(struct drm_device *dev, int pipe, | ||
527 | union drm_wait_vblank *vblwait, | ||
528 | struct drm_file *file_priv) | ||
529 | { | ||
530 | struct drm_pending_vblank_event *e; | ||
531 | struct timeval now; | ||
532 | unsigned long flags; | ||
533 | unsigned int seq; | ||
534 | |||
535 | e = kzalloc(sizeof *e, GFP_KERNEL); | ||
536 | if (e == NULL) | ||
537 | return -ENOMEM; | ||
538 | |||
539 | e->pipe = pipe; | ||
540 | e->event.base.type = DRM_EVENT_VBLANK; | ||
541 | e->event.base.length = sizeof e->event; | ||
542 | e->event.user_data = vblwait->request.signal; | ||
543 | e->base.event = &e->event.base; | ||
544 | e->base.file_priv = file_priv; | ||
545 | e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; | ||
546 | |||
547 | do_gettimeofday(&now); | ||
548 | spin_lock_irqsave(&dev->event_lock, flags); | ||
549 | |||
550 | if (file_priv->event_space < sizeof e->event) { | ||
551 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
552 | kfree(e); | ||
553 | return -ENOMEM; | ||
554 | } | ||
555 | |||
556 | file_priv->event_space -= sizeof e->event; | ||
557 | seq = drm_vblank_count(dev, pipe); | ||
558 | if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && | ||
559 | (seq - vblwait->request.sequence) <= (1 << 23)) { | ||
560 | vblwait->request.sequence = seq + 1; | ||
561 | } | ||
562 | |||
563 | DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n", | ||
564 | vblwait->request.sequence, seq, pipe); | ||
565 | |||
566 | e->event.sequence = vblwait->request.sequence; | ||
567 | if ((seq - vblwait->request.sequence) <= (1 << 23)) { | ||
568 | e->event.tv_sec = now.tv_sec; | ||
569 | e->event.tv_usec = now.tv_usec; | ||
570 | drm_vblank_put(dev, e->pipe); | ||
571 | list_add_tail(&e->base.link, &e->base.file_priv->event_list); | ||
572 | wake_up_interruptible(&e->base.file_priv->event_wait); | ||
573 | } else { | ||
574 | list_add_tail(&e->base.link, &dev->vblank_event_list); | ||
575 | } | ||
576 | |||
577 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
526 | /** | 582 | /** |
527 | * Wait for VBLANK. | 583 | * Wait for VBLANK. |
528 | * | 584 | * |
@@ -582,6 +638,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
582 | goto done; | 638 | goto done; |
583 | } | 639 | } |
584 | 640 | ||
641 | if (flags & _DRM_VBLANK_EVENT) | ||
642 | return drm_queue_vblank_event(dev, crtc, vblwait, file_priv); | ||
643 | |||
585 | if ((flags & _DRM_VBLANK_NEXTONMISS) && | 644 | if ((flags & _DRM_VBLANK_NEXTONMISS) && |
586 | (seq - vblwait->request.sequence) <= (1<<23)) { | 645 | (seq - vblwait->request.sequence) <= (1<<23)) { |
587 | vblwait->request.sequence = seq + 1; | 646 | vblwait->request.sequence = seq + 1; |
@@ -614,6 +673,38 @@ done: | |||
614 | return ret; | 673 | return ret; |
615 | } | 674 | } |
616 | 675 | ||
676 | void drm_handle_vblank_events(struct drm_device *dev, int crtc) | ||
677 | { | ||
678 | struct drm_pending_vblank_event *e, *t; | ||
679 | struct timeval now; | ||
680 | unsigned long flags; | ||
681 | unsigned int seq; | ||
682 | |||
683 | do_gettimeofday(&now); | ||
684 | seq = drm_vblank_count(dev, crtc); | ||
685 | |||
686 | spin_lock_irqsave(&dev->event_lock, flags); | ||
687 | |||
688 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { | ||
689 | if (e->pipe != crtc) | ||
690 | continue; | ||
691 | if ((seq - e->event.sequence) > (1<<23)) | ||
692 | continue; | ||
693 | |||
694 | DRM_DEBUG("vblank event on %d, current %d\n", | ||
695 | e->event.sequence, seq); | ||
696 | |||
697 | e->event.sequence = seq; | ||
698 | e->event.tv_sec = now.tv_sec; | ||
699 | e->event.tv_usec = now.tv_usec; | ||
700 | drm_vblank_put(dev, e->pipe); | ||
701 | list_move_tail(&e->base.link, &e->base.file_priv->event_list); | ||
702 | wake_up_interruptible(&e->base.file_priv->event_wait); | ||
703 | } | ||
704 | |||
705 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
706 | } | ||
707 | |||
617 | /** | 708 | /** |
618 | * drm_handle_vblank - handle a vblank event | 709 | * drm_handle_vblank - handle a vblank event |
619 | * @dev: DRM device | 710 | * @dev: DRM device |
@@ -624,7 +715,11 @@ done: | |||
624 | */ | 715 | */ |
625 | void drm_handle_vblank(struct drm_device *dev, int crtc) | 716 | void drm_handle_vblank(struct drm_device *dev, int crtc) |
626 | { | 717 | { |
718 | if (!dev->num_crtcs) | ||
719 | return; | ||
720 | |||
627 | atomic_inc(&dev->_vblank_count[crtc]); | 721 | atomic_inc(&dev->_vblank_count[crtc]); |
628 | DRM_WAKEUP(&dev->vbl_queue[crtc]); | 722 | DRM_WAKEUP(&dev->vbl_queue[crtc]); |
723 | drm_handle_vblank_events(dev, crtc); | ||
629 | } | 724 | } |
630 | EXPORT_SYMBOL(drm_handle_vblank); | 725 | EXPORT_SYMBOL(drm_handle_vblank); |
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 55bb8a82d612..adb864dfef3e 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c | |||
@@ -220,9 +220,11 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, | |||
220 | INIT_LIST_HEAD(&dev->ctxlist); | 220 | INIT_LIST_HEAD(&dev->ctxlist); |
221 | INIT_LIST_HEAD(&dev->vmalist); | 221 | INIT_LIST_HEAD(&dev->vmalist); |
222 | INIT_LIST_HEAD(&dev->maplist); | 222 | INIT_LIST_HEAD(&dev->maplist); |
223 | INIT_LIST_HEAD(&dev->vblank_event_list); | ||
223 | 224 | ||
224 | spin_lock_init(&dev->count_lock); | 225 | spin_lock_init(&dev->count_lock); |
225 | spin_lock_init(&dev->drw_lock); | 226 | spin_lock_init(&dev->drw_lock); |
227 | spin_lock_init(&dev->event_lock); | ||
226 | init_timer(&dev->timer); | 228 | init_timer(&dev->timer); |
227 | mutex_init(&dev->struct_mutex); | 229 | mutex_init(&dev->struct_mutex); |
228 | mutex_init(&dev->ctxlist_mutex); | 230 | mutex_init(&dev->ctxlist_mutex); |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index dbe568c9327b..b81305e33c79 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -206,6 +206,7 @@ static struct drm_driver driver = { | |||
206 | .mmap = drm_gem_mmap, | 206 | .mmap = drm_gem_mmap, |
207 | .poll = drm_poll, | 207 | .poll = drm_poll, |
208 | .fasync = drm_fasync, | 208 | .fasync = drm_fasync, |
209 | .read = drm_read, | ||
209 | #ifdef CONFIG_COMPAT | 210 | #ifdef CONFIG_COMPAT |
210 | .compat_ioctl = i915_compat_ioctl, | 211 | .compat_ioctl = i915_compat_ioctl, |
211 | #endif | 212 | #endif |
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 4f7afc79dd82..0b2f9c2ad2c1 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c | |||
@@ -1941,8 +1941,8 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev) | |||
1941 | for (t = 0; t < dev_priv->usec_timeout; t++) { | 1941 | for (t = 0; t < dev_priv->usec_timeout; t++) { |
1942 | u32 done_age = GET_SCRATCH(dev_priv, 1); | 1942 | u32 done_age = GET_SCRATCH(dev_priv, 1); |
1943 | DRM_DEBUG("done_age = %d\n", done_age); | 1943 | DRM_DEBUG("done_age = %d\n", done_age); |
1944 | for (i = start; i < dma->buf_count; i++) { | 1944 | for (i = 0; i < dma->buf_count; i++) { |
1945 | buf = dma->buflist[i]; | 1945 | buf = dma->buflist[start]; |
1946 | buf_priv = buf->dev_private; | 1946 | buf_priv = buf->dev_private; |
1947 | if (buf->file_priv == NULL || (buf->pending && | 1947 | if (buf->file_priv == NULL || (buf->pending && |
1948 | buf_priv->age <= | 1948 | buf_priv->age <= |
@@ -1951,7 +1951,8 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev) | |||
1951 | buf->pending = 0; | 1951 | buf->pending = 0; |
1952 | return buf; | 1952 | return buf; |
1953 | } | 1953 | } |
1954 | start = 0; | 1954 | if (++start >= dma->buf_count) |
1955 | start = 0; | ||
1955 | } | 1956 | } |
1956 | 1957 | ||
1957 | if (t) { | 1958 | if (t) { |
@@ -1960,47 +1961,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev) | |||
1960 | } | 1961 | } |
1961 | } | 1962 | } |
1962 | 1963 | ||
1963 | DRM_DEBUG("returning NULL!\n"); | ||
1964 | return NULL; | 1964 | return NULL; |
1965 | } | 1965 | } |
1966 | 1966 | ||
1967 | #if 0 | ||
1968 | struct drm_buf *radeon_freelist_get(struct drm_device * dev) | ||
1969 | { | ||
1970 | struct drm_device_dma *dma = dev->dma; | ||
1971 | drm_radeon_private_t *dev_priv = dev->dev_private; | ||
1972 | drm_radeon_buf_priv_t *buf_priv; | ||
1973 | struct drm_buf *buf; | ||
1974 | int i, t; | ||
1975 | int start; | ||
1976 | u32 done_age; | ||
1977 | |||
1978 | done_age = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1)); | ||
1979 | if (++dev_priv->last_buf >= dma->buf_count) | ||
1980 | dev_priv->last_buf = 0; | ||
1981 | |||
1982 | start = dev_priv->last_buf; | ||
1983 | dev_priv->stats.freelist_loops++; | ||
1984 | |||
1985 | for (t = 0; t < 2; t++) { | ||
1986 | for (i = start; i < dma->buf_count; i++) { | ||
1987 | buf = dma->buflist[i]; | ||
1988 | buf_priv = buf->dev_private; | ||
1989 | if (buf->file_priv == 0 || (buf->pending && | ||
1990 | buf_priv->age <= | ||
1991 | done_age)) { | ||
1992 | dev_priv->stats.requested_bufs++; | ||
1993 | buf->pending = 0; | ||
1994 | return buf; | ||
1995 | } | ||
1996 | } | ||
1997 | start = 0; | ||
1998 | } | ||
1999 | |||
2000 | return NULL; | ||
2001 | } | ||
2002 | #endif | ||
2003 | |||
2004 | void radeon_freelist_reset(struct drm_device * dev) | 1967 | void radeon_freelist_reset(struct drm_device * dev) |
2005 | { | 1968 | { |
2006 | struct drm_device_dma *dma = dev->dma; | 1969 | struct drm_device_dma *dma = dev->dma; |