diff mbox

drm: move check for min/max width/height for atomic drivers

Message ID 1478096864-14639-1-git-send-email-robdclark@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Rob Clark Nov. 2, 2016, 2:27 p.m. UTC
drm-hwc + android tries to create an fb for the wallpaper layer, which
is larger than the screen resolution, and potentially larger than
mode_config->max_{width,height}.  But the plane src_w/src_h is within
the max limits, so it is something the hardware can otherwise do.

For atomic drivers, defer the check to drm_atomic_plane_check().

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
 drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
 2 files changed, 34 insertions(+), 9 deletions(-)

Comments

Rob Clark Nov. 3, 2016, 1:58 p.m. UTC | #1
On Wed, Nov 2, 2016 at 10:27 AM, Rob Clark <robdclark@gmail.com> wrote:
> drm-hwc + android tries to create an fb for the wallpaper layer, which
> is larger than the screen resolution, and potentially larger than
> mode_config->max_{width,height}.  But the plane src_w/src_h is within
> the max limits, so it is something the hardware can otherwise do.
>
> For atomic drivers, defer the check to drm_atomic_plane_check().
>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
>  2 files changed, 34 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 34edd4f..fb0f07ce 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
>  static int drm_atomic_plane_check(struct drm_plane *plane,
>                 struct drm_plane_state *state)
>  {
> +       struct drm_mode_config *config = &plane->dev->mode_config;
>         unsigned int fb_width, fb_height;
> +       unsigned int min_width, max_width, min_height, max_height;
>         int ret;
>
>         /* either *both* CRTC and FB must be set, or neither */
> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
>                 return -ENOSPC;
>         }
>
> +       min_width = config->min_width << 16;
> +       max_width = config->max_width << 16;
> +       min_height = config->min_height << 16;
> +       max_height = config->max_height << 16;
> +
> +       /* Make sure source dimensions are within bounds. */
> +       if (min_width > state->src_w || state->src_w > max_width ||
> +           min_height > state->src_h || state->src_h > max_height) {
> +               DRM_DEBUG_ATOMIC("Invalid source size "
> +                                "%u.%06ux%u.%06u\n",
> +                                state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
> +                                state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
> +               return -ERANGE;
> +       }
> +
>         if (plane_switching_crtc(state->state, plane, state)) {
>                 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
>                                  plane->base.id, plane->name);
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index b4b973f..7294bde 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
>                 return ERR_PTR(-EINVAL);
>         }
>
> -       if ((config->min_width > r->width) || (r->width > config->max_width)) {
> -               DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> -                         r->width, config->min_width, config->max_width);
> -               return ERR_PTR(-EINVAL);
> -       }
> -       if ((config->min_height > r->height) || (r->height > config->max_height)) {
> -               DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> -                         r->height, config->min_height, config->max_height);
> -               return ERR_PTR(-EINVAL);
> +       /* for atomic drivers, we check the src dimensions in
> +        * drm_atomic_plane_check().. allow creation of a fb
> +        * that is larger than what can be scanned out, as
> +        * long as userspace doesn't try to scanout a portion
> +        * of the fb that is too large.
> +        */
> +       if (!file_priv->atomic) {

btw, possibly we should loosen this restriction to just DRIVER_ATOMIC?
 It is a problem w/ x11 and multiple screens as well.

BR,
-R

> +               if ((config->min_width > r->width) || (r->width > config->max_width)) {
> +                       DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> +                                 r->width, config->min_width, config->max_width);
> +                       return ERR_PTR(-EINVAL);
> +               }
> +               if ((config->min_height > r->height) || (r->height > config->max_height)) {
> +                       DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> +                                 r->height, config->min_height, config->max_height);
> +                       return ERR_PTR(-EINVAL);
> +               }
>         }
>
>         if (r->flags & DRM_MODE_FB_MODIFIERS &&
> --
> 2.7.4
>
Ville Syrjälä Nov. 3, 2016, 2:12 p.m. UTC | #2
On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
> drm-hwc + android tries to create an fb for the wallpaper layer, which
> is larger than the screen resolution, and potentially larger than
> mode_config->max_{width,height}.  But the plane src_w/src_h is within
> the max limits, so it is something the hardware can otherwise do.
> 
> For atomic drivers, defer the check to drm_atomic_plane_check().
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
>  2 files changed, 34 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 34edd4f..fb0f07ce 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
>  static int drm_atomic_plane_check(struct drm_plane *plane,
>  		struct drm_plane_state *state)
>  {
> +	struct drm_mode_config *config = &plane->dev->mode_config;
>  	unsigned int fb_width, fb_height;
> +	unsigned int min_width, max_width, min_height, max_height;
>  	int ret;
>  
>  	/* either *both* CRTC and FB must be set, or neither */
> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
>  		return -ENOSPC;
>  	}
>  
> +	min_width = config->min_width << 16;
> +	max_width = config->max_width << 16;
> +	min_height = config->min_height << 16;
> +	max_height = config->max_height << 16;
> +
> +	/* Make sure source dimensions are within bounds. */
> +	if (min_width > state->src_w || state->src_w > max_width ||
> +	    min_height > state->src_h || state->src_h > max_height) {
> +		DRM_DEBUG_ATOMIC("Invalid source size "
> +				 "%u.%06ux%u.%06u\n",
> +				 state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
> +				 state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
> +		return -ERANGE;
> +	}
> +
>  	if (plane_switching_crtc(state->state, plane, state)) {
>  		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
>  				 plane->base.id, plane->name);
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index b4b973f..7294bde 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> -	if ((config->min_width > r->width) || (r->width > config->max_width)) {
> -		DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> -			  r->width, config->min_width, config->max_width);
> -		return ERR_PTR(-EINVAL);
> -	}
> -	if ((config->min_height > r->height) || (r->height > config->max_height)) {
> -		DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> -			  r->height, config->min_height, config->max_height);
> -		return ERR_PTR(-EINVAL);
> +	/* for atomic drivers, we check the src dimensions in
> +	 * drm_atomic_plane_check().. allow creation of a fb
> +	 * that is larger than what can be scanned out, as
> +	 * long as userspace doesn't try to scanout a portion
> +	 * of the fb that is too large.
> +	 */
> +	if (!file_priv->atomic) {
> +		if ((config->min_width > r->width) || (r->width > config->max_width)) {
> +			DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> +				  r->width, config->min_width, config->max_width);
> +			return ERR_PTR(-EINVAL);
> +		}
> +		if ((config->min_height > r->height) || (r->height > config->max_height)) {
> +			DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> +				  r->height, config->min_height, config->max_height);
> +			return ERR_PTR(-EINVAL);
> +		}

So why not just bump max_foo in your driver?

Removing the restriction from the core seems likely to break some
drivers as they would now have to check the fb dimensions themselves.

