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 <drm/ttm/ttm_placement.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "vmwgfx_drv.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct vmw_temp_set_context { 358c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 368c2ecf20Sopenharmony_ci SVGA3dCmdDXTempSetContext body; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cibool vmw_fifo_have_3d(struct vmw_private *dev_priv) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 428c2ecf20Sopenharmony_ci uint32_t fifo_min, hwversion; 438c2ecf20Sopenharmony_ci const struct vmw_fifo_state *fifo = &dev_priv->fifo; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_3D)) 468c2ecf20Sopenharmony_ci return false; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { 498c2ecf20Sopenharmony_ci uint32_t result; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (!dev_priv->has_mob) 528c2ecf20Sopenharmony_ci return false; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci spin_lock(&dev_priv->cap_lock); 558c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_3D); 568c2ecf20Sopenharmony_ci result = vmw_read(dev_priv, SVGA_REG_DEV_CAP); 578c2ecf20Sopenharmony_ci spin_unlock(&dev_priv->cap_lock); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return (result != 0); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) 638c2ecf20Sopenharmony_ci return false; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci fifo_min = vmw_mmio_read(fifo_mem + SVGA_FIFO_MIN); 668c2ecf20Sopenharmony_ci if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) 678c2ecf20Sopenharmony_ci return false; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci hwversion = vmw_mmio_read(fifo_mem + 708c2ecf20Sopenharmony_ci ((fifo->capabilities & 718c2ecf20Sopenharmony_ci SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? 728c2ecf20Sopenharmony_ci SVGA_FIFO_3D_HWVERSION_REVISED : 738c2ecf20Sopenharmony_ci SVGA_FIFO_3D_HWVERSION)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (hwversion == 0) 768c2ecf20Sopenharmony_ci return false; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (hwversion < SVGA3D_HWVERSION_WS8_B1) 798c2ecf20Sopenharmony_ci return false; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* Legacy Display Unit does not support surfaces */ 828c2ecf20Sopenharmony_ci if (dev_priv->active_display_unit == vmw_du_legacy) 838c2ecf20Sopenharmony_ci return false; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return true; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cibool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 918c2ecf20Sopenharmony_ci uint32_t caps; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) 948c2ecf20Sopenharmony_ci return false; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci caps = vmw_mmio_read(fifo_mem + SVGA_FIFO_CAPABILITIES); 978c2ecf20Sopenharmony_ci if (caps & SVGA_FIFO_CAP_PITCHLOCK) 988c2ecf20Sopenharmony_ci return true; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return false; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciint vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 1068c2ecf20Sopenharmony_ci uint32_t max; 1078c2ecf20Sopenharmony_ci uint32_t min; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci fifo->dx = false; 1108c2ecf20Sopenharmony_ci fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE; 1118c2ecf20Sopenharmony_ci fifo->static_buffer = vmalloc(fifo->static_buffer_size); 1128c2ecf20Sopenharmony_ci if (unlikely(fifo->static_buffer == NULL)) 1138c2ecf20Sopenharmony_ci return -ENOMEM; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci fifo->dynamic_buffer = NULL; 1168c2ecf20Sopenharmony_ci fifo->reserved_size = 0; 1178c2ecf20Sopenharmony_ci fifo->using_bounce_buffer = false; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci mutex_init(&fifo->fifo_mutex); 1208c2ecf20Sopenharmony_ci init_rwsem(&fifo->rwsem); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci DRM_INFO("width %d\n", vmw_read(dev_priv, SVGA_REG_WIDTH)); 1238c2ecf20Sopenharmony_ci DRM_INFO("height %d\n", vmw_read(dev_priv, SVGA_REG_HEIGHT)); 1248c2ecf20Sopenharmony_ci DRM_INFO("bpp %d\n", vmw_read(dev_priv, SVGA_REG_BITS_PER_PIXEL)); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE); 1278c2ecf20Sopenharmony_ci dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE); 1288c2ecf20Sopenharmony_ci dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE | 1318c2ecf20Sopenharmony_ci SVGA_REG_ENABLE_HIDE); 1328c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_TRACES, 0); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci min = 4; 1358c2ecf20Sopenharmony_ci if (dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO) 1368c2ecf20Sopenharmony_ci min = vmw_read(dev_priv, SVGA_REG_MEM_REGS); 1378c2ecf20Sopenharmony_ci min <<= 2; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (min < PAGE_SIZE) 1408c2ecf20Sopenharmony_ci min = PAGE_SIZE; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci vmw_mmio_write(min, fifo_mem + SVGA_FIFO_MIN); 1438c2ecf20Sopenharmony_ci vmw_mmio_write(dev_priv->mmio_size, fifo_mem + SVGA_FIFO_MAX); 1448c2ecf20Sopenharmony_ci wmb(); 1458c2ecf20Sopenharmony_ci vmw_mmio_write(min, fifo_mem + SVGA_FIFO_NEXT_CMD); 1468c2ecf20Sopenharmony_ci vmw_mmio_write(min, fifo_mem + SVGA_FIFO_STOP); 1478c2ecf20Sopenharmony_ci vmw_mmio_write(0, fifo_mem + SVGA_FIFO_BUSY); 1488c2ecf20Sopenharmony_ci mb(); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci max = vmw_mmio_read(fifo_mem + SVGA_FIFO_MAX); 1538c2ecf20Sopenharmony_ci min = vmw_mmio_read(fifo_mem + SVGA_FIFO_MIN); 1548c2ecf20Sopenharmony_ci fifo->capabilities = vmw_mmio_read(fifo_mem + SVGA_FIFO_CAPABILITIES); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci DRM_INFO("Fifo max 0x%08x min 0x%08x cap 0x%08x\n", 1578c2ecf20Sopenharmony_ci (unsigned int) max, 1588c2ecf20Sopenharmony_ci (unsigned int) min, 1598c2ecf20Sopenharmony_ci (unsigned int) fifo->capabilities); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno); 1628c2ecf20Sopenharmony_ci vmw_mmio_write(dev_priv->last_read_seqno, fifo_mem + SVGA_FIFO_FENCE); 1638c2ecf20Sopenharmony_ci vmw_marker_queue_init(&fifo->marker_queue); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_civoid vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (cmpxchg(fifo_mem + SVGA_FIFO_BUSY, 0, 1) == 0) 1738c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_SYNC, reason); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_civoid vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); 1818c2ecf20Sopenharmony_ci while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0) 1828c2ecf20Sopenharmony_ci ; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci dev_priv->last_read_seqno = vmw_mmio_read(fifo_mem + SVGA_FIFO_FENCE); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1878c2ecf20Sopenharmony_ci dev_priv->config_done_state); 1888c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_ENABLE, 1898c2ecf20Sopenharmony_ci dev_priv->enable_state); 1908c2ecf20Sopenharmony_ci vmw_write(dev_priv, SVGA_REG_TRACES, 1918c2ecf20Sopenharmony_ci dev_priv->traces_state); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci vmw_marker_queue_takedown(&fifo->marker_queue); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (likely(fifo->static_buffer != NULL)) { 1968c2ecf20Sopenharmony_ci vfree(fifo->static_buffer); 1978c2ecf20Sopenharmony_ci fifo->static_buffer = NULL; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (likely(fifo->dynamic_buffer != NULL)) { 2018c2ecf20Sopenharmony_ci vfree(fifo->dynamic_buffer); 2028c2ecf20Sopenharmony_ci fifo->dynamic_buffer = NULL; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic bool vmw_fifo_is_full(struct vmw_private *dev_priv, uint32_t bytes) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 2098c2ecf20Sopenharmony_ci uint32_t max = vmw_mmio_read(fifo_mem + SVGA_FIFO_MAX); 2108c2ecf20Sopenharmony_ci uint32_t next_cmd = vmw_mmio_read(fifo_mem + SVGA_FIFO_NEXT_CMD); 2118c2ecf20Sopenharmony_ci uint32_t min = vmw_mmio_read(fifo_mem + SVGA_FIFO_MIN); 2128c2ecf20Sopenharmony_ci uint32_t stop = vmw_mmio_read(fifo_mem + SVGA_FIFO_STOP); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return ((max - next_cmd) + (stop - min) <= bytes); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic int vmw_fifo_wait_noirq(struct vmw_private *dev_priv, 2188c2ecf20Sopenharmony_ci uint32_t bytes, bool interruptible, 2198c2ecf20Sopenharmony_ci unsigned long timeout) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci int ret = 0; 2228c2ecf20Sopenharmony_ci unsigned long end_jiffies = jiffies + timeout; 2238c2ecf20Sopenharmony_ci DEFINE_WAIT(__wait); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci DRM_INFO("Fifo wait noirq.\n"); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci for (;;) { 2288c2ecf20Sopenharmony_ci prepare_to_wait(&dev_priv->fifo_queue, &__wait, 2298c2ecf20Sopenharmony_ci (interruptible) ? 2308c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); 2318c2ecf20Sopenharmony_ci if (!vmw_fifo_is_full(dev_priv, bytes)) 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, end_jiffies)) { 2348c2ecf20Sopenharmony_ci ret = -EBUSY; 2358c2ecf20Sopenharmony_ci DRM_ERROR("SVGA device lockup.\n"); 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci schedule_timeout(1); 2398c2ecf20Sopenharmony_ci if (interruptible && signal_pending(current)) { 2408c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci finish_wait(&dev_priv->fifo_queue, &__wait); 2458c2ecf20Sopenharmony_ci wake_up_all(&dev_priv->fifo_queue); 2468c2ecf20Sopenharmony_ci DRM_INFO("Fifo noirq exit.\n"); 2478c2ecf20Sopenharmony_ci return ret; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int vmw_fifo_wait(struct vmw_private *dev_priv, 2518c2ecf20Sopenharmony_ci uint32_t bytes, bool interruptible, 2528c2ecf20Sopenharmony_ci unsigned long timeout) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci long ret = 1L; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (likely(!vmw_fifo_is_full(dev_priv, bytes))) 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci vmw_fifo_ping_host(dev_priv, SVGA_SYNC_FIFOFULL); 2608c2ecf20Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) 2618c2ecf20Sopenharmony_ci return vmw_fifo_wait_noirq(dev_priv, bytes, 2628c2ecf20Sopenharmony_ci interruptible, timeout); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FIFO_PROGRESS, 2658c2ecf20Sopenharmony_ci &dev_priv->fifo_queue_waiters); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (interruptible) 2688c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout 2698c2ecf20Sopenharmony_ci (dev_priv->fifo_queue, 2708c2ecf20Sopenharmony_ci !vmw_fifo_is_full(dev_priv, bytes), timeout); 2718c2ecf20Sopenharmony_ci else 2728c2ecf20Sopenharmony_ci ret = wait_event_timeout 2738c2ecf20Sopenharmony_ci (dev_priv->fifo_queue, 2748c2ecf20Sopenharmony_ci !vmw_fifo_is_full(dev_priv, bytes), timeout); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (unlikely(ret == 0)) 2778c2ecf20Sopenharmony_ci ret = -EBUSY; 2788c2ecf20Sopenharmony_ci else if (likely(ret > 0)) 2798c2ecf20Sopenharmony_ci ret = 0; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FIFO_PROGRESS, 2828c2ecf20Sopenharmony_ci &dev_priv->fifo_queue_waiters); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/** 2888c2ecf20Sopenharmony_ci * Reserve @bytes number of bytes in the fifo. 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * This function will return NULL (error) on two conditions: 2918c2ecf20Sopenharmony_ci * If it timeouts waiting for fifo space, or if @bytes is larger than the 2928c2ecf20Sopenharmony_ci * available fifo space. 2938c2ecf20Sopenharmony_ci * 2948c2ecf20Sopenharmony_ci * Returns: 2958c2ecf20Sopenharmony_ci * Pointer to the fifo, or null on error (possible hardware hang). 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_cistatic void *vmw_local_fifo_reserve(struct vmw_private *dev_priv, 2988c2ecf20Sopenharmony_ci uint32_t bytes) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct vmw_fifo_state *fifo_state = &dev_priv->fifo; 3018c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 3028c2ecf20Sopenharmony_ci uint32_t max; 3038c2ecf20Sopenharmony_ci uint32_t min; 3048c2ecf20Sopenharmony_ci uint32_t next_cmd; 3058c2ecf20Sopenharmony_ci uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE; 3068c2ecf20Sopenharmony_ci int ret; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci mutex_lock(&fifo_state->fifo_mutex); 3098c2ecf20Sopenharmony_ci max = vmw_mmio_read(fifo_mem + SVGA_FIFO_MAX); 3108c2ecf20Sopenharmony_ci min = vmw_mmio_read(fifo_mem + SVGA_FIFO_MIN); 3118c2ecf20Sopenharmony_ci next_cmd = vmw_mmio_read(fifo_mem + SVGA_FIFO_NEXT_CMD); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (unlikely(bytes >= (max - min))) 3148c2ecf20Sopenharmony_ci goto out_err; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci BUG_ON(fifo_state->reserved_size != 0); 3178c2ecf20Sopenharmony_ci BUG_ON(fifo_state->dynamic_buffer != NULL); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci fifo_state->reserved_size = bytes; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci while (1) { 3228c2ecf20Sopenharmony_ci uint32_t stop = vmw_mmio_read(fifo_mem + SVGA_FIFO_STOP); 3238c2ecf20Sopenharmony_ci bool need_bounce = false; 3248c2ecf20Sopenharmony_ci bool reserve_in_place = false; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (next_cmd >= stop) { 3278c2ecf20Sopenharmony_ci if (likely((next_cmd + bytes < max || 3288c2ecf20Sopenharmony_ci (next_cmd + bytes == max && stop > min)))) 3298c2ecf20Sopenharmony_ci reserve_in_place = true; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci else if (vmw_fifo_is_full(dev_priv, bytes)) { 3328c2ecf20Sopenharmony_ci ret = vmw_fifo_wait(dev_priv, bytes, 3338c2ecf20Sopenharmony_ci false, 3 * HZ); 3348c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 3358c2ecf20Sopenharmony_ci goto out_err; 3368c2ecf20Sopenharmony_ci } else 3378c2ecf20Sopenharmony_ci need_bounce = true; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci } else { 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (likely((next_cmd + bytes < stop))) 3428c2ecf20Sopenharmony_ci reserve_in_place = true; 3438c2ecf20Sopenharmony_ci else { 3448c2ecf20Sopenharmony_ci ret = vmw_fifo_wait(dev_priv, bytes, 3458c2ecf20Sopenharmony_ci false, 3 * HZ); 3468c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 3478c2ecf20Sopenharmony_ci goto out_err; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (reserve_in_place) { 3528c2ecf20Sopenharmony_ci if (reserveable || bytes <= sizeof(uint32_t)) { 3538c2ecf20Sopenharmony_ci fifo_state->using_bounce_buffer = false; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (reserveable) 3568c2ecf20Sopenharmony_ci vmw_mmio_write(bytes, fifo_mem + 3578c2ecf20Sopenharmony_ci SVGA_FIFO_RESERVED); 3588c2ecf20Sopenharmony_ci return (void __force *) (fifo_mem + 3598c2ecf20Sopenharmony_ci (next_cmd >> 2)); 3608c2ecf20Sopenharmony_ci } else { 3618c2ecf20Sopenharmony_ci need_bounce = true; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (need_bounce) { 3668c2ecf20Sopenharmony_ci fifo_state->using_bounce_buffer = true; 3678c2ecf20Sopenharmony_ci if (bytes < fifo_state->static_buffer_size) 3688c2ecf20Sopenharmony_ci return fifo_state->static_buffer; 3698c2ecf20Sopenharmony_ci else { 3708c2ecf20Sopenharmony_ci fifo_state->dynamic_buffer = vmalloc(bytes); 3718c2ecf20Sopenharmony_ci if (!fifo_state->dynamic_buffer) 3728c2ecf20Sopenharmony_ci goto out_err; 3738c2ecf20Sopenharmony_ci return fifo_state->dynamic_buffer; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ciout_err: 3788c2ecf20Sopenharmony_ci fifo_state->reserved_size = 0; 3798c2ecf20Sopenharmony_ci mutex_unlock(&fifo_state->fifo_mutex); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return NULL; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_civoid *vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes, 3858c2ecf20Sopenharmony_ci int ctx_id) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci void *ret; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (dev_priv->cman) 3908c2ecf20Sopenharmony_ci ret = vmw_cmdbuf_reserve(dev_priv->cman, bytes, 3918c2ecf20Sopenharmony_ci ctx_id, false, NULL); 3928c2ecf20Sopenharmony_ci else if (ctx_id == SVGA3D_INVALID_ID) 3938c2ecf20Sopenharmony_ci ret = vmw_local_fifo_reserve(dev_priv, bytes); 3948c2ecf20Sopenharmony_ci else { 3958c2ecf20Sopenharmony_ci WARN(1, "Command buffer has not been allocated.\n"); 3968c2ecf20Sopenharmony_ci ret = NULL; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(ret)) 3998c2ecf20Sopenharmony_ci return NULL; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic void vmw_fifo_res_copy(struct vmw_fifo_state *fifo_state, 4058c2ecf20Sopenharmony_ci u32 *fifo_mem, 4068c2ecf20Sopenharmony_ci uint32_t next_cmd, 4078c2ecf20Sopenharmony_ci uint32_t max, uint32_t min, uint32_t bytes) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci uint32_t chunk_size = max - next_cmd; 4108c2ecf20Sopenharmony_ci uint32_t rest; 4118c2ecf20Sopenharmony_ci uint32_t *buffer = (fifo_state->dynamic_buffer != NULL) ? 4128c2ecf20Sopenharmony_ci fifo_state->dynamic_buffer : fifo_state->static_buffer; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (bytes < chunk_size) 4158c2ecf20Sopenharmony_ci chunk_size = bytes; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci vmw_mmio_write(bytes, fifo_mem + SVGA_FIFO_RESERVED); 4188c2ecf20Sopenharmony_ci mb(); 4198c2ecf20Sopenharmony_ci memcpy(fifo_mem + (next_cmd >> 2), buffer, chunk_size); 4208c2ecf20Sopenharmony_ci rest = bytes - chunk_size; 4218c2ecf20Sopenharmony_ci if (rest) 4228c2ecf20Sopenharmony_ci memcpy(fifo_mem + (min >> 2), buffer + (chunk_size >> 2), rest); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state, 4268c2ecf20Sopenharmony_ci u32 *fifo_mem, 4278c2ecf20Sopenharmony_ci uint32_t next_cmd, 4288c2ecf20Sopenharmony_ci uint32_t max, uint32_t min, uint32_t bytes) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci uint32_t *buffer = (fifo_state->dynamic_buffer != NULL) ? 4318c2ecf20Sopenharmony_ci fifo_state->dynamic_buffer : fifo_state->static_buffer; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci while (bytes > 0) { 4348c2ecf20Sopenharmony_ci vmw_mmio_write(*buffer++, fifo_mem + (next_cmd >> 2)); 4358c2ecf20Sopenharmony_ci next_cmd += sizeof(uint32_t); 4368c2ecf20Sopenharmony_ci if (unlikely(next_cmd == max)) 4378c2ecf20Sopenharmony_ci next_cmd = min; 4388c2ecf20Sopenharmony_ci mb(); 4398c2ecf20Sopenharmony_ci vmw_mmio_write(next_cmd, fifo_mem + SVGA_FIFO_NEXT_CMD); 4408c2ecf20Sopenharmony_ci mb(); 4418c2ecf20Sopenharmony_ci bytes -= sizeof(uint32_t); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct vmw_fifo_state *fifo_state = &dev_priv->fifo; 4488c2ecf20Sopenharmony_ci u32 *fifo_mem = dev_priv->mmio_virt; 4498c2ecf20Sopenharmony_ci uint32_t next_cmd = vmw_mmio_read(fifo_mem + SVGA_FIFO_NEXT_CMD); 4508c2ecf20Sopenharmony_ci uint32_t max = vmw_mmio_read(fifo_mem + SVGA_FIFO_MAX); 4518c2ecf20Sopenharmony_ci uint32_t min = vmw_mmio_read(fifo_mem + SVGA_FIFO_MIN); 4528c2ecf20Sopenharmony_ci bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (fifo_state->dx) 4558c2ecf20Sopenharmony_ci bytes += sizeof(struct vmw_temp_set_context); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci fifo_state->dx = false; 4588c2ecf20Sopenharmony_ci BUG_ON((bytes & 3) != 0); 4598c2ecf20Sopenharmony_ci BUG_ON(bytes > fifo_state->reserved_size); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci fifo_state->reserved_size = 0; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (fifo_state->using_bounce_buffer) { 4648c2ecf20Sopenharmony_ci if (reserveable) 4658c2ecf20Sopenharmony_ci vmw_fifo_res_copy(fifo_state, fifo_mem, 4668c2ecf20Sopenharmony_ci next_cmd, max, min, bytes); 4678c2ecf20Sopenharmony_ci else 4688c2ecf20Sopenharmony_ci vmw_fifo_slow_copy(fifo_state, fifo_mem, 4698c2ecf20Sopenharmony_ci next_cmd, max, min, bytes); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (fifo_state->dynamic_buffer) { 4728c2ecf20Sopenharmony_ci vfree(fifo_state->dynamic_buffer); 4738c2ecf20Sopenharmony_ci fifo_state->dynamic_buffer = NULL; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci down_write(&fifo_state->rwsem); 4798c2ecf20Sopenharmony_ci if (fifo_state->using_bounce_buffer || reserveable) { 4808c2ecf20Sopenharmony_ci next_cmd += bytes; 4818c2ecf20Sopenharmony_ci if (next_cmd >= max) 4828c2ecf20Sopenharmony_ci next_cmd -= max - min; 4838c2ecf20Sopenharmony_ci mb(); 4848c2ecf20Sopenharmony_ci vmw_mmio_write(next_cmd, fifo_mem + SVGA_FIFO_NEXT_CMD); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (reserveable) 4888c2ecf20Sopenharmony_ci vmw_mmio_write(0, fifo_mem + SVGA_FIFO_RESERVED); 4898c2ecf20Sopenharmony_ci mb(); 4908c2ecf20Sopenharmony_ci up_write(&fifo_state->rwsem); 4918c2ecf20Sopenharmony_ci vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); 4928c2ecf20Sopenharmony_ci mutex_unlock(&fifo_state->fifo_mutex); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_civoid vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci if (dev_priv->cman) 4988c2ecf20Sopenharmony_ci vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, false); 4998c2ecf20Sopenharmony_ci else 5008c2ecf20Sopenharmony_ci vmw_local_fifo_commit(dev_priv, bytes); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * vmw_fifo_commit_flush - Commit fifo space and flush any buffered commands. 5068c2ecf20Sopenharmony_ci * 5078c2ecf20Sopenharmony_ci * @dev_priv: Pointer to device private structure. 5088c2ecf20Sopenharmony_ci * @bytes: Number of bytes to commit. 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_civoid vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci if (dev_priv->cman) 5138c2ecf20Sopenharmony_ci vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, true); 5148c2ecf20Sopenharmony_ci else 5158c2ecf20Sopenharmony_ci vmw_local_fifo_commit(dev_priv, bytes); 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci/** 5198c2ecf20Sopenharmony_ci * vmw_fifo_flush - Flush any buffered commands and make sure command processing 5208c2ecf20Sopenharmony_ci * starts. 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * @dev_priv: Pointer to device private structure. 5238c2ecf20Sopenharmony_ci * @interruptible: Whether to wait interruptible if function needs to sleep. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ciint vmw_fifo_flush(struct vmw_private *dev_priv, bool interruptible) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci might_sleep(); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (dev_priv->cman) 5308c2ecf20Sopenharmony_ci return vmw_cmdbuf_cur_flush(dev_priv->cman, interruptible); 5318c2ecf20Sopenharmony_ci else 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ciint vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct vmw_fifo_state *fifo_state = &dev_priv->fifo; 5388c2ecf20Sopenharmony_ci struct svga_fifo_cmd_fence *cmd_fence; 5398c2ecf20Sopenharmony_ci u32 *fm; 5408c2ecf20Sopenharmony_ci int ret = 0; 5418c2ecf20Sopenharmony_ci uint32_t bytes = sizeof(u32) + sizeof(*cmd_fence); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci fm = VMW_FIFO_RESERVE(dev_priv, bytes); 5448c2ecf20Sopenharmony_ci if (unlikely(fm == NULL)) { 5458c2ecf20Sopenharmony_ci *seqno = atomic_read(&dev_priv->marker_seq); 5468c2ecf20Sopenharmony_ci ret = -ENOMEM; 5478c2ecf20Sopenharmony_ci (void)vmw_fallback_wait(dev_priv, false, true, *seqno, 5488c2ecf20Sopenharmony_ci false, 3*HZ); 5498c2ecf20Sopenharmony_ci goto out_err; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci do { 5538c2ecf20Sopenharmony_ci *seqno = atomic_add_return(1, &dev_priv->marker_seq); 5548c2ecf20Sopenharmony_ci } while (*seqno == 0); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE)) { 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* 5598c2ecf20Sopenharmony_ci * Don't request hardware to send a fence. The 5608c2ecf20Sopenharmony_ci * waiting code in vmwgfx_irq.c will emulate this. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, 0); 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci *fm++ = SVGA_CMD_FENCE; 5688c2ecf20Sopenharmony_ci cmd_fence = (struct svga_fifo_cmd_fence *) fm; 5698c2ecf20Sopenharmony_ci cmd_fence->fence = *seqno; 5708c2ecf20Sopenharmony_ci vmw_fifo_commit_flush(dev_priv, bytes); 5718c2ecf20Sopenharmony_ci (void) vmw_marker_push(&fifo_state->marker_queue, *seqno); 5728c2ecf20Sopenharmony_ci vmw_update_seqno(dev_priv, fifo_state); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ciout_err: 5758c2ecf20Sopenharmony_ci return ret; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci/** 5798c2ecf20Sopenharmony_ci * vmw_fifo_emit_dummy_legacy_query - emits a dummy query to the fifo using 5808c2ecf20Sopenharmony_ci * legacy query commands. 5818c2ecf20Sopenharmony_ci * 5828c2ecf20Sopenharmony_ci * @dev_priv: The device private structure. 5838c2ecf20Sopenharmony_ci * @cid: The hardware context id used for the query. 5848c2ecf20Sopenharmony_ci * 5858c2ecf20Sopenharmony_ci * See the vmw_fifo_emit_dummy_query documentation. 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_cistatic int vmw_fifo_emit_dummy_legacy_query(struct vmw_private *dev_priv, 5888c2ecf20Sopenharmony_ci uint32_t cid) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci /* 5918c2ecf20Sopenharmony_ci * A query wait without a preceding query end will 5928c2ecf20Sopenharmony_ci * actually finish all queries for this cid 5938c2ecf20Sopenharmony_ci * without writing to the query result structure. 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci struct ttm_buffer_object *bo = &dev_priv->dummy_query_bo->base; 5978c2ecf20Sopenharmony_ci struct { 5988c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 5998c2ecf20Sopenharmony_ci SVGA3dCmdWaitForQuery body; 6008c2ecf20Sopenharmony_ci } *cmd; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 6038c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) 6048c2ecf20Sopenharmony_ci return -ENOMEM; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_WAIT_FOR_QUERY; 6078c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 6088c2ecf20Sopenharmony_ci cmd->body.cid = cid; 6098c2ecf20Sopenharmony_ci cmd->body.type = SVGA3D_QUERYTYPE_OCCLUSION; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (bo->mem.mem_type == TTM_PL_VRAM) { 6128c2ecf20Sopenharmony_ci cmd->body.guestResult.gmrId = SVGA_GMR_FRAMEBUFFER; 6138c2ecf20Sopenharmony_ci cmd->body.guestResult.offset = bo->mem.start << PAGE_SHIFT; 6148c2ecf20Sopenharmony_ci } else { 6158c2ecf20Sopenharmony_ci cmd->body.guestResult.gmrId = bo->mem.start; 6168c2ecf20Sopenharmony_ci cmd->body.guestResult.offset = 0; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci/** 6258c2ecf20Sopenharmony_ci * vmw_fifo_emit_dummy_gb_query - emits a dummy query to the fifo using 6268c2ecf20Sopenharmony_ci * guest-backed resource query commands. 6278c2ecf20Sopenharmony_ci * 6288c2ecf20Sopenharmony_ci * @dev_priv: The device private structure. 6298c2ecf20Sopenharmony_ci * @cid: The hardware context id used for the query. 6308c2ecf20Sopenharmony_ci * 6318c2ecf20Sopenharmony_ci * See the vmw_fifo_emit_dummy_query documentation. 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_cistatic int vmw_fifo_emit_dummy_gb_query(struct vmw_private *dev_priv, 6348c2ecf20Sopenharmony_ci uint32_t cid) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci /* 6378c2ecf20Sopenharmony_ci * A query wait without a preceding query end will 6388c2ecf20Sopenharmony_ci * actually finish all queries for this cid 6398c2ecf20Sopenharmony_ci * without writing to the query result structure. 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci struct ttm_buffer_object *bo = &dev_priv->dummy_query_bo->base; 6438c2ecf20Sopenharmony_ci struct { 6448c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 6458c2ecf20Sopenharmony_ci SVGA3dCmdWaitForGBQuery body; 6468c2ecf20Sopenharmony_ci } *cmd; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 6498c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) 6508c2ecf20Sopenharmony_ci return -ENOMEM; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_WAIT_FOR_GB_QUERY; 6538c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 6548c2ecf20Sopenharmony_ci cmd->body.cid = cid; 6558c2ecf20Sopenharmony_ci cmd->body.type = SVGA3D_QUERYTYPE_OCCLUSION; 6568c2ecf20Sopenharmony_ci BUG_ON(bo->mem.mem_type != VMW_PL_MOB); 6578c2ecf20Sopenharmony_ci cmd->body.mobid = bo->mem.start; 6588c2ecf20Sopenharmony_ci cmd->body.offset = 0; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return 0; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci/** 6678c2ecf20Sopenharmony_ci * vmw_fifo_emit_dummy_gb_query - emits a dummy query to the fifo using 6688c2ecf20Sopenharmony_ci * appropriate resource query commands. 6698c2ecf20Sopenharmony_ci * 6708c2ecf20Sopenharmony_ci * @dev_priv: The device private structure. 6718c2ecf20Sopenharmony_ci * @cid: The hardware context id used for the query. 6728c2ecf20Sopenharmony_ci * 6738c2ecf20Sopenharmony_ci * This function is used to emit a dummy occlusion query with 6748c2ecf20Sopenharmony_ci * no primitives rendered between query begin and query end. 6758c2ecf20Sopenharmony_ci * It's used to provide a query barrier, in order to know that when 6768c2ecf20Sopenharmony_ci * this query is finished, all preceding queries are also finished. 6778c2ecf20Sopenharmony_ci * 6788c2ecf20Sopenharmony_ci * A Query results structure should have been initialized at the start 6798c2ecf20Sopenharmony_ci * of the dev_priv->dummy_query_bo buffer object. And that buffer object 6808c2ecf20Sopenharmony_ci * must also be either reserved or pinned when this function is called. 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * Returns -ENOMEM on failure to reserve fifo space. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ciint vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv, 6858c2ecf20Sopenharmony_ci uint32_t cid) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci if (dev_priv->has_mob) 6888c2ecf20Sopenharmony_ci return vmw_fifo_emit_dummy_gb_query(dev_priv, cid); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return vmw_fifo_emit_dummy_legacy_query(dev_priv, cid); 6918c2ecf20Sopenharmony_ci} 692