aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2016-06-08 08:19:00 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-06-10 10:57:54 -0400
commit3b24f7d6758165919ba7b83b3c8365c38ffacc0b (patch)
tree004c7580981a828075ff01e3fa764675febab6cc
parenta33e93dba23b7f03297d1eb5ab91feaa88cccd97 (diff)
drm/atomic: Add struct drm_crtc_commit to track async updates
Split out from my big nonblocking atomic commit helper code as prep work. While add it, also add some neat asciiart to document how it's supposed to be used. v2: Resurrect misplaced hunk in the kerneldoc. v3: Wording improvements from Liviu. Tested-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Tomeu Vizoso <tomeu.vizoso@gmail.com> Cc: Daniel Stone <daniels@collabora.com> Tested-by: Liviu Dudau <Liviu.Dudau@arm.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1465388359-8070-8-git-send-email-daniel.vetter@ffwll.ch
-rw-r--r--drivers/gpu/drm/drm_atomic.c22
-rw-r--r--drivers/gpu/drm/drm_crtc.c3
-rw-r--r--drivers/gpu/drm/drm_fops.c6
-rw-r--r--include/drm/drmP.h1
-rw-r--r--include/drm/drm_atomic.h6
-rw-r--r--include/drm/drm_crtc.h149
6 files changed, 181 insertions, 6 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5e4b820a977c..d99ab2f6663f 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -33,6 +33,20 @@
33 33
34#include "drm_crtc_internal.h" 34#include "drm_crtc_internal.h"
35 35
36static void crtc_commit_free(struct kref *kref)
37{
38 struct drm_crtc_commit *commit =
39 container_of(kref, struct drm_crtc_commit, ref);
40
41 kfree(commit);
42}
43
44void drm_crtc_commit_put(struct drm_crtc_commit *commit)
45{
46 kref_put(&commit->ref, crtc_commit_free);
47}
48EXPORT_SYMBOL(drm_crtc_commit_put);
49
36/** 50/**
37 * drm_atomic_state_default_release - 51 * drm_atomic_state_default_release -
38 * release memory initialized by drm_atomic_state_init 52 * release memory initialized by drm_atomic_state_init
@@ -148,6 +162,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
148 162
149 crtc->funcs->atomic_destroy_state(crtc, 163 crtc->funcs->atomic_destroy_state(crtc,
150 state->crtcs[i].state); 164 state->crtcs[i].state);
165
166 if (state->crtcs[i].commit) {
167 kfree(state->crtcs[i].commit->event);
168 state->crtcs[i].commit->event = NULL;
169 drm_crtc_commit_put(state->crtcs[i].commit);
170 }
171
172 state->crtcs[i].commit = NULL;
151 state->crtcs[i].ptr = NULL; 173 state->crtcs[i].ptr = NULL;
152 state->crtcs[i].state = NULL; 174 state->crtcs[i].state = NULL;
153 } 175 }
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index aeb5d9e087fc..4ec35f9e6de5 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -638,6 +638,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
638 crtc->dev = dev; 638 crtc->dev = dev;
639 crtc->funcs = funcs; 639 crtc->funcs = funcs;
640 640
641 INIT_LIST_HEAD(&crtc->commit_list);
642 spin_lock_init(&crtc->commit_lock);
643
641 drm_modeset_lock_init(&crtc->mutex); 644 drm_modeset_lock_init(&crtc->mutex);
642 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 645 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
643 if (ret) 646 if (ret)
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 64121f567234..a27bc7cda975 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -797,6 +797,12 @@ void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e)
797{ 797{
798 assert_spin_locked(&dev->event_lock); 798 assert_spin_locked(&dev->event_lock);
799 799
800 if (e->completion) {
801 /* ->completion might disappear as soon as it signalled. */
802 complete_all(e->completion);
803 e->completion = NULL;
804 }
805
800 if (e->fence) { 806 if (e->fence) {
801 fence_signal(e->fence); 807 fence_signal(e->fence);
802 fence_put(e->fence); 808 fence_put(e->fence);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 086ad96d7d62..ae9ff73f1a0c 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -284,6 +284,7 @@ struct drm_ioctl_desc {
284 284
285/* Event queued up for userspace to read */ 285/* Event queued up for userspace to read */
286struct drm_pending_event { 286struct drm_pending_event {
287 struct completion *completion;
287 struct drm_event *event; 288 struct drm_event *event;
288 struct fence *fence; 289 struct fence *fence;
289 struct list_head link; 290 struct list_head link;
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index a16861c882aa..856a9c85a838 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -30,6 +30,12 @@
30 30
31#include <drm/drm_crtc.h> 31#include <drm/drm_crtc.h>
32 32
33void drm_crtc_commit_put(struct drm_crtc_commit *commit);
34static inline void drm_crtc_commit_get(struct drm_crtc_commit *commit)
35{
36 kref_get(&commit->ref);
37}
38
33struct drm_atomic_state * __must_check 39struct drm_atomic_state * __must_check
34drm_atomic_state_alloc(struct drm_device *dev); 40drm_atomic_state_alloc(struct drm_device *dev);
35void drm_atomic_state_clear(struct drm_atomic_state *state); 41void drm_atomic_state_clear(struct drm_atomic_state *state);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 7bf065b61316..5eb1f0884848 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -728,9 +728,6 @@ struct drm_crtc_funcs {
728 * @gamma_store: gamma ramp values 728 * @gamma_store: gamma ramp values
729 * @helper_private: mid-layer private data 729 * @helper_private: mid-layer private data
730 * @properties: property tracking for this CRTC 730 * @properties: property tracking for this CRTC
731 * @state: current atomic state for this CRTC
732 * @acquire_ctx: per-CRTC implicit acquire context used by atomic drivers for
733 * legacy IOCTLs
734 * 731 *
735 * Each CRTC may have one or more connectors associated with it. This structure 732 * Each CRTC may have one or more connectors associated with it. This structure
736 * allows the CRTC to be controlled. 733 * allows the CRTC to be controlled.
@@ -787,11 +784,37 @@ struct drm_crtc {
787 784
788 struct drm_object_properties properties; 785 struct drm_object_properties properties;
789 786
787 /**
788 * @state:
789 *
790 * Current atomic state for this CRTC.
791 */
790 struct drm_crtc_state *state; 792 struct drm_crtc_state *state;
791 793
792 /* 794 /**
793 * For legacy crtc IOCTLs so that atomic drivers can get at the locking 795 * @commit_list:
794 * acquire context. 796 *
797 * List of &drm_crtc_commit structures tracking pending commits.
798 * Protected by @commit_lock. This list doesn't hold its own full
799 * reference, but burrows it from the ongoing commit. Commit entries
800 * must be removed from this list once the commit is fully completed,
801 * but before it's correspoding &drm_atomic_state gets destroyed.
802 */
803 struct list_head commit_list;
804
805 /**
806 * @commit_lock:
807 *
808 * Spinlock to protect @commit_list.
809 */
810 spinlock_t commit_lock;
811
812 /**
813 * @acquire_ctx:
814 *
815 * Per-CRTC implicit acquire context used by atomic drivers for legacy
816 * IOCTLs, so that atomic drivers can get at the locking acquire
817 * context.
795 */ 818 */
796 struct drm_modeset_acquire_ctx *acquire_ctx; 819 struct drm_modeset_acquire_ctx *acquire_ctx;
797}; 820};
@@ -1733,6 +1756,111 @@ struct drm_bridge {
1733 void *driver_private; 1756 void *driver_private;
1734}; 1757};
1735 1758
1759/**
1760 * struct drm_crtc_commit - track modeset commits on a CRTC
1761 *
1762 * This structure is used to track pending modeset changes and atomic commit on
1763 * a per-CRTC basis. Since updating the list should never block this structure
1764 * is reference counted to allow waiters to safely wait on an event to complete,
1765 * without holding any locks.
1766 *
1767 * It has 3 different events in total to allow a fine-grained synchronization
1768 * between outstanding updates::
1769 *
1770 * atomic commit thread hardware
1771 *
1772 * write new state into hardware ----> ...
1773 * signal hw_done
1774 * switch to new state on next
1775 * ... v/hblank
1776 *
1777 * wait for buffers to show up ...
1778 *
1779 * ... send completion irq
1780 * irq handler signals flip_done
1781 * cleanup old buffers
1782 *
1783 * signal cleanup_done
1784 *
1785 * wait for flip_done <----
1786 * clean up atomic state
1787 *
1788 * The important bit to know is that cleanup_done is the terminal event, but the
1789 * ordering between flip_done and hw_done is entirely up to the specific driver
1790 * and modeset state change.
1791 *
1792 * For an implementation of how to use this look at
1793 * drm_atomic_helper_setup_commit() from the atomic helper library.
1794 */
1795struct drm_crtc_commit {
1796 /**
1797 * @crtc:
1798 *
1799 * DRM CRTC for this commit.
1800 */
1801 struct drm_crtc *crtc;
1802
1803 /**
1804 * @ref:
1805 *
1806 * Reference count for this structure. Needed to allow blocking on
1807 * completions without the risk of the completion disappearing
1808 * meanwhile.
1809 */
1810 struct kref ref;
1811
1812 /**
1813 * @flip_done:
1814 *
1815 * Will be signaled when the hardware has flipped to the new set of
1816 * buffers. Signals at the same time as when the drm event for this
1817 * commit is sent to userspace, or when an out-fence is singalled. Note
1818 * that for most hardware, in most cases this happens after @hw_done is
1819 * signalled.
1820 */
1821 struct completion flip_done;
1822
1823 /**
1824 * @hw_done:
1825 *
1826 * Will be signalled when all hw register changes for this commit have
1827 * been written out. Especially when disabling a pipe this can be much
1828 * later than than @flip_done, since that can signal already when the
1829 * screen goes black, whereas to fully shut down a pipe more register
1830 * I/O is required.
1831 *
1832 * Note that this does not need to include separately reference-counted
1833 * resources like backing storage buffer pinning, or runtime pm
1834 * management.
1835 */
1836 struct completion hw_done;
1837
1838 /**
1839 * @cleanup_done:
1840 *
1841 * Will be signalled after old buffers have been cleaned up by calling
1842 * drm_atomic_helper_cleanup_planes(). Since this can only happen after
1843 * a vblank wait completed it might be a bit later. This completion is
1844 * useful to throttle updates and avoid hardware updates getting ahead
1845 * of the buffer cleanup too much.
1846 */
1847 struct completion cleanup_done;
1848
1849 /**
1850 * @commit_entry:
1851 *
1852 * Entry on the per-CRTC commit_list. Protected by crtc->commit_lock.
1853 */
1854 struct list_head commit_entry;
1855
1856 /**
1857 * @event:
1858 *
1859 * &drm_pending_vblank_event pointer to clean up private events.
1860 */
1861 struct drm_pending_vblank_event *event;
1862};
1863
1736struct __drm_planes_state { 1864struct __drm_planes_state {
1737 struct drm_plane *ptr; 1865 struct drm_plane *ptr;
1738 struct drm_plane_state *state; 1866 struct drm_plane_state *state;
@@ -1741,6 +1869,7 @@ struct __drm_planes_state {
1741struct __drm_crtcs_state { 1869struct __drm_crtcs_state {
1742 struct drm_crtc *ptr; 1870 struct drm_crtc *ptr;
1743 struct drm_crtc_state *state; 1871 struct drm_crtc_state *state;
1872 struct drm_crtc_commit *commit;
1744}; 1873};
1745 1874
1746struct __drm_connnectors_state { 1875struct __drm_connnectors_state {
@@ -1771,6 +1900,14 @@ struct drm_atomic_state {
1771 struct __drm_connnectors_state *connectors; 1900 struct __drm_connnectors_state *connectors;
1772 1901
1773 struct drm_modeset_acquire_ctx *acquire_ctx; 1902 struct drm_modeset_acquire_ctx *acquire_ctx;
1903
1904 /**
1905 * @commit_work:
1906 *
1907 * Work item which can be used by the driver or helpers to execute the
1908 * commit without blocking.
1909 */
1910 struct work_struct commit_work;
1774}; 1911};
1775 1912
1776 1913