>  	}
>  
>  	if (r->flags & DRM_MODE_FB_MODIFIERS &&
> -- 
> 2.7.4
Rob Clark Nov. 3, 2016, 2:14 p.m. UTC | #3
On Thu, Nov 3, 2016 at 10:12 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
>> drm-hwc + android tries to create an fb for the wallpaper layer, which
>> is larger than the screen resolution, and potentially larger than
>> mode_config->max_{width,height}.  But the plane src_w/src_h is within
>> the max limits, so it is something the hardware can otherwise do.
>>
>> For atomic drivers, defer the check to drm_atomic_plane_check().
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
>>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
>>  2 files changed, 34 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> index 34edd4f..fb0f07ce 100644
>> --- a/drivers/gpu/drm/drm_atomic.c
>> +++ b/drivers/gpu/drm/drm_atomic.c
>> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
>>  static int drm_atomic_plane_check(struct drm_plane *plane,
>>               struct drm_plane_state *state)
>>  {
>> +     struct drm_mode_config *config = &plane->dev->mode_config;
>>       unsigned int fb_width, fb_height;
>> +     unsigned int min_width, max_width, min_height, max_height;
>>       int ret;
>>
>>       /* either *both* CRTC and FB must be set, or neither */
>> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
>>               return -ENOSPC;
>>       }
>>
>> +     min_width = config->min_width << 16;
>> +     max_width = config->max_width << 16;
>> +     min_height = config->min_height << 16;
>> +     max_height = config->max_height << 16;
>> +
>> +     /* Make sure source dimensions are within bounds. */
>> +     if (min_width > state->src_w || state->src_w > max_width ||
>> +         min_height > state->src_h || state->src_h > max_height) {
>> +             DRM_DEBUG_ATOMIC("Invalid source size "
>> +                              "%u.%06ux%u.%06u\n",
>> +                              state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
>> +                              state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
>> +             return -ERANGE;
>> +     }
>> +
>>       if (plane_switching_crtc(state->state, plane, state)) {
>>               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
>>                                plane->base.id, plane->name);
>> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> index b4b973f..7294bde 100644
>> --- a/drivers/gpu/drm/drm_crtc.c
>> +++ b/drivers/gpu/drm/drm_crtc.c
>> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
>>               return ERR_PTR(-EINVAL);
>>       }
>>
>> -     if ((config->min_width > r->width) || (r->width > config->max_width)) {
>> -             DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
>> -                       r->width, config->min_width, config->max_width);
>> -             return ERR_PTR(-EINVAL);
>> -     }
>> -     if ((config->min_height > r->height) || (r->height > config->max_height)) {
>> -             DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
>> -                       r->height, config->min_height, config->max_height);
>> -             return ERR_PTR(-EINVAL);
>> +     /* for atomic drivers, we check the src dimensions in
>> +      * drm_atomic_plane_check().. allow creation of a fb
>> +      * that is larger than what can be scanned out, as
>> +      * long as userspace doesn't try to scanout a portion
>> +      * of the fb that is too large.
>> +      */
>> +     if (!file_priv->atomic) {
>> +             if ((config->min_width > r->width) || (r->width > config->max_width)) {
>> +                     DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
>> +                               r->width, config->min_width, config->max_width);
>> +                     return ERR_PTR(-EINVAL);
>> +             }
>> +             if ((config->min_height > r->height) || (r->height > config->max_height)) {
>> +                     DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
>> +                               r->height, config->min_height, config->max_height);
>> +                     return ERR_PTR(-EINVAL);
>> +             }
>
> So why not just bump max_foo in your driver?
>
> Removing the restriction from the core seems likely to break some
> drivers as they would now have to check the fb dimensions themselves.

that is why I did it only for atomic drivers, so we could rely on the
checking in drm_atomic_plane_check()..

BR,
-R

>>       }
>>
>>       if (r->flags & DRM_MODE_FB_MODIFIERS &&
>> --
>> 2.7.4
>
> --
> Ville Syrjälä
> Intel OTC
Ville Syrjälä Nov. 3, 2016, 2:55 p.m. UTC | #4
On Thu, Nov 03, 2016 at 10:14:20AM -0400, Rob Clark wrote:
> On Thu, Nov 3, 2016 at 10:12 AM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
> >> drm-hwc + android tries to create an fb for the wallpaper layer, which
> >> is larger than the screen resolution, and potentially larger than
> >> mode_config->max_{width,height}.  But the plane src_w/src_h is within
> >> the max limits, so it is something the hardware can otherwise do.
> >>
> >> For atomic drivers, defer the check to drm_atomic_plane_check().
> >>
> >> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >> ---
> >>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
> >>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
> >>  2 files changed, 34 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >> index 34edd4f..fb0f07ce 100644
> >> --- a/drivers/gpu/drm/drm_atomic.c
> >> +++ b/drivers/gpu/drm/drm_atomic.c
> >> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
> >>  static int drm_atomic_plane_check(struct drm_plane *plane,
> >>               struct drm_plane_state *state)
> >>  {
> >> +     struct drm_mode_config *config = &plane->dev->mode_config;
> >>       unsigned int fb_width, fb_height;
> >> +     unsigned int min_width, max_width, min_height, max_height;
> >>       int ret;
> >>
> >>       /* either *both* CRTC and FB must be set, or neither */
> >> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
> >>               return -ENOSPC;
> >>       }
> >>
> >> +     min_width = config->min_width << 16;
> >> +     max_width = config->max_width << 16;
> >> +     min_height = config->min_height << 16;
> >> +     max_height = config->max_height << 16;
> >> +
> >> +     /* Make sure source dimensions are within bounds. */
> >> +     if (min_width > state->src_w || state->src_w > max_width ||
> >> +         min_height > state->src_h || state->src_h > max_height) {
> >> +             DRM_DEBUG_ATOMIC("Invalid source size "
> >> +                              "%u.%06ux%u.%06u\n",
> >> +                              state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
> >> +                              state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
> >> +             return -ERANGE;
> >> +     }
> >> +
> >>       if (plane_switching_crtc(state->state, plane, state)) {
> >>               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
> >>                                plane->base.id, plane->name);
> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> >> index b4b973f..7294bde 100644
> >> --- a/drivers/gpu/drm/drm_crtc.c
> >> +++ b/drivers/gpu/drm/drm_crtc.c
> >> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
> >>               return ERR_PTR(-EINVAL);
> >>       }
> >>
> >> -     if ((config->min_width > r->width) || (r->width > config->max_width)) {
> >> -             DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> >> -                       r->width, config->min_width, config->max_width);
> >> -             return ERR_PTR(-EINVAL);
> >> -     }
> >> -     if ((config->min_height > r->height) || (r->height > config->max_height)) {
> >> -             DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> >> -                       r->height, config->min_height, config->max_height);
> >> -             return ERR_PTR(-EINVAL);
> >> +     /* for atomic drivers, we check the src dimensions in
> >> +      * drm_atomic_plane_check().. allow creation of a fb
> >> +      * that is larger than what can be scanned out, as
> >> +      * long as userspace doesn't try to scanout a portion
> >> +      * of the fb that is too large.
> >> +      */
> >> +     if (!file_priv->atomic) {
> >> +             if ((config->min_width > r->width) || (r->width > config->max_width)) {
> >> +                     DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> >> +                               r->width, config->min_width, config->max_width);
> >> +                     return ERR_PTR(-EINVAL);
> >> +             }
> >> +             if ((config->min_height > r->height) || (r->height > config->max_height)) {
> >> +                     DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> >> +                               r->height, config->min_height, config->max_height);
> >> +                     return ERR_PTR(-EINVAL);
> >> +             }
> >
> > So why not just bump max_foo in your driver?
> >
> > Removing the restriction from the core seems likely to break some
> > drivers as they would now have to check the fb dimensions themselves.
> 
> that is why I did it only for atomic drivers, so we could rely on the
> checking in drm_atomic_plane_check()..

