brintos

brintos / linux-shallow public Read only

0
0
Text · 18.0 KiB · dd4ca6a Raw
690 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR MIT2/**************************************************************************3 *4 * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA5 *6 * Permission is hereby granted, free of charge, to any person obtaining a7 * copy of this software and associated documentation files (the8 * "Software"), to deal in the Software without restriction, including9 * without limitation the rights to use, copy, modify, merge, publish,10 * distribute, sub license, and/or sell copies of the Software, and to11 * permit persons to whom the Software is furnished to do so, subject to12 * the following conditions:13 *14 * The above copyright notice and this permission notice (including the15 * next paragraph) shall be included in all copies or substantial portions16 * of the Software.17 *18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE24 * USE OR OTHER DEALINGS IN THE SOFTWARE.25 *26 **************************************************************************/27#include "vmwgfx_bo.h"28#include "vmwgfx_drv.h"29#include "vmwgfx_devcaps.h"30 31#include <drm/ttm/ttm_placement.h>32 33#include <linux/sched/signal.h>34#include <linux/vmalloc.h>35 36bool vmw_supports_3d(struct vmw_private *dev_priv)37{38	uint32_t fifo_min, hwversion;39	const struct vmw_fifo_state *fifo = dev_priv->fifo;40 41	if (!(dev_priv->capabilities & SVGA_CAP_3D))42		return false;43 44	if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {45		uint32_t result;46 47		if (!dev_priv->has_mob)48			return false;49 50		result = vmw_devcap_get(dev_priv, SVGA3D_DEVCAP_3D);51 52		return (result != 0);53	}54 55	if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))56		return false;57 58	BUG_ON(vmw_is_svga_v3(dev_priv));59 60	fifo_min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN);61	if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int))62		return false;63 64	hwversion = vmw_fifo_mem_read(dev_priv,65				      ((fifo->capabilities &66					SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ?67					       SVGA_FIFO_3D_HWVERSION_REVISED :68					       SVGA_FIFO_3D_HWVERSION));69 70	if (hwversion == 0)71		return false;72 73	if (hwversion < SVGA3D_HWVERSION_WS8_B1)74		return false;75 76	/* Legacy Display Unit does not support surfaces */77	if (dev_priv->active_display_unit == vmw_du_legacy)78		return false;79 80	return true;81}82 83bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv)84{85	uint32_t caps;86 87	if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))88		return false;89 90	caps = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CAPABILITIES);91	if (caps & SVGA_FIFO_CAP_PITCHLOCK)92		return true;93 94	return false;95}96 97struct vmw_fifo_state *vmw_fifo_create(struct vmw_private *dev_priv)98{99	struct vmw_fifo_state *fifo;100	uint32_t max;101	uint32_t min;102 103	if (!dev_priv->fifo_mem)104		return NULL;105 106	fifo = kzalloc(sizeof(*fifo), GFP_KERNEL);107	if (!fifo)108		return ERR_PTR(-ENOMEM);109	fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE;110	fifo->static_buffer = vmalloc(fifo->static_buffer_size);111	if (unlikely(fifo->static_buffer == NULL)) {112		kfree(fifo);113		return ERR_PTR(-ENOMEM);114	}115 116	fifo->dynamic_buffer = NULL;117	fifo->reserved_size = 0;118	fifo->using_bounce_buffer = false;119 120	mutex_init(&fifo->fifo_mutex);121	init_rwsem(&fifo->rwsem);122	min = 4;123	if (dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)124		min = vmw_read(dev_priv, SVGA_REG_MEM_REGS);125	min <<= 2;126 127	if (min < PAGE_SIZE)128		min = PAGE_SIZE;129 130	vmw_fifo_mem_write(dev_priv, SVGA_FIFO_MIN, min);131	vmw_fifo_mem_write(dev_priv, SVGA_FIFO_MAX, dev_priv->fifo_mem_size);132	wmb();133	vmw_fifo_mem_write(dev_priv, SVGA_FIFO_NEXT_CMD, min);134	vmw_fifo_mem_write(dev_priv, SVGA_FIFO_STOP, min);135	vmw_fifo_mem_write(dev_priv, SVGA_FIFO_BUSY, 0);136	mb();137 138	vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1);139 140	max = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MAX);141	min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN);142	fifo->capabilities = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_CAPABILITIES);143 144	drm_info(&dev_priv->drm,145		 "Fifo max 0x%08x min 0x%08x cap 0x%08x\n",146		 (unsigned int) max,147		 (unsigned int) min,148		 (unsigned int) fifo->capabilities);149 150	if (unlikely(min >= max)) {151		drm_warn(&dev_priv->drm,152			 "FIFO memory is not usable. Driver failed to initialize.");153		return ERR_PTR(-ENXIO);154	}155 156	return fifo;157}158 159void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)160{161	u32 *fifo_mem = dev_priv->fifo_mem;162	if (fifo_mem && cmpxchg(fifo_mem + SVGA_FIFO_BUSY, 0, 1) == 0)163		vmw_write(dev_priv, SVGA_REG_SYNC, reason);164 165}166 167void vmw_fifo_destroy(struct vmw_private *dev_priv)168{169	struct vmw_fifo_state *fifo = dev_priv->fifo;170 171	if (!fifo)172		return;173 174	if (likely(fifo->static_buffer != NULL)) {175		vfree(fifo->static_buffer);176		fifo->static_buffer = NULL;177	}178 179	if (likely(fifo->dynamic_buffer != NULL)) {180		vfree(fifo->dynamic_buffer);181		fifo->dynamic_buffer = NULL;182	}183	kfree(fifo);184	dev_priv->fifo = NULL;185}186 187static bool vmw_fifo_is_full(struct vmw_private *dev_priv, uint32_t bytes)188{189	uint32_t max = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MAX);190	uint32_t next_cmd = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_NEXT_CMD);191	uint32_t min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN);192	uint32_t stop = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_STOP);193 194	return ((max - next_cmd) + (stop - min) <= bytes);195}196 197static int vmw_fifo_wait_noirq(struct vmw_private *dev_priv,198			       uint32_t bytes, bool interruptible,199			       unsigned long timeout)200{201	int ret = 0;202	unsigned long end_jiffies = jiffies + timeout;203	DEFINE_WAIT(__wait);204 205	DRM_INFO("Fifo wait noirq.\n");206 207	for (;;) {208		prepare_to_wait(&dev_priv->fifo_queue, &__wait,209				(interruptible) ?210				TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);211		if (!vmw_fifo_is_full(dev_priv, bytes))212			break;213		if (time_after_eq(jiffies, end_jiffies)) {214			ret = -EBUSY;215			DRM_ERROR("SVGA device lockup.\n");216			break;217		}218		schedule_timeout(1);219		if (interruptible && signal_pending(current)) {220			ret = -ERESTARTSYS;221			break;222		}223	}224	finish_wait(&dev_priv->fifo_queue, &__wait);225	wake_up_all(&dev_priv->fifo_queue);226	DRM_INFO("Fifo noirq exit.\n");227	return ret;228}229 230static int vmw_fifo_wait(struct vmw_private *dev_priv,231			 uint32_t bytes, bool interruptible,232			 unsigned long timeout)233{234	long ret = 1L;235 236	if (likely(!vmw_fifo_is_full(dev_priv, bytes)))237		return 0;238 239	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_FIFOFULL);240	if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))241		return vmw_fifo_wait_noirq(dev_priv, bytes,242					   interruptible, timeout);243 244	vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FIFO_PROGRESS,245			       &dev_priv->fifo_queue_waiters);246 247	if (interruptible)248		ret = wait_event_interruptible_timeout249		    (dev_priv->fifo_queue,250		     !vmw_fifo_is_full(dev_priv, bytes), timeout);251	else252		ret = wait_event_timeout253		    (dev_priv->fifo_queue,254		     !vmw_fifo_is_full(dev_priv, bytes), timeout);255 256	if (unlikely(ret == 0))257		ret = -EBUSY;258	else if (likely(ret > 0))259		ret = 0;260 261	vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FIFO_PROGRESS,262				  &dev_priv->fifo_queue_waiters);263 264	return ret;265}266 267/*268 * Reserve @bytes number of bytes in the fifo.269 *270 * This function will return NULL (error) on two conditions:271 *  If it timeouts waiting for fifo space, or if @bytes is larger than the272 *   available fifo space.273 *274 * Returns:275 *   Pointer to the fifo, or null on error (possible hardware hang).276 */277static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,278				    uint32_t bytes)279{280	struct vmw_fifo_state *fifo_state = dev_priv->fifo;281	u32  *fifo_mem = dev_priv->fifo_mem;282	uint32_t max;283	uint32_t min;284	uint32_t next_cmd;285	uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;286	int ret;287 288	mutex_lock(&fifo_state->fifo_mutex);289	max = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MAX);290	min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN);291	next_cmd = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_NEXT_CMD);292 293	if (unlikely(bytes >= (max - min)))294		goto out_err;295 296	BUG_ON(fifo_state->reserved_size != 0);297	BUG_ON(fifo_state->dynamic_buffer != NULL);298 299	fifo_state->reserved_size = bytes;300 301	while (1) {302		uint32_t stop = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_STOP);303		bool need_bounce = false;304		bool reserve_in_place = false;305 306		if (next_cmd >= stop) {307			if (likely((next_cmd + bytes < max ||308				    (next_cmd + bytes == max && stop > min))))309				reserve_in_place = true;310 311			else if (vmw_fifo_is_full(dev_priv, bytes)) {312				ret = vmw_fifo_wait(dev_priv, bytes,313						    false, 3 * HZ);314				if (unlikely(ret != 0))315					goto out_err;316			} else317				need_bounce = true;318 319		} else {320 321			if (likely((next_cmd + bytes < stop)))322				reserve_in_place = true;323			else {324				ret = vmw_fifo_wait(dev_priv, bytes,325						    false, 3 * HZ);326				if (unlikely(ret != 0))327					goto out_err;328			}329		}330 331		if (reserve_in_place) {332			if (reserveable || bytes <= sizeof(uint32_t)) {333				fifo_state->using_bounce_buffer = false;334 335				if (reserveable)336					vmw_fifo_mem_write(dev_priv,337							   SVGA_FIFO_RESERVED,338							   bytes);339				return (void __force *) (fifo_mem +340							 (next_cmd >> 2));341			} else {342				need_bounce = true;343			}344		}345 346		if (need_bounce) {347			fifo_state->using_bounce_buffer = true;348			if (bytes < fifo_state->static_buffer_size)349				return fifo_state->static_buffer;350			else {351				fifo_state->dynamic_buffer = vmalloc(bytes);352				if (!fifo_state->dynamic_buffer)353					goto out_err;354				return fifo_state->dynamic_buffer;355			}356		}357	}358out_err:359	fifo_state->reserved_size = 0;360	mutex_unlock(&fifo_state->fifo_mutex);361 362	return NULL;363}364 365void *vmw_cmd_ctx_reserve(struct vmw_private *dev_priv, uint32_t bytes,366			  int ctx_id)367{368	void *ret;369 370	if (dev_priv->cman)371		ret = vmw_cmdbuf_reserve(dev_priv->cman, bytes,372					 ctx_id, false, NULL);373	else if (ctx_id == SVGA3D_INVALID_ID)374		ret = vmw_local_fifo_reserve(dev_priv, bytes);375	else {376		WARN(1, "Command buffer has not been allocated.\n");377		ret = NULL;378	}379	if (IS_ERR_OR_NULL(ret))380		return NULL;381 382	return ret;383}384 385static void vmw_fifo_res_copy(struct vmw_fifo_state *fifo_state,386			      struct vmw_private *vmw,387			      uint32_t next_cmd,388			      uint32_t max, uint32_t min, uint32_t bytes)389{390	u32 *fifo_mem = vmw->fifo_mem;391	uint32_t chunk_size = max - next_cmd;392	uint32_t rest;393	uint32_t *buffer = (fifo_state->dynamic_buffer != NULL) ?394	    fifo_state->dynamic_buffer : fifo_state->static_buffer;395 396	if (bytes < chunk_size)397		chunk_size = bytes;398 399	vmw_fifo_mem_write(vmw, SVGA_FIFO_RESERVED, bytes);400	mb();401	memcpy(fifo_mem + (next_cmd >> 2), buffer, chunk_size);402	rest = bytes - chunk_size;403	if (rest)404		memcpy(fifo_mem + (min >> 2), buffer + (chunk_size >> 2), rest);405}406 407static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state,408			       struct vmw_private *vmw,409			       uint32_t next_cmd,410			       uint32_t max, uint32_t min, uint32_t bytes)411{412	uint32_t *buffer = (fifo_state->dynamic_buffer != NULL) ?413	    fifo_state->dynamic_buffer : fifo_state->static_buffer;414 415	while (bytes > 0) {416		vmw_fifo_mem_write(vmw, (next_cmd >> 2), *buffer++);417		next_cmd += sizeof(uint32_t);418		if (unlikely(next_cmd == max))419			next_cmd = min;420		mb();421		vmw_fifo_mem_write(vmw, SVGA_FIFO_NEXT_CMD, next_cmd);422		mb();423		bytes -= sizeof(uint32_t);424	}425}426 427static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes)428{429	struct vmw_fifo_state *fifo_state = dev_priv->fifo;430	uint32_t next_cmd = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_NEXT_CMD);431	uint32_t max = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MAX);432	uint32_t min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN);433	bool reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;434 435	BUG_ON((bytes & 3) != 0);436	BUG_ON(bytes > fifo_state->reserved_size);437 438	fifo_state->reserved_size = 0;439 440	if (fifo_state->using_bounce_buffer) {441		if (reserveable)442			vmw_fifo_res_copy(fifo_state, dev_priv,443					  next_cmd, max, min, bytes);444		else445			vmw_fifo_slow_copy(fifo_state, dev_priv,446					   next_cmd, max, min, bytes);447 448		if (fifo_state->dynamic_buffer) {449			vfree(fifo_state->dynamic_buffer);450			fifo_state->dynamic_buffer = NULL;451		}452 453	}454 455	down_write(&fifo_state->rwsem);456	if (fifo_state->using_bounce_buffer || reserveable) {457		next_cmd += bytes;458		if (next_cmd >= max)459			next_cmd -= max - min;460		mb();461		vmw_fifo_mem_write(dev_priv, SVGA_FIFO_NEXT_CMD, next_cmd);462	}463 464	if (reserveable)465		vmw_fifo_mem_write(dev_priv, SVGA_FIFO_RESERVED, 0);466	mb();467	up_write(&fifo_state->rwsem);468	vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);469	mutex_unlock(&fifo_state->fifo_mutex);470}471 472void vmw_cmd_commit(struct vmw_private *dev_priv, uint32_t bytes)473{474	if (dev_priv->cman)475		vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, false);476	else477		vmw_local_fifo_commit(dev_priv, bytes);478}479 480 481/**482 * vmw_cmd_commit_flush - Commit fifo space and flush any buffered commands.483 *484 * @dev_priv: Pointer to device private structure.485 * @bytes: Number of bytes to commit.486 */487void vmw_cmd_commit_flush(struct vmw_private *dev_priv, uint32_t bytes)488{489	if (dev_priv->cman)490		vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, true);491	else492		vmw_local_fifo_commit(dev_priv, bytes);493}494 495/**496 * vmw_cmd_flush - Flush any buffered commands and make sure command processing497 * starts.498 *499 * @dev_priv: Pointer to device private structure.500 * @interruptible: Whether to wait interruptible if function needs to sleep.501 */502int vmw_cmd_flush(struct vmw_private *dev_priv, bool interruptible)503{504	might_sleep();505 506	if (dev_priv->cman)507		return vmw_cmdbuf_cur_flush(dev_priv->cman, interruptible);508	else509		return 0;510}511 512int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno)513{514	struct svga_fifo_cmd_fence *cmd_fence;515	u32 *fm;516	int ret = 0;517	uint32_t bytes = sizeof(u32) + sizeof(*cmd_fence);518 519	fm = VMW_CMD_RESERVE(dev_priv, bytes);520	if (unlikely(fm == NULL)) {521		*seqno = atomic_read(&dev_priv->marker_seq);522		ret = -ENOMEM;523		(void)vmw_fallback_wait(dev_priv, false, true, *seqno,524					false, 3*HZ);525		goto out_err;526	}527 528	do {529		*seqno = atomic_add_return(1, &dev_priv->marker_seq);530	} while (*seqno == 0);531 532	if (!vmw_has_fences(dev_priv)) {533 534		/*535		 * Don't request hardware to send a fence. The536		 * waiting code in vmwgfx_irq.c will emulate this.537		 */538 539		vmw_cmd_commit(dev_priv, 0);540		return 0;541	}542 543	*fm++ = SVGA_CMD_FENCE;544	cmd_fence = (struct svga_fifo_cmd_fence *) fm;545	cmd_fence->fence = *seqno;546	vmw_cmd_commit_flush(dev_priv, bytes);547	vmw_update_seqno(dev_priv);548 549out_err:550	return ret;551}552 553/**554 * vmw_cmd_emit_dummy_legacy_query - emits a dummy query to the fifo using555 * legacy query commands.556 *557 * @dev_priv: The device private structure.558 * @cid: The hardware context id used for the query.559 *560 * See the vmw_cmd_emit_dummy_query documentation.561 */562static int vmw_cmd_emit_dummy_legacy_query(struct vmw_private *dev_priv,563					    uint32_t cid)564{565	/*566	 * A query wait without a preceding query end will567	 * actually finish all queries for this cid568	 * without writing to the query result structure.569	 */570 571	struct ttm_buffer_object *bo = &dev_priv->dummy_query_bo->tbo;572	struct {573		SVGA3dCmdHeader header;574		SVGA3dCmdWaitForQuery body;575	} *cmd;576 577	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));578	if (unlikely(cmd == NULL))579		return -ENOMEM;580 581	cmd->header.id = SVGA_3D_CMD_WAIT_FOR_QUERY;582	cmd->header.size = sizeof(cmd->body);583	cmd->body.cid = cid;584	cmd->body.type = SVGA3D_QUERYTYPE_OCCLUSION;585 586	if (bo->resource->mem_type == TTM_PL_VRAM) {587		cmd->body.guestResult.gmrId = SVGA_GMR_FRAMEBUFFER;588		cmd->body.guestResult.offset = bo->resource->start << PAGE_SHIFT;589	} else {590		cmd->body.guestResult.gmrId = bo->resource->start;591		cmd->body.guestResult.offset = 0;592	}593 594	vmw_cmd_commit(dev_priv, sizeof(*cmd));595 596	return 0;597}598 599/**600 * vmw_cmd_emit_dummy_gb_query - emits a dummy query to the fifo using601 * guest-backed resource query commands.602 *603 * @dev_priv: The device private structure.604 * @cid: The hardware context id used for the query.605 *606 * See the vmw_cmd_emit_dummy_query documentation.607 */608static int vmw_cmd_emit_dummy_gb_query(struct vmw_private *dev_priv,609				       uint32_t cid)610{611	/*612	 * A query wait without a preceding query end will613	 * actually finish all queries for this cid614	 * without writing to the query result structure.615	 */616 617	struct ttm_buffer_object *bo = &dev_priv->dummy_query_bo->tbo;618	struct {619		SVGA3dCmdHeader header;620		SVGA3dCmdWaitForGBQuery body;621	} *cmd;622 623	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));624	if (unlikely(cmd == NULL))625		return -ENOMEM;626 627	cmd->header.id = SVGA_3D_CMD_WAIT_FOR_GB_QUERY;628	cmd->header.size = sizeof(cmd->body);629	cmd->body.cid = cid;630	cmd->body.type = SVGA3D_QUERYTYPE_OCCLUSION;631	BUG_ON(bo->resource->mem_type != VMW_PL_MOB);632	cmd->body.mobid = bo->resource->start;633	cmd->body.offset = 0;634 635	vmw_cmd_commit(dev_priv, sizeof(*cmd));636 637	return 0;638}639 640 641/**642 * vmw_cmd_emit_dummy_query - emits a dummy query to the fifo using643 * appropriate resource query commands.644 *645 * @dev_priv: The device private structure.646 * @cid: The hardware context id used for the query.647 *648 * This function is used to emit a dummy occlusion query with649 * no primitives rendered between query begin and query end.650 * It's used to provide a query barrier, in order to know that when651 * this query is finished, all preceding queries are also finished.652 *653 * A Query results structure should have been initialized at the start654 * of the dev_priv->dummy_query_bo buffer object. And that buffer object655 * must also be either reserved or pinned when this function is called.656 *657 * Returns -ENOMEM on failure to reserve fifo space.658 */659int vmw_cmd_emit_dummy_query(struct vmw_private *dev_priv,660			      uint32_t cid)661{662	if (dev_priv->has_mob)663		return vmw_cmd_emit_dummy_gb_query(dev_priv, cid);664 665	return vmw_cmd_emit_dummy_legacy_query(dev_priv, cid);666}667 668 669/**670 * vmw_cmd_supported - returns true if the given device supports671 * command queues.672 *673 * @vmw: The device private structure.674 *675 * Returns true if we can issue commands.676 */677bool vmw_cmd_supported(struct vmw_private *vmw)678{679	bool has_cmdbufs =680		(vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |681				      SVGA_CAP_CMD_BUFFERS_2)) != 0;682	if (vmw_is_svga_v3(vmw))683		return (has_cmdbufs &&684			(vmw->capabilities & SVGA_CAP_GBOBJECTS) != 0);685	/*686	 * We have FIFO cmd's687	 */688	return has_cmdbufs || vmw->fifo_mem != NULL;689}690