[PATCH v2] drm/radeon/kms/blit: fix blit copy for very large buffers

Alex Deucher alexdeucher at gmail.com
Thu Feb 2 07:31:59 PST 2012


On Thu, Feb 2, 2012 at 10:26 AM, Ilija Hadzic
<ihadzic at research.bell-labs.com> wrote:
> Evergreen and NI blit copy was broken if the buffer maps to a rectangle
> whose one dimension is 16384 (max dimension allowed by these chips).
> In the mainline kernel, the problem is exposed only when buffers are
> very large (1G), but it's still a problem. The problem could be exposed
> for smaller buffers if anyone modifies the algorithm for rectangle
> construction in r600_blit_create_rect() (the reason why someone would
> modify that algorithm is to tune the performance of buffer moves).
>
> The root cause was in i2f() function which only operated on range between
> 0 and 16383. Fix this by extending the range of i2f() function to 0 to
> 32767.
>
> While at it improve the function so that the range can be easily
> extended in the future (if it becomes necessary), cleanup lines
> over 80 characters, and replace in-line comments with one strategic
> comment that explains the crux of the function.
>
> Credits to michel at daenzer.net for pointing out the root cause of
> the bug.
>
> v2: Fix I2F_MAX_INPUT constant definition goof and warn only once
>    if input argument is out of range. Edit the comment a little
>    bit to avoid some linguistic confusion and make it look better
>    in general.
>
> Signed-off-by: Ilija Hadzic <ihadzic at research.bell-labs.com>

Should probably CC stable as well.

Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  drivers/gpu/drm/radeon/r600_blit_kms.c |   35 ++++++++++++++++++++++---------
>  1 files changed, 25 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
> index d996f43..accc032 100644
> --- a/drivers/gpu/drm/radeon/r600_blit_kms.c
> +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
> @@ -468,27 +468,42 @@ set_default_state(struct radeon_device *rdev)
>        radeon_ring_write(ring, sq_stack_resource_mgmt_2);
>  }
>
> +#define I2F_MAX_BITS 15
> +#define I2F_MAX_INPUT  ((1 << I2F_MAX_BITS) - 1)
> +#define I2F_SHIFT (24 - I2F_MAX_BITS)
> +
> +/*
> + * Converts unsigned integer into 32-bit IEEE floating point representation.
> + * Conversion is not universal and only works for the range from 0
> + * to 2^I2F_MAX_BITS-1. Currently we only use it with inputs between
> + * 0 and 16384 (inclusive), so I2F_MAX_BITS=15 is enough. If necessary,
> + * I2F_MAX_BITS can be increased, but that will add to the loop iterations
> + * and slow us down. Conversion is done by shifting the input and counting
> + * down until the first 1 reaches bit position 23. The resulting counter
> + * and the shifted input are, respectively, the exponent and the fraction.
> + * The sign is always zero.
> + */
>  static uint32_t i2f(uint32_t input)
>  {
>        u32 result, i, exponent, fraction;
>
> -       if ((input & 0x3fff) == 0)
> -               result = 0; /* 0 is a special case */
> +       WARN_ON_ONCE(input > I2F_MAX_INPUT);
> +
> +       if ((input & I2F_MAX_INPUT) == 0)
> +               result = 0;
>        else {
> -               exponent = 140; /* exponent biased by 127; */
> -               fraction = (input & 0x3fff) << 10; /* cheat and only
> -                                                     handle numbers below 2^^15 */
> -               for (i = 0; i < 14; i++) {
> +               exponent = 126 + I2F_MAX_BITS;
> +               fraction = (input & I2F_MAX_INPUT) << I2F_SHIFT;
> +
> +               for (i = 0; i < I2F_MAX_BITS; i++) {
>                        if (fraction & 0x800000)
>                                break;
>                        else {
> -                               fraction = fraction << 1; /* keep
> -                                                            shifting left until top bit = 1 */
> +                               fraction = fraction << 1;
>                                exponent = exponent - 1;
>                        }
>                }
> -               result = exponent << 23 | (fraction & 0x7fffff); /* mask
> -                                                                   off top bit; assumed 1 */
> +               result = exponent << 23 | (fraction & 0x7fffff);
>        }
>        return result;
>  }
> --
> 1.7.7
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list