18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 28c2ecf20Sopenharmony_ci/************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the 88c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 98c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 108c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 118c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 128c2ecf20Sopenharmony_ci * the following conditions: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 158c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 168c2ecf20Sopenharmony_ci * of the Software. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 218c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 228c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 238c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 248c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci **************************************************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define VMW_FENCE_WRAP (1 << 24) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/** 358c2ecf20Sopenharmony_ci * vmw_thread_fn - Deferred (process context) irq handler 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * @irq: irq number 388c2ecf20Sopenharmony_ci * @arg: Closure argument. Pointer to a struct drm_device cast to void * 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * This function implements the deferred part of irq processing. 418c2ecf20Sopenharmony_ci * The function is guaranteed to run at least once after the 428c2ecf20Sopenharmony_ci * vmw_irq_handler has returned with IRQ_WAKE_THREAD. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistatic irqreturn_t vmw_thread_fn(int irq, void *arg) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct drm_device *dev = (struct drm_device *)arg; 488c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 498c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (test_and_clear_bit(VMW_IRQTHREAD_FENCE, 528c2ecf20Sopenharmony_ci dev_priv->irqthread_pending)) { 538c2ecf20Sopenharmony_ci vmw_fences_update(dev_priv->fman); 548c2ecf20Sopenharmony_ci wake_up_all(&dev_priv->fence_queue); 558c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (test_and_clear_bit(VMW_IRQTHREAD_CMDBUF, 598c2ecf20Sopenharmony_ci dev_priv->irqthread_pending)) { 608c2ecf20Sopenharmony_ci vmw_cmdbuf_irqthread(dev_priv->cman); 618c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return ret; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/** 688c2ecf20Sopenharmony_ci * vmw_irq_handler irq handler 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * @irq: irq number 718c2ecf20Sopenharmony_ci * @arg: Closure argument. Pointer to a struct drm_device cast to void * 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * This function implements the quick part of irq processing. 748c2ecf20Sopenharmony_ci * The function performs fast actions like clearing the device interrupt 758c2ecf20Sopenharmony_ci * flags and also reasonably quick actions like waking processes waiting for 768c2ecf20Sopenharmony_ci * FIFO space. Other IRQ actions are deferred to the IRQ thread. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistatic irqreturn_t vmw_irq_handler(int irq, void *arg) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct drm_device *dev = (struct drm_device *)arg; 818c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 828c2ecf20Sopenharmony_ci uint32_t status, masked_status; 838c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_HANDLED; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 868c2ecf20Sopenharmony_ci masked_status = status & READ_ONCE(dev_priv->irq_mask); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (likely(status)) 898c2ecf20Sopenharmony_ci outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!status) 928c2ecf20Sopenharmony_ci return IRQ_NONE; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (masked_status & SVGA_IRQFLAG_FIFO_PROGRESS) 958c2ecf20Sopenharmony_ci wake_up_all(&dev_priv->fifo_queue); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if ((masked_status & (SVGA_IRQFLAG_ANY_FENCE | 988c2ecf20Sopenharmony_ci SVGA_IRQFLAG_FENCE_GOAL)) && 998c2ecf20Sopenharmony_ci !test_and_set_bit(VMW_IRQTHREAD_FENCE, dev_priv->irqthread_pending)) 1008c2ecf20Sopenharmony_ci ret = IRQ_WAKE_THREAD; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if ((masked_status & (SVGA_IRQFLAG_COMMAND_BUFFER | 1038c2ecf20Sopenharmony_ci SVGA_IRQFLAG_ERROR)) && 1048c2ecf20Sopenharmony_ci !test_and_set_bit(VMW_IRQTHREAD_CMDBUF, 1058c2ecf20Sopenharmony_ci dev_priv->irqthread_pending)) 1068c2ecf20Sopenharmony_ci ret = IRQ_WAKE_THREAD; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return ret; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return (vmw_read(dev_priv, SVGA_REG_BUSY) == 0); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_civoid vmw_update_seqno(struct vmw_private *dev_priv, 1188c2ecf20Sopenharmony_ci struct vmw_fifo_state *fifo_state) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 1218c2ecf20Sopenharmony_ci uint32_t seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (dev_priv->last_read_seqno != seqno) { 1248c2ecf20Sopenharmony_ci dev_priv->last_read_seqno = seqno; 1258c2ecf20Sopenharmony_ci vmw_marker_pull(&fifo_state->marker_queue, seqno); 1268c2ecf20Sopenharmony_ci vmw_fences_update(dev_priv->fman); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cibool vmw_seqno_passed(struct vmw_private *dev_priv, 1318c2ecf20Sopenharmony_ci uint32_t seqno) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct vmw_fifo_state *fifo_state; 1348c2ecf20Sopenharmony_ci bool ret; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) 1378c2ecf20Sopenharmony_ci return true; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci fifo_state = &dev_priv->fifo; 1408c2ecf20Sopenharmony_ci vmw_update_seqno(dev_priv, fifo_state); 1418c2ecf20Sopenharmony_ci if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) 1428c2ecf20Sopenharmony_ci return true; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && 1458c2ecf20Sopenharmony_ci vmw_fifo_idle(dev_priv, seqno)) 1468c2ecf20Sopenharmony_ci return true; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /** 1498c2ecf20Sopenharmony_ci * Then check if the seqno is higher than what we've actually 1508c2ecf20Sopenharmony_ci * emitted. Then the fence is stale and signaled. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ret = ((atomic_read(&dev_priv->marker_seq) - seqno) 1548c2ecf20Sopenharmony_ci > VMW_FENCE_WRAP); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return ret; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ciint vmw_fallback_wait(struct vmw_private *dev_priv, 1608c2ecf20Sopenharmony_ci bool lazy, 1618c2ecf20Sopenharmony_ci bool fifo_idle, 1628c2ecf20Sopenharmony_ci uint32_t seqno, 1638c2ecf20Sopenharmony_ci bool interruptible, 1648c2ecf20Sopenharmony_ci unsigned long timeout) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct vmw_fifo_state *fifo_state = &dev_priv->fifo; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci uint32_t count = 0; 1698c2ecf20Sopenharmony_ci uint32_t signal_seq; 1708c2ecf20Sopenharmony_ci int ret; 1718c2ecf20Sopenharmony_ci unsigned long end_jiffies = jiffies + timeout; 1728c2ecf20Sopenharmony_ci bool (*wait_condition)(struct vmw_private *, uint32_t); 1738c2ecf20Sopenharmony_ci DEFINE_WAIT(__wait); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci wait_condition = (fifo_idle) ? &vmw_fifo_idle : 1768c2ecf20Sopenharmony_ci &vmw_seqno_passed; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /** 1798c2ecf20Sopenharmony_ci * Block command submission while waiting for idle. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (fifo_idle) { 1838c2ecf20Sopenharmony_ci down_read(&fifo_state->rwsem); 1848c2ecf20Sopenharmony_ci if (dev_priv->cman) { 1858c2ecf20Sopenharmony_ci ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible, 1868c2ecf20Sopenharmony_ci 10*HZ); 1878c2ecf20Sopenharmony_ci if (ret) 1888c2ecf20Sopenharmony_ci goto out_err; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci signal_seq = atomic_read(&dev_priv->marker_seq); 1938c2ecf20Sopenharmony_ci ret = 0; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci for (;;) { 1968c2ecf20Sopenharmony_ci prepare_to_wait(&dev_priv->fence_queue, &__wait, 1978c2ecf20Sopenharmony_ci (interruptible) ? 1988c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); 1998c2ecf20Sopenharmony_ci if (wait_condition(dev_priv, seqno)) 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, end_jiffies)) { 2028c2ecf20Sopenharmony_ci DRM_ERROR("SVGA device lockup.\n"); 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci if (lazy) 2068c2ecf20Sopenharmony_ci schedule_timeout(1); 2078c2ecf20Sopenharmony_ci else if ((++count & 0x0F) == 0) { 2088c2ecf20Sopenharmony_ci /** 2098c2ecf20Sopenharmony_ci * FIXME: Use schedule_hr_timeout here for 2108c2ecf20Sopenharmony_ci * newer kernels and lower CPU utilization. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 2148c2ecf20Sopenharmony_ci schedule(); 2158c2ecf20Sopenharmony_ci __set_current_state((interruptible) ? 2168c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE : 2178c2ecf20Sopenharmony_ci TASK_UNINTERRUPTIBLE); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci if (interruptible && signal_pending(current)) { 2208c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci finish_wait(&dev_priv->fence_queue, &__wait); 2258c2ecf20Sopenharmony_ci if (ret == 0 && fifo_idle) { 2268c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci vmw_mmio_write(signal_seq, fifo_mem + SVGA_FIFO_FENCE); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci wake_up_all(&dev_priv->fence_queue); 2318c2ecf20Sopenharmony_ciout_err: 2328c2ecf20Sopenharmony_ci if (fifo_idle) 2338c2ecf20Sopenharmony_ci up_read(&fifo_state->rwsem); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_civoid vmw_generic_waiter_add(struct vmw_private *dev_priv, 2398c2ecf20Sopenharmony_ci u32 flag, int *waiter_count) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci spin_lock_bh(&dev_priv->waiter_lock); 2428c2ecf20Sopenharmony_ci if ((*waiter_count)++ == 0) { 2438c2ecf20Sopenharmony_ci outl(flag, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 2448c2ecf20Sopenharmony_ci dev_priv->irq_mask |= flag; 2458c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci spin_unlock_bh(&dev_priv->waiter_lock); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_civoid vmw_generic_waiter_remove(struct vmw_private *dev_priv, 2518c2ecf20Sopenharmony_ci u32 flag, int *waiter_count) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci spin_lock_bh(&dev_priv->waiter_lock); 2548c2ecf20Sopenharmony_ci if (--(*waiter_count) == 0) { 2558c2ecf20Sopenharmony_ci dev_priv->irq_mask &= ~flag; 2568c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci spin_unlock_bh(&dev_priv->waiter_lock); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_civoid vmw_seqno_waiter_add(struct vmw_private *dev_priv) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_ANY_FENCE, 2648c2ecf20Sopenharmony_ci &dev_priv->fence_queue_waiters); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_civoid vmw_seqno_waiter_remove(struct vmw_private *dev_priv) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_ANY_FENCE, 2708c2ecf20Sopenharmony_ci &dev_priv->fence_queue_waiters); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_civoid vmw_goal_waiter_add(struct vmw_private *dev_priv) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL, 2768c2ecf20Sopenharmony_ci &dev_priv->goal_queue_waiters); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_civoid vmw_goal_waiter_remove(struct vmw_private *dev_priv) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL, 2828c2ecf20Sopenharmony_ci &dev_priv->goal_queue_waiters); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ciint vmw_wait_seqno(struct vmw_private *dev_priv, 2868c2ecf20Sopenharmony_ci bool lazy, uint32_t seqno, 2878c2ecf20Sopenharmony_ci bool interruptible, unsigned long timeout) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci long ret; 2908c2ecf20Sopenharmony_ci struct vmw_fifo_state *fifo = &dev_priv->fifo; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (likely(vmw_seqno_passed(dev_priv, seqno))) 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE)) 3018c2ecf20Sopenharmony_ci return vmw_fallback_wait(dev_priv, lazy, true, seqno, 3028c2ecf20Sopenharmony_ci interruptible, timeout); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) 3058c2ecf20Sopenharmony_ci return vmw_fallback_wait(dev_priv, lazy, false, seqno, 3068c2ecf20Sopenharmony_ci interruptible, timeout); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci vmw_seqno_waiter_add(dev_priv); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (interruptible) 3118c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout 3128c2ecf20Sopenharmony_ci (dev_priv->fence_queue, 3138c2ecf20Sopenharmony_ci vmw_seqno_passed(dev_priv, seqno), 3148c2ecf20Sopenharmony_ci timeout); 3158c2ecf20Sopenharmony_ci else 3168c2ecf20Sopenharmony_ci ret = wait_event_timeout 3178c2ecf20Sopenharmony_ci (dev_priv->fence_queue, 3188c2ecf20Sopenharmony_ci vmw_seqno_passed(dev_priv, seqno), 3198c2ecf20Sopenharmony_ci timeout); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci vmw_seqno_waiter_remove(dev_priv); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (unlikely(ret == 0)) 3248c2ecf20Sopenharmony_ci ret = -EBUSY; 3258c2ecf20Sopenharmony_ci else if (likely(ret > 0)) 3268c2ecf20Sopenharmony_ci ret = 0; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic void vmw_irq_preinstall(struct drm_device *dev) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 3348c2ecf20Sopenharmony_ci uint32_t status; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 3378c2ecf20Sopenharmony_ci outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_civoid vmw_irq_uninstall(struct drm_device *dev) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(dev); 3438c2ecf20Sopenharmony_ci uint32_t status; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) 3468c2ecf20Sopenharmony_ci return; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (!dev->irq_enabled) 3498c2ecf20Sopenharmony_ci return; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_IRQMASK, 0); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 3548c2ecf20Sopenharmony_ci outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci dev->irq_enabled = false; 3578c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/** 3618c2ecf20Sopenharmony_ci * vmw_irq_install - Install the irq handlers 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * @dev: Pointer to the drm device. 3648c2ecf20Sopenharmony_ci * @irq: The irq number. 3658c2ecf20Sopenharmony_ci * Return: Zero if successful. Negative number otherwise. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ciint vmw_irq_install(struct drm_device *dev, int irq) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci int ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (dev->irq_enabled) 3728c2ecf20Sopenharmony_ci return -EBUSY; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci vmw_irq_preinstall(dev); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci ret = request_threaded_irq(irq, vmw_irq_handler, vmw_thread_fn, 3778c2ecf20Sopenharmony_ci IRQF_SHARED, VMWGFX_DRIVER_NAME, dev); 3788c2ecf20Sopenharmony_ci if (ret < 0) 3798c2ecf20Sopenharmony_ci return ret; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci dev->irq_enabled = true; 3828c2ecf20Sopenharmony_ci dev->irq = irq; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci} 386