That's not used to check the framebuffer dimensions.
Rob Clark Nov. 3, 2016, 3:22 p.m. UTC | #5
On Thu, Nov 3, 2016 at 10:55 AM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Thu, Nov 03, 2016 at 10:14:20AM -0400, Rob Clark wrote:
>> On Thu, Nov 3, 2016 at 10:12 AM, Ville Syrjälä
>> <ville.syrjala@linux.intel.com> wrote:
>> > On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
>> >> drm-hwc + android tries to create an fb for the wallpaper layer, which
>> >> is larger than the screen resolution, and potentially larger than
>> >> mode_config->max_{width,height}.  But the plane src_w/src_h is within
>> >> the max limits, so it is something the hardware can otherwise do.
>> >>
>> >> For atomic drivers, defer the check to drm_atomic_plane_check().
>> >>
>> >> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> >> ---
>> >>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
>> >>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
>> >>  2 files changed, 34 insertions(+), 9 deletions(-)
>> >>
>> >> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> >> index 34edd4f..fb0f07ce 100644
>> >> --- a/drivers/gpu/drm/drm_atomic.c
>> >> +++ b/drivers/gpu/drm/drm_atomic.c
>> >> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
>> >>  static int drm_atomic_plane_check(struct drm_plane *plane,
>> >>               struct drm_plane_state *state)
>> >>  {
>> >> +     struct drm_mode_config *config = &plane->dev->mode_config;
>> >>       unsigned int fb_width, fb_height;
>> >> +     unsigned int min_width, max_width, min_height, max_height;
>> >>       int ret;
>> >>
>> >>       /* either *both* CRTC and FB must be set, or neither */
>> >> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
>> >>               return -ENOSPC;
>> >>       }
>> >>
>> >> +     min_width = config->min_width << 16;
>> >> +     max_width = config->max_width << 16;
>> >> +     min_height = config->min_height << 16;
>> >> +     max_height = config->max_height << 16;
>> >> +
>> >> +     /* Make sure source dimensions are within bounds. */
>> >> +     if (min_width > state->src_w || state->src_w > max_width ||
>> >> +         min_height > state->src_h || state->src_h > max_height) {
>> >> +             DRM_DEBUG_ATOMIC("Invalid source size "
>> >> +                              "%u.%06ux%u.%06u\n",
>> >> +                              state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
>> >> +                              state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
>> >> +             return -ERANGE;
>> >> +     }
>> >> +
>> >>       if (plane_switching_crtc(state->state, plane, state)) {
>> >>               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
>> >>                                plane->base.id, plane->name);
>> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> >> index b4b973f..7294bde 100644
>> >> --- a/drivers/gpu/drm/drm_crtc.c
>> >> +++ b/drivers/gpu/drm/drm_crtc.c
>> >> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
>> >>               return ERR_PTR(-EINVAL);
>> >>       }
>> >>
>> >> -     if ((config->min_width > r->width) || (r->width > config->max_width)) {
>> >> -             DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
>> >> -                       r->width, config->min_width, config->max_width);
>> >> -             return ERR_PTR(-EINVAL);
>> >> -     }
>> >> -     if ((config->min_height > r->height) || (r->height > config->max_height)) {
>> >> -             DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
>> >> -                       r->height, config->min_height, config->max_height);
>> >> -             return ERR_PTR(-EINVAL);
>> >> +     /* for atomic drivers, we check the src dimensions in
>> >> +      * drm_atomic_plane_check().. allow creation of a fb
>> >> +      * that is larger than what can be scanned out, as
>> >> +      * long as userspace doesn't try to scanout a portion
>> >> +      * of the fb that is too large.
>> >> +      */
>> >> +     if (!file_priv->atomic) {
>> >> +             if ((config->min_width > r->width) || (r->width > config->max_width)) {
>> >> +                     DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
>> >> +                               r->width, config->min_width, config->max_width);
>> >> +                     return ERR_PTR(-EINVAL);
>> >> +             }
>> >> +             if ((config->min_height > r->height) || (r->height > config->max_height)) {
>> >> +                     DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
>> >> +                               r->height, config->min_height, config->max_height);
>> >> +                     return ERR_PTR(-EINVAL);
>> >> +             }
>> >
>> > So why not just bump max_foo in your driver?
>> >
>> > Removing the restriction from the core seems likely to break some
>> > drivers as they would now have to check the fb dimensions themselves.
>>
>> that is why I did it only for atomic drivers, so we could rely on the
>> checking in drm_atomic_plane_check()..
>
> That's not used to check the framebuffer dimensions.

but it is used to check scanout dimensions and that is usually what
matters..  we could add a max-pitch param if needed, but the max-fb
dimension check is mostly useless.

BR,
-R

