Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: Add CRTC_GET_SEQUENCE and CRTC_QUEUE_SEQUENCE ioctls [v3]

These provide crtc-id based functions instead of pipe-number, while
also offering higher resolution time (ns) and wider frame count (64)
as required by the Vulkan API.

v2:

* Check for DRIVER_MODESET in new crtc-based vblank ioctls

Failing to check this will oops the driver.

* Ensure vblank interupt is running in crtc_get_sequence ioctl

The sequence and timing values are not correct while the
interrupt is off, so make sure it's running before asking for
them.

* Short-circuit get_sequence if the counter is enabled and accurate

Steal the idea from the code in wait_vblank to avoid the
expense of drm_vblank_get/put

* Return active state of crtc in crtc_get_sequence ioctl

Might be useful for applications that aren't in charge of
modesetting?

* Use drm_crtc_vblank_get/put in new crtc-based vblank sequence ioctls

Daniel Vetter prefers these over the old drm_vblank_put/get
APIs.

* Return s64 ns instead of u64 in new sequence event

Suggested-by: Daniel Vetter <daniel@ffwll.ch>
Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

v3:

* Removed FIRST_PIXEL_OUT_FLAG
* Document that the timestamp in the query and event are
that of the first pixel leaving the display engine for
the display (using the same wording as the Vulkan spec).

Suggested-by: Michel Dänzer <michel@daenzer.net>
Acked-by: Dave Airlie <airlied@redhat.com>

[airlied: left->leaves (Michel)]

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Keith Packard and committed by
Dave Airlie
3064abfa bd386e51

