diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 122 | 
1 files changed, 109 insertions, 13 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index c509d40c489..37881ecf5d7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -29,12 +29,18 @@  #include <drm/vmwgfx_drm.h>  #include "vmwgfx_kms.h" +struct svga_3d_compat_cap { +	SVGA3dCapsRecordHeader header; +	SVGA3dCapPair pairs[SVGA3D_DEVCAP_MAX]; +}; +  int vmw_getparam_ioctl(struct drm_device *dev, void *data,  		       struct drm_file *file_priv)  {  	struct vmw_private *dev_priv = vmw_priv(dev);  	struct drm_vmw_getparam_arg *param =  	    (struct drm_vmw_getparam_arg *)data; +	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);  	switch (param->param) {  	case DRM_VMW_PARAM_NUM_STREAMS: @@ -53,13 +59,18 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,  		param->value = dev_priv->fifo.capabilities;  		break;  	case DRM_VMW_PARAM_MAX_FB_SIZE: -		param->value = dev_priv->vram_size; +		param->value = dev_priv->prim_bb_mem;  		break;  	case DRM_VMW_PARAM_FIFO_HW_VERSION:  	{  		__le32 __iomem *fifo_mem = dev_priv->mmio_virt;  		const struct vmw_fifo_state *fifo = &dev_priv->fifo; +		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) { +			param->value = SVGA3D_HWVERSION_WS8_B1; +			break; +		} +  		param->value =  			ioread32(fifo_mem +  				 ((fifo->capabilities & @@ -68,6 +79,32 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,  				  SVGA_FIFO_3D_HWVERSION));  		break;  	} +	case DRM_VMW_PARAM_MAX_SURF_MEMORY: +		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) && +		    !vmw_fp->gb_aware) +			param->value = dev_priv->max_mob_pages * PAGE_SIZE / 2; +		else +			param->value = dev_priv->memory_size; +		break; +	case DRM_VMW_PARAM_3D_CAPS_SIZE: +		if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS) && +		    vmw_fp->gb_aware) +			param->value = SVGA3D_DEVCAP_MAX * sizeof(uint32_t); +		else if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) +			param->value = sizeof(struct svga_3d_compat_cap) + +				sizeof(uint32_t); +		else +			param->value = (SVGA_FIFO_3D_CAPS_LAST - +					SVGA_FIFO_3D_CAPS + 1) * +				sizeof(uint32_t); +		break; +	case DRM_VMW_PARAM_MAX_MOB_MEMORY: +		vmw_fp->gb_aware = true; +		param->value = dev_priv->max_mob_pages * PAGE_SIZE; +		break; +	case DRM_VMW_PARAM_MAX_MOB_SIZE: +		param->value = dev_priv->max_mob_size; +		break;  	default:  		DRM_ERROR("Illegal vmwgfx get param request: %d\n",  			  param->param); @@ -77,6 +114,38 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,  	return 0;  } +static int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce, +			       size_t size) +{ +	struct svga_3d_compat_cap *compat_cap = +		(struct svga_3d_compat_cap *) bounce; +	unsigned int i; +	size_t pair_offset = offsetof(struct svga_3d_compat_cap, pairs); +	unsigned int max_size; + +	if (size < pair_offset) +		return -EINVAL; + +	max_size = (size - pair_offset) / sizeof(SVGA3dCapPair); + +	if (max_size > SVGA3D_DEVCAP_MAX) +		max_size = SVGA3D_DEVCAP_MAX; + +	compat_cap->header.length = +		(pair_offset + max_size * sizeof(SVGA3dCapPair)) / sizeof(u32); +	compat_cap->header.type = SVGA3DCAPS_RECORD_DEVCAPS; + +	mutex_lock(&dev_priv->hw_mutex); +	for (i = 0; i < max_size; ++i) { +		vmw_write(dev_priv, SVGA_REG_DEV_CAP, i); +		compat_cap->pairs[i][0] = i; +		compat_cap->pairs[i][1] = vmw_read(dev_priv, SVGA_REG_DEV_CAP); +	} +	mutex_unlock(&dev_priv->hw_mutex); + +	return 0; +} +  int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,  			 struct drm_file *file_priv) @@ -89,29 +158,58 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,  	void __user *buffer = (void __user *)((unsigned long)(arg->buffer));  	void *bounce;  	int ret; +	bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS); +	struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);  	if (unlikely(arg->pad64 != 0)) {  		DRM_ERROR("Illegal GET_3D_CAP argument.\n");  		return -EINVAL;  	} -	size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) << 2; +	if (gb_objects && vmw_fp->gb_aware) +		size = SVGA3D_DEVCAP_MAX * sizeof(uint32_t); +	else if (gb_objects) +		size = sizeof(struct svga_3d_compat_cap) + sizeof(uint32_t); +	else +		size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) * +			sizeof(uint32_t);  	if (arg->max_size < size)  		size = arg->max_size; -	bounce = vmalloc(size); +	bounce = vzalloc(size);  	if (unlikely(bounce == NULL)) {  		DRM_ERROR("Failed to allocate bounce buffer for 3D caps.\n");  		return -ENOMEM;  	} -	fifo_mem = dev_priv->mmio_virt; -	memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size); +	if (gb_objects && vmw_fp->gb_aware) { +		int i, num; +		uint32_t *bounce32 = (uint32_t *) bounce; + +		num = size / sizeof(uint32_t); +		if (num > SVGA3D_DEVCAP_MAX) +			num = SVGA3D_DEVCAP_MAX; + +		mutex_lock(&dev_priv->hw_mutex); +		for (i = 0; i < num; ++i) { +			vmw_write(dev_priv, SVGA_REG_DEV_CAP, i); +			*bounce32++ = vmw_read(dev_priv, SVGA_REG_DEV_CAP); +		} +		mutex_unlock(&dev_priv->hw_mutex); +	} else if (gb_objects) { +		ret = vmw_fill_compat_cap(dev_priv, bounce, size); +		if (unlikely(ret != 0)) +			goto out_err; +	} else { +		fifo_mem = dev_priv->mmio_virt; +		memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size); +	}  	ret = copy_to_user(buffer, bounce, size);  	if (ret)  		ret = -EFAULT; +out_err:  	vfree(bounce);  	if (unlikely(ret != 0)) @@ -128,7 +226,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,  	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_framebuffer *fb; @@ -168,12 +265,12 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,  	fb = drm_framebuffer_lookup(dev, arg->fb_id);  	if (!fb) {  		DRM_ERROR("Invalid framebuffer id.\n"); -		ret = -EINVAL; +		ret = -ENOENT;  		goto out_no_fb;  	}  	vfb = vmw_framebuffer_to_vfb(fb); -	ret = ttm_read_lock(&vmaster->lock, true); +	ret = ttm_read_lock(&dev_priv->reservation_sem, true);  	if (unlikely(ret != 0))  		goto out_no_ttm_lock; @@ -193,7 +290,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,  	vmw_surface_unreference(&surface);  out_no_surface: -	ttm_read_unlock(&vmaster->lock); +	ttm_read_unlock(&dev_priv->reservation_sem);  out_no_ttm_lock:  	drm_framebuffer_unreference(fb);  out_no_fb: @@ -213,7 +310,6 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *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_framebuffer *fb; @@ -252,7 +348,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,  	fb = drm_framebuffer_lookup(dev, arg->fb_id);  	if (!fb) {  		DRM_ERROR("Invalid framebuffer id.\n"); -		ret = -EINVAL; +		ret = -ENOENT;  		goto out_no_fb;  	} @@ -263,7 +359,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,  		goto out_no_ttm_lock;  	} -	ret = ttm_read_lock(&vmaster->lock, true); +	ret = ttm_read_lock(&dev_priv->reservation_sem, true);  	if (unlikely(ret != 0))  		goto out_no_ttm_lock; @@ -271,7 +367,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,  			       vfb, user_fence_rep,  			       clips, num_clips); -	ttm_read_unlock(&vmaster->lock); +	ttm_read_unlock(&dev_priv->reservation_sem);  out_no_ttm_lock:  	drm_framebuffer_unreference(fb);  out_no_fb:  | 
