Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mach64: fix image corruption due to reading accelerator registers

Reading the registers without waiting for engine idle returns
unpredictable values. These unpredictable values result in display
corruption - if atyfb_imageblit reads the content of DP_PIX_WIDTH with the
bit DP_HOST_TRIPLE_EN set (from previous invocation), the driver would
never ever clear the bit, resulting in display corruption.

We don't want to wait for idle because it would degrade performance, so
this patch modifies the driver so that it never reads accelerator
registers.

HOST_CNTL doesn't have to be read, we can just write it with
HOST_BYTE_ALIGN because no other part of the driver cares if
HOST_BYTE_ALIGN is set.

DP_PIX_WIDTH is written in the functions atyfb_copyarea and atyfb_fillrect
with the default value and in atyfb_imageblit with the value set according
to the source image data.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Ville Syrjälä <syrjala@sci.fi>
Cc: stable@vger.kernel.org
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>

authored by

Mikulas Patocka and committed by
Bartlomiej Zolnierkiewicz
c09bcc91 3c6c6a78

+9 -13
+9 -13
drivers/video/fbdev/aty/mach64_accel.c
··· 127 127 128 128 /* set host attributes */ 129 129 wait_for_fifo(13, par); 130 - aty_st_le32(HOST_CNTL, 0, par); 130 + aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par); 131 131 132 132 /* set pattern attributes */ 133 133 aty_st_le32(PAT_REG0, 0, par); ··· 233 233 rotation = rotation24bpp(dx, direction); 234 234 } 235 235 236 - wait_for_fifo(4, par); 236 + wait_for_fifo(5, par); 237 + aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); 237 238 aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par); 238 239 aty_st_le32(SRC_Y_X, (sx << 16) | sy, par); 239 240 aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par); ··· 270 269 rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT); 271 270 } 272 271 273 - wait_for_fifo(3, par); 272 + wait_for_fifo(4, par); 273 + aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par); 274 274 aty_st_le32(DP_FRGD_CLR, color, par); 275 275 aty_st_le32(DP_SRC, 276 276 BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE, ··· 286 284 { 287 285 struct atyfb_par *par = (struct atyfb_par *) info->par; 288 286 u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width; 289 - u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix; 287 + u32 pix_width, rotation = 0, src, mix; 290 288 291 289 if (par->asleep) 292 290 return; ··· 298 296 return; 299 297 } 300 298 301 - pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par); 302 - host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN; 299 + pix_width = par->crtc.dp_pix_width; 303 300 304 301 switch (image->depth) { 305 302 case 1: ··· 371 370 mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D; 372 371 } 373 372 374 - wait_for_fifo(6, par); 375 - aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par); 373 + wait_for_fifo(5, par); 376 374 aty_st_le32(DP_PIX_WIDTH, pix_width, par); 377 375 aty_st_le32(DP_MIX, mix, par); 378 376 aty_st_le32(DP_SRC, src, par); 379 - aty_st_le32(HOST_CNTL, host_cntl, par); 377 + aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par); 380 378 aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par); 381 379 382 380 draw_rect(dx, dy, width, image->height, par); ··· 424 424 aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par); 425 425 } 426 426 } 427 - 428 - /* restore pix_width */ 429 - wait_for_fifo(1, par); 430 - aty_st_le32(DP_PIX_WIDTH, pix_width_save, par); 431 427 }