> --
> Ville Syrjälä
> Intel OTC
Sean Paul Nov. 3, 2016, 3:35 p.m. UTC | #6
On Thu, Nov 3, 2016 at 9:22 AM, Rob Clark <robdclark@gmail.com> wrote:
> On Thu, Nov 3, 2016 at 10:55 AM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
>> On Thu, Nov 03, 2016 at 10:14:20AM -0400, Rob Clark wrote:
>>> On Thu, Nov 3, 2016 at 10:12 AM, Ville Syrjälä
>>> <ville.syrjala@linux.intel.com> wrote:
>>> > On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
>>> >> drm-hwc + android tries to create an fb for the wallpaper layer, which
>>> >> is larger than the screen resolution, and potentially larger than
>>> >> mode_config->max_{width,height}.  But the plane src_w/src_h is within
>>> >> the max limits, so it is something the hardware can otherwise do.
>>> >>
>>> >> For atomic drivers, defer the check to drm_atomic_plane_check().
>>> >>
>>> >> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> >> ---
>>> >>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
>>> >>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
>>> >>  2 files changed, 34 insertions(+), 9 deletions(-)
>>> >>
>>> >> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>>> >> index 34edd4f..fb0f07ce 100644
>>> >> --- a/drivers/gpu/drm/drm_atomic.c
>>> >> +++ b/drivers/gpu/drm/drm_atomic.c
>>> >> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
>>> >>  static int drm_atomic_plane_check(struct drm_plane *plane,
>>> >>               struct drm_plane_state *state)
>>> >>  {
>>> >> +     struct drm_mode_config *config = &plane->dev->mode_config;
>>> >>       unsigned int fb_width, fb_height;
>>> >> +     unsigned int min_width, max_width, min_height, max_height;
>>> >>       int ret;
>>> >>
>>> >>       /* either *both* CRTC and FB must be set, or neither */
>>> >> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
>>> >>               return -ENOSPC;
>>> >>       }
>>> >>
>>> >> +     min_width = config->min_width << 16;
>>> >> +     max_width = config->max_width << 16;
>>> >> +     min_height = config->min_height << 16;
>>> >> +     max_height = config->max_height << 16;
>>> >> +
>>> >> +     /* Make sure source dimensions are within bounds. */
>>> >> +     if (min_width > state->src_w || state->src_w > max_width ||
>>> >> +         min_height > state->src_h || state->src_h > max_height) {
>>> >> +             DRM_DEBUG_ATOMIC("Invalid source size "
>>> >> +                              "%u.%06ux%u.%06u\n",
>>> >> +                              state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
>>> >> +                              state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
>>> >> +             return -ERANGE;
>>> >> +     }
>>> >> +
>>> >>       if (plane_switching_crtc(state->state, plane, state)) {
>>> >>               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
>>> >>                                plane->base.id, plane->name);
>>> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>>> >> index b4b973f..7294bde 100644
>>> >> --- a/drivers/gpu/drm/drm_crtc.c
>>> >> +++ b/drivers/gpu/drm/drm_crtc.c
>>> >> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
>>> >>               return ERR_PTR(-EINVAL);
>>> >>       }
>>> >>
>>> >> -     if ((config->min_width > r->width) || (r->width > config->max_width)) {
>>> >> -             DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
>>> >> -                       r->width, config->min_width, config->max_width);
>>> >> -             return ERR_PTR(-EINVAL);
>>> >> -     }
>>> >> -     if ((config->min_height > r->height) || (r->height > config->max_height)) {
>>> >> -             DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
>>> >> -                       r->height, config->min_height, config->max_height);
>>> >> -             return ERR_PTR(-EINVAL);
>>> >> +     /* for atomic drivers, we check the src dimensions in
>>> >> +      * drm_atomic_plane_check().. allow creation of a fb
>>> >> +      * that is larger than what can be scanned out, as
>>> >> +      * long as userspace doesn't try to scanout a portion
>>> >> +      * of the fb that is too large.
>>> >> +      */
>>> >> +     if (!file_priv->atomic) {
>>> >> +             if ((config->min_width > r->width) || (r->width > config->max_width)) {
>>> >> +                     DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
>>> >> +                               r->width, config->min_width, config->max_width);
>>> >> +                     return ERR_PTR(-EINVAL);
>>> >> +             }
>>> >> +             if ((config->min_height > r->height) || (r->height > config->max_height)) {
>>> >> +                     DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
>>> >> +                               r->height, config->min_height, config->max_height);
>>> >> +                     return ERR_PTR(-EINVAL);
>>> >> +             }
>>> >
>>> > So why not just bump max_foo in your driver?
>>> >
>>> > Removing the restriction from the core seems likely to break some
>>> > drivers as they would now have to check the fb dimensions themselves.
>>>
>>> that is why I did it only for atomic drivers, so we could rely on the
>>> checking in drm_atomic_plane_check()..
>>
>> That's not used to check the framebuffer dimensions.
>
> but it is used to check scanout dimensions and that is usually what
> matters..  we could add a max-pitch param if needed, but the max-fb
> dimension check is mostly useless.
>

Yeah, I suppose this depends on how you interpret the mode_config
constraints. I think this change makes sense since we shouldn't limit
fb size on scanout restrictions.

Sean


> BR,
> -R
>
>> --
>> Ville Syrjälä
>> Intel OTC
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
Ville Syrjälä Nov. 3, 2016, 6:32 p.m. UTC | #7
On Thu, Nov 03, 2016 at 11:22:37AM -0400, Rob Clark wrote:
> On Thu, Nov 3, 2016 at 10:55 AM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Thu, Nov 03, 2016 at 10:14:20AM -0400, Rob Clark wrote:
> >> On Thu, Nov 3, 2016 at 10:12 AM, Ville Syrjälä
> >> <ville.syrjala@linux.intel.com> wrote:
> >> > On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
> >> >> drm-hwc + android tries to create an fb for the wallpaper layer, which
> >> >> is larger than the screen resolution, and potentially larger than
> >> >> mode_config->max_{width,height}.  But the plane src_w/src_h is within
> >> >> the max limits, so it is something the hardware can otherwise do.
> >> >>
> >> >> For atomic drivers, defer the check to drm_atomic_plane_check().
> >> >>
> >> >> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >> >> ---
> >> >>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
> >> >>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
> >> >>  2 files changed, 34 insertions(+), 9 deletions(-)
> >> >>
> >> >> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >> >> index 34edd4f..fb0f07ce 100644
> >> >> --- a/drivers/gpu/drm/drm_atomic.c
> >> >> +++ b/drivers/gpu/drm/drm_atomic.c
> >> >> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
> >> >>  static int drm_atomic_plane_check(struct drm_plane *plane,
> >> >>               struct drm_plane_state *state)
> >> >>  {
> >> >> +     struct drm_mode_config *config = &plane->dev->mode_config;
> >> >>       unsigned int fb_width, fb_height;
> >> >> +     unsigned int min_width, max_width, min_height, max_height;
> >> >>       int ret;
> >> >>
> >> >>       /* either *both* CRTC and FB must be set, or neither */
> >> >> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
> >> >>               return -ENOSPC;
> >> >>       }
> >> >>
> >> >> +     min_width = config->min_width << 16;
> >> >> +     max_width = config->max_width << 16;
> >> >> +     min_height = config->min_height << 16;
> >> >> +     max_height = config->max_height << 16;
> >> >> +
> >> >> +     /* Make sure source dimensions are within bounds. */
> >> >> +     if (min_width > state->src_w || state->src_w > max_width ||
> >> >> +         min_height > state->src_h || state->src_h > max_height) {
> >> >> +             DRM_DEBUG_ATOMIC("Invalid source size "
> >> >> +                              "%u.%06ux%u.%06u\n",
> >> >> +                              state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
> >> >> +                              state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
> >> >> +             return -ERANGE;
> >> >> +     }
> >> >> +
> >> >>       if (plane_switching_crtc(state->state, plane, state)) {
> >> >>               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
> >> >>                                plane->base.id, plane->name);
> >> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> >> >> index b4b973f..7294bde 100644
> >> >> --- a/drivers/gpu/drm/drm_crtc.c
> >> >> +++ b/drivers/gpu/drm/drm_crtc.c
> >> >> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
> >> >>               return ERR_PTR(-EINVAL);
> >> >>       }
> >> >>
> >> >> -     if ((config->min_width > r->width) || (r->width > config->max_width)) {
> >> >> -             DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> >> >> -                       r->width, config->min_width, config->max_width);
> >> >> -             return ERR_PTR(-EINVAL);
> >> >> -     }
> >> >> -     if ((config->min_height > r->height) || (r->height > config->max_height)) {
> >> >> -             DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> >> >> -                       r->height, config->min_height, config->max_height);
> >> >> -             return ERR_PTR(-EINVAL);
> >> >> +     /* for atomic drivers, we check the src dimensions in
> >> >> +      * drm_atomic_plane_check().. allow creation of a fb
> >> >> +      * that is larger than what can be scanned out, as
> >> >> +      * long as userspace doesn't try to scanout a portion
> >> >> +      * of the fb that is too large.
> >> >> +      */
> >> >> +     if (!file_priv->atomic) {
> >> >> +             if ((config->min_width > r->width) || (r->width > config->max_width)) {
> >> >> +                     DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> >> >> +                               r->width, config->min_width, config->max_width);
> >> >> +                     return ERR_PTR(-EINVAL);
> >> >> +             }
> >> >> +             if ((config->min_height > r->height) || (r->height > config->max_height)) {
> >> >> +                     DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> >> >> +                               r->height, config->min_height, config->max_height);
> >> >> +                     return ERR_PTR(-EINVAL);
> >> >> +             }
> >> >
> >> > So why not just bump max_foo in your driver?
> >> >
> >> > Removing the restriction from the core seems likely to break some
> >> > drivers as they would now have to check the fb dimensions themselves.
> >>
> >> that is why I did it only for atomic drivers, so we could rely on the
> >> checking in drm_atomic_plane_check()..
> >
> > That's not used to check the framebuffer dimensions.
> 
> but it is used to check scanout dimensions and that is usually what
> matters..  we could add a max-pitch param if needed, but the max-fb
> dimension check is mostly useless.

