aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_irq.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_irq.c187
1 files changed, 107 insertions, 80 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index e92298a6a383..cabc95f7517e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -34,26 +34,33 @@ irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS)
34{ 34{
35 struct drm_device *dev = (struct drm_device *)arg; 35 struct drm_device *dev = (struct drm_device *)arg;
36 struct vmw_private *dev_priv = vmw_priv(dev); 36 struct vmw_private *dev_priv = vmw_priv(dev);
37 uint32_t status; 37 uint32_t status, masked_status;
38 38
39 spin_lock(&dev_priv->irq_lock); 39 spin_lock(&dev_priv->irq_lock);
40 status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 40 status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
41 masked_status = status & dev_priv->irq_mask;
41 spin_unlock(&dev_priv->irq_lock); 42 spin_unlock(&dev_priv->irq_lock);
42 43
43 if (status & SVGA_IRQFLAG_ANY_FENCE) 44 if (likely(status))
45 outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
46
47 if (!masked_status)
48 return IRQ_NONE;
49
50 if (masked_status & (SVGA_IRQFLAG_ANY_FENCE |
51 SVGA_IRQFLAG_FENCE_GOAL)) {
52 vmw_fences_update(dev_priv->fman);
44 wake_up_all(&dev_priv->fence_queue); 53 wake_up_all(&dev_priv->fence_queue);
45 if (status & SVGA_IRQFLAG_FIFO_PROGRESS) 54 }
55
56 if (masked_status & SVGA_IRQFLAG_FIFO_PROGRESS)
46 wake_up_all(&dev_priv->fifo_queue); 57 wake_up_all(&dev_priv->fifo_queue);
47 58
48 if (likely(status)) {
49 outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
50 return IRQ_HANDLED;
51 }
52 59
53 return IRQ_NONE; 60 return IRQ_HANDLED;
54} 61}
55 62
56static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence) 63static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno)
57{ 64{
58 uint32_t busy; 65 uint32_t busy;
59 66
@@ -64,43 +71,43 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence)
64 return (busy == 0); 71 return (busy == 0);
65} 72}
66 73
67void vmw_update_sequence(struct vmw_private *dev_priv, 74void vmw_update_seqno(struct vmw_private *dev_priv,
68 struct vmw_fifo_state *fifo_state) 75 struct vmw_fifo_state *fifo_state)
69{ 76{
70 __le32 __iomem *fifo_mem = dev_priv->mmio_virt; 77 __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
78 uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
71 79
72 uint32_t sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); 80 if (dev_priv->last_read_seqno != seqno) {
73 81 dev_priv->last_read_seqno = seqno;
74 if (dev_priv->last_read_sequence != sequence) { 82 vmw_marker_pull(&fifo_state->marker_queue, seqno);
75 dev_priv->last_read_sequence = sequence; 83 vmw_fences_update(dev_priv->fman);
76 vmw_fence_pull(&fifo_state->fence_queue, sequence);
77 } 84 }
78} 85}
79 86
80bool vmw_fence_signaled(struct vmw_private *dev_priv, 87bool vmw_seqno_passed(struct vmw_private *dev_priv,
81 uint32_t sequence) 88 uint32_t seqno)
82{ 89{
83 struct vmw_fifo_state *fifo_state; 90 struct vmw_fifo_state *fifo_state;
84 bool ret; 91 bool ret;
85 92
86 if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) 93 if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
87 return true; 94 return true;
88 95
89 fifo_state = &dev_priv->fifo; 96 fifo_state = &dev_priv->fifo;
90 vmw_update_sequence(dev_priv, fifo_state); 97 vmw_update_seqno(dev_priv, fifo_state);
91 if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) 98 if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
92 return true; 99 return true;
93 100
94 if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && 101 if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) &&
95 vmw_fifo_idle(dev_priv, sequence)) 102 vmw_fifo_idle(dev_priv, seqno))
96 return true; 103 return true;
97 104
98 /** 105 /**
99 * Then check if the sequence is higher than what we've actually 106 * Then check if the seqno is higher than what we've actually
100 * emitted. Then the fence is stale and signaled. 107 * emitted. Then the fence is stale and signaled.
101 */ 108 */
102 109
103 ret = ((atomic_read(&dev_priv->fence_seq) - sequence) 110 ret = ((atomic_read(&dev_priv->marker_seq) - seqno)
104 > VMW_FENCE_WRAP); 111 > VMW_FENCE_WRAP);
105 112
106 return ret; 113 return ret;
@@ -109,7 +116,7 @@ bool vmw_fence_signaled(struct vmw_private *dev_priv,
109int vmw_fallback_wait(struct vmw_private *dev_priv, 116int vmw_fallback_wait(struct vmw_private *dev_priv,
110 bool lazy, 117 bool lazy,
111 bool fifo_idle, 118 bool fifo_idle,
112 uint32_t sequence, 119 uint32_t seqno,
113 bool interruptible, 120 bool interruptible,
114 unsigned long timeout) 121 unsigned long timeout)
115{ 122{
@@ -123,7 +130,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
123 DEFINE_WAIT(__wait); 130 DEFINE_WAIT(__wait);
124 131
125 wait_condition = (fifo_idle) ? &vmw_fifo_idle : 132 wait_condition = (fifo_idle) ? &vmw_fifo_idle :
126 &vmw_fence_signaled; 133 &vmw_seqno_passed;
127 134
128 /** 135 /**
129 * Block command submission while waiting for idle. 136 * Block command submission while waiting for idle.
@@ -131,14 +138,14 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
131 138
132 if (fifo_idle) 139 if (fifo_idle)
133 down_read(&fifo_state->rwsem); 140 down_read(&fifo_state->rwsem);
134 signal_seq = atomic_read(&dev_priv->fence_seq); 141 signal_seq = atomic_read(&dev_priv->marker_seq);
135 ret = 0; 142 ret = 0;
136 143
137 for (;;) { 144 for (;;) {
138 prepare_to_wait(&dev_priv->fence_queue, &__wait, 145 prepare_to_wait(&dev_priv->fence_queue, &__wait,
139 (interruptible) ? 146 (interruptible) ?
140 TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); 147 TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
141 if (wait_condition(dev_priv, sequence)) 148 if (wait_condition(dev_priv, seqno))
142 break; 149 break;
143 if (time_after_eq(jiffies, end_jiffies)) { 150 if (time_after_eq(jiffies, end_jiffies)) {
144 DRM_ERROR("SVGA device lockup.\n"); 151 DRM_ERROR("SVGA device lockup.\n");
@@ -175,68 +182,110 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
175 return ret; 182 return ret;
176} 183}
177 184
178int vmw_wait_fence(struct vmw_private *dev_priv, 185void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
179 bool lazy, uint32_t sequence, 186{
180 bool interruptible, unsigned long timeout) 187 mutex_lock(&dev_priv->hw_mutex);
188 if (dev_priv->fence_queue_waiters++ == 0) {
189 unsigned long irq_flags;
190
191 spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
192 outl(SVGA_IRQFLAG_ANY_FENCE,
193 dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
194 dev_priv->irq_mask |= SVGA_IRQFLAG_ANY_FENCE;
195 vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
196 spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
197 }
198 mutex_unlock(&dev_priv->hw_mutex);
199}
200
201void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
202{
203 mutex_lock(&dev_priv->hw_mutex);
204 if (--dev_priv->fence_queue_waiters == 0) {
205 unsigned long irq_flags;
206
207 spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
208 dev_priv->irq_mask &= ~SVGA_IRQFLAG_ANY_FENCE;
209 vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
210 spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
211 }
212 mutex_unlock(&dev_priv->hw_mutex);
213}
214
215
216void vmw_goal_waiter_add(struct vmw_private *dev_priv)
217{
218 mutex_lock(&dev_priv->hw_mutex);
219 if (dev_priv->goal_queue_waiters++ == 0) {
220 unsigned long irq_flags;
221
222 spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
223 outl(SVGA_IRQFLAG_FENCE_GOAL,
224 dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
225 dev_priv->irq_mask |= SVGA_IRQFLAG_FENCE_GOAL;
226 vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
227 spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
228 }
229 mutex_unlock(&dev_priv->hw_mutex);
230}
231
232void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
233{
234 mutex_lock(&dev_priv->hw_mutex);
235 if (--dev_priv->goal_queue_waiters == 0) {
236 unsigned long irq_flags;
237
238 spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
239 dev_priv->irq_mask &= ~SVGA_IRQFLAG_FENCE_GOAL;
240 vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
241 spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
242 }
243 mutex_unlock(&dev_priv->hw_mutex);
244}
245
246int vmw_wait_seqno(struct vmw_private *dev_priv,
247 bool lazy, uint32_t seqno,
248 bool interruptible, unsigned long timeout)
181{ 249{
182 long ret; 250 long ret;
183 unsigned long irq_flags;
184 struct vmw_fifo_state *fifo = &dev_priv->fifo; 251 struct vmw_fifo_state *fifo = &dev_priv->fifo;
185 252
186 if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) 253 if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
187 return 0; 254 return 0;
188 255
189 if (likely(vmw_fence_signaled(dev_priv, sequence))) 256 if (likely(vmw_seqno_passed(dev_priv, seqno)))
190 return 0; 257 return 0;
191 258
192 vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); 259 vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
193 260
194 if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE)) 261 if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE))
195 return vmw_fallback_wait(dev_priv, lazy, true, sequence, 262 return vmw_fallback_wait(dev_priv, lazy, true, seqno,
196 interruptible, timeout); 263 interruptible, timeout);
197 264
198 if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) 265 if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
199 return vmw_fallback_wait(dev_priv, lazy, false, sequence, 266 return vmw_fallback_wait(dev_priv, lazy, false, seqno,
200 interruptible, timeout); 267 interruptible, timeout);
201 268
202 mutex_lock(&dev_priv->hw_mutex); 269 vmw_seqno_waiter_add(dev_priv);
203 if (atomic_add_return(1, &dev_priv->fence_queue_waiters) > 0) {
204 spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
205 outl(SVGA_IRQFLAG_ANY_FENCE,
206 dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
207 vmw_write(dev_priv, SVGA_REG_IRQMASK,
208 vmw_read(dev_priv, SVGA_REG_IRQMASK) |
209 SVGA_IRQFLAG_ANY_FENCE);
210 spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
211 }
212 mutex_unlock(&dev_priv->hw_mutex);
213 270
214 if (interruptible) 271 if (interruptible)
215 ret = wait_event_interruptible_timeout 272 ret = wait_event_interruptible_timeout
216 (dev_priv->fence_queue, 273 (dev_priv->fence_queue,
217 vmw_fence_signaled(dev_priv, sequence), 274 vmw_seqno_passed(dev_priv, seqno),
218 timeout); 275 timeout);
219 else 276 else
220 ret = wait_event_timeout 277 ret = wait_event_timeout
221 (dev_priv->fence_queue, 278 (dev_priv->fence_queue,
222 vmw_fence_signaled(dev_priv, sequence), 279 vmw_seqno_passed(dev_priv, seqno),
223 timeout); 280 timeout);
224 281
282 vmw_seqno_waiter_remove(dev_priv);
283
225 if (unlikely(ret == 0)) 284 if (unlikely(ret == 0))
226 ret = -EBUSY; 285 ret = -EBUSY;
227 else if (likely(ret > 0)) 286 else if (likely(ret > 0))
228 ret = 0; 287 ret = 0;
229 288
230 mutex_lock(&dev_priv->hw_mutex);
231 if (atomic_dec_and_test(&dev_priv->fence_queue_waiters)) {
232 spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
233 vmw_write(dev_priv, SVGA_REG_IRQMASK,
234 vmw_read(dev_priv, SVGA_REG_IRQMASK) &
235 ~SVGA_IRQFLAG_ANY_FENCE);
236 spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
237 }
238 mutex_unlock(&dev_priv->hw_mutex);
239
240 return ret; 289 return ret;
241} 290}
242 291
@@ -273,25 +322,3 @@ void vmw_irq_uninstall(struct drm_device *dev)
273 status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 322 status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
274 outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 323 outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
275} 324}
276
277#define VMW_FENCE_WAIT_TIMEOUT 3*HZ;
278
279int vmw_fence_wait_ioctl(struct drm_device *dev, void *data,
280 struct drm_file *file_priv)
281{
282 struct drm_vmw_fence_wait_arg *arg =
283 (struct drm_vmw_fence_wait_arg *)data;
284 unsigned long timeout;
285
286 if (!arg->cookie_valid) {
287 arg->cookie_valid = 1;
288 arg->kernel_cookie = jiffies + VMW_FENCE_WAIT_TIMEOUT;
289 }
290
291 timeout = jiffies;
292 if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie))
293 return -EBUSY;
294
295 timeout = (unsigned long)arg->kernel_cookie - timeout;
296 return vmw_wait_fence(vmw_priv(dev), true, arg->sequence, true, timeout);
297}