1
0
Fork 0

drm/vmwgfx: Add a kernel interface to create a framebuffer v2

The kernel interface is needed for fbdev, and needs to be free from
a file_priv member. To accomplish this, remove the fb surface mutex
and list which isn't used anymore, anyway.

Finally, make the pin() and unpin() pin the framebuffer for all display
system backends, so that fbdev can pin its framebuffer before mapping it.

v2: Address review comments:
- Fix vmw_framebuffer_unpin() to handle also the surface framebuffer case.
- Fix vmw_kms_new_framebuffer() to actually use the only_2d parameter.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
hifive-unleashed-5.1
Thomas Hellstrom 2015-06-28 02:50:56 -07:00
parent 9b590783b3
commit fd006a43a8
4 changed files with 109 additions and 79 deletions

View File

@ -1142,8 +1142,6 @@ static void vmw_lastclose(struct drm_device *dev)
static void vmw_master_init(struct vmw_master *vmaster)
{
ttm_lock_init(&vmaster->lock);
INIT_LIST_HEAD(&vmaster->fb_surf);
mutex_init(&vmaster->fb_surf_mutex);
}
static int vmw_master_create(struct drm_device *dev,

View File

@ -372,8 +372,6 @@ struct vmw_overlay;
struct vmw_master {
struct ttm_lock lock;
struct mutex fb_surf_mutex;
struct list_head fb_surf;
};
struct vmw_vga_topology_state {

View File

@ -369,14 +369,7 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
{
struct vmw_framebuffer_surface *vfbs =
vmw_framebuffer_to_vfbs(framebuffer);
struct vmw_master *vmaster = vmw_master(vfbs->master);
mutex_lock(&vmaster->fb_surf_mutex);
list_del(&vfbs->head);
mutex_unlock(&vmaster->fb_surf_mutex);
drm_master_put(&vfbs->master);
drm_framebuffer_cleanup(framebuffer);
vmw_surface_unreference(&vfbs->surface);
ttm_base_object_unref(&vfbs->base.user_obj);
@ -396,9 +389,6 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
struct drm_clip_rect norect;
int ret, inc = 1;
if (unlikely(vfbs->master != file_priv->master))
return -EINVAL;
/* Legacy Display Unit does not support 3D */
if (dev_priv->active_display_unit == vmw_du_legacy)
return -EINVAL;
@ -485,7 +475,6 @@ static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
};
static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
struct drm_file *file_priv,
struct vmw_surface *surface,
struct vmw_framebuffer **out,
const struct drm_mode_fb_cmd
@ -496,7 +485,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
struct drm_device *dev = dev_priv->dev;
struct vmw_framebuffer_surface *vfbs;
enum SVGA3dSurfaceFormat format;
struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret;
/* 3D is only supported on HWv8 and newer hosts */
@ -564,13 +552,8 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
vfbs->base.base.height = mode_cmd->height;
vfbs->surface = surface;
vfbs->base.user_handle = mode_cmd->handle;
vfbs->master = drm_master_get(file_priv->master);
vfbs->is_dmabuf_proxy = is_dmabuf_proxy;
mutex_lock(&vmaster->fb_surf_mutex);
list_add_tail(&vfbs->head, &vmaster->fb_surf);
mutex_unlock(&vmaster->fb_surf_mutex);
*out = &vfbs->base;
ret = drm_framebuffer_init(dev, &vfbs->base.base,
@ -670,39 +653,51 @@ static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = {
/**
* Pin the dmabuffer to the start of vram.
*/
static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb)
{
struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
struct vmw_framebuffer_dmabuf *vfbd =
vmw_framebuffer_to_vfbd(&vfb->base);
struct vmw_dma_buffer *buf;
int ret;
/* This code should only be used with Legacy Display Unit */
BUG_ON(dev_priv->active_display_unit != vmw_du_legacy);
buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer :
vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup;
vmw_overlay_pause_all(dev_priv);
ret = vmw_dmabuf_pin_in_start_of_vram(dev_priv, vfbd->buffer, false);
vmw_overlay_resume_all(dev_priv);
WARN_ON(ret != 0);
return 0;
}
static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb)
{
struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
struct vmw_framebuffer_dmabuf *vfbd =
vmw_framebuffer_to_vfbd(&vfb->base);
if (!vfbd->buffer) {
WARN_ON(!vfbd->buffer);
if (!buf)
return 0;
switch (dev_priv->active_display_unit) {
case vmw_du_legacy:
vmw_overlay_pause_all(dev_priv);
ret = vmw_dmabuf_pin_in_start_of_vram(dev_priv, buf, false);
vmw_overlay_resume_all(dev_priv);
break;
case vmw_du_screen_object:
case vmw_du_screen_target:
if (vfb->dmabuf)
return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf,
false);
return vmw_dmabuf_pin_in_placement(dev_priv, buf,
&vmw_mob_placement, false);
default:
return -EINVAL;
}
return vmw_dmabuf_unpin(dev_priv, vfbd->buffer, false);
return ret;
}
static int vmw_framebuffer_unpin(struct vmw_framebuffer *vfb)
{
struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
struct vmw_dma_buffer *buf;
buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer :
vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup;
if (WARN_ON(!buf))
return 0;
return vmw_dmabuf_unpin(dev_priv, buf, false);
}
/**
@ -721,7 +716,7 @@ static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb)
* 0 on success, error code otherwise
*/
static int vmw_create_dmabuf_proxy(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd,
const struct drm_mode_fb_cmd *mode_cmd,
struct vmw_dma_buffer *dmabuf_mob,
struct vmw_surface **srf_out)
{
@ -847,10 +842,6 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
vfbd->base.base.depth = mode_cmd->depth;
vfbd->base.base.width = mode_cmd->width;
vfbd->base.base.height = mode_cmd->height;
if (dev_priv->active_display_unit == vmw_du_legacy) {
vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
}
vfbd->base.dmabuf = true;
vfbd->buffer = dmabuf;
vfbd->base.user_handle = mode_cmd->handle;
@ -871,6 +862,64 @@ out_err1:
return ret;
}
/**
* vmw_kms_new_framebuffer - Create a new framebuffer.
*
* @dev_priv: Pointer to device private struct.
* @dmabuf: Pointer to dma buffer to wrap the kms framebuffer around.
* Either @dmabuf or @surface must be NULL.
* @surface: Pointer to a surface to wrap the kms framebuffer around.
* Either @dmabuf or @surface must be NULL.
* @only_2d: No presents will occur to this dma buffer based framebuffer. This
* Helps the code to do some important optimizations.
* @mode_cmd: Frame-buffer metadata.
*/
struct vmw_framebuffer *
vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
struct vmw_dma_buffer *dmabuf,
struct vmw_surface *surface,
bool only_2d,
const struct drm_mode_fb_cmd *mode_cmd)
{
struct vmw_framebuffer *vfb;
bool is_dmabuf_proxy = false;
int ret;
/*
* We cannot use the SurfaceDMA command in an non-accelerated VM,
* therefore, wrap the DMA buf in a surface so we can use the
* SurfaceCopy command.
*/
if (dmabuf && only_2d &&
dev_priv->active_display_unit == vmw_du_screen_target) {
ret = vmw_create_dmabuf_proxy(dev_priv->dev, mode_cmd,
dmabuf, &surface);
if (ret)
return ERR_PTR(ret);
is_dmabuf_proxy = true;
}
/* Create the new framebuffer depending one what we have */
if (surface)
ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
mode_cmd,
is_dmabuf_proxy);
else if (dmabuf)
ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, dmabuf, &vfb,
mode_cmd);
else
BUG();
if (ret)
return ERR_PTR(ret);
vfb->pin = vmw_framebuffer_pin;
vfb->unpin = vmw_framebuffer_unpin;
return vfb;
}
/*
* Generic Kernel modesetting functions
*/
@ -886,7 +935,6 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
struct vmw_dma_buffer *bo = NULL;
struct ttm_base_object *user_obj;
struct drm_mode_fb_cmd mode_cmd;
bool is_dmabuf_proxy = false;
int ret;
mode_cmd.width = mode_cmd2->width;
@ -935,31 +983,13 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
if (ret)
goto err_out;
/*
* We cannot use the SurfaceDMA command in an non-accelerated VM,
* therefore, wrap the DMA buf in a surface so we can use the
* SurfaceCopy command.
*/
if (bo && !(dev_priv->capabilities & SVGA_CAP_3D) &&
dev_priv->active_display_unit == vmw_du_screen_target) {
ret = vmw_create_dmabuf_proxy(dev_priv->dev, &mode_cmd, bo,
&surface);
if (ret)
goto err_out;
is_dmabuf_proxy = true;
}
/* Create the new framebuffer depending one what we have */
if (surface)
ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv,
surface, &vfb, &mode_cmd,
is_dmabuf_proxy);
else if (bo)
ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
&mode_cmd);
else
BUG();
vfb = vmw_kms_new_framebuffer(dev_priv, bo, surface,
!(dev_priv->capabilities & SVGA_CAP_3D),
&mode_cmd);
if (IS_ERR(vfb)) {
ret = PTR_ERR(vfb);
goto err_out;
}
err_out:
/* vmw_user_lookup_handle takes one ref so does new_fb */

View File

@ -114,7 +114,6 @@ struct vmw_framebuffer_surface {
struct vmw_surface *surface;
struct vmw_dma_buffer *buffer;
struct list_head head;
struct drm_master *master;
bool is_dmabuf_proxy; /* true if this is proxy surface for DMA buf */
};
@ -238,7 +237,12 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
struct drm_vmw_fence_rep __user *user_fence_rep,
struct drm_vmw_rect *vclips,
uint32_t num_clips);
struct vmw_framebuffer *
vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
struct vmw_dma_buffer *dmabuf,
struct vmw_surface *surface,
bool only_2d,
const struct drm_mode_fb_cmd *mode_cmd);
/*
* Legacy display unit functions - vmwgfx_ldu.c