There's no point in letting the user create a framebuffer that can't be
scanned out at all.
Rob Clark Nov. 3, 2016, 6:37 p.m. UTC | #8
On Thu, Nov 3, 2016 at 2:32 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Thu, Nov 03, 2016 at 11:22:37AM -0400, Rob Clark wrote:
>> On Thu, Nov 3, 2016 at 10:55 AM, Ville Syrjälä
>> <ville.syrjala@linux.intel.com> wrote:
>> > On Thu, Nov 03, 2016 at 10:14:20AM -0400, Rob Clark wrote:
>> >> On Thu, Nov 3, 2016 at 10:12 AM, Ville Syrjälä
>> >> <ville.syrjala@linux.intel.com> wrote:
>> >> > On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
>> >> >> drm-hwc + android tries to create an fb for the wallpaper layer, which
>> >> >> is larger than the screen resolution, and potentially larger than
>> >> >> mode_config->max_{width,height}.  But the plane src_w/src_h is within
>> >> >> the max limits, so it is something the hardware can otherwise do.
>> >> >>
>> >> >> For atomic drivers, defer the check to drm_atomic_plane_check().
>> >> >>
>> >> >> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> >> >> ---
>> >> >>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
>> >> >>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
>> >> >>  2 files changed, 34 insertions(+), 9 deletions(-)
>> >> >>
>> >> >> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> >> >> index 34edd4f..fb0f07ce 100644
>> >> >> --- a/drivers/gpu/drm/drm_atomic.c
>> >> >> +++ b/drivers/gpu/drm/drm_atomic.c
>> >> >> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
>> >> >>  static int drm_atomic_plane_check(struct drm_plane *plane,
>> >> >>               struct drm_plane_state *state)
>> >> >>  {
>> >> >> +     struct drm_mode_config *config = &plane->dev->mode_config;
>> >> >>       unsigned int fb_width, fb_height;
>> >> >> +     unsigned int min_width, max_width, min_height, max_height;
>> >> >>       int ret;
>> >> >>
>> >> >>       /* either *both* CRTC and FB must be set, or neither */
>> >> >> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
>> >> >>               return -ENOSPC;
>> >> >>       }
>> >> >>
>> >> >> +     min_width = config->min_width << 16;
>> >> >> +     max_width = config->max_width << 16;
>> >> >> +     min_height = config->min_height << 16;
>> >> >> +     max_height = config->max_height << 16;
>> >> >> +
>> >> >> +     /* Make sure source dimensions are within bounds. */
>> >> >> +     if (min_width > state->src_w || state->src_w > max_width ||
>> >> >> +         min_height > state->src_h || state->src_h > max_height) {
>> >> >> +             DRM_DEBUG_ATOMIC("Invalid source size "
>> >> >> +                              "%u.%06ux%u.%06u\n",
>> >> >> +                              state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
>> >> >> +                              state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
>> >> >> +             return -ERANGE;
>> >> >> +     }
>> >> >> +
>> >> >>       if (plane_switching_crtc(state->state, plane, state)) {
>> >> >>               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
>> >> >>                                plane->base.id, plane->name);
>> >> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> >> >> index b4b973f..7294bde 100644
>> >> >> --- a/drivers/gpu/drm/drm_crtc.c
>> >> >> +++ b/drivers/gpu/drm/drm_crtc.c
>> >> >> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
>> >> >>               return ERR_PTR(-EINVAL);
>> >> >>       }
>> >> >>
>> >> >> -     if ((config->min_width > r->width) || (r->width > config->max_width)) {
>> >> >> -             DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
>> >> >> -                       r->width, config->min_width, config->max_width);
>> >> >> -             return ERR_PTR(-EINVAL);
>> >> >> -     }
>> >> >> -     if ((config->min_height > r->height) || (r->height > config->max_height)) {
>> >> >> -             DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
>> >> >> -                       r->height, config->min_height, config->max_height);
>> >> >> -             return ERR_PTR(-EINVAL);
>> >> >> +     /* for atomic drivers, we check the src dimensions in
>> >> >> +      * drm_atomic_plane_check().. allow creation of a fb
>> >> >> +      * that is larger than what can be scanned out, as
>> >> >> +      * long as userspace doesn't try to scanout a portion
>> >> >> +      * of the fb that is too large.
>> >> >> +      */
>> >> >> +     if (!file_priv->atomic) {
>> >> >> +             if ((config->min_width > r->width) || (r->width > config->max_width)) {
>> >> >> +                     DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
>> >> >> +                               r->width, config->min_width, config->max_width);
>> >> >> +                     return ERR_PTR(-EINVAL);
>> >> >> +             }
>> >> >> +             if ((config->min_height > r->height) || (r->height > config->max_height)) {
>> >> >> +                     DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
>> >> >> +                               r->height, config->min_height, config->max_height);
>> >> >> +                     return ERR_PTR(-EINVAL);
>> >> >> +             }
>> >> >
>> >> > So why not just bump max_foo in your driver?
>> >> >
>> >> > Removing the restriction from the core seems likely to break some
>> >> > drivers as they would now have to check the fb dimensions themselves.
>> >>
>> >> that is why I did it only for atomic drivers, so we could rely on the
>> >> checking in drm_atomic_plane_check()..
>> >
>> > That's not used to check the framebuffer dimensions.
>>
>> but it is used to check scanout dimensions and that is usually what
>> matters..  we could add a max-pitch param if needed, but the max-fb
>> dimension check is mostly useless.
>
> There's no point in letting the user create a framebuffer that can't be
> scanned out at all.

But if a user can scan out *part* of it.. which is the case here.  And
a common case.

tbh, our min/max checks are pretty bogus for most hardware, other than
maybe tilcdc where width==pitch...  it should be more along the lines
of max_pitch or stride, plus src_w/src_h checks in
drm_atomic_plane_check().

BR,
-R
Ville Syrjälä Nov. 3, 2016, 6:48 p.m. UTC | #9
On Thu, Nov 03, 2016 at 09:35:24AM -0600, Sean Paul wrote:
> On Thu, Nov 3, 2016 at 9:22 AM, Rob Clark <robdclark@gmail.com> wrote:
> > On Thu, Nov 3, 2016 at 10:55 AM, Ville Syrjälä
> > <ville.syrjala@linux.intel.com> wrote:
> >> On Thu, Nov 03, 2016 at 10:14:20AM -0400, Rob Clark wrote:
> >>> On Thu, Nov 3, 2016 at 10:12 AM, Ville Syrjälä
> >>> <ville.syrjala@linux.intel.com> wrote:
> >>> > On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
> >>> >> drm-hwc + android tries to create an fb for the wallpaper layer, which
> >>> >> is larger than the screen resolution, and potentially larger than
> >>> >> mode_config->max_{width,height}.  But the plane src_w/src_h is within
> >>> >> the max limits, so it is something the hardware can otherwise do.
> >>> >>
> >>> >> For atomic drivers, defer the check to drm_atomic_plane_check().
> >>> >>
> >>> >> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>> >> ---
> >>> >>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
> >>> >>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
> >>> >>  2 files changed, 34 insertions(+), 9 deletions(-)
> >>> >>
> >>> >> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >>> >> index 34edd4f..fb0f07ce 100644
> >>> >> --- a/drivers/gpu/drm/drm_atomic.c
> >>> >> +++ b/drivers/gpu/drm/drm_atomic.c
> >>> >> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
> >>> >>  static int drm_atomic_plane_check(struct drm_plane *plane,
> >>> >>               struct drm_plane_state *state)
> >>> >>  {
> >>> >> +     struct drm_mode_config *config = &plane->dev->mode_config;
> >>> >>       unsigned int fb_width, fb_height;
> >>> >> +     unsigned int min_width, max_width, min_height, max_height;
> >>> >>       int ret;
> >>> >>
> >>> >>       /* either *both* CRTC and FB must be set, or neither */
> >>> >> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
> >>> >>               return -ENOSPC;
> >>> >>       }
> >>> >>
> >>> >> +     min_width = config->min_width << 16;
> >>> >> +     max_width = config->max_width << 16;
> >>> >> +     min_height = config->min_height << 16;
> >>> >> +     max_height = config->max_height << 16;
> >>> >> +
> >>> >> +     /* Make sure source dimensions are within bounds. */
> >>> >> +     if (min_width > state->src_w || state->src_w > max_width ||
> >>> >> +         min_height > state->src_h || state->src_h > max_height) {
> >>> >> +             DRM_DEBUG_ATOMIC("Invalid source size "
> >>> >> +                              "%u.%06ux%u.%06u\n",
> >>> >> +                              state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
> >>> >> +                              state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
> >>> >> +             return -ERANGE;
> >>> >> +     }
> >>> >> +
> >>> >>       if (plane_switching_crtc(state->state, plane, state)) {
> >>> >>               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
> >>> >>                                plane->base.id, plane->name);
> >>> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> >>> >> index b4b973f..7294bde 100644
> >>> >> --- a/drivers/gpu/drm/drm_crtc.c
> >>> >> +++ b/drivers/gpu/drm/drm_crtc.c
> >>> >> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
> >>> >>               return ERR_PTR(-EINVAL);
> >>> >>       }
> >>> >>
> >>> >> -     if ((config->min_width > r->width) || (r->width > config->max_width)) {
> >>> >> -             DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> >>> >> -                       r->width, config->min_width, config->max_width);
> >>> >> -             return ERR_PTR(-EINVAL);
> >>> >> -     }
> >>> >> -     if ((config->min_height > r->height) || (r->height > config->max_height)) {
> >>> >> -             DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> >>> >> -                       r->height, config->min_height, config->max_height);
> >>> >> -             return ERR_PTR(-EINVAL);
> >>> >> +     /* for atomic drivers, we check the src dimensions in
> >>> >> +      * drm_atomic_plane_check().. allow creation of a fb
> >>> >> +      * that is larger than what can be scanned out, as
> >>> >> +      * long as userspace doesn't try to scanout a portion
> >>> >> +      * of the fb that is too large.
> >>> >> +      */
> >>> >> +     if (!file_priv->atomic) {
> >>> >> +             if ((config->min_width > r->width) || (r->width > config->max_width)) {
> >>> >> +                     DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> >>> >> +                               r->width, config->min_width, config->max_width);
> >>> >> +                     return ERR_PTR(-EINVAL);
> >>> >> +             }
> >>> >> +             if ((config->min_height > r->height) || (r->height > config->max_height)) {
> >>> >> +                     DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> >>> >> +                               r->height, config->min_height, config->max_height);
> >>> >> +                     return ERR_PTR(-EINVAL);
> >>> >> +             }
> >>> >
> >>> > So why not just bump max_foo in your driver?
> >>> >
> >>> > Removing the restriction from the core seems likely to break some
> >>> > drivers as they would now have to check the fb dimensions themselves.
> >>>
> >>> that is why I did it only for atomic drivers, so we could rely on the
> >>> checking in drm_atomic_plane_check()..
> >>
> >> That's not used to check the framebuffer dimensions.
> >
> > but it is used to check scanout dimensions and that is usually what
> > matters..  we could add a max-pitch param if needed, but the max-fb
> > dimension check is mostly useless.
> >
> 
> Yeah, I suppose this depends on how you interpret the mode_config
> constraints. I think this change makes sense since we shouldn't limit
> fb size on scanout restrictions.

