On Thu, Feb 2, 2012 at 10:26 AM, Ilija Hadzic ihadzic@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@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@research.bell-labs.com
Should probably CC stable as well.
Reviewed-by: Alex Deucher alexander.deucher@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@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel