diff options
author | Sinclair Yeh <syeh@vmware.com> | 2014-11-24 11:57:24 -0800 |
---|---|---|
committer | Sinclair Yeh <syeh@vmware.com> | 2014-12-22 08:03:01 -0800 |
commit | 3f6d507eb0011a66098406f010f53cddd07e8f97 (patch) | |
tree | 338fad8f88d120b9e3fa304d15f5cc711adec837 | |
parent | e9606c2faa513b819d7f2136873ccf83c82e2656 (diff) |
drm/vmwgfx: enforce Screen Target boundary conditionsfeature/syeh/screen-targets
Added code to enforce the following conditions
* Mode cannot be larger than maximum screen target size
* Unindented a block in vmwgfx_kms
* Max topology dimensions have to be less than max texture dimensions
* Remove limiting bounding box to VRAM size if Screen Target is used
Signed-off-by: Sinclair Yeh <syeh@vmware.com>
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
-rw-r--r-- | vmwgfx_drv.c | 24 | ||||
-rw-r--r-- | vmwgfx_drv.h | 4 | ||||
-rw-r--r-- | vmwgfx_kms.c | 74 | ||||
-rw-r--r-- | vmwgfx_stdu.c | 2 |
4 files changed, 75 insertions, 29 deletions
diff --git a/vmwgfx_drv.c b/vmwgfx_drv.c index 7128be9..54ecf2f 100644 --- a/vmwgfx_drv.c +++ b/vmwgfx_drv.c @@ -666,16 +666,28 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->prim_bb_mem = vmw_read(dev_priv, SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM); - dev_priv->max_mob_size = + dev_priv->max_mob_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); + + dev_priv->stdu_max_width = + vmw_read(dev_priv, SVGA_REG_SCREENTARGET_MAX_WIDTH); + dev_priv->stdu_max_height = + vmw_read(dev_priv, SVGA_REG_SCREENTARGET_MAX_HEIGHT); + + vmw_write(dev_priv, SVGA_REG_DEV_CAP, + SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH); + dev_priv->texture_max_width = vmw_read(dev_priv, + SVGA_REG_DEV_CAP); + vmw_write(dev_priv, SVGA_REG_DEV_CAP, + SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT); + dev_priv->texture_max_height = vmw_read(dev_priv, + SVGA_REG_DEV_CAP); } else dev_priv->prim_bb_mem = dev_priv->vram_size; - /* - * Limit back buffer size to VRAM size. Remove this once - * screen targets are implemented. - */ - if (dev_priv->prim_bb_mem > dev_priv->vram_size) + /* For non-screen target displays, limit back buffer to VRAM size */ + if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE && + dev_priv->prim_bb_mem > dev_priv->vram_size) dev_priv->prim_bb_mem = dev_priv->vram_size; mutex_unlock(&dev_priv->hw_mutex); diff --git a/vmwgfx_drv.h b/vmwgfx_drv.h index 6fbe9fe..908ec47 100644 --- a/vmwgfx_drv.h +++ b/vmwgfx_drv.h @@ -418,6 +418,10 @@ struct vmw_private { uint32_t mmio_size; uint32_t fb_max_width; uint32_t fb_max_height; + uint32_t texture_max_width; + uint32_t texture_max_height; + uint32_t stdu_max_width; + uint32_t stdu_max_height; uint32_t initial_width; uint32_t initial_height; __le32 __iomem *mmio_virt; diff --git a/vmwgfx_kms.c b/vmwgfx_kms.c index 20940c3..0acd885 100644 --- a/vmwgfx_kms.c +++ b/vmwgfx_kms.c @@ -72,6 +72,7 @@ void vmw_du_cleanup(struct vmw_display_unit *du) vmw_surface_unreference(&du->cursor_surface); if (du->cursor_dmabuf) vmw_dmabuf_unreference(&du->cursor_dmabuf); + drm_sysfs_connector_remove(&du->connector); drm_crtc_cleanup(&du->crtc); drm_encoder_cleanup(&du->encoder); drm_connector_cleanup(&du->connector); @@ -772,7 +773,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, required_size = mode_cmd->pitch * mode_cmd->height; if (unlikely(required_size > (u64) dev_priv->prim_bb_mem)) { - DRM_ERROR("VRAM size is too small for requested mode.\n"); + DRM_ERROR("Requested mode exceeds bounding box limit\n"); return ERR_PTR(-ENOMEM); } @@ -1532,33 +1533,36 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, if (dev_priv->active_display_unit == vmw_du_screen_object) assumed_bpp = 4; + if (dev_priv->active_display_unit == vmw_du_screen_target) { + max_width = min(max_width, dev_priv->stdu_max_width); + max_height = min(max_height, dev_priv->stdu_max_height); + } + /* Add preferred mode */ - { - mode = drm_mode_duplicate(dev, &prefmode); - if (!mode) - return 0; - mode->hdisplay = du->pref_width; - mode->vdisplay = du->pref_height; - vmw_guess_mode_timing(mode); - - if (vmw_kms_validate_mode_vram(dev_priv, - mode->hdisplay * assumed_bpp, - mode->vdisplay)) { - drm_mode_probed_add(connector, mode); - } else { - drm_mode_destroy(dev, mode); - mode = NULL; - } + mode = drm_mode_duplicate(dev, &prefmode); + if (!mode) + return 0; + mode->hdisplay = du->pref_width; + mode->vdisplay = du->pref_height; + vmw_guess_mode_timing(mode); - if (du->pref_mode) { - list_del_init(&du->pref_mode->head); - drm_mode_destroy(dev, du->pref_mode); - } + if (vmw_kms_validate_mode_vram(dev_priv, + mode->hdisplay * assumed_bpp, + mode->vdisplay)) { + drm_mode_probed_add(connector, mode); + } else { + drm_mode_destroy(dev, mode); + mode = NULL; + } - /* mode might be null here, this is intended */ - du->pref_mode = mode; + if (du->pref_mode) { + list_del_init(&du->pref_mode->head); + drm_mode_destroy(dev, du->pref_mode); } + /* mode might be null here, this is intended */ + du->pref_mode = mode; + for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { bmode = &vmw_kms_connector_builtin[i]; if (bmode->hdisplay > max_width || @@ -1608,6 +1612,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, int ret; int i; struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_vmw_rect bounding_box = {0}; ret = ttm_read_lock(&vmaster->lock, true); if (unlikely(ret != 0)) @@ -1644,8 +1649,31 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, ret = -EINVAL; goto out_free; } + + /* + * bounding_box.w and bunding_box.h are used as + * lower-right coordinates + */ + if (rects[i].x + rects[i].w > bounding_box.w) + bounding_box.w = rects[i].x + rects[i].w; + + if (rects[i].y + rects[i].h > bounding_box.h) + bounding_box.h = rects[i].y + rects[i].h; } + /* + * For Screen Target Display Unit, all the displays must fit + * inside of maximum texture size. + */ + if (dev_priv->active_display_unit == vmw_du_screen_target) + if (bounding_box.w > dev_priv->texture_max_width || + bounding_box.h > dev_priv->texture_max_height) { + DRM_ERROR("Layout exceeds maximum texture size\n"); + ret = -EINVAL; + goto out_free; + } + + vmw_du_update_layout(dev_priv, arg->num_outputs, rects); out_free: diff --git a/vmwgfx_stdu.c b/vmwgfx_stdu.c index 8274163..f48f343 100644 --- a/vmwgfx_stdu.c +++ b/vmwgfx_stdu.c @@ -979,6 +979,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; + (void) drm_sysfs_connector_add(connector); + drm_crtc_init(dev, crtc, &vmw_stdu_crtc_funcs); drm_mode_crtc_set_gamma_size(crtc, 256); |