Hmm. So what are the uses we have for this information?

First one is the max fb size, the other one is mode filtering.
So I'm thinking we could just split the fb size limit into its
own thing and leave the current thing indicating the limits of
the timing generators hdisplay/vdisplay for mode filtering.

Although drivers should still filter the modes further based on
the other timings as well, so not sure how much use there is
in having the core do part of it. But I think currently many
drivers might not do the filtering very robustly so having
something in the core is probably better than nothing.

Additionally planes could have additional scanout limitations,
but those should already be handled by any reasonably competemnt
atomic_check implementation. Although I suspect a bunch of things
would go a bit nuts if we couldn't support an unscaled full
screen primary plane. So potentially the mode_config limits
should be the minimum of the timing generator and plane scanout
limits? I suppose the two would ususally be matched in the hardware
anyway.
Ville Syrjälä Nov. 3, 2016, 6:52 p.m. UTC | #10
On Thu, Nov 03, 2016 at 02:37:30PM -0400, Rob Clark wrote:
> On Thu, Nov 3, 2016 at 2:32 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Thu, Nov 03, 2016 at 11:22:37AM -0400, Rob Clark wrote:
> >> On Thu, Nov 3, 2016 at 10:55 AM, Ville Syrjälä
> >> <ville.syrjala@linux.intel.com> wrote:
> >> > On Thu, Nov 03, 2016 at 10:14:20AM -0400, Rob Clark wrote:
> >> >> On Thu, Nov 3, 2016 at 10:12 AM, Ville Syrjälä
> >> >> <ville.syrjala@linux.intel.com> wrote:
> >> >> > On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
> >> >> >> drm-hwc + android tries to create an fb for the wallpaper layer, which
> >> >> >> is larger than the screen resolution, and potentially larger than
> >> >> >> mode_config->max_{width,height}.  But the plane src_w/src_h is within
> >> >> >> the max limits, so it is something the hardware can otherwise do.
> >> >> >>
> >> >> >> For atomic drivers, defer the check to drm_atomic_plane_check().
> >> >> >>
> >> >> >> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >> >> >> ---
> >> >> >>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
> >> >> >>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
> >> >> >>  2 files changed, 34 insertions(+), 9 deletions(-)
> >> >> >>
> >> >> >> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >> >> >> index 34edd4f..fb0f07ce 100644
> >> >> >> --- a/drivers/gpu/drm/drm_atomic.c
> >> >> >> +++ b/drivers/gpu/drm/drm_atomic.c
> >> >> >> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
> >> >> >>  static int drm_atomic_plane_check(struct drm_plane *plane,
> >> >> >>               struct drm_plane_state *state)
> >> >> >>  {
> >> >> >> +     struct drm_mode_config *config = &plane->dev->mode_config;
> >> >> >>       unsigned int fb_width, fb_height;
> >> >> >> +     unsigned int min_width, max_width, min_height, max_height;
> >> >> >>       int ret;
> >> >> >>
> >> >> >>       /* either *both* CRTC and FB must be set, or neither */
> >> >> >> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
> >> >> >>               return -ENOSPC;
> >> >> >>       }
> >> >> >>
> >> >> >> +     min_width = config->min_width << 16;
> >> >> >> +     max_width = config->max_width << 16;
> >> >> >> +     min_height = config->min_height << 16;
> >> >> >> +     max_height = config->max_height << 16;
> >> >> >> +
> >> >> >> +     /* Make sure source dimensions are within bounds. */
> >> >> >> +     if (min_width > state->src_w || state->src_w > max_width ||
> >> >> >> +         min_height > state->src_h || state->src_h > max_height) {
> >> >> >> +             DRM_DEBUG_ATOMIC("Invalid source size "
> >> >> >> +                              "%u.%06ux%u.%06u\n",
> >> >> >> +                              state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
> >> >> >> +                              state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
> >> >> >> +             return -ERANGE;
> >> >> >> +     }
> >> >> >> +
> >> >> >>       if (plane_switching_crtc(state->state, plane, state)) {
> >> >> >>               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
> >> >> >>                                plane->base.id, plane->name);
> >> >> >> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> >> >> >> index b4b973f..7294bde 100644
> >> >> >> --- a/drivers/gpu/drm/drm_crtc.c
> >> >> >> +++ b/drivers/gpu/drm/drm_crtc.c
> >> >> >> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
> >> >> >>               return ERR_PTR(-EINVAL);
> >> >> >>       }
> >> >> >>
> >> >> >> -     if ((config->min_width > r->width) || (r->width > config->max_width)) {
> >> >> >> -             DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> >> >> >> -                       r->width, config->min_width, config->max_width);
> >> >> >> -             return ERR_PTR(-EINVAL);
> >> >> >> -     }
> >> >> >> -     if ((config->min_height > r->height) || (r->height > config->max_height)) {
> >> >> >> -             DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> >> >> >> -                       r->height, config->min_height, config->max_height);
> >> >> >> -             return ERR_PTR(-EINVAL);
> >> >> >> +     /* for atomic drivers, we check the src dimensions in
> >> >> >> +      * drm_atomic_plane_check().. allow creation of a fb
> >> >> >> +      * that is larger than what can be scanned out, as
> >> >> >> +      * long as userspace doesn't try to scanout a portion
> >> >> >> +      * of the fb that is too large.
> >> >> >> +      */
> >> >> >> +     if (!file_priv->atomic) {
> >> >> >> +             if ((config->min_width > r->width) || (r->width > config->max_width)) {
> >> >> >> +                     DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> >> >> >> +                               r->width, config->min_width, config->max_width);
> >> >> >> +                     return ERR_PTR(-EINVAL);
> >> >> >> +             }
> >> >> >> +             if ((config->min_height > r->height) || (r->height > config->max_height)) {
> >> >> >> +                     DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> >> >> >> +                               r->height, config->min_height, config->max_height);
> >> >> >> +                     return ERR_PTR(-EINVAL);
> >> >> >> +             }
> >> >> >
> >> >> > So why not just bump max_foo in your driver?
> >> >> >
> >> >> > Removing the restriction from the core seems likely to break some
> >> >> > drivers as they would now have to check the fb dimensions themselves.
> >> >>
> >> >> that is why I did it only for atomic drivers, so we could rely on the
> >> >> checking in drm_atomic_plane_check()..
> >> >
> >> > That's not used to check the framebuffer dimensions.
> >>
> >> but it is used to check scanout dimensions and that is usually what
> >> matters..  we could add a max-pitch param if needed, but the max-fb
> >> dimension check is mostly useless.
> >
> > There's no point in letting the user create a framebuffer that can't be
> > scanned out at all.
> 
> But if a user can scan out *part* of it.. which is the case here.  And
> a common case.