+213
+6
drivers/gpu/drm/drm_internal.h
··· 70 70 int drm_legacy_irq_control(struct drm_device *dev, void *data, 71 71 struct drm_file *file_priv); 72 72 73 + int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, 74 + struct drm_file *filp); 75 + 76 + int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, 77 + struct drm_file *filp); 78 + 73 79 /* drm_auth.c */ 74 80 int drm_getmagic(struct drm_device *dev, void *data, 75 81 struct drm_file *file_priv);
+2
drivers/gpu/drm/drm_ioctl.c
··· 663 663 DRM_UNLOCKED|DRM_RENDER_ALLOW), 664 664 DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_SIGNAL, drm_syncobj_signal_ioctl, 665 665 DRM_UNLOCKED|DRM_RENDER_ALLOW), 666 + DRM_IOCTL_DEF(DRM_IOCTL_CRTC_GET_SEQUENCE, drm_crtc_get_sequence_ioctl, DRM_UNLOCKED), 667 + DRM_IOCTL_DEF(DRM_IOCTL_CRTC_QUEUE_SEQUENCE, drm_crtc_queue_sequence_ioctl, DRM_UNLOCKED), 666 668 }; 667 669 668 670 #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
+168
drivers/gpu/drm/drm_vblank.c
··· 819 819 e->event.vbl.tv_sec = tv.tv_sec; 820 820 e->event.vbl.tv_usec = tv.tv_nsec / 1000; 821 821 break; 822 + case DRM_EVENT_CRTC_SEQUENCE: 823 + if (seq) 824 + e->event.seq.sequence = seq; 825 + e->event.seq.time_ns = ktime_to_ns(now); 826 + break; 822 827 } 823 828 trace_drm_vblank_event_delivered(e->base.file_priv, e->pipe, seq); 824 829 drm_send_event_locked(dev, &e->base); ··· 1655 1650 return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc)); 1656 1651 } 1657 1652 EXPORT_SYMBOL(drm_crtc_handle_vblank); 1653 + 1654 + /* 1655 + * Get crtc VBLANK count. 1656 + * 1657 + * \param dev DRM device 1658 + * \param data user arguement, pointing to a drm_crtc_get_sequence structure. 1659 + * \param file_priv drm file private for the user's open file descriptor 1660 + */ 1661 + 1662 + int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, 1663 + struct drm_file *file_priv) 1664 + { 1665 + struct drm_crtc *crtc; 1666 + struct drm_vblank_crtc *vblank; 1667 + int pipe; 1668 + struct drm_crtc_get_sequence *get_seq = data; 1669 + ktime_t now; 1670 + bool vblank_enabled; 1671 + int ret; 1672 + 1673 + if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1674 + return -EINVAL; 1675 + 1676 + if (!dev->irq_enabled) 1677 + return -EINVAL; 1678 + 1679 + crtc = drm_crtc_find(dev, file_priv, get_seq->crtc_id); 1680 + if (!crtc) 1681 + return -ENOENT; 1682 + 1683 + pipe = drm_crtc_index(crtc); 1684 + 1685 + vblank = &dev->vblank[pipe]; 1686 + vblank_enabled = dev->vblank_disable_immediate && READ_ONCE(vblank->enabled); 1687 + 1688 + if (!vblank_enabled) { 1689 + ret = drm_crtc_vblank_get(crtc); 1690 + if (ret) { 1691 + DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret); 1692 + return ret; 1693 + } 1694 + } 1695 + drm_modeset_lock(&crtc->mutex, NULL); 1696 + if (crtc->state) 1697 + get_seq->active = crtc->state->enable; 1698 + else 1699 + get_seq->active = crtc->enabled; 1700 + drm_modeset_unlock(&crtc->mutex); 1701 + get_seq->sequence = drm_vblank_count_and_time(dev, pipe, &now); 1702 + get_seq->sequence_ns = ktime_to_ns(now); 1703 + if (!vblank_enabled) 1704 + drm_crtc_vblank_put(crtc); 1705 + return 0; 1706 + } 1707 + 1708 + /* 1709 + * Queue a event for VBLANK sequence 1710 + * 1711 + * \param dev DRM device 1712 + * \param data user arguement, pointing to a drm_crtc_queue_sequence structure. 1713 + * \param file_priv drm file private for the user's open file descriptor 1714 + */ 1715 + 1716 + int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, 1717 + struct drm_file *file_priv) 1718 + { 1719 + struct drm_crtc *crtc; 1720 + struct drm_vblank_crtc *vblank; 1721 + int pipe; 1722 + struct drm_crtc_queue_sequence *queue_seq = data; 1723 + ktime_t now; 1724 + struct drm_pending_vblank_event *e; 1725 + u32 flags; 1726 + u64 seq; 1727 + u64 req_seq; 1728 + int ret; 1729 + unsigned long spin_flags; 1730 + 1731 + if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1732 + return -EINVAL; 1733 + 1734 + if (!dev->irq_enabled) 1735 + return -EINVAL; 1736 + 1737 + crtc = drm_crtc_find(dev, file_priv, queue_seq->crtc_id); 1738 + if (!crtc) 1739 + return -ENOENT; 1740 + 1741 + flags = queue_seq->flags; 1742 + /* Check valid flag bits */ 1743 + if (flags & ~(DRM_CRTC_SEQUENCE_RELATIVE| 1744 + DRM_CRTC_SEQUENCE_NEXT_ON_MISS)) 1745 + return -EINVAL; 1746 + 1747 + pipe = drm_crtc_index(crtc); 1748 + 1749 + vblank = &dev->vblank[pipe]; 1750 + 1751 + e = kzalloc(sizeof(*e), GFP_KERNEL); 1752 + if (e == NULL) 1753 + return -ENOMEM; 1754 + 1755 + ret = drm_crtc_vblank_get(crtc); 1756 + if (ret) { 1757 + DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret); 1758 + goto err_free; 1759 + } 1760 + 1761 + seq = drm_vblank_count_and_time(dev, pipe, &now); 1762 + req_seq = queue_seq->sequence; 1763 + 1764 + if (flags & DRM_CRTC_SEQUENCE_RELATIVE) 1765 + req_seq += seq; 1766 + 1767 + if ((flags & DRM_CRTC_SEQUENCE_NEXT_ON_MISS) && vblank_passed(seq, req_seq)) 1768 + req_seq = seq + 1; 1769 + 1770 + e->pipe = pipe; 1771 + e->event.base.type = DRM_EVENT_CRTC_SEQUENCE; 1772 + e->event.base.length = sizeof(e->event.seq); 1773 + e->event.seq.user_data = queue_seq->user_data; 1774 + 1775 + spin_lock_irqsave(&dev->event_lock, spin_flags); 1776 + 1777 + /* 1778 + * drm_crtc_vblank_off() might have been called after we called 1779 + * drm_crtc_vblank_get(). drm_crtc_vblank_off() holds event_lock around the 1780 + * vblank disable, so no need for further locking. The reference from 1781 + * drm_crtc_vblank_get() protects against vblank disable from another source. 1782 + */ 1783 + if (!READ_ONCE(vblank->enabled)) { 1784 + ret = -EINVAL; 1785 + goto err_unlock; 1786 + } 1787 + 1788 + ret = drm_event_reserve_init_locked(dev, file_priv, &e->base, 1789 + &e->event.base); 1790 + 1791 + if (ret) 1792 + goto err_unlock; 1793 + 1794 + e->sequence = req_seq; 1795 + 1796 + if (vblank_passed(seq, req_seq)) { 1797 + drm_crtc_vblank_put(crtc); 1798 + send_vblank_event(dev, e, seq, now); 1799 + queue_seq->sequence = seq; 1800 + } else { 1801 + /* drm_handle_vblank_events will call drm_vblank_put */ 1802 + list_add_tail(&e->base.link, &dev->vblank_event_list); 1803 + queue_seq->sequence = req_seq; 1804 + } 1805 + 1806 + spin_unlock_irqrestore(&dev->event_lock, spin_flags); 1807 + return 0; 1808 + 1809 + err_unlock: 1810 + spin_unlock_irqrestore(&dev->event_lock, spin_flags); 1811 + drm_crtc_vblank_put(crtc); 1812 + err_free: 1813 + kfree(e); 1814 + return ret; 1815 + }
+1
include/drm/drm_vblank.h
··· 57 57 union { 58 58 struct drm_event base; 59 59 struct drm_event_vblank vbl; 60 + struct drm_event_crtc_sequence seq; 60 61 } event; 61 62 }; 62 63
+36
include/uapi/drm/drm.h
··· 737 737 __u32 pad; 738 738 }; 739 739 740 + /* Query current scanout sequence number */ 741 + struct drm_crtc_get_sequence { 742 + __u32 crtc_id; /* requested crtc_id */ 743 + __u32 active; /* return: crtc output is active */ 744 + __u64 sequence; /* return: most recent vblank sequence */ 745 + __s64 sequence_ns; /* return: most recent time of first pixel out */ 746 + }; 747 + 748 + /* Queue event to be delivered at specified sequence. Time stamp marks 749 + * when the first pixel of the refresh cycle leaves the display engine 750 + * for the display 751 + */ 752 + #define DRM_CRTC_SEQUENCE_RELATIVE 0x00000001 /* sequence is relative to current */ 753 + #define DRM_CRTC_SEQUENCE_NEXT_ON_MISS 0x00000002 /* Use next sequence if we've missed */ 754 + 755 + struct drm_crtc_queue_sequence { 756 + __u32 crtc_id; 757 + __u32 flags; 758 + __u64 sequence; /* on input, target sequence. on output, actual sequence */ 759 + __u64 user_data; /* user data passed to event */ 760 + }; 761 + 740 762 #if defined(__cplusplus) 741 763 } 742 764 #endif ··· 841 819 842 820 #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, union drm_wait_vblank) 843 821 822 + #define DRM_IOCTL_CRTC_GET_SEQUENCE DRM_IOWR(0x3b, struct drm_crtc_get_sequence) 823 + #define DRM_IOCTL_CRTC_QUEUE_SEQUENCE DRM_IOWR(0x3c, struct drm_crtc_queue_sequence) 824 + 844 825 #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) 845 826 846 827 #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) ··· 918 893 919 894 #define DRM_EVENT_VBLANK 0x01 920 895 #define DRM_EVENT_FLIP_COMPLETE 0x02 896 + #define DRM_EVENT_CRTC_SEQUENCE 0x03 921 897 922 898 struct drm_event_vblank { 923 899 struct drm_event base; ··· 927 901 __u32 tv_usec; 928 902 __u32 sequence; 929 903 __u32 crtc_id; /* 0 on older kernels that do not support this */ 904 + }; 905 + 906 + /* Event delivered at sequence. Time stamp marks when the first pixel 907 + * of the refresh cycle leaves the display engine for the display 908 + */ 909 + struct drm_event_crtc_sequence { 910 + struct drm_event base; 911 + __u64 user_data; 912 + __s64 time_ns; 913 + __u64 sequence; 930 914 }; 931 915 932 916 /* typedef area */