1fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**************************************************************************
2fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
3fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
4fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * All Rights Reserved.
5fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
6fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Permission is hereby granted, free of charge, to any person obtaining a
7fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * copy of this software and associated documentation files (the
8fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * "Software"), to deal in the Software without restriction, including
9fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * without limitation the rights to use, copy, modify, merge, publish,
10fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * distribute, sub license, and/or sell copies of the Software, and to
11fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * permit persons to whom the Software is furnished to do so, subject to
12fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * the following conditions:
13fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
14fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * The above copyright notice and this permission notice (including the
15fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * next paragraph) shall be included in all copies or substantial portions
16fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * of the Software.
17fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
18fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * USE OR OTHER DEALINGS IN THE SOFTWARE.
25fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
26fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz **************************************************************************/
27fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
28fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "drmP.h"
29fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "vmwgfx_drv.h"
30fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
31fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#define VMW_FENCE_WRAP (1 << 24)
32fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
33fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzirqreturn_t vmw_irq_handler(DRM_IRQ_ARGS)
34fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
35fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_device *dev = (struct drm_device *)arg;
36fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
3757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	uint32_t status, masked_status;
38fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
39fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	spin_lock(&dev_priv->irq_lock);
40fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
4157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	masked_status = status & dev_priv->irq_mask;
42fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	spin_unlock(&dev_priv->irq_lock);
43fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
4457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (likely(status))
4557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
46ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom
4757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (!masked_status)
4857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		return IRQ_NONE;
4957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
5057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (masked_status & (SVGA_IRQFLAG_ANY_FENCE |
5157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom			     SVGA_IRQFLAG_FENCE_GOAL)) {
5257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_fences_update(dev_priv->fman);
53fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		wake_up_all(&dev_priv->fence_queue);
54ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstrom	}
5557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
5657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (masked_status & SVGA_IRQFLAG_FIFO_PROGRESS)
57fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		wake_up_all(&dev_priv->fifo_queue);
58fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
59fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
6057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	return IRQ_HANDLED;
61fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
62fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
636bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstromstatic bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno)
64fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
65fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	uint32_t busy;
66fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
67fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	mutex_lock(&dev_priv->hw_mutex);
68fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	busy = vmw_read(dev_priv, SVGA_REG_BUSY);
69fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	mutex_unlock(&dev_priv->hw_mutex);
70fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
71fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return (busy == 0);
72fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
73fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
746bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstromvoid vmw_update_seqno(struct vmw_private *dev_priv,
751925d4565888eb313cc923372da6a08bbfb3a859Thomas Hellstrom			 struct vmw_fifo_state *fifo_state)
761925d4565888eb313cc923372da6a08bbfb3a859Thomas Hellstrom{
771925d4565888eb313cc923372da6a08bbfb3a859Thomas Hellstrom	__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
786bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
791925d4565888eb313cc923372da6a08bbfb3a859Thomas Hellstrom
806bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	if (dev_priv->last_read_seqno != seqno) {
816bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		dev_priv->last_read_seqno = seqno;
826bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		vmw_marker_pull(&fifo_state->marker_queue, seqno);
8357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_fences_update(dev_priv->fman);
841925d4565888eb313cc923372da6a08bbfb3a859Thomas Hellstrom	}
851925d4565888eb313cc923372da6a08bbfb3a859Thomas Hellstrom}
86fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
876bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrombool vmw_seqno_passed(struct vmw_private *dev_priv,
886bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom			 uint32_t seqno)
89fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
90fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_fifo_state *fifo_state;
91fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	bool ret;
92fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
936bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
94fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return true;
95fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
961925d4565888eb313cc923372da6a08bbfb3a859Thomas Hellstrom	fifo_state = &dev_priv->fifo;
976bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	vmw_update_seqno(dev_priv, fifo_state);
986bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
99fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return true;
100fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
101fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) &&
1026bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	    vmw_fifo_idle(dev_priv, seqno))
103fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return true;
104fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
105fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	/**
1066bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	 * Then check if the seqno is higher than what we've actually
107fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	 * emitted. Then the fence is stale and signaled.
108fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	 */
109fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1106bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	ret = ((atomic_read(&dev_priv->marker_seq) - seqno)
11185b9e4878f3b16993fba871c0c68d0948ec9c7c6Thomas Hellstrom	       > VMW_FENCE_WRAP);
112fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
113fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
114fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
115fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
116fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_fallback_wait(struct vmw_private *dev_priv,
117fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		      bool lazy,
118fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		      bool fifo_idle,
1196bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		      uint32_t seqno,
120fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		      bool interruptible,
121fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		      unsigned long timeout)
122fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
123fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
124fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
125fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	uint32_t count = 0;
126fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	uint32_t signal_seq;
127fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
128fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	unsigned long end_jiffies = jiffies + timeout;
129fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	bool (*wait_condition)(struct vmw_private *, uint32_t);
130fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	DEFINE_WAIT(__wait);
131fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
132fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	wait_condition = (fifo_idle) ? &vmw_fifo_idle :
1336bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		&vmw_seqno_passed;
134fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
135fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	/**
136fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	 * Block command submission while waiting for idle.
137fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	 */
138fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
139fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (fifo_idle)
140fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		down_read(&fifo_state->rwsem);
1416bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	signal_seq = atomic_read(&dev_priv->marker_seq);
142fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = 0;
143fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
144fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	for (;;) {
145fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		prepare_to_wait(&dev_priv->fence_queue, &__wait,
146fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				(interruptible) ?
147fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
1486bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		if (wait_condition(dev_priv, seqno))
149fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			break;
150fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		if (time_after_eq(jiffies, end_jiffies)) {
151fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			DRM_ERROR("SVGA device lockup.\n");
152fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			break;
153fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		}
154fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		if (lazy)
155fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			schedule_timeout(1);
156fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		else if ((++count & 0x0F) == 0) {
157fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			/**
158fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			 * FIXME: Use schedule_hr_timeout here for
159fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			 * newer kernels and lower CPU utilization.
160fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			 */
161fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
162fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			__set_current_state(TASK_RUNNING);
163fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			schedule();
164fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			__set_current_state((interruptible) ?
165fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz					    TASK_INTERRUPTIBLE :
166fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz					    TASK_UNINTERRUPTIBLE);
167fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		}
168fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		if (interruptible && signal_pending(current)) {
1693d3a5b3290043618e8409f3fb68a63de6156fdd4Thomas Hellstrom			ret = -ERESTARTSYS;
170fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			break;
171fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		}
172fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
173fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	finish_wait(&dev_priv->fence_queue, &__wait);
174fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (ret == 0 && fifo_idle) {
175fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
176fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		iowrite32(signal_seq, fifo_mem + SVGA_FIFO_FENCE);
177fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
178fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	wake_up_all(&dev_priv->fence_queue);
179fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (fifo_idle)
180fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		up_read(&fifo_state->rwsem);
181fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
182fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
183fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
184fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
185ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromvoid vmw_seqno_waiter_add(struct vmw_private *dev_priv)
1864f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom{
1874f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	mutex_lock(&dev_priv->hw_mutex);
1884f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	if (dev_priv->fence_queue_waiters++ == 0) {
1894f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom		unsigned long irq_flags;
1904f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom
1914f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom		spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
1924f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom		outl(SVGA_IRQFLAG_ANY_FENCE,
1934f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom		     dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
19457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		dev_priv->irq_mask |= SVGA_IRQFLAG_ANY_FENCE;
19557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
1964f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom		spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
1974f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	}
1984f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	mutex_unlock(&dev_priv->hw_mutex);
1994f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom}
2004f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom
201ae2a104058e217548215bfe6c6c8a98752139c29Thomas Hellstromvoid vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
2024f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom{
2034f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	mutex_lock(&dev_priv->hw_mutex);
2044f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	if (--dev_priv->fence_queue_waiters == 0) {
2054f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom		unsigned long irq_flags;
2064f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom
2074f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom		spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
20857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		dev_priv->irq_mask &= ~SVGA_IRQFLAG_ANY_FENCE;
20957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
21057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
21157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
21257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	mutex_unlock(&dev_priv->hw_mutex);
21357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
21457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
21557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
21657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromvoid vmw_goal_waiter_add(struct vmw_private *dev_priv)
21757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
21857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	mutex_lock(&dev_priv->hw_mutex);
21957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (dev_priv->goal_queue_waiters++ == 0) {
22057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		unsigned long irq_flags;
22157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
22257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
22357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		outl(SVGA_IRQFLAG_FENCE_GOAL,
22457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		     dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
22557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		dev_priv->irq_mask |= SVGA_IRQFLAG_FENCE_GOAL;
22657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
22757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
22857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	}
22957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	mutex_unlock(&dev_priv->hw_mutex);
23057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom}
23157c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
23257c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstromvoid vmw_goal_waiter_remove(struct vmw_private *dev_priv)
23357c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom{
23457c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	mutex_lock(&dev_priv->hw_mutex);
23557c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom	if (--dev_priv->goal_queue_waiters == 0) {
23657c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		unsigned long irq_flags;
23757c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom
23857c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
23957c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		dev_priv->irq_mask &= ~SVGA_IRQFLAG_FENCE_GOAL;
24057c5ee79acba9582762c09c269e0e2ae1adf1b31Thomas Hellstrom		vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
2414f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom		spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
2424f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	}
2434f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	mutex_unlock(&dev_priv->hw_mutex);
2444f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom}
2454f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom
2466bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstromint vmw_wait_seqno(struct vmw_private *dev_priv,
2476bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		      bool lazy, uint32_t seqno,
2486bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		      bool interruptible, unsigned long timeout)
249fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
250fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	long ret;
251fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_fifo_state *fifo = &dev_priv->fifo;
252fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
2536bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
254fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return 0;
255fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
2566bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom	if (likely(vmw_seqno_passed(dev_priv, seqno)))
257fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return 0;
258fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
259fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
260fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
261fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE))
2626bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		return vmw_fallback_wait(dev_priv, lazy, true, seqno,
263fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz					 interruptible, timeout);
264fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
265fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
2666bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		return vmw_fallback_wait(dev_priv, lazy, false, seqno,
267fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz					 interruptible, timeout);
268fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
2694f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	vmw_seqno_waiter_add(dev_priv);
270fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
271fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (interruptible)
272fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = wait_event_interruptible_timeout
273fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		    (dev_priv->fence_queue,
2746bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		     vmw_seqno_passed(dev_priv, seqno),
275fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		     timeout);
276fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	else
277fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = wait_event_timeout
278fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		    (dev_priv->fence_queue,
2796bcd8d3c782b7b2c98c8f414a6bb43cf6b84e53cThomas Hellstrom		     vmw_seqno_passed(dev_priv, seqno),
280fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		     timeout);
281fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
2824f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom	vmw_seqno_waiter_remove(dev_priv);
2834f73a96bd76914009682432842ac04a32ab9115bThomas Hellstrom
2843d3a5b3290043618e8409f3fb68a63de6156fdd4Thomas Hellstrom	if (unlikely(ret == 0))
285fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -EBUSY;
286fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	else if (likely(ret > 0))
287fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = 0;
288fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
289fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
290fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
291fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
292fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzvoid vmw_irq_preinstall(struct drm_device *dev)
293fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
294fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
295fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	uint32_t status;
296fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
297fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
298fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return;
299fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
300fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	spin_lock_init(&dev_priv->irq_lock);
301fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
302fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
303fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
304fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
305fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_irq_postinstall(struct drm_device *dev)
306fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
307fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return 0;
308fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
309fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
310fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzvoid vmw_irq_uninstall(struct drm_device *dev)
311fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
312fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
313fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	uint32_t status;
314fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
315fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
316fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return;
317fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
318fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	mutex_lock(&dev_priv->hw_mutex);
319fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_write(dev_priv, SVGA_REG_IRQMASK, 0);
320fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	mutex_unlock(&dev_priv->hw_mutex);
321fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
322fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
323fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
324fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
325