aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamien Lespiau <damien.lespiau@intel.com>2013-10-21 09:29:30 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-10-21 18:27:49 -0400
commitd538bbdfde34028b5c5b0ba92b3c2096c5afb82c (patch)
tree20bd5f906e81cf13ae577048608d8f77be8f72b4
parentc459787294e8375210a3d26fe8ed83f40eca3276 (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.c66
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c12
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
1801static int pipe_crc_data_count(struct intel_pipe_crc *pipe_crc) 1808static 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
1811static ssize_t 1815static 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
1251struct intel_pipe_crc { 1251struct 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}