That's not how I interpret these limits. In my book they're supposed to
be the max fb size you can scan out (or what you're willing to support
in your driver). Whether you can scan out just a part of it is another
matter (and a matter for atomic_check() at that).

> 
> tbh, our min/max checks are pretty bogus for most hardware, other than
> maybe tilcdc where width==pitch...  it should be more along the lines
> of max_pitch or stride, plus src_w/src_h checks in
> drm_atomic_plane_check().

Yeah, I guess stride is often the limiting factor. Although with
rotation even the vertical stride might start to matter.
Daniel Vetter Nov. 8, 2016, 9:53 a.m. UTC | #11
On Wed, Nov 02, 2016 at 10:27:44AM -0400, Rob Clark wrote:
> drm-hwc + android tries to create an fb for the wallpaper layer, which
> is larger than the screen resolution, and potentially larger than
> mode_config->max_{width,height}.  But the plane src_w/src_h is within
> the max limits, so it is something the hardware can otherwise do.
> 
> For atomic drivers, defer the check to drm_atomic_plane_check().
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>

Top-posting since the discussion kinda disintegrated, but I think an
optional max_fb_w/h (if 0 we use the screen limits) would be the better
approach. More common code ftw at least.
-Daniel

> ---
>  drivers/gpu/drm/drm_atomic.c | 17 +++++++++++++++++
>  drivers/gpu/drm/drm_crtc.c   | 26 +++++++++++++++++---------
>  2 files changed, 34 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 34edd4f..fb0f07ce 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -846,7 +846,9 @@ plane_switching_crtc(struct drm_atomic_state *state,
>  static int drm_atomic_plane_check(struct drm_plane *plane,
>  		struct drm_plane_state *state)
>  {
> +	struct drm_mode_config *config = &plane->dev->mode_config;
>  	unsigned int fb_width, fb_height;
> +	unsigned int min_width, max_width, min_height, max_height;
>  	int ret;
>  
>  	/* either *both* CRTC and FB must be set, or neither */
> @@ -909,6 +911,21 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
>  		return -ENOSPC;
>  	}
>  
> +	min_width = config->min_width << 16;
> +	max_width = config->max_width << 16;
> +	min_height = config->min_height << 16;
> +	max_height = config->max_height << 16;
> +
> +	/* Make sure source dimensions are within bounds. */
> +	if (min_width > state->src_w || state->src_w > max_width ||
> +	    min_height > state->src_h || state->src_h > max_height) {
> +		DRM_DEBUG_ATOMIC("Invalid source size "
> +				 "%u.%06ux%u.%06u\n",
> +				 state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
> +				 state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
> +		return -ERANGE;
> +	}
> +
>  	if (plane_switching_crtc(state->state, plane, state)) {
>  		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
>  				 plane->base.id, plane->name);
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index b4b973f..7294bde 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -3369,15 +3369,23 @@ internal_framebuffer_create(struct drm_device *dev,
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> -	if ((config->min_width > r->width) || (r->width > config->max_width)) {
> -		DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> -			  r->width, config->min_width, config->max_width);
> -		return ERR_PTR(-EINVAL);
> -	}
> -	if ((config->min_height > r->height) || (r->height > config->max_height)) {
> -		DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> -			  r->height, config->min_height, config->max_height);
> -		return ERR_PTR(-EINVAL);
> +	/* for atomic drivers, we check the src dimensions in
> +	 * drm_atomic_plane_check().. allow creation of a fb
> +	 * that is larger than what can be scanned out, as
> +	 * long as userspace doesn't try to scanout a portion
> +	 * of the fb that is too large.
> +	 */
> +	if (!file_priv->atomic) {
> +		if ((config->min_width > r->width) || (r->width > config->max_width)) {
> +			DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
> +				  r->width, config->min_width, config->max_width);
> +			return ERR_PTR(-EINVAL);
> +		}
> +		if ((config->min_height > r->height) || (r->height > config->max_height)) {
> +			DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
> +				  r->height, config->min_height, config->max_height);
> +			return ERR_PTR(-EINVAL);
> +		}
>  	}
>  
>  	if (r->flags & DRM_MODE_FB_MODIFIERS &&
> -- 
> 2.7.4
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 34edd4f..fb0f07ce 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -846,7 +846,9 @@  plane_switching_crtc(struct drm_atomic_state *state,
 static int drm_atomic_plane_check(struct drm_plane *plane,
 		struct drm_plane_state *state)
 {
+	struct drm_mode_config *config = &plane->dev->mode_config;
 	unsigned int fb_width, fb_height;
+	unsigned int min_width, max_width, min_height, max_height;
 	int ret;
 
 	/* either *both* CRTC and FB must be set, or neither */
@@ -909,6 +911,21 @@  static int drm_atomic_plane_check(struct drm_plane *plane,
 		return -ENOSPC;
 	}
 
+	min_width = config->min_width << 16;
+	max_width = config->max_width << 16;
+	min_height = config->min_height << 16;
+	max_height = config->max_height << 16;
+
+	/* Make sure source dimensions are within bounds. */
+	if (min_width > state->src_w || state->src_w > max_width ||
+	    min_height > state->src_h || state->src_h > max_height) {
+		DRM_DEBUG_ATOMIC("Invalid source size "
+				 "%u.%06ux%u.%06u\n",
+				 state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
+				 state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10);
+		return -ERANGE;
+	}
+
 	if (plane_switching_crtc(state->state, plane, state)) {
 		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
 				 plane->base.id, plane->name);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index b4b973f..7294bde 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3369,15 +3369,23 @@  internal_framebuffer_create(struct drm_device *dev,
 		return ERR_PTR(-EINVAL);
 	}
 
-	if ((config->min_width > r->width) || (r->width > config->max_width)) {
-		DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
-			  r->width, config->min_width, config->max_width);
-		return ERR_PTR(-EINVAL);
-	}
-	if ((config->min_height > r->height) || (r->height > config->max_height)) {
-		DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
-			  r->height, config->min_height, config->max_height);
-		return ERR_PTR(-EINVAL);
+	/* for atomic drivers, we check the src dimensions in
+	 * drm_atomic_plane_check().. allow creation of a fb
+	 * that is larger than what can be scanned out, as
+	 * long as userspace doesn't try to scanout a portion
+	 * of the fb that is too large.
+	 */
+	if (!file_priv->atomic) {
+		if ((config->min_width > r->width) || (r->width > config->max_width)) {
+			DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
+				  r->width, config->min_width, config->max_width);
+			return ERR_PTR(-EINVAL);
+		}
+		if ((config->min_height > r->height) || (r->height > config->max_height)) {
+			DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
+				  r->height, config->min_height, config->max_height);
+			return ERR_PTR(-EINVAL);
+		}
 	}
 
 	if (r->flags & DRM_MODE_FB_MODIFIERS &&