forked from Minki/linux
drm/vmwgfx: Use modeset display memory validation for layout ioctl
Call the same display memory validation function which is used by modeset_check. This ensure consistency that kernel change preferred mode/topology only if supported. Also change the internal function to use drm_rect instead of drm_vmw_rect. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
This commit is contained in:
parent
0a80eb4c12
commit
5e24133ea3
@ -1968,13 +1968,15 @@ void vmw_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
* vmw_du_update_layout - Update the display unit with topology from resolution
|
||||||
* Small shared kms functions.
|
* plugin and generate DRM uevent
|
||||||
|
* @dev_priv: device private
|
||||||
|
* @num_rects: number of drm_rect in rects
|
||||||
|
* @rects: toplogy to update
|
||||||
*/
|
*/
|
||||||
|
static int vmw_du_update_layout(struct vmw_private *dev_priv,
|
||||||
static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
|
unsigned int num_rects, struct drm_rect *rects)
|
||||||
struct drm_vmw_rect *rects)
|
|
||||||
{
|
{
|
||||||
struct drm_device *dev = dev_priv->dev;
|
struct drm_device *dev = dev_priv->dev;
|
||||||
struct vmw_display_unit *du;
|
struct vmw_display_unit *du;
|
||||||
@ -1982,26 +1984,14 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
|
|||||||
|
|
||||||
mutex_lock(&dev->mode_config.mutex);
|
mutex_lock(&dev->mode_config.mutex);
|
||||||
|
|
||||||
#if 0
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
DRM_INFO("%s: new layout ", __func__);
|
|
||||||
for (i = 0; i < num; i++)
|
|
||||||
DRM_INFO("(%i, %i %ux%u) ", rects[i].x, rects[i].y,
|
|
||||||
rects[i].w, rects[i].h);
|
|
||||||
DRM_INFO("\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
list_for_each_entry(con, &dev->mode_config.connector_list, head) {
|
list_for_each_entry(con, &dev->mode_config.connector_list, head) {
|
||||||
du = vmw_connector_to_du(con);
|
du = vmw_connector_to_du(con);
|
||||||
if (num > du->unit) {
|
if (num_rects > du->unit) {
|
||||||
du->pref_width = rects[du->unit].w;
|
du->pref_width = drm_rect_width(&rects[du->unit]);
|
||||||
du->pref_height = rects[du->unit].h;
|
du->pref_height = drm_rect_height(&rects[du->unit]);
|
||||||
du->pref_active = true;
|
du->pref_active = true;
|
||||||
du->gui_x = rects[du->unit].x;
|
du->gui_x = rects[du->unit].x1;
|
||||||
du->gui_y = rects[du->unit].y;
|
du->gui_y = rects[du->unit].y1;
|
||||||
drm_object_property_set_value
|
drm_object_property_set_value
|
||||||
(&con->base, dev->mode_config.suggested_x_property,
|
(&con->base, dev->mode_config.suggested_x_property,
|
||||||
du->gui_x);
|
du->gui_x);
|
||||||
@ -2322,7 +2312,25 @@ vmw_du_connector_atomic_get_property(struct drm_connector *connector,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl
|
||||||
|
* @dev: drm device for the ioctl
|
||||||
|
* @data: data pointer for the ioctl
|
||||||
|
* @file_priv: drm file for the ioctl call
|
||||||
|
*
|
||||||
|
* Update preferred topology of display unit as per ioctl request. The topology
|
||||||
|
* is expressed as array of drm_vmw_rect.
|
||||||
|
* e.g.
|
||||||
|
* [0 0 640 480] [640 0 800 600] [0 480 640 480]
|
||||||
|
*
|
||||||
|
* NOTE:
|
||||||
|
* The x and y offset (upper left) in drm_vmw_rect cannot be less than 0. Beside
|
||||||
|
* device limit on topology, x + w and y + h (lower right) cannot be greater
|
||||||
|
* than INT_MAX. So topology beyond these limits will return with error.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Zero on success, negative errno on failure.
|
||||||
|
*/
|
||||||
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
|
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
@ -2331,15 +2339,12 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
|
|||||||
(struct drm_vmw_update_layout_arg *)data;
|
(struct drm_vmw_update_layout_arg *)data;
|
||||||
void __user *user_rects;
|
void __user *user_rects;
|
||||||
struct drm_vmw_rect *rects;
|
struct drm_vmw_rect *rects;
|
||||||
|
struct drm_rect *drm_rects;
|
||||||
unsigned rects_size;
|
unsigned rects_size;
|
||||||
int ret;
|
int ret, i;
|
||||||
int i;
|
|
||||||
u64 total_pixels = 0;
|
|
||||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
|
||||||
struct drm_vmw_rect bounding_box = {0};
|
|
||||||
|
|
||||||
if (!arg->num_outputs) {
|
if (!arg->num_outputs) {
|
||||||
struct drm_vmw_rect def_rect = {0, 0, 800, 600};
|
struct drm_rect def_rect = {0, 0, 800, 600};
|
||||||
vmw_du_update_layout(dev_priv, 1, &def_rect);
|
vmw_du_update_layout(dev_priv, 1, &def_rect);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2358,52 +2363,29 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
|
|||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < arg->num_outputs; ++i) {
|
drm_rects = (struct drm_rect *)rects;
|
||||||
if (rects[i].x < 0 ||
|
|
||||||
rects[i].y < 0 ||
|
for (i = 0; i < arg->num_outputs; i++) {
|
||||||
rects[i].x + rects[i].w > mode_config->max_width ||
|
struct drm_vmw_rect curr_rect;
|
||||||
rects[i].y + rects[i].h > mode_config->max_height) {
|
|
||||||
DRM_ERROR("Invalid GUI layout.\n");
|
/* Verify user-space for overflow as kernel use drm_rect */
|
||||||
ret = -EINVAL;
|
if ((rects[i].x + rects[i].w > INT_MAX) ||
|
||||||
|
(rects[i].y + rects[i].h > INT_MAX)) {
|
||||||
|
ret = -ERANGE;
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
curr_rect = rects[i];
|
||||||
* bounding_box.w and bunding_box.h are used as
|
drm_rects[i].x1 = curr_rect.x;
|
||||||
* lower-right coordinates
|
drm_rects[i].y1 = curr_rect.y;
|
||||||
*/
|
drm_rects[i].x2 = curr_rect.x + curr_rect.w;
|
||||||
if (rects[i].x + rects[i].w > bounding_box.w)
|
drm_rects[i].y2 = curr_rect.y + curr_rect.h;
|
||||||
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;
|
|
||||||
|
|
||||||
total_pixels += (u64) rects[i].w * (u64) rects[i].h;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev_priv->active_display_unit == vmw_du_screen_target) {
|
ret = vmw_kms_check_display_memory(dev, arg->num_outputs, drm_rects);
|
||||||
/*
|
|
||||||
* For Screen Targets, the limits for a toplogy are:
|
|
||||||
* 1. Bounding box (assuming 32bpp) must be < prim_bb_mem
|
|
||||||
* 2. Total pixels (assuming 32bpp) must be < prim_bb_mem
|
|
||||||
*/
|
|
||||||
u64 bb_mem = (u64) bounding_box.w * bounding_box.h * 4;
|
|
||||||
u64 pixel_mem = total_pixels * 4;
|
|
||||||
|
|
||||||
if (bb_mem > dev_priv->prim_bb_mem) {
|
if (ret == 0)
|
||||||
DRM_ERROR("Topology is beyond supported limits.\n");
|
vmw_du_update_layout(dev_priv, arg->num_outputs, drm_rects);
|
||||||
ret = -EINVAL;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pixel_mem > dev_priv->prim_bb_mem) {
|
|
||||||
DRM_ERROR("Combined output size too large\n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vmw_du_update_layout(dev_priv, arg->num_outputs, rects);
|
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
kfree(rects);
|
kfree(rects);
|
||||||
|
Loading…
Reference in New Issue
Block a user