Commit 53830536 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-vmware-next' into drm-core-next

* drm-vmware-next: (26 commits)
  vmwgfx: Minor cleanups
  vmwgfx: Bump driver minor to advertise support for new ioctls.
  vmwgfx: Be more strict with fb depths when using screen objects
  vmwgfx: Handle device surface memory limit
  vmwgfx: Make sure we always have a user-space handle to use for objects that are backing kms framebuffers.
  vmwgfx: Optimize the command submission resource list
  vmwgfx: Fix up query processing
  vmwgfx: Allow reference and unreference of NULL fence objects.
  vmwgfx: minor dmabuf utilities cleanup
  vmwgfx: Disallow user space to send present and readback commands
  vmwgfx: Add present and readback ioctls
  vmwgfx: Place overlays in GMR area if we can
  vmwgfx: Drop 3D Legacy Display Unit support
  vmwgfx: Require HWV8 for 3d support
  vmwgfx: Add screen object support
  vmwgfx: Add dmabuf helper functions for pinning
  vmwgfx: Refactor common display unit functions to shared file
  vmwgfx: Expand the command checker to cover screen object commands
  vmwgfx: Break out dirty submission code
  vmwgfx: Break out execbuf command processing
  ...
parents 88ef4e3f 6ea77d13
......@@ -1295,6 +1295,7 @@ int ttm_bo_create(struct ttm_bo_device *bdev,
return ret;
}
EXPORT_SYMBOL(ttm_bo_create);
static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
unsigned mem_type, bool allow_errors)
......
......@@ -5,6 +5,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \
vmwgfx_fence.o
vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
This diff is collapsed.
......@@ -75,7 +75,7 @@
*/
#define SVGA_ESCAPE_VMWARE_HINT 0x00030000
#define SVGA_ESCAPE_VMWARE_HINT_FULLSCREEN 0x00030001 // Deprecated
#define SVGA_ESCAPE_VMWARE_HINT_FULLSCREEN 0x00030001 /* Deprecated */
typedef
struct {
......
......@@ -38,9 +38,9 @@
* Video formats we support
*/
#define VMWARE_FOURCC_YV12 0x32315659 // 'Y' 'V' '1' '2'
#define VMWARE_FOURCC_YUY2 0x32595559 // 'Y' 'U' 'Y' '2'
#define VMWARE_FOURCC_UYVY 0x59565955 // 'U' 'Y' 'V' 'Y'
#define VMWARE_FOURCC_YV12 0x32315659 /* 'Y' 'V' '1' '2' */
#define VMWARE_FOURCC_YUY2 0x32595559 /* 'Y' 'U' 'Y' '2' */
#define VMWARE_FOURCC_UYVY 0x59565955 /* 'U' 'Y' 'V' 'Y' */
typedef enum {
SVGA_OVERLAY_FORMAT_INVALID = 0,
......@@ -68,7 +68,7 @@ struct SVGAEscapeVideoSetRegs {
uint32 streamId;
} header;
// May include zero or more items.
/* May include zero or more items. */
struct {
uint32 registerId;
uint32 value;
......@@ -134,12 +134,12 @@ struct {
*/
static inline bool
VMwareVideoGetAttributes(const SVGAOverlayFormat format, // IN
uint32 *width, // IN / OUT
uint32 *height, // IN / OUT
uint32 *size, // OUT
uint32 *pitches, // OUT (optional)
uint32 *offsets) // OUT (optional)
VMwareVideoGetAttributes(const SVGAOverlayFormat format, /* IN */
uint32 *width, /* IN / OUT */
uint32 *height, /* IN / OUT */
uint32 *size, /* OUT */
uint32 *pitches, /* OUT (optional) */
uint32 *offsets) /* OUT (optional) */
{
int tmp;
......@@ -198,4 +198,4 @@ VMwareVideoGetAttributes(const SVGAOverlayFormat format, // IN
return true;
}
#endif // _SVGA_OVERLAY_H_
#endif /* _SVGA_OVERLAY_H_ */
This diff is collapsed.
......@@ -42,6 +42,10 @@ static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
TTM_PL_FLAG_CACHED;
static uint32_t gmr_ne_placement_flags = VMW_PL_FLAG_GMR |
TTM_PL_FLAG_CACHED |
TTM_PL_FLAG_NO_EVICT;
struct ttm_placement vmw_vram_placement = {
.fpfn = 0,
.lpfn = 0,
......@@ -56,6 +60,11 @@ static uint32_t vram_gmr_placement_flags[] = {
VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
};
static uint32_t gmr_vram_placement_flags[] = {
VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED,
TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED
};
struct ttm_placement vmw_vram_gmr_placement = {
.fpfn = 0,
.lpfn = 0,
......@@ -65,6 +74,20 @@ struct ttm_placement vmw_vram_gmr_placement = {
.busy_placement = &gmr_placement_flags
};
static uint32_t vram_gmr_ne_placement_flags[] = {
TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT,
VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT
};
struct ttm_placement vmw_vram_gmr_ne_placement = {
.fpfn = 0,
.lpfn = 0,
.num_placement = 2,
.placement = vram_gmr_ne_placement_flags,
.num_busy_placement = 1,
.busy_placement = &gmr_ne_placement_flags
};
struct ttm_placement vmw_vram_sys_placement = {
.fpfn = 0,
.lpfn = 0,
......@@ -92,6 +115,30 @@ struct ttm_placement vmw_sys_placement = {
.busy_placement = &sys_placement_flags
};
static uint32_t evictable_placement_flags[] = {
TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED,
TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED,
VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
};
struct ttm_placement vmw_evictable_placement = {
.fpfn = 0,
.lpfn = 0,
.num_placement = 3,
.placement = evictable_placement_flags,
.num_busy_placement = 1,
.busy_placement = &sys_placement_flags
};
struct ttm_placement vmw_srf_placement = {
.fpfn = 0,
.lpfn = 0,
.num_placement = 1,
.num_busy_placement = 2,
.placement = &gmr_placement_flags,
.busy_placement = gmr_vram_placement_flags
};
struct vmw_ttm_backend {
struct ttm_backend backend;
struct page **pages;
......
/**************************************************************************
*
* Copyright © 2011 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include "ttm/ttm_placement.h"
#include "drmP.h"
#include "vmwgfx_drv.h"
/**
* vmw_dmabuf_to_placement - Validate a buffer to placement.
*
* @dev_priv: Driver private.
* @buf: DMA buffer to move.
* @pin: Pin buffer if true.
* @interruptible: Use interruptible wait.
*
* May only be called by the current master since it assumes that the
* master lock is the current master's lock.
* This function takes the master's lock in write mode.
* Flushes and unpins the query bo to avoid failures.
*
* Returns
* -ERESTARTSYS if interrupted by a signal.
*/
int vmw_dmabuf_to_placement(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
struct ttm_placement *placement,
bool interruptible)
{
struct vmw_master *vmaster = dev_priv->active_master;
struct ttm_buffer_object *bo = &buf->base;
int ret;
ret = ttm_write_lock(&vmaster->lock, interruptible);
if (unlikely(ret != 0))
return ret;
vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
if (unlikely(ret != 0))
goto err;
ret = ttm_bo_validate(bo, placement, interruptible, false, false);
ttm_bo_unreserve(bo);
err:
ttm_write_unlock(&vmaster->lock);
return ret;
}
/**
* vmw_dmabuf_to_vram_or_gmr - Move a buffer to vram or gmr.
*
* May only be called by the current master since it assumes that the
* master lock is the current master's lock.
* This function takes the master's lock in write mode.
* Flushes and unpins the query bo if @pin == true to avoid failures.
*
* @dev_priv: Driver private.
* @buf: DMA buffer to move.
* @pin: Pin buffer if true.
* @interruptible: Use interruptible wait.
*
* Returns
* -ERESTARTSYS if interrupted by a signal.
*/
int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
bool pin, bool interruptible)
{
struct vmw_master *vmaster = dev_priv->active_master;
struct ttm_buffer_object *bo = &buf->base;
struct ttm_placement *placement;
int ret;
ret = ttm_write_lock(&vmaster->lock, interruptible);
if (unlikely(ret != 0))
return ret;
if (pin)
vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
if (unlikely(ret != 0))
goto err;
/**
* Put BO in VRAM if there is space, otherwise as a GMR.
* If there is no space in VRAM and GMR ids are all used up,
* start evicting GMRs to make room. If the DMA buffer can't be
* used as a GMR, this will return -ENOMEM.
*/
if (pin)
placement = &vmw_vram_gmr_ne_placement;
else
placement = &vmw_vram_gmr_placement;
ret = ttm_bo_validate(bo, placement, interruptible, false, false);
if (likely(ret == 0) || ret == -ERESTARTSYS)
goto err_unreserve;
/**
* If that failed, try VRAM again, this time evicting
* previous contents.
*/
if (pin)
placement = &vmw_vram_ne_placement;
else
placement = &vmw_vram_placement;
ret = ttm_bo_validate(bo, placement, interruptible, false, false);
err_unreserve:
ttm_bo_unreserve(bo);
err:
ttm_write_unlock(&vmaster->lock);
return ret;
}
/**
* vmw_dmabuf_to_vram - Move a buffer to vram.
*
* May only be called by the current master since it assumes that the
* master lock is the current master's lock.
* This function takes the master's lock in write mode.
*
* @dev_priv: Driver private.
* @buf: DMA buffer to move.
* @pin: Pin buffer in vram if true.
* @interruptible: Use interruptible wait.
*
* Returns
* -ERESTARTSYS if interrupted by a signal.
*/
int vmw_dmabuf_to_vram(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
bool pin, bool interruptible)
{
struct ttm_placement *placement;
if (pin)
placement = &vmw_vram_ne_placement;
else
placement = &vmw_vram_placement;
return vmw_dmabuf_to_placement(dev_priv, buf,
placement,
interruptible);
}
/**
* vmw_dmabuf_to_start_of_vram - Move a buffer to start of vram.
*
* May only be called by the current master since it assumes that the
* master lock is the current master's lock.
* This function takes the master's lock in write mode.
* Flushes and unpins the query bo if @pin == true to avoid failures.
*
* @dev_priv: Driver private.
* @buf: DMA buffer to move.
* @pin: Pin buffer in vram if true.
* @interruptible: Use interruptible wait.
*
* Returns
* -ERESTARTSYS if interrupted by a signal.
*/
int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
bool pin, bool interruptible)
{
struct vmw_master *vmaster = dev_priv->active_master;
struct ttm_buffer_object *bo = &buf->base;
struct ttm_placement placement;
int ret = 0;
if (pin)
placement = vmw_vram_ne_placement;
else
placement = vmw_vram_placement;
placement.lpfn = bo->num_pages;
ret = ttm_write_lock(&vmaster->lock, interruptible);
if (unlikely(ret != 0))
return ret;
if (pin)
vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
if (unlikely(ret != 0))
goto err_unlock;
/* Is this buffer already in vram but not at the start of it? */
if (bo->mem.mem_type == TTM_PL_VRAM &&
bo->mem.start < bo->num_pages &&
bo->mem.start > 0)
(void) ttm_bo_validate(bo, &vmw_sys_placement, false,
false, false);
ret = ttm_bo_validate(bo, &placement, interruptible, false, false);
/* For some reason we didn't up at the start of vram */
WARN_ON(ret == 0 && bo->offset != 0);
ttm_bo_unreserve(bo);
err_unlock:
ttm_write_unlock(&vmaster->lock);
return ret;
}
/**
* vmw_dmabuf_upin - Unpin the buffer given buffer, does not move the buffer.
*
* May only be called by the current master since it assumes that the
* master lock is the current master's lock.
* This function takes the master's lock in write mode.
*
* @dev_priv: Driver private.
* @buf: DMA buffer to unpin.
* @interruptible: Use interruptible wait.
*
* Returns
* -ERESTARTSYS if interrupted by a signal.
*/
int vmw_dmabuf_unpin(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
bool interruptible)
{
/*
* We could in theory early out if the buffer is
* unpinned but we need to lock and reserve the buffer
* anyways so we don't gain much by that.
*/
return vmw_dmabuf_to_placement(dev_priv, buf,
&vmw_evictable_placement,
interruptible);
}
/**
* vmw_bo_get_guest_ptr - Get the guest ptr representing the current placement
* of a buffer.
*
* @bo: Pointer to a struct ttm_buffer_object. Must be pinned or reserved.
* @ptr: SVGAGuestPtr returning the result.
*/
void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo,
SVGAGuestPtr *ptr)
{
if (bo->mem.mem_type == TTM_PL_VRAM) {
ptr->gmrId = SVGA_GMR_FRAMEBUFFER;
ptr->offset = bo->offset;
} else {
ptr->gmrId = bo->mem.start;
ptr->offset = 0;
}
}
/**
* vmw_bo_pin - Pin or unpin a buffer object without moving it.
*
* @bo: The buffer object. Must be reserved, and present either in VRAM
* or GMR memory.
* @pin: Whether to pin or unpin.
*
*/
void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin)
{
uint32_t pl_flags;
struct ttm_placement placement;
uint32_t old_mem_type = bo->mem.mem_type;
int ret;
BUG_ON(!atomic_read(&bo->reserved));
BUG_ON(old_mem_type != TTM_PL_VRAM &&
old_mem_type != VMW_PL_FLAG_GMR);
pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED;
if (pin)
pl_flags |= TTM_PL_FLAG_NO_EVICT;
memset(&placement, 0, sizeof(placement));
placement.num_placement = 1;
placement.placement = &pl_flags;
ret = ttm_bo_validate(bo, &placement, false, true, true);
BUG_ON(ret != 0 || bo->mem.mem_type != old_mem_type);
}
......@@ -94,6 +94,12 @@
#define DRM_IOCTL_VMW_FENCE_UNREF \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_FENCE_UNREF, \
struct drm_vmw_fence_arg)
#define DRM_IOCTL_VMW_PRESENT \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT, \
struct drm_vmw_present_arg)
#define DRM_IOCTL_VMW_PRESENT_READBACK \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT_READBACK, \
struct drm_vmw_present_readback_arg)
/**
* The core DRM version of this macro doesn't account for
......@@ -146,6 +152,13 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl,
DRM_AUTH | DRM_UNLOCKED),
/* these allow direct access to the framebuffers mark as master only */
VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl,
DRM_MASTER | DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(VMW_PRESENT_READBACK,
vmw_present_readback_ioctl,
DRM_MASTER | DRM_AUTH | DRM_UNLOCKED),
};
static struct pci_device_id vmw_pci_id_list[] = {
......@@ -200,6 +213,72 @@ static void vmw_print_capabilities(uint32_t capabilities)
DRM_INFO(" Screen Object 2.\n");
}
/**
* vmw_execbuf_prepare_dummy_query - Initialize a query result structure at
* the start of a buffer object.
*
* @dev_priv: The device private structure.
*
* This function will idle the buffer using an uninterruptible wait, then
* map the first page and initialize a pending occlusion query result structure,
* Finally it will unmap the buffer.
*
* TODO: Since we're only mapping a single page, we should optimize the map
* to use kmap_atomic / iomap_atomic.
*/
static void vmw_dummy_query_bo_prepare(struct vmw_private *dev_priv)
{
struct ttm_bo_kmap_obj map;
volatile SVGA3dQueryResult *result;
bool dummy;
int ret;
struct ttm_bo_device *bdev = &dev_priv->bdev;
struct ttm_buffer_object *bo = dev_priv->dummy_query_bo;
ttm_bo_reserve(bo, false, false, false, 0);
spin_lock(&bdev->fence_lock);
ret = ttm_bo_wait(bo, false, false, false, TTM_USAGE_READWRITE);
spin_unlock(&bdev->fence_lock);
if (unlikely(ret != 0))
(void) vmw_fallback_wait(dev_priv, false, true, 0, false,
10*HZ);
ret = ttm_bo_kmap(bo, 0, 1, &map);
if (likely(ret == 0)) {
result = ttm_kmap_obj_virtual(&map, &dummy);
result->totalSize = sizeof(*result);
result->state = SVGA3D_QUERYSTATE_PENDING;
result->result32 = 0xff;
ttm_bo_kunmap(&map);
} else
DRM_ERROR("Dummy query buffer map failed.\n");
ttm_bo_unreserve(bo);
}
/**
* vmw_dummy_query_bo_create - create a bo to hold a dummy query result
*
* @dev_priv: A device private structure.
*
* This function creates a small buffer object that holds the query
* result for dummy queries emitted as query barriers.
* No interruptible waits are done within this function.
*
* Returns an error if bo creation fails.
*/
static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv)
{
return ttm_bo_create(&dev_priv->bdev,
PAGE_SIZE,
ttm_bo_type_device,
&vmw_vram_sys_placement,
0, 0, false, NULL,
&dev_priv->dummy_query_bo);
}
static int vmw_request_device(struct vmw_private *dev_priv)
{
int ret;
......@@ -210,12 +289,29 @@ static int vmw_request_device(struct vmw_private *dev_priv)
return ret;
}
vmw_fence_fifo_up(dev_priv->fman);
ret = vmw_dummy_query_bo_create(dev_priv);
if (unlikely(ret != 0))
goto out_no_query_bo;
vmw_dummy_query_bo_prepare(dev_priv);
return 0;
out_no_query_bo:
vmw_fence_fifo_down(dev_priv->fman);
vmw_fifo_release(dev_priv, &dev_priv->fifo);
return ret;
}
static void vmw_release_device(struct vmw_private *dev_priv)
{
/*
* Previous destructions should've released
* the pinned bo.
*/
BUG_ON(dev_priv->pinned_bo != NULL);
ttm_bo_unref(&dev_priv->dummy_query_bo);
vmw_fence_fifo_down(dev_priv->fman);
vmw_fifo_release(dev_priv, &dev_priv->fifo);
}
......@@ -306,6 +402,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
init_waitqueue_head(&dev_priv->fifo_queue);
dev_priv->fence_queue_waiters = 0;
atomic_set(&dev_priv->fifo_queue_waiters, 0);
INIT_LIST_HEAD(&dev_priv->surface_lru);
dev_priv->used_memory_size = 0;
dev_priv->io_start = pci_resource_start(dev->pdev, 0);
dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
......@@ -326,6 +424,10 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE);
dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE);
dev_priv->fb_max_width = vmw_read(dev_priv, SVGA_REG_MAX_WIDTH);
dev_priv->fb_max_height = vmw_read(dev_priv, SVGA_REG_MAX_HEIGHT);
if (dev_priv->capabilities & SVGA_CAP_GMR) {
dev_priv->max_gmr_descriptors =
vmw_read(dev_priv,
......@@ -338,13 +440,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
vmw_read(dev_priv, SVGA_REG_GMRS_MAX_PAGES);
dev_priv->memory_size =
vmw_read(dev_priv, SVGA_REG_MEMORY_SIZE);
dev_priv->memory_size -= dev_priv->vram_size;
} else {
/*
* An arbitrary limit of 512MiB on surface
* memory. But all HWV8 hardware supports GMR2.
*/
dev_priv->memory_size = 512*1024*1024;
}
dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE);
dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE);
dev_priv->fb_max_width = vmw_read(dev_priv, SVGA_REG_MAX_WIDTH);
dev_priv->fb_max_height = vmw_read(dev_priv, SVGA_REG_MAX_HEIGHT);
mutex_unlock(&dev_priv->hw_mutex);
vmw_print_capabilities(dev_priv->capabilities);
......@@ -358,8 +462,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
if (dev_priv->capabilities & SVGA_CAP_GMR2) {
DRM_INFO("Max number of GMR pages is %u\n",
(unsigned)dev_priv->max_gmr_pages);
DRM_INFO("Max dedicated hypervisor graphics memory is %u\n",
(unsigned)dev_priv->memory_size);
DRM_INFO("Max dedicated hypervisor surface memory is %u kiB\n",
(unsigned)dev_priv->memory_size / 1024);
}
DRM_INFO("VRAM at 0x%08x size is %u kiB\n",
dev_priv->vram_start, dev_priv->vram_size / 1024);
......@@ -451,22 +555,30 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->fman = vmw_fence_manager_init(dev_priv);
if (unlikely(dev_priv->fman == NULL))
goto out_no_fman;
/* Need to start the fifo to check if we can do screen objects */
ret = vmw_3d_resource_inc(dev_priv, true);
if (unlikely(ret != 0))
goto out_no_fifo;
vmw_kms_save_vga(dev_priv);
/* Start kms and overlay systems, needs fifo. */
ret = vmw_kms_init(dev_priv);
if (unlikely(ret != 0))
goto out_no_kms;
vmw_overlay_init(dev_priv);
/* 3D Depends on Screen Objects being used. */
DRM_INFO("Detected %sdevice 3D availability.\n",
vmw_fifo_have_3d(dev_priv) ?
"" : "no ");
/* We might be done with the fifo now */
if (dev_priv->enable_fb) {
ret = vmw_3d_resource_inc(dev_priv, false);
if (unlikely(ret != 0))
goto out_no_fifo;
vmw_kms_save_vga(dev_priv);
vmw_fb_init(dev_priv);
DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ?
"Detected device 3D availability.\n" :
"Detected no device 3D availability.\n");
} else {
DRM_INFO("Delayed 3D detection since we're not "
"running the device in SVGA mode yet.\n");
vmw_kms_restore_vga(dev_priv);
vmw_3d_resource_dec(dev_priv, true);
}
if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
......@@ -483,15 +595,17 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
return 0;
out_no_irq:
if (dev_priv->enable_fb) {
if (dev_priv->enable_fb)
vmw_fb_close(dev_priv);
vmw_overlay_close(dev_priv);
vmw_kms_close(dev_priv);
out_no_kms:
/* We still have a 3D resource reference held */
if (dev_priv->enable_fb) {
vmw_kms_restore_vga(dev_priv);
vmw_3d_resource_dec(dev_priv, false);
}
out_no_fifo:
vmw_overlay_close(dev_priv);
vmw_kms_close(dev_priv);
out_no_kms:
vmw_fence_manager_takedown(dev_priv->fman);
out_no_fman:
if (dev_priv->stealth)
......@@ -771,7 +885,7 @@ static void vmw_master_drop(struct drm_device *dev,
vmw_fp->locked_master = drm_master_get(file_priv->master);
ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
vmw_kms_idle_workqueues(vmaster);
vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
if (unlikely((ret != 0))) {
DRM_ERROR("Unable to lock TTM at VT switch.\n");
......@@ -823,6 +937,7 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
* This empties VRAM and unbinds all GMR bindings.
* Buffer contents is moved to swappable memory.
*/
vmw_execbuf_release_pinned_bo(dev_priv, false, 0);
ttm_bo_swapout_all(&dev_priv->bdev);
break;
......
......@@ -40,9 +40,9 @@
#include "ttm/ttm_module.h"
#include "vmwgfx_fence.h"
#define VMWGFX_DRIVER_DATE "20110901"
#define VMWGFX_DRIVER_DATE "20110927"
#define VMWGFX_DRIVER_MAJOR 2
#define VMWGFX_DRIVER_MINOR 0
#define VMWGFX_DRIVER_MINOR 1
#define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FILE_PAGE_OFFSET 0x00100000
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
......@@ -79,9 +79,11 @@ struct vmw_resource {
int id;
enum ttm_object_type res_type;
bool avail;
void (*remove_from_lists) (struct vmw_resource *res);
void (*hw_destroy) (struct vmw_resource *res);
void (*res_free) (struct vmw_resource *res);
bool on_validate_list;
struct list_head validate_head;
struct list_head query_head; /* Protected by the cmdbuf mutex */
/* TODO is a generic snooper needed? */
#if 0
void (*snoop)(struct vmw_resource *res,
......@@ -97,8 +99,12 @@ struct vmw_cursor_snooper {
uint32_t *image;
};
struct vmw_framebuffer;
struct vmw_surface_offset;
struct vmw_surface {
struct vmw_resource res;
struct list_head lru_head; /* Protected by the resource lock */
uint32_t flags;
uint32_t format;
uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES];
......@@ -109,6 +115,9 @@ struct vmw_surface {
/* TODO so far just a extra pointer */
struct vmw_cursor_snooper snooper;
struct ttm_buffer_object *backup;
struct vmw_surface_offset *offsets;
uint32_t backup_size;
};
struct vmw_marker_queue {
......@@ -139,6 +148,8 @@ struct vmw_sw_context{
struct ida bo_list;
uint32_t last_cid;
bool cid_valid;
bool kernel; /**< is the called made from the kernel */
struct vmw_resource *cur_ctx;
uint32_t last_sid;
uint32_t sid_translation;
bool sid_valid;
......@@ -150,8 +161,12 @@ struct vmw_sw_context{
uint32_t cur_val_buf;
uint32_t *cmd_bounce;
uint32_t cmd_bounce_size;
struct vmw_resource *resources[VMWGFX_MAX_VALIDATIONS];
uint32_t num_ref_resources;
struct list_head resource_list;
uint32_t fence_flags;
struct list_head query_list;
struct ttm_buffer_object *cur_query_bo;
uint32_t cur_query_cid;
bool query_cid_valid;
};
struct vmw_legacy_display;
......@@ -216,6 +231,7 @@ struct vmw_private {
void *fb_info;
struct vmw_legacy_display *ldu_priv;
struct vmw_screen_object_display *sou_priv;
struct vmw_overlay *overlay_priv;
/*
......@@ -290,6 +306,26 @@ struct vmw_private {
struct mutex release_mutex;
uint32_t num_3d_resources;
/*
* Query processing. These members
* are protected by the cmdbuf mutex.
*/
struct ttm_buffer_object *dummy_query_bo;
struct ttm_buffer_object *pinned_bo;
uint32_t query_cid;
bool dummy_query_bo_pinned;
/*
* Surface swapping. The "surface_lru" list is protected by the
* resource lock in order to be able to destroy a surface and take
* it off the lru atomically. "used_memory_size" is currently
* protected by the cmdbuf mutex for simplicity.
*/
struct list_head surface_lru;
uint32_t used_memory_size;
};
static inline struct vmw_private *vmw_priv(struct drm_device *dev)
......@@ -369,6 +405,8 @@ extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
extern int vmw_surface_check(struct vmw_private *dev_priv,
struct ttm_object_file *tfile,
uint32_t handle, int *id);
extern int vmw_surface_validate(struct vmw_private *dev_priv,
struct vmw_surface *srf);
extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo);
extern int vmw_dmabuf_init(struct vmw_private *dev_priv,
struct vmw_dma_buffer *vmw_bo,
......@@ -384,10 +422,6 @@ extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
uint32_t id, struct vmw_dma_buffer **out);
extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo);
extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo);
extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
......@@ -396,7 +430,30 @@ extern int vmw_user_stream_lookup(struct vmw_private *dev_priv,
struct ttm_object_file *tfile,
uint32_t *inout_id,
struct vmw_resource **out);
extern void vmw_resource_unreserve(struct list_head *list);
/**
* DMA buffer helper routines - vmwgfx_dmabuf.c
*/
extern int vmw_dmabuf_to_placement(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo,
struct ttm_placement *placement,
bool interruptible);
extern int vmw_dmabuf_to_vram(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
bool pin, bool interruptible);
extern int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
bool pin, bool interruptible);
extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo,
bool pin, bool interruptible);
extern int vmw_dmabuf_unpin(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo,
bool interruptible);
extern void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *buf,
SVGAGuestPtr *ptr);
extern void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin);
/**
* Misc Ioctl functionality - vmwgfx_ioctl.c
......@@ -406,6 +463,10 @@ extern int vmw_getparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_present_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/**
* Fifo utilities - vmwgfx_fifo.c
......@@ -422,6 +483,8 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason);
extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv);
extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv);
extern int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv,
uint32_t cid);
/**
* TTM glue - vmwgfx_ttm_glue.c
......@@ -439,7 +502,10 @@ extern struct ttm_placement vmw_vram_placement;
extern struct ttm_placement vmw_vram_ne_placement;
extern struct ttm_placement vmw_vram_sys_placement;
extern struct ttm_placement vmw_vram_gmr_placement;
extern struct ttm_placement vmw_vram_gmr_ne_placement;
extern struct ttm_placement vmw_sys_placement;
extern struct ttm_placement vmw_evictable_placement;
extern struct ttm_placement vmw_srf_placement;
extern struct ttm_bo_driver vmw_bo_driver;
extern int vmw_dma_quiescent(struct drm_device *dev);
......@@ -449,6 +515,24 @@ extern int vmw_dma_quiescent(struct drm_device *dev);
extern int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_execbuf_process(struct drm_file *file_priv,
struct vmw_private *dev_priv,
void __user *user_commands,
void *kernel_commands,
uint32_t command_size,
uint64_t throttle_us,
struct drm_vmw_fence_rep __user
*user_fence_rep);
extern void
vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
bool only_on_cid_match, uint32_t cid);
extern int vmw_execbuf_fence_commands(struct drm_file *file_priv,
struct vmw_private *dev_priv,
struct vmw_fence_obj **p_fence,
uint32_t *p_handle);
/**
* IRQs and wating - vmwgfx_irq.c
......@@ -520,6 +604,19 @@ bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
uint32_t pitch,
uint32_t height);
u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc);
int vmw_kms_present(struct vmw_private *dev_priv,
struct drm_file *file_priv,
struct vmw_framebuffer *vfb,
struct vmw_surface *surface,
uint32_t sid, int32_t destX, int32_t destY,
struct drm_vmw_rect *clips,
uint32_t num_clips);
int vmw_kms_readback(struct vmw_private *dev_priv,
struct drm_file *file_priv,
struct vmw_framebuffer *vfb,
struct drm_vmw_fence_rep __user *user_fence_rep,
struct drm_vmw_rect *clips,
uint32_t num_clips);
/**
* Overlay control - vmwgfx_overlay.c
......
This diff is collapsed.
......@@ -592,58 +592,6 @@ int vmw_fb_close(struct vmw_private *vmw_priv)
return 0;
}
int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *vmw_bo)
{
struct ttm_buffer_object *bo = &vmw_bo->base;
int ret = 0;
ret = ttm_bo_reserve(bo, false, false, false, 0);
if (unlikely(ret != 0))
return ret;
ret = ttm_bo_validate(bo, &vmw_sys_placement, false, false, false);
ttm_bo_unreserve(bo);
return ret;
}
int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *vmw_bo)
{
struct ttm_buffer_object *bo = &vmw_bo->base;
struct ttm_placement ne_placement = vmw_vram_ne_placement;
int ret = 0;
ne_placement.lpfn = bo->num_pages;
/* interuptable? */
ret = ttm_write_lock(&vmw_priv->active_master->lock, false);
if (unlikely(ret != 0))
return ret;
ret = ttm_bo_reserve(bo, false, false, false, 0);
if (unlikely(ret != 0))
goto err_unlock;
if (bo->mem.mem_type == TTM_PL_VRAM &&
bo->mem.start < bo->num_pages &&
bo->mem.start > 0)
(void) ttm_bo_validate(bo, &vmw_sys_placement, false,
false, false);
ret = ttm_bo_validate(bo, &ne_placement, false, false, false);
/* Could probably bug on */
WARN_ON(bo->offset != 0);
ttm_bo_unreserve(bo);
err_unlock:
ttm_write_unlock(&vmw_priv->active_master->lock);
return ret;
}
int vmw_fb_off(struct vmw_private *vmw_priv)
{
struct fb_info *info;
......@@ -665,7 +613,7 @@ int vmw_fb_off(struct vmw_private *vmw_priv)
par->bo_ptr = NULL;
ttm_bo_kunmap(&par->map);
vmw_dmabuf_from_vram(vmw_priv, par->vmw_bo);
vmw_dmabuf_unpin(vmw_priv, par->vmw_bo, false);
return 0;
}
......@@ -691,7 +639,7 @@ int vmw_fb_on(struct vmw_private *vmw_priv)
/* Make sure that all overlays are stoped when we take over */
vmw_overlay_stop_all(vmw_priv);
ret = vmw_dmabuf_to_start_of_vram(vmw_priv, par->vmw_bo);
ret = vmw_dmabuf_to_start_of_vram(vmw_priv, par->vmw_bo, true, false);
if (unlikely(ret != 0)) {
DRM_ERROR("could not move buffer to start of VRAM\n");
goto err_no_buffer;
......
......@@ -177,6 +177,9 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
struct vmw_fence_obj *vmw_fence_obj_reference(struct vmw_fence_obj *fence)
{
if (unlikely(fence == NULL))
return NULL;
kref_get(&fence->kref);
return fence;
}
......@@ -191,8 +194,12 @@ struct vmw_fence_obj *vmw_fence_obj_reference(struct vmw_fence_obj *fence)
void vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p)
{
struct vmw_fence_obj *fence = *fence_p;
struct vmw_fence_manager *fman = fence->fman;
struct vmw_fence_manager *fman;
if (unlikely(fence == NULL))
return;
fman = fence->fman;
*fence_p = NULL;
spin_lock_irq(&fman->lock);
BUG_ON(atomic_read(&fence->kref.refcount) == 0);
......
......@@ -45,7 +45,11 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
if (hwversion == 0)
return false;
if (hwversion < SVGA3D_HWVERSION_WS65_B1)
if (hwversion < SVGA3D_HWVERSION_WS8_B1)
return false;
/* Non-Screen Object path does not support surfaces */
if (!dev_priv->sou_priv)
return false;
return true;
......@@ -277,6 +281,16 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
return ret;
}
/**
* Reserve @bytes number of bytes in the fifo.
*
* This function will return NULL (error) on two conditions:
* If it timeouts waiting for fifo space, or if @bytes is larger than the
* available fifo space.
*
* Returns:
* Pointer to the fifo, or null on error (possible hardware hang).
*/
void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes)
{
struct vmw_fifo_state *fifo_state = &dev_priv->fifo;
......@@ -491,3 +505,60 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno)
out_err:
return ret;
}
/**
* vmw_fifo_emit_dummy_query - emits a dummy query to the fifo.
*
* @dev_priv: The device private structure.
* @cid: The hardware context id used for the query.
*
* This function is used to emit a dummy occlusion query with
* no primitives rendered between query begin and query end.
* It's used to provide a query barrier, in order to know that when
* this query is finished, all preceding queries are also finished.
*
* A Query results structure should have been initialized at the start
* of the dev_priv->dummy_query_bo buffer object. And that buffer object
* must also be either reserved or pinned when this function is called.
*
* Returns -ENOMEM on failure to reserve fifo space.
*/
int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv,
uint32_t cid)
{
/*
* A query wait without a preceding query end will
* actually finish all queries for this cid
* without writing to the query result structure.
*/
struct ttm_buffer_object *bo = dev_priv->dummy_query_bo;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdWaitForQuery body;
} *cmd;
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
if (unlikely(cmd == NULL)) {
DRM_ERROR("Out of fifo space for dummy query.\n");
return -ENOMEM;
}
cmd->header.id = SVGA_3D_CMD_WAIT_FOR_QUERY;
cmd->header.size = sizeof(cmd->body);
cmd->body.cid = cid;
cmd->body.type = SVGA3D_QUERYTYPE_OCCLUSION;
if (bo->mem.mem_type == TTM_PL_VRAM) {
cmd->body.guestResult.gmrId = SVGA_GMR_FRAMEBUFFER;
cmd->body.guestResult.offset = bo->offset;
} else {
cmd->body.guestResult.gmrId = bo->mem.start;
cmd->body.guestResult.offset = 0;
}
vmw_fifo_commit(dev_priv, sizeof(*cmd));
return 0;
}
......@@ -27,6 +27,7 @@
#include "vmwgfx_drv.h"
#include "vmwgfx_drm.h"
#include "vmwgfx_kms.h"
int vmw_getparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
......@@ -110,3 +111,174 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
return ret;
}
int vmw_present_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
struct vmw_private *dev_priv = vmw_priv(dev);
struct drm_vmw_present_arg *arg =
(struct drm_vmw_present_arg *)data;
struct vmw_surface *surface;
struct vmw_master *vmaster = vmw_master(file_priv->master);
struct drm_vmw_rect __user *clips_ptr;
struct drm_vmw_rect *clips = NULL;
struct drm_mode_object *obj;
struct vmw_framebuffer *vfb;
uint32_t num_clips;
int ret;
num_clips = arg->num_clips;
clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
if (unlikely(num_clips == 0))
return 0;
if (clips_ptr == NULL) {
DRM_ERROR("Variable clips_ptr must be specified.\n");
ret = -EINVAL;
goto out_clips;
}
clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
if (clips == NULL) {
DRM_ERROR("Failed to allocate clip rect list.\n");
ret = -ENOMEM;
goto out_clips;
}
ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
if (ret) {
DRM_ERROR("Failed to copy clip rects from userspace.\n");
goto out_no_copy;
}
ret = mutex_lock_interruptible(&dev->mode_config.mutex);
if (unlikely(ret != 0)) {
ret = -ERESTARTSYS;
goto out_no_mode_mutex;
}
obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
if (!obj) {
DRM_ERROR("Invalid framebuffer id.\n");
ret = -EINVAL;
goto out_no_fb;
}
vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
if (!vfb->dmabuf) {
DRM_ERROR("Framebuffer not dmabuf backed.\n");
ret = -EINVAL;
goto out_no_fb;
}
ret = ttm_read_lock(&vmaster->lock, true);
if (unlikely(ret != 0))
goto out_no_ttm_lock;
ret = vmw_user_surface_lookup_handle(dev_priv, tfile, arg->sid,
&surface);
if (ret)
goto out_no_surface;
ret = vmw_kms_present(dev_priv, file_priv,
vfb, surface, arg->sid,
arg->dest_x, arg->dest_y,
clips, num_clips);
/* vmw_user_surface_lookup takes one ref so does new_fb */
vmw_surface_unreference(&surface);
out_no_surface:
ttm_read_unlock(&vmaster->lock);
out_no_ttm_lock:
out_no_fb:
mutex_unlock(&dev->mode_config.mutex);
out_no_mode_mutex:
out_no_copy:
kfree(clips);
out_clips:
return ret;
}
int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct drm_vmw_present_readback_arg *arg =
(struct drm_vmw_present_readback_arg *)data;
struct drm_vmw_fence_rep __user *user_fence_rep =
(struct drm_vmw_fence_rep __user *)
(unsigned long)arg->fence_rep;
struct vmw_master *vmaster = vmw_master(file_priv->master);
struct drm_vmw_rect __user *clips_ptr;
struct drm_vmw_rect *clips = NULL;
struct drm_mode_object *obj;
struct vmw_framebuffer *vfb;
uint32_t num_clips;
int ret;
num_clips = arg->num_clips;
clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr;
if (unlikely(num_clips == 0))
return 0;
if (clips_ptr == NULL) {
DRM_ERROR("Argument clips_ptr must be specified.\n");
ret = -EINVAL;
goto out_clips;
}
clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
if (clips == NULL) {
DRM_ERROR("Failed to allocate clip rect list.\n");
ret = -ENOMEM;
goto out_clips;
}
ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips));
if (ret) {
DRM_ERROR("Failed to copy clip rects from userspace.\n");
goto out_no_copy;
}
ret = mutex_lock_interruptible(&dev->mode_config.mutex);
if (unlikely(ret != 0)) {
ret = -ERESTARTSYS;
goto out_no_mode_mutex;
}
obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
if (!obj) {
DRM_ERROR("Invalid framebuffer id.\n");
ret = -EINVAL;
goto out_no_fb;
}
vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
if (!vfb->dmabuf) {
DRM_ERROR("Framebuffer not dmabuf backed.\n");
ret = -EINVAL;
goto out_no_fb;
}
ret = ttm_read_lock(&vmaster->lock, true);
if (unlikely(ret != 0))
goto out_no_ttm_lock;
ret = vmw_kms_readback(dev_priv, file_priv,
vfb, user_fence_rep,
clips, num_clips);
ttm_read_unlock(&vmaster->lock);
out_no_ttm_lock:
out_no_fb:
mutex_unlock(&dev->mode_config.mutex);
out_no_mode_mutex:
out_no_copy:
kfree(clips);
out_clips:
return ret;
}
This diff is collapsed.
......@@ -31,6 +31,8 @@
#include "drmP.h"
#include "vmwgfx_drv.h"
#define VMWGFX_NUM_DISPLAY_UNITS 8
#define vmw_framebuffer_to_vfb(x) \
container_of(x, struct vmw_framebuffer, base)
......@@ -45,6 +47,9 @@ struct vmw_framebuffer {
struct drm_framebuffer base;
int (*pin)(struct vmw_framebuffer *fb);
int (*unpin)(struct vmw_framebuffer *fb);
bool dmabuf;
struct ttm_base_object *user_obj;
uint32_t user_handle;
};
......@@ -83,22 +88,59 @@ struct vmw_display_unit {
int hotspot_y;
unsigned unit;
/*
* Prefered mode tracking.
*/
unsigned pref_width;
unsigned pref_height;
bool pref_active;
struct drm_display_mode *pref_mode;
};
#define vmw_crtc_to_du(x) \
container_of(x, struct vmw_display_unit, crtc)
#define vmw_connector_to_du(x) \
container_of(x, struct vmw_display_unit, connector)
/*
* Shared display unit functions - vmwgfx_kms.c
*/
void vmw_display_unit_cleanup(struct vmw_display_unit *du);
void vmw_du_crtc_save(struct drm_crtc *crtc);
void vmw_du_crtc_restore(struct drm_crtc *crtc);
void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
u16 *r, u16 *g, u16 *b,
uint32_t start, uint32_t size);
int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
uint32_t handle, uint32_t width, uint32_t height);
int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
void vmw_du_connector_dpms(struct drm_connector *connector, int mode);
void vmw_du_connector_save(struct drm_connector *connector);
void vmw_du_connector_restore(struct drm_connector *connector);
enum drm_connector_status
vmw_du_connector_detect(struct drm_connector *connector, bool force);
int vmw_du_connector_fill_modes(struct drm_connector *connector,
uint32_t max_width, uint32_t max_height);
int vmw_du_connector_set_property(struct drm_connector *connector,
struct drm_property *property,
uint64_t val);
int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
struct drm_vmw_rect *rects);
/*
* Legacy display unit functions - vmwgfx_ldu.c
*/
int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv);
int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv);
int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num,
/*
* Screen Objects display functions - vmwgfx_scrn.c
*/
int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv);
int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv);
int vmw_kms_sou_update_layout(struct vmw_private *dev_priv, unsigned num,
struct drm_vmw_rect *rects);
#endif
This diff is collapsed.
......@@ -86,48 +86,6 @@ static inline void fill_flush(struct vmw_escape_video_flush *cmd,
cmd->flush.streamId = stream_id;
}
/**
* Pin or unpin a buffer in vram.
*
* @dev_priv: Driver private.
* @buf: DMA buffer to pin or unpin.
* @pin: Pin buffer in vram if true.
* @interruptible: Use interruptible wait.
*
* Takes the current masters ttm lock in read.
*
* Returns
* -ERESTARTSYS if interrupted by a signal.
*/
static int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
bool pin, bool interruptible)
{
struct ttm_buffer_object *bo = &buf->base;
struct ttm_placement *overlay_placement = &vmw_vram_placement;
int ret;
ret = ttm_read_lock(&dev_priv->active_master->lock, interruptible);
if (unlikely(ret != 0))
return ret;
ret = ttm_bo_reserve(bo, interruptible, false, false, 0);
if (unlikely(ret != 0))
goto err;
if (pin)
overlay_placement = &vmw_vram_ne_placement;
ret = ttm_bo_validate(bo, overlay_placement, interruptible, false, false);
ttm_bo_unreserve(bo);
err:
ttm_read_unlock(&dev_priv->active_master->lock);
return ret;
}
/**
* Send put command to hw.
*
......@@ -139,68 +97,80 @@ static int vmw_overlay_send_put(struct vmw_private *dev_priv,
struct drm_vmw_control_stream_arg *arg,
bool interruptible)
{
struct vmw_escape_video_flush *flush;
size_t fifo_size;
bool have_so = dev_priv->sou_priv ? true : false;
int i, num_items;
SVGAGuestPtr ptr;
struct {
struct vmw_escape_header escape;
struct {
struct {
uint32_t cmdType;
uint32_t streamId;
} header;
struct {
uint32_t registerId;
uint32_t value;
} items[SVGA_VIDEO_PITCH_3 + 1];
} body;
struct vmw_escape_video_flush flush;
uint32_t cmdType;
uint32_t streamId;
} header;
} *cmds;
uint32_t offset;
int i, ret;
struct {
uint32_t registerId;
uint32_t value;
} *items;
for (;;) {
cmds = vmw_fifo_reserve(dev_priv, sizeof(*cmds));
if (cmds)
break;
/* defines are a index needs + 1 */
if (have_so)
num_items = SVGA_VIDEO_DST_SCREEN_ID + 1;
else
num_items = SVGA_VIDEO_PITCH_3 + 1;
ret = vmw_fallback_wait(dev_priv, false, true, 0,
interruptible, 3*HZ);
if (interruptible && ret == -ERESTARTSYS)
return ret;
else
BUG_ON(ret != 0);
fifo_size = sizeof(*cmds) + sizeof(*flush) + sizeof(*items) * num_items;
cmds = vmw_fifo_reserve(dev_priv, fifo_size);
/* hardware has hung, can't do anything here */
if (!cmds)
return -ENOMEM;
items = (typeof(items))&cmds[1];
flush = (struct vmw_escape_video_flush *)&items[num_items];
/* the size is header + number of items */
fill_escape(&cmds->escape, sizeof(*items) * (num_items + 1));
cmds->header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
cmds->header.streamId = arg->stream_id;
/* the IDs are neatly numbered */
for (i = 0; i < num_items; i++)
items[i].registerId = i;
vmw_bo_get_guest_ptr(&buf->base, &ptr);
ptr.offset += arg->offset;
items[SVGA_VIDEO_ENABLED].value = true;
items[SVGA_VIDEO_FLAGS].value = arg->flags;
items[SVGA_VIDEO_DATA_OFFSET].value = ptr.offset;
items[SVGA_VIDEO_FORMAT].value = arg->format;
items[SVGA_VIDEO_COLORKEY].value = arg->color_key;
items[SVGA_VIDEO_SIZE].value = arg->size;
items[SVGA_VIDEO_WIDTH].value = arg->width;
items[SVGA_VIDEO_HEIGHT].value = arg->height;
items[SVGA_VIDEO_SRC_X].value = arg->src.x;
items[SVGA_VIDEO_SRC_Y].value = arg->src.y;
items[SVGA_VIDEO_SRC_WIDTH].value = arg->src.w;
items[SVGA_VIDEO_SRC_HEIGHT].value = arg->src.h;
items[SVGA_VIDEO_DST_X].value = arg->dst.x;
items[SVGA_VIDEO_DST_Y].value = arg->dst.y;
items[SVGA_VIDEO_DST_WIDTH].value = arg->dst.w;
items[SVGA_VIDEO_DST_HEIGHT].value = arg->dst.h;
items[SVGA_VIDEO_PITCH_1].value = arg->pitch[0];
items[SVGA_VIDEO_PITCH_2].value = arg->pitch[1];
items[SVGA_VIDEO_PITCH_3].value = arg->pitch[2];
if (have_so) {
items[SVGA_VIDEO_DATA_GMRID].value = ptr.gmrId;
items[SVGA_VIDEO_DST_SCREEN_ID].value = SVGA_ID_INVALID;
}
fill_escape(&cmds->escape, sizeof(cmds->body));
cmds->body.header.cmdType = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
cmds->body.header.streamId = arg->stream_id;
for (i = 0; i <= SVGA_VIDEO_PITCH_3; i++)
cmds->body.items[i].registerId = i;
offset = buf->base.offset + arg->offset;
cmds->body.items[SVGA_VIDEO_ENABLED].value = true;
cmds->body.items[SVGA_VIDEO_FLAGS].value = arg->flags;
cmds->body.items[SVGA_VIDEO_DATA_OFFSET].value = offset;
cmds->body.items[SVGA_VIDEO_FORMAT].value = arg->format;
cmds->body.items[SVGA_VIDEO_COLORKEY].value = arg->color_key;
cmds->body.items[SVGA_VIDEO_SIZE].value = arg->size;
cmds->body.items[SVGA_VIDEO_WIDTH].value = arg->width;
cmds->body.items[SVGA_VIDEO_HEIGHT].value = arg->height;
cmds->body.items[SVGA_VIDEO_SRC_X].value = arg->src.x;
cmds->body.items[SVGA_VIDEO_SRC_Y].value = arg->src.y;
cmds->body.items[SVGA_VIDEO_SRC_WIDTH].value = arg->src.w;
cmds->body.items[SVGA_VIDEO_SRC_HEIGHT].value = arg->src.h;
cmds->body.items[SVGA_VIDEO_DST_X].value = arg->dst.x;
cmds->body.items[SVGA_VIDEO_DST_Y].value = arg->dst.y;
cmds->body.items[SVGA_VIDEO_DST_WIDTH].value = arg->dst.w;
cmds->body.items[SVGA_VIDEO_DST_HEIGHT].value = arg->dst.h;
cmds->body.items[SVGA_VIDEO_PITCH_1].value = arg->pitch[0];
cmds->body.items[SVGA_VIDEO_PITCH_2].value = arg->pitch[1];
cmds->body.items[SVGA_VIDEO_PITCH_3].value = arg->pitch[2];
fill_flush(&cmds->flush, arg->stream_id);
fill_flush(flush, arg->stream_id);
vmw_fifo_commit(dev_priv, sizeof(*cmds));
vmw_fifo_commit(dev_priv, fifo_size);
return 0;
}
......@@ -247,6 +217,25 @@ static int vmw_overlay_send_stop(struct vmw_private *dev_priv,
return 0;
}
/**
* Move a buffer to vram or gmr if @pin is set, else unpin the buffer.
*
* With the introduction of screen objects buffers could now be
* used with GMRs instead of being locked to vram.
*/
static int vmw_overlay_move_buffer(struct vmw_private *dev_priv,
struct vmw_dma_buffer *buf,
bool pin, bool inter)
{
if (!pin)
return vmw_dmabuf_unpin(dev_priv, buf, inter);
if (!dev_priv->sou_priv)
return vmw_dmabuf_to_vram(dev_priv, buf, true, inter);
return vmw_dmabuf_to_vram_or_gmr(dev_priv, buf, true, inter);
}
/**
* Stop or pause a stream.
*
......@@ -279,8 +268,8 @@ static int vmw_overlay_stop(struct vmw_private *dev_priv,
return ret;
/* We just remove the NO_EVICT flag so no -ENOMEM */
ret = vmw_dmabuf_pin_in_vram(dev_priv, stream->buf, false,
interruptible);
ret = vmw_overlay_move_buffer(dev_priv, stream->buf, false,
interruptible);
if (interruptible && ret == -ERESTARTSYS)
return ret;
else
......@@ -342,7 +331,7 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv,
/* We don't start the old stream if we are interrupted.
* Might return -ENOMEM if it can't fit the buffer in vram.
*/
ret = vmw_dmabuf_pin_in_vram(dev_priv, buf, true, interruptible);
ret = vmw_overlay_move_buffer(dev_priv, buf, true, interruptible);
if (ret)
return ret;
......@@ -351,7 +340,8 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv,
/* This one needs to happen no matter what. We only remove
* the NO_EVICT flag so this is safe from -ENOMEM.
*/
BUG_ON(vmw_dmabuf_pin_in_vram(dev_priv, buf, false, false) != 0);
BUG_ON(vmw_overlay_move_buffer(dev_priv, buf, false, false)
!= 0);
return ret;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -52,6 +52,8 @@
#define DRM_VMW_FENCE_SIGNALED 15
#define DRM_VMW_FENCE_UNREF 16
#define DRM_VMW_FENCE_EVENT 17
#define DRM_VMW_PRESENT 18
#define DRM_VMW_PRESENT_READBACK 19
/*************************************************************************/
......@@ -681,5 +683,66 @@ struct drm_vmw_fence_arg {
};
/*************************************************************************/
/**
* DRM_VMW_PRESENT
*
* Executes an SVGA present on a given fb for a given surface. The surface
* is placed on the framebuffer. Cliprects are given relative to the given
* point (the point disignated by dest_{x|y}).
*
*/
/**
* struct drm_vmw_present_arg
* @fb_id: framebuffer id to present / read back from.
* @sid: Surface id to present from.
* @dest_x: X placement coordinate for surface.
* @dest_y: Y placement coordinate for surface.
* @clips_ptr: Pointer to an array of clip rects cast to an uint64_t.
* @num_clips: Number of cliprects given relative to the framebuffer origin,
* in the same coordinate space as the frame buffer.
* @pad64: Unused 64-bit padding.
*
* Input argument to the DRM_VMW_PRESENT ioctl.
*/
struct drm_vmw_present_arg {
uint32_t fb_id;
uint32_t sid;
int32_t dest_x;
int32_t dest_y;
uint64_t clips_ptr;
uint32_t num_clips;
uint32_t pad64;
};
/*************************************************************************/
/**
* DRM_VMW_PRESENT_READBACK
*
* Executes an SVGA present readback from a given fb to the dma buffer
* currently bound as the fb. If there is no dma buffer bound to the fb,
* an error will be returned.
*
*/
/**
* struct drm_vmw_present_arg
* @fb_id: fb_id to present / read back from.
* @num_clips: Number of cliprects.
* @clips_ptr: Pointer to an array of clip rects cast to an uint64_t.
* @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an uint64_t.
* If this member is NULL, then the ioctl should not return a fence.
*/
struct drm_vmw_present_readback_arg {
uint32_t fb_id;
uint32_t num_clips;
uint64_t clips_ptr;
uint64_t fence_rep;
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment