1dff96888SDirk Hohndel (VMware) // SPDX-License-Identifier: GPL-2.0 OR MIT 2fb1d9738SJakob Bornecrantz /************************************************************************** 3fb1d9738SJakob Bornecrantz * 4dff96888SDirk Hohndel (VMware) * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 5fb1d9738SJakob Bornecrantz * 6fb1d9738SJakob Bornecrantz * Permission is hereby granted, free of charge, to any person obtaining a 7fb1d9738SJakob Bornecrantz * copy of this software and associated documentation files (the 8fb1d9738SJakob Bornecrantz * "Software"), to deal in the Software without restriction, including 9fb1d9738SJakob Bornecrantz * without limitation the rights to use, copy, modify, merge, publish, 10fb1d9738SJakob Bornecrantz * distribute, sub license, and/or sell copies of the Software, and to 11fb1d9738SJakob Bornecrantz * permit persons to whom the Software is furnished to do so, subject to 12fb1d9738SJakob Bornecrantz * the following conditions: 13fb1d9738SJakob Bornecrantz * 14fb1d9738SJakob Bornecrantz * The above copyright notice and this permission notice (including the 15fb1d9738SJakob Bornecrantz * next paragraph) shall be included in all copies or substantial portions 16fb1d9738SJakob Bornecrantz * of the Software. 17fb1d9738SJakob Bornecrantz * 18fb1d9738SJakob Bornecrantz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19fb1d9738SJakob Bornecrantz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20fb1d9738SJakob Bornecrantz * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21fb1d9738SJakob Bornecrantz * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22fb1d9738SJakob Bornecrantz * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23fb1d9738SJakob Bornecrantz * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24fb1d9738SJakob Bornecrantz * USE OR OTHER DEALINGS IN THE SOFTWARE. 25fb1d9738SJakob Bornecrantz * 26fb1d9738SJakob Bornecrantz **************************************************************************/ 27fb1d9738SJakob Bornecrantz 286ae8748bSSam Ravnborg #include <linux/sched/signal.h> 296ae8748bSSam Ravnborg 30fb1d9738SJakob Bornecrantz #include "vmwgfx_drv.h" 31fb1d9738SJakob Bornecrantz 32fb1d9738SJakob Bornecrantz #define VMW_FENCE_WRAP (1 << 24) 33fb1d9738SJakob Bornecrantz 34ef369904SThomas Hellstrom /** 35ef369904SThomas Hellstrom * vmw_thread_fn - Deferred (process context) irq handler 36ef369904SThomas Hellstrom * 37ef369904SThomas Hellstrom * @irq: irq number 38ef369904SThomas Hellstrom * @arg: Closure argument. Pointer to a struct drm_device cast to void * 39ef369904SThomas Hellstrom * 40ef369904SThomas Hellstrom * This function implements the deferred part of irq processing. 41ef369904SThomas Hellstrom * The function is guaranteed to run at least once after the 42ef369904SThomas Hellstrom * vmw_irq_handler has returned with IRQ_WAKE_THREAD. 43ef369904SThomas Hellstrom * 44ef369904SThomas Hellstrom */ 45ef369904SThomas Hellstrom static irqreturn_t vmw_thread_fn(int irq, void *arg) 46ef369904SThomas Hellstrom { 47ef369904SThomas Hellstrom struct drm_device *dev = (struct drm_device *)arg; 48ef369904SThomas Hellstrom struct vmw_private *dev_priv = vmw_priv(dev); 49ef369904SThomas Hellstrom irqreturn_t ret = IRQ_NONE; 50ef369904SThomas Hellstrom 51ef369904SThomas Hellstrom if (test_and_clear_bit(VMW_IRQTHREAD_FENCE, 52ef369904SThomas Hellstrom dev_priv->irqthread_pending)) { 53ef369904SThomas Hellstrom vmw_fences_update(dev_priv->fman); 54ef369904SThomas Hellstrom wake_up_all(&dev_priv->fence_queue); 55ef369904SThomas Hellstrom ret = IRQ_HANDLED; 56ef369904SThomas Hellstrom } 57ef369904SThomas Hellstrom 58ef369904SThomas Hellstrom if (test_and_clear_bit(VMW_IRQTHREAD_CMDBUF, 59ef369904SThomas Hellstrom dev_priv->irqthread_pending)) { 60ef369904SThomas Hellstrom vmw_cmdbuf_irqthread(dev_priv->cman); 61ef369904SThomas Hellstrom ret = IRQ_HANDLED; 62ef369904SThomas Hellstrom } 63ef369904SThomas Hellstrom 64ef369904SThomas Hellstrom return ret; 65ef369904SThomas Hellstrom } 66ef369904SThomas Hellstrom 67ef369904SThomas Hellstrom /** 68ef369904SThomas Hellstrom * vmw_irq_handler irq handler 69ef369904SThomas Hellstrom * 70ef369904SThomas Hellstrom * @irq: irq number 71ef369904SThomas Hellstrom * @arg: Closure argument. Pointer to a struct drm_device cast to void * 72ef369904SThomas Hellstrom * 73ef369904SThomas Hellstrom * This function implements the quick part of irq processing. 74ef369904SThomas Hellstrom * The function performs fast actions like clearing the device interrupt 75ef369904SThomas Hellstrom * flags and also reasonably quick actions like waking processes waiting for 76ef369904SThomas Hellstrom * FIFO space. Other IRQ actions are deferred to the IRQ thread. 77ef369904SThomas Hellstrom */ 78e300173fSThomas Hellstrom static irqreturn_t vmw_irq_handler(int irq, void *arg) 79fb1d9738SJakob Bornecrantz { 80fb1d9738SJakob Bornecrantz struct drm_device *dev = (struct drm_device *)arg; 81fb1d9738SJakob Bornecrantz struct vmw_private *dev_priv = vmw_priv(dev); 8257c5ee79SThomas Hellstrom uint32_t status, masked_status; 83ef369904SThomas Hellstrom irqreturn_t ret = IRQ_HANDLED; 84fb1d9738SJakob Bornecrantz 85fb1d9738SJakob Bornecrantz status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 86d2e8851aSThomas Hellstrom masked_status = status & READ_ONCE(dev_priv->irq_mask); 87fb1d9738SJakob Bornecrantz 8857c5ee79SThomas Hellstrom if (likely(status)) 8957c5ee79SThomas Hellstrom outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 90ae2a1040SThomas Hellstrom 91d2e8851aSThomas Hellstrom if (!status) 9257c5ee79SThomas Hellstrom return IRQ_NONE; 9357c5ee79SThomas Hellstrom 9457c5ee79SThomas Hellstrom if (masked_status & SVGA_IRQFLAG_FIFO_PROGRESS) 95fb1d9738SJakob Bornecrantz wake_up_all(&dev_priv->fifo_queue); 96fb1d9738SJakob Bornecrantz 97ef369904SThomas Hellstrom if ((masked_status & (SVGA_IRQFLAG_ANY_FENCE | 98ef369904SThomas Hellstrom SVGA_IRQFLAG_FENCE_GOAL)) && 99ef369904SThomas Hellstrom !test_and_set_bit(VMW_IRQTHREAD_FENCE, dev_priv->irqthread_pending)) 100ef369904SThomas Hellstrom ret = IRQ_WAKE_THREAD; 101fb1d9738SJakob Bornecrantz 102ef369904SThomas Hellstrom if ((masked_status & (SVGA_IRQFLAG_COMMAND_BUFFER | 103ef369904SThomas Hellstrom SVGA_IRQFLAG_ERROR)) && 104ef369904SThomas Hellstrom !test_and_set_bit(VMW_IRQTHREAD_CMDBUF, 105ef369904SThomas Hellstrom dev_priv->irqthread_pending)) 106ef369904SThomas Hellstrom ret = IRQ_WAKE_THREAD; 107ef369904SThomas Hellstrom 108ef369904SThomas Hellstrom return ret; 109fb1d9738SJakob Bornecrantz } 110fb1d9738SJakob Bornecrantz 1116bcd8d3cSThomas Hellstrom static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno) 112fb1d9738SJakob Bornecrantz { 113fb1d9738SJakob Bornecrantz 114496eb6fdSThomas Hellstrom return (vmw_read(dev_priv, SVGA_REG_BUSY) == 0); 115fb1d9738SJakob Bornecrantz } 116fb1d9738SJakob Bornecrantz 1176bcd8d3cSThomas Hellstrom void vmw_update_seqno(struct vmw_private *dev_priv, 1181925d456SThomas Hellstrom struct vmw_fifo_state *fifo_state) 1191925d456SThomas Hellstrom { 120b76ff5eaSThomas Hellstrom u32 *fifo_mem = dev_priv->mmio_virt; 121b76ff5eaSThomas Hellstrom uint32_t seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE); 1221925d456SThomas Hellstrom 1236bcd8d3cSThomas Hellstrom if (dev_priv->last_read_seqno != seqno) { 1246bcd8d3cSThomas Hellstrom dev_priv->last_read_seqno = seqno; 1256bcd8d3cSThomas Hellstrom vmw_marker_pull(&fifo_state->marker_queue, seqno); 12657c5ee79SThomas Hellstrom vmw_fences_update(dev_priv->fman); 1271925d456SThomas Hellstrom } 1281925d456SThomas Hellstrom } 129fb1d9738SJakob Bornecrantz 1306bcd8d3cSThomas Hellstrom bool vmw_seqno_passed(struct vmw_private *dev_priv, 1316bcd8d3cSThomas Hellstrom uint32_t seqno) 132fb1d9738SJakob Bornecrantz { 133fb1d9738SJakob Bornecrantz struct vmw_fifo_state *fifo_state; 134fb1d9738SJakob Bornecrantz bool ret; 135fb1d9738SJakob Bornecrantz 1366bcd8d3cSThomas Hellstrom if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) 137fb1d9738SJakob Bornecrantz return true; 138fb1d9738SJakob Bornecrantz 1391925d456SThomas Hellstrom fifo_state = &dev_priv->fifo; 1406bcd8d3cSThomas Hellstrom vmw_update_seqno(dev_priv, fifo_state); 1416bcd8d3cSThomas Hellstrom if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) 142fb1d9738SJakob Bornecrantz return true; 143fb1d9738SJakob Bornecrantz 144fb1d9738SJakob Bornecrantz if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && 1456bcd8d3cSThomas Hellstrom vmw_fifo_idle(dev_priv, seqno)) 146fb1d9738SJakob Bornecrantz return true; 147fb1d9738SJakob Bornecrantz 148fb1d9738SJakob Bornecrantz /** 1496bcd8d3cSThomas Hellstrom * Then check if the seqno is higher than what we've actually 150fb1d9738SJakob Bornecrantz * emitted. Then the fence is stale and signaled. 151fb1d9738SJakob Bornecrantz */ 152fb1d9738SJakob Bornecrantz 1536bcd8d3cSThomas Hellstrom ret = ((atomic_read(&dev_priv->marker_seq) - seqno) 15485b9e487SThomas Hellstrom > VMW_FENCE_WRAP); 155fb1d9738SJakob Bornecrantz 156fb1d9738SJakob Bornecrantz return ret; 157fb1d9738SJakob Bornecrantz } 158fb1d9738SJakob Bornecrantz 159fb1d9738SJakob Bornecrantz int vmw_fallback_wait(struct vmw_private *dev_priv, 160fb1d9738SJakob Bornecrantz bool lazy, 161fb1d9738SJakob Bornecrantz bool fifo_idle, 1626bcd8d3cSThomas Hellstrom uint32_t seqno, 163fb1d9738SJakob Bornecrantz bool interruptible, 164fb1d9738SJakob Bornecrantz unsigned long timeout) 165fb1d9738SJakob Bornecrantz { 166fb1d9738SJakob Bornecrantz struct vmw_fifo_state *fifo_state = &dev_priv->fifo; 167fb1d9738SJakob Bornecrantz 168fb1d9738SJakob Bornecrantz uint32_t count = 0; 169fb1d9738SJakob Bornecrantz uint32_t signal_seq; 170fb1d9738SJakob Bornecrantz int ret; 171fb1d9738SJakob Bornecrantz unsigned long end_jiffies = jiffies + timeout; 172fb1d9738SJakob Bornecrantz bool (*wait_condition)(struct vmw_private *, uint32_t); 173fb1d9738SJakob Bornecrantz DEFINE_WAIT(__wait); 174fb1d9738SJakob Bornecrantz 175fb1d9738SJakob Bornecrantz wait_condition = (fifo_idle) ? &vmw_fifo_idle : 1766bcd8d3cSThomas Hellstrom &vmw_seqno_passed; 177fb1d9738SJakob Bornecrantz 178fb1d9738SJakob Bornecrantz /** 179fb1d9738SJakob Bornecrantz * Block command submission while waiting for idle. 180fb1d9738SJakob Bornecrantz */ 181fb1d9738SJakob Bornecrantz 1823eab3d9eSThomas Hellstrom if (fifo_idle) { 183fb1d9738SJakob Bornecrantz down_read(&fifo_state->rwsem); 1843eab3d9eSThomas Hellstrom if (dev_priv->cman) { 1853eab3d9eSThomas Hellstrom ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible, 1863eab3d9eSThomas Hellstrom 10*HZ); 1873eab3d9eSThomas Hellstrom if (ret) 1883eab3d9eSThomas Hellstrom goto out_err; 1893eab3d9eSThomas Hellstrom } 1903eab3d9eSThomas Hellstrom } 1913eab3d9eSThomas Hellstrom 1926bcd8d3cSThomas Hellstrom signal_seq = atomic_read(&dev_priv->marker_seq); 193fb1d9738SJakob Bornecrantz ret = 0; 194fb1d9738SJakob Bornecrantz 195fb1d9738SJakob Bornecrantz for (;;) { 196fb1d9738SJakob Bornecrantz prepare_to_wait(&dev_priv->fence_queue, &__wait, 197fb1d9738SJakob Bornecrantz (interruptible) ? 198fb1d9738SJakob Bornecrantz TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); 1996bcd8d3cSThomas Hellstrom if (wait_condition(dev_priv, seqno)) 200fb1d9738SJakob Bornecrantz break; 201fb1d9738SJakob Bornecrantz if (time_after_eq(jiffies, end_jiffies)) { 202fb1d9738SJakob Bornecrantz DRM_ERROR("SVGA device lockup.\n"); 203fb1d9738SJakob Bornecrantz break; 204fb1d9738SJakob Bornecrantz } 205fb1d9738SJakob Bornecrantz if (lazy) 206fb1d9738SJakob Bornecrantz schedule_timeout(1); 207fb1d9738SJakob Bornecrantz else if ((++count & 0x0F) == 0) { 208fb1d9738SJakob Bornecrantz /** 209fb1d9738SJakob Bornecrantz * FIXME: Use schedule_hr_timeout here for 210fb1d9738SJakob Bornecrantz * newer kernels and lower CPU utilization. 211fb1d9738SJakob Bornecrantz */ 212fb1d9738SJakob Bornecrantz 213fb1d9738SJakob Bornecrantz __set_current_state(TASK_RUNNING); 214fb1d9738SJakob Bornecrantz schedule(); 215fb1d9738SJakob Bornecrantz __set_current_state((interruptible) ? 216fb1d9738SJakob Bornecrantz TASK_INTERRUPTIBLE : 217fb1d9738SJakob Bornecrantz TASK_UNINTERRUPTIBLE); 218fb1d9738SJakob Bornecrantz } 219fb1d9738SJakob Bornecrantz if (interruptible && signal_pending(current)) { 2203d3a5b32SThomas Hellstrom ret = -ERESTARTSYS; 221fb1d9738SJakob Bornecrantz break; 222fb1d9738SJakob Bornecrantz } 223fb1d9738SJakob Bornecrantz } 224fb1d9738SJakob Bornecrantz finish_wait(&dev_priv->fence_queue, &__wait); 225fb1d9738SJakob Bornecrantz if (ret == 0 && fifo_idle) { 226b76ff5eaSThomas Hellstrom u32 *fifo_mem = dev_priv->mmio_virt; 227b76ff5eaSThomas Hellstrom 228b76ff5eaSThomas Hellstrom vmw_mmio_write(signal_seq, fifo_mem + SVGA_FIFO_FENCE); 229fb1d9738SJakob Bornecrantz } 230fb1d9738SJakob Bornecrantz wake_up_all(&dev_priv->fence_queue); 2313eab3d9eSThomas Hellstrom out_err: 232fb1d9738SJakob Bornecrantz if (fifo_idle) 233fb1d9738SJakob Bornecrantz up_read(&fifo_state->rwsem); 234fb1d9738SJakob Bornecrantz 235fb1d9738SJakob Bornecrantz return ret; 236fb1d9738SJakob Bornecrantz } 237fb1d9738SJakob Bornecrantz 238d2e8851aSThomas Hellstrom void vmw_generic_waiter_add(struct vmw_private *dev_priv, 239d2e8851aSThomas Hellstrom u32 flag, int *waiter_count) 240d2e8851aSThomas Hellstrom { 241d2e8851aSThomas Hellstrom spin_lock_bh(&dev_priv->waiter_lock); 242d2e8851aSThomas Hellstrom if ((*waiter_count)++ == 0) { 243d2e8851aSThomas Hellstrom outl(flag, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 244d2e8851aSThomas Hellstrom dev_priv->irq_mask |= flag; 245d2e8851aSThomas Hellstrom vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); 246d2e8851aSThomas Hellstrom } 247d2e8851aSThomas Hellstrom spin_unlock_bh(&dev_priv->waiter_lock); 248d2e8851aSThomas Hellstrom } 249d2e8851aSThomas Hellstrom 250d2e8851aSThomas Hellstrom void vmw_generic_waiter_remove(struct vmw_private *dev_priv, 251d2e8851aSThomas Hellstrom u32 flag, int *waiter_count) 252d2e8851aSThomas Hellstrom { 253d2e8851aSThomas Hellstrom spin_lock_bh(&dev_priv->waiter_lock); 254d2e8851aSThomas Hellstrom if (--(*waiter_count) == 0) { 255d2e8851aSThomas Hellstrom dev_priv->irq_mask &= ~flag; 256d2e8851aSThomas Hellstrom vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); 257d2e8851aSThomas Hellstrom } 258d2e8851aSThomas Hellstrom spin_unlock_bh(&dev_priv->waiter_lock); 259d2e8851aSThomas Hellstrom } 260d2e8851aSThomas Hellstrom 261ae2a1040SThomas Hellstrom void vmw_seqno_waiter_add(struct vmw_private *dev_priv) 2624f73a96bSThomas Hellstrom { 263d2e8851aSThomas Hellstrom vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_ANY_FENCE, 264d2e8851aSThomas Hellstrom &dev_priv->fence_queue_waiters); 2654f73a96bSThomas Hellstrom } 2664f73a96bSThomas Hellstrom 267ae2a1040SThomas Hellstrom void vmw_seqno_waiter_remove(struct vmw_private *dev_priv) 2684f73a96bSThomas Hellstrom { 269d2e8851aSThomas Hellstrom vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_ANY_FENCE, 270d2e8851aSThomas Hellstrom &dev_priv->fence_queue_waiters); 27157c5ee79SThomas Hellstrom } 27257c5ee79SThomas Hellstrom 27357c5ee79SThomas Hellstrom void vmw_goal_waiter_add(struct vmw_private *dev_priv) 27457c5ee79SThomas Hellstrom { 275d2e8851aSThomas Hellstrom vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL, 276d2e8851aSThomas Hellstrom &dev_priv->goal_queue_waiters); 27757c5ee79SThomas Hellstrom } 27857c5ee79SThomas Hellstrom 27957c5ee79SThomas Hellstrom void vmw_goal_waiter_remove(struct vmw_private *dev_priv) 28057c5ee79SThomas Hellstrom { 281d2e8851aSThomas Hellstrom vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL, 282d2e8851aSThomas Hellstrom &dev_priv->goal_queue_waiters); 2834f73a96bSThomas Hellstrom } 2844f73a96bSThomas Hellstrom 2856bcd8d3cSThomas Hellstrom int vmw_wait_seqno(struct vmw_private *dev_priv, 2866bcd8d3cSThomas Hellstrom bool lazy, uint32_t seqno, 287fb1d9738SJakob Bornecrantz bool interruptible, unsigned long timeout) 288fb1d9738SJakob Bornecrantz { 289fb1d9738SJakob Bornecrantz long ret; 290fb1d9738SJakob Bornecrantz struct vmw_fifo_state *fifo = &dev_priv->fifo; 291fb1d9738SJakob Bornecrantz 2926bcd8d3cSThomas Hellstrom if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) 293fb1d9738SJakob Bornecrantz return 0; 294fb1d9738SJakob Bornecrantz 2956bcd8d3cSThomas Hellstrom if (likely(vmw_seqno_passed(dev_priv, seqno))) 296fb1d9738SJakob Bornecrantz return 0; 297fb1d9738SJakob Bornecrantz 298fb1d9738SJakob Bornecrantz vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); 299fb1d9738SJakob Bornecrantz 300fb1d9738SJakob Bornecrantz if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE)) 3016bcd8d3cSThomas Hellstrom return vmw_fallback_wait(dev_priv, lazy, true, seqno, 302fb1d9738SJakob Bornecrantz interruptible, timeout); 303fb1d9738SJakob Bornecrantz 304fb1d9738SJakob Bornecrantz if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) 3056bcd8d3cSThomas Hellstrom return vmw_fallback_wait(dev_priv, lazy, false, seqno, 306fb1d9738SJakob Bornecrantz interruptible, timeout); 307fb1d9738SJakob Bornecrantz 3084f73a96bSThomas Hellstrom vmw_seqno_waiter_add(dev_priv); 309fb1d9738SJakob Bornecrantz 310fb1d9738SJakob Bornecrantz if (interruptible) 311fb1d9738SJakob Bornecrantz ret = wait_event_interruptible_timeout 312fb1d9738SJakob Bornecrantz (dev_priv->fence_queue, 3136bcd8d3cSThomas Hellstrom vmw_seqno_passed(dev_priv, seqno), 314fb1d9738SJakob Bornecrantz timeout); 315fb1d9738SJakob Bornecrantz else 316fb1d9738SJakob Bornecrantz ret = wait_event_timeout 317fb1d9738SJakob Bornecrantz (dev_priv->fence_queue, 3186bcd8d3cSThomas Hellstrom vmw_seqno_passed(dev_priv, seqno), 319fb1d9738SJakob Bornecrantz timeout); 320fb1d9738SJakob Bornecrantz 3214f73a96bSThomas Hellstrom vmw_seqno_waiter_remove(dev_priv); 3224f73a96bSThomas Hellstrom 3233d3a5b32SThomas Hellstrom if (unlikely(ret == 0)) 324fb1d9738SJakob Bornecrantz ret = -EBUSY; 325fb1d9738SJakob Bornecrantz else if (likely(ret > 0)) 326fb1d9738SJakob Bornecrantz ret = 0; 327fb1d9738SJakob Bornecrantz 328fb1d9738SJakob Bornecrantz return ret; 329fb1d9738SJakob Bornecrantz } 330fb1d9738SJakob Bornecrantz 331e300173fSThomas Hellstrom static void vmw_irq_preinstall(struct drm_device *dev) 332fb1d9738SJakob Bornecrantz { 333fb1d9738SJakob Bornecrantz struct vmw_private *dev_priv = vmw_priv(dev); 334fb1d9738SJakob Bornecrantz uint32_t status; 335fb1d9738SJakob Bornecrantz 336fb1d9738SJakob Bornecrantz status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 337fb1d9738SJakob Bornecrantz outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 338fb1d9738SJakob Bornecrantz } 339fb1d9738SJakob Bornecrantz 340fb1d9738SJakob Bornecrantz void vmw_irq_uninstall(struct drm_device *dev) 341fb1d9738SJakob Bornecrantz { 342fb1d9738SJakob Bornecrantz struct vmw_private *dev_priv = vmw_priv(dev); 343fb1d9738SJakob Bornecrantz uint32_t status; 344fb1d9738SJakob Bornecrantz 345fb1d9738SJakob Bornecrantz if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) 346fb1d9738SJakob Bornecrantz return; 347fb1d9738SJakob Bornecrantz 348e300173fSThomas Hellstrom if (!dev->irq_enabled) 349e300173fSThomas Hellstrom return; 350e300173fSThomas Hellstrom 351fb1d9738SJakob Bornecrantz vmw_write(dev_priv, SVGA_REG_IRQMASK, 0); 352fb1d9738SJakob Bornecrantz 353fb1d9738SJakob Bornecrantz status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 354fb1d9738SJakob Bornecrantz outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 355e300173fSThomas Hellstrom 356e300173fSThomas Hellstrom dev->irq_enabled = false; 357e300173fSThomas Hellstrom free_irq(dev->irq, dev); 358e300173fSThomas Hellstrom } 359e300173fSThomas Hellstrom 360e300173fSThomas Hellstrom /** 361e300173fSThomas Hellstrom * vmw_irq_install - Install the irq handlers 362e300173fSThomas Hellstrom * 363e300173fSThomas Hellstrom * @dev: Pointer to the drm device. 364e300173fSThomas Hellstrom * @irq: The irq number. 365e300173fSThomas Hellstrom * Return: Zero if successful. Negative number otherwise. 366e300173fSThomas Hellstrom */ 367e300173fSThomas Hellstrom int vmw_irq_install(struct drm_device *dev, int irq) 368e300173fSThomas Hellstrom { 369e300173fSThomas Hellstrom int ret; 370e300173fSThomas Hellstrom 371e300173fSThomas Hellstrom if (dev->irq_enabled) 372e300173fSThomas Hellstrom return -EBUSY; 373e300173fSThomas Hellstrom 374e300173fSThomas Hellstrom vmw_irq_preinstall(dev); 375e300173fSThomas Hellstrom 376ef369904SThomas Hellstrom ret = request_threaded_irq(irq, vmw_irq_handler, vmw_thread_fn, 377e300173fSThomas Hellstrom IRQF_SHARED, VMWGFX_DRIVER_NAME, dev); 378e300173fSThomas Hellstrom if (ret < 0) 379e300173fSThomas Hellstrom return ret; 380e300173fSThomas Hellstrom 381e300173fSThomas Hellstrom dev->irq_enabled = true; 382e300173fSThomas Hellstrom dev->irq = irq; 383e300173fSThomas Hellstrom 384e300173fSThomas Hellstrom return ret; 385fb1d9738SJakob Bornecrantz } 386