diff options
author | Damien Lespiau <damien.lespiau@intel.com> | 2013-10-21 09:29:30 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-10-21 18:27:49 -0400 |
commit | d538bbdfde34028b5c5b0ba92b3c2096c5afb82c (patch) | |
tree | 20bd5f906e81cf13ae577048608d8f77be8f72b4 | |
parent | c459787294e8375210a3d26fe8ed83f40eca3276 (diff) |
drm/i915: Use a spin lock to protect the pipe crc struct
Daniel pointed out that it was hard to get anything lockless to work
correctly, so don't even try for this non critical piece of code and
just use a spin lock.
v2: Make intel_pipe_crc->opened a bool
v3: Use assert_spin_locked() instead of a comment (Daniel Vetter)
v4: Use spin_lock_irq() in the debugfs functions (they can only be
called from process context),
Use spin_lock() in the pipe_crc_update() function that can only be
called from an interrupt handler,
Use wait_event_interruptible_lock_irq() when waiting for data in the
cicular buffer to ensure proper locking around the condition we are
waiting for. (Daniel Vetter)
Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 66 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 12 |
3 files changed, 58 insertions, 25 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 25fc3841a2b1..5c45e9e598de 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -1772,13 +1772,18 @@ static int i915_pipe_crc_open(struct inode *inode, struct file *filep) | |||
1772 | struct drm_i915_private *dev_priv = info->dev->dev_private; | 1772 | struct drm_i915_private *dev_priv = info->dev->dev_private; |
1773 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; | 1773 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; |
1774 | 1774 | ||
1775 | if (!atomic_dec_and_test(&pipe_crc->available)) { | 1775 | spin_lock_irq(&pipe_crc->lock); |
1776 | atomic_inc(&pipe_crc->available); | 1776 | |
1777 | if (pipe_crc->opened) { | ||
1778 | spin_unlock_irq(&pipe_crc->lock); | ||
1777 | return -EBUSY; /* already open */ | 1779 | return -EBUSY; /* already open */ |
1778 | } | 1780 | } |
1779 | 1781 | ||
1782 | pipe_crc->opened = true; | ||
1780 | filep->private_data = inode->i_private; | 1783 | filep->private_data = inode->i_private; |
1781 | 1784 | ||
1785 | spin_unlock_irq(&pipe_crc->lock); | ||
1786 | |||
1782 | return 0; | 1787 | return 0; |
1783 | } | 1788 | } |
1784 | 1789 | ||
@@ -1788,7 +1793,9 @@ static int i915_pipe_crc_release(struct inode *inode, struct file *filep) | |||
1788 | struct drm_i915_private *dev_priv = info->dev->dev_private; | 1793 | struct drm_i915_private *dev_priv = info->dev->dev_private; |
1789 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; | 1794 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; |
1790 | 1795 | ||
1791 | atomic_inc(&pipe_crc->available); /* release the device */ | 1796 | spin_lock_irq(&pipe_crc->lock); |
1797 | pipe_crc->opened = false; | ||
1798 | spin_unlock_irq(&pipe_crc->lock); | ||
1792 | 1799 | ||
1793 | return 0; | 1800 | return 0; |
1794 | } | 1801 | } |
@@ -1800,12 +1807,9 @@ static int i915_pipe_crc_release(struct inode *inode, struct file *filep) | |||
1800 | 1807 | ||
1801 | static int pipe_crc_data_count(struct intel_pipe_crc *pipe_crc) | 1808 | static int pipe_crc_data_count(struct intel_pipe_crc *pipe_crc) |
1802 | { | 1809 | { |
1803 | int head, tail; | 1810 | assert_spin_locked(&pipe_crc->lock); |
1804 | 1811 | return CIRC_CNT(pipe_crc->head, pipe_crc->tail, | |
1805 | head = atomic_read(&pipe_crc->head); | 1812 | INTEL_PIPE_CRC_ENTRIES_NR); |
1806 | tail = atomic_read(&pipe_crc->tail); | ||
1807 | |||
1808 | return CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR); | ||
1809 | } | 1813 | } |
1810 | 1814 | ||
1811 | static ssize_t | 1815 | static ssize_t |
@@ -1831,20 +1835,30 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count, | |||
1831 | return 0; | 1835 | return 0; |
1832 | 1836 | ||
1833 | /* nothing to read */ | 1837 | /* nothing to read */ |
1838 | spin_lock_irq(&pipe_crc->lock); | ||
1834 | while (pipe_crc_data_count(pipe_crc) == 0) { | 1839 | while (pipe_crc_data_count(pipe_crc) == 0) { |
1835 | if (filep->f_flags & O_NONBLOCK) | 1840 | int ret; |
1841 | |||
1842 | if (filep->f_flags & O_NONBLOCK) { | ||
1843 | spin_unlock_irq(&pipe_crc->lock); | ||
1836 | return -EAGAIN; | 1844 | return -EAGAIN; |
1845 | } | ||
1837 | 1846 | ||
1838 | if (wait_event_interruptible(pipe_crc->wq, | 1847 | ret = wait_event_interruptible_lock_irq(pipe_crc->wq, |
1839 | pipe_crc_data_count(pipe_crc))) | 1848 | pipe_crc_data_count(pipe_crc), pipe_crc->lock); |
1840 | return -ERESTARTSYS; | 1849 | if (ret) { |
1850 | spin_unlock_irq(&pipe_crc->lock); | ||
1851 | return ret; | ||
1852 | } | ||
1841 | } | 1853 | } |
1842 | 1854 | ||
1843 | /* We now have one or more entries to read */ | 1855 | /* We now have one or more entries to read */ |
1844 | head = atomic_read(&pipe_crc->head); | 1856 | head = pipe_crc->head; |
1845 | tail = atomic_read(&pipe_crc->tail); | 1857 | tail = pipe_crc->tail; |
1846 | n_entries = min((size_t)CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR), | 1858 | n_entries = min((size_t)CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR), |
1847 | count / PIPE_CRC_LINE_LEN); | 1859 | count / PIPE_CRC_LINE_LEN); |
1860 | spin_unlock_irq(&pipe_crc->lock); | ||
1861 | |||
1848 | bytes_read = 0; | 1862 | bytes_read = 0; |
1849 | n = 0; | 1863 | n = 0; |
1850 | do { | 1864 | do { |
@@ -1864,10 +1878,13 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count, | |||
1864 | 1878 | ||
1865 | BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); | 1879 | BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); |
1866 | tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); | 1880 | tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); |
1867 | atomic_set(&pipe_crc->tail, tail); | ||
1868 | n++; | 1881 | n++; |
1869 | } while (--n_entries); | 1882 | } while (--n_entries); |
1870 | 1883 | ||
1884 | spin_lock_irq(&pipe_crc->lock); | ||
1885 | pipe_crc->tail = tail; | ||
1886 | spin_unlock_irq(&pipe_crc->lock); | ||
1887 | |||
1871 | return bytes_read; | 1888 | return bytes_read; |
1872 | } | 1889 | } |
1873 | 1890 | ||
@@ -2111,8 +2128,10 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, | |||
2111 | if (!pipe_crc->entries) | 2128 | if (!pipe_crc->entries) |
2112 | return -ENOMEM; | 2129 | return -ENOMEM; |
2113 | 2130 | ||
2114 | atomic_set(&pipe_crc->head, 0); | 2131 | spin_lock_irq(&pipe_crc->lock); |
2115 | atomic_set(&pipe_crc->tail, 0); | 2132 | pipe_crc->head = 0; |
2133 | pipe_crc->tail = 0; | ||
2134 | spin_unlock_irq(&pipe_crc->lock); | ||
2116 | } | 2135 | } |
2117 | 2136 | ||
2118 | pipe_crc->source = source; | 2137 | pipe_crc->source = source; |
@@ -2122,13 +2141,19 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, | |||
2122 | 2141 | ||
2123 | /* real source -> none transition */ | 2142 | /* real source -> none transition */ |
2124 | if (source == INTEL_PIPE_CRC_SOURCE_NONE) { | 2143 | if (source == INTEL_PIPE_CRC_SOURCE_NONE) { |
2144 | struct intel_pipe_crc_entry *entries; | ||
2145 | |||
2125 | DRM_DEBUG_DRIVER("stopping CRCs for pipe %c\n", | 2146 | DRM_DEBUG_DRIVER("stopping CRCs for pipe %c\n", |
2126 | pipe_name(pipe)); | 2147 | pipe_name(pipe)); |
2127 | 2148 | ||
2128 | intel_wait_for_vblank(dev, pipe); | 2149 | intel_wait_for_vblank(dev, pipe); |
2129 | 2150 | ||
2130 | kfree(pipe_crc->entries); | 2151 | spin_lock_irq(&pipe_crc->lock); |
2152 | entries = pipe_crc->entries; | ||
2131 | pipe_crc->entries = NULL; | 2153 | pipe_crc->entries = NULL; |
2154 | spin_unlock_irq(&pipe_crc->lock); | ||
2155 | |||
2156 | kfree(entries); | ||
2132 | } | 2157 | } |
2133 | 2158 | ||
2134 | return 0; | 2159 | return 0; |
@@ -2823,7 +2848,8 @@ void intel_display_crc_init(struct drm_device *dev) | |||
2823 | for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { | 2848 | for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { |
2824 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[i]; | 2849 | struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[i]; |
2825 | 2850 | ||
2826 | atomic_set(&pipe_crc->available, 1); | 2851 | pipe_crc->opened = false; |
2852 | spin_lock_init(&pipe_crc->lock); | ||
2827 | init_waitqueue_head(&pipe_crc->wq); | 2853 | init_waitqueue_head(&pipe_crc->wq); |
2828 | } | 2854 | } |
2829 | } | 2855 | } |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2e1e884ac86c..5bfcf0f91a51 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -1249,10 +1249,11 @@ struct intel_pipe_crc_entry { | |||
1249 | 1249 | ||
1250 | #define INTEL_PIPE_CRC_ENTRIES_NR 128 | 1250 | #define INTEL_PIPE_CRC_ENTRIES_NR 128 |
1251 | struct intel_pipe_crc { | 1251 | struct intel_pipe_crc { |
1252 | atomic_t available; /* exclusive access to the device */ | 1252 | spinlock_t lock; |
1253 | bool opened; /* exclusive access to the result file */ | ||
1253 | struct intel_pipe_crc_entry *entries; | 1254 | struct intel_pipe_crc_entry *entries; |
1254 | enum intel_pipe_crc_source source; | 1255 | enum intel_pipe_crc_source source; |
1255 | atomic_t head, tail; | 1256 | int head, tail; |
1256 | wait_queue_head_t wq; | 1257 | wait_queue_head_t wq; |
1257 | }; | 1258 | }; |
1258 | 1259 | ||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8f7baad72316..1a7dc7754e2f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -1200,15 +1200,19 @@ static void display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe, | |||
1200 | struct intel_pipe_crc_entry *entry; | 1200 | struct intel_pipe_crc_entry *entry; |
1201 | int head, tail; | 1201 | int head, tail; |
1202 | 1202 | ||
1203 | spin_lock(&pipe_crc->lock); | ||
1204 | |||
1203 | if (!pipe_crc->entries) { | 1205 | if (!pipe_crc->entries) { |
1206 | spin_unlock(&pipe_crc->lock); | ||
1204 | DRM_ERROR("spurious interrupt\n"); | 1207 | DRM_ERROR("spurious interrupt\n"); |
1205 | return; | 1208 | return; |
1206 | } | 1209 | } |
1207 | 1210 | ||
1208 | head = atomic_read(&pipe_crc->head); | 1211 | head = pipe_crc->head; |
1209 | tail = atomic_read(&pipe_crc->tail); | 1212 | tail = pipe_crc->tail; |
1210 | 1213 | ||
1211 | if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) { | 1214 | if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) { |
1215 | spin_unlock(&pipe_crc->lock); | ||
1212 | DRM_ERROR("CRC buffer overflowing\n"); | 1216 | DRM_ERROR("CRC buffer overflowing\n"); |
1213 | return; | 1217 | return; |
1214 | } | 1218 | } |
@@ -1223,7 +1227,9 @@ static void display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe, | |||
1223 | entry->crc[4] = crc4; | 1227 | entry->crc[4] = crc4; |
1224 | 1228 | ||
1225 | head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); | 1229 | head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); |
1226 | atomic_set(&pipe_crc->head, head); | 1230 | pipe_crc->head = head; |
1231 | |||
1232 | spin_unlock(&pipe_crc->lock); | ||
1227 | 1233 | ||
1228 | wake_up_interruptible(&pipe_crc->wq); | 1234 | wake_up_interruptible(&pipe_crc->wq); |
1229 | } | 1235 | } |