Commit 96837e8b authored by Imre Deak's avatar Imre Deak

drm/i915/adlp/fb: Fix remapping of linear CCS AUX surfaces

During remapping CCS FBs the CCS AUX surface mapped size and offset->x,y
coordinate calculations assumed a tiled layout. This works as long as
the CCS surface height is aligned to 64 lines (ensuring a 4k bytes CCS
surface tile layout).  However this alignment is not required by the HW
(and the driver doesn't enforces it either).

Add the remapping logic required to remap the pages of CCS surfaces
without the above alignment, assuming the natural linear layout of the
CCS surface (vs. tiled main surface layout).

Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Fixes: 3d1adc3d ("drm/i915/adlp: Add support for remapping CCS FBs")
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarJuha-Pekka Heikkila <juhapekka.heikkila@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211026225105.2783797-5-imre.deak@intel.com
parent dd5ba4ff
...@@ -622,7 +622,11 @@ unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info ...@@ -622,7 +622,11 @@ unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info
for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) {
unsigned int plane_size; unsigned int plane_size;
plane_size = rem_info->plane[i].dst_stride * rem_info->plane[i].height; if (rem_info->plane[i].linear)
plane_size = rem_info->plane[i].size;
else
plane_size = rem_info->plane[i].dst_stride * rem_info->plane[i].height;
if (plane_size == 0) if (plane_size == 0)
continue; continue;
......
...@@ -853,6 +853,20 @@ static u32 intel_adjust_tile_offset(int *x, int *y, ...@@ -853,6 +853,20 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
return new_offset; return new_offset;
} }
static u32 intel_adjust_linear_offset(int *x, int *y,
unsigned int cpp,
unsigned int pitch,
u32 old_offset,
u32 new_offset)
{
old_offset += *y * pitch + *x * cpp;
*y = (old_offset - new_offset) / pitch;
*x = ((old_offset - new_offset) - *y * pitch) / cpp;
return new_offset;
}
static u32 intel_adjust_aligned_offset(int *x, int *y, static u32 intel_adjust_aligned_offset(int *x, int *y,
const struct drm_framebuffer *fb, const struct drm_framebuffer *fb,
int color_plane, int color_plane,
...@@ -883,10 +897,8 @@ static u32 intel_adjust_aligned_offset(int *x, int *y, ...@@ -883,10 +897,8 @@ static u32 intel_adjust_aligned_offset(int *x, int *y,
tile_size, pitch_tiles, tile_size, pitch_tiles,
old_offset, new_offset); old_offset, new_offset);
} else { } else {
old_offset += *y * pitch + *x * cpp; intel_adjust_linear_offset(x, y, cpp, pitch,
old_offset, new_offset);
*y = (old_offset - new_offset) / pitch;
*x = ((old_offset - new_offset) - *y * pitch) / cpp;
} }
return new_offset; return new_offset;
...@@ -1258,12 +1270,11 @@ plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane, ...@@ -1258,12 +1270,11 @@ plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
unsigned int pitch_tiles) unsigned int pitch_tiles)
{ {
if (intel_fb_needs_pot_stride_remap(fb)) { if (intel_fb_needs_pot_stride_remap(fb)) {
unsigned int min_stride = intel_fb_is_ccs_aux_plane(&fb->base, color_plane) ? 2 : 8;
/* /*
* ADL_P, the only platform needing a POT stride has a minimum * ADL_P, the only platform needing a POT stride has a minimum
* of 8 main surface and 2 CCS AUX stride tiles. * of 8 main surface tiles.
*/ */
return roundup_pow_of_two(max(pitch_tiles, min_stride)); return roundup_pow_of_two(max(pitch_tiles, 8u));
} else { } else {
return pitch_tiles; return pitch_tiles;
} }
...@@ -1285,11 +1296,31 @@ plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane, ...@@ -1285,11 +1296,31 @@ plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane,
return DIV_ROUND_UP(y + dims->height, dims->tile_height); return DIV_ROUND_UP(y + dims->height, dims->tile_height);
} }
static unsigned int
plane_view_linear_tiles(const struct intel_framebuffer *fb, int color_plane,
const struct fb_plane_view_dims *dims,
int x, int y)
{
struct drm_i915_private *i915 = to_i915(fb->base.dev);
unsigned int size;
size = (y + dims->height) * fb->base.pitches[color_plane] +
x * fb->base.format->cpp[color_plane];
return DIV_ROUND_UP(size, intel_tile_size(i915));
}
#define assign_chk_ovf(i915, var, val) ({ \ #define assign_chk_ovf(i915, var, val) ({ \
drm_WARN_ON(&(i915)->drm, overflows_type(val, var)); \ drm_WARN_ON(&(i915)->drm, overflows_type(val, var)); \
(var) = (val); \ (var) = (val); \
}) })
#define assign_bfld_chk_ovf(i915, var, val) ({ \
(var) = (val); \
drm_WARN_ON(&(i915)->drm, (var) != (val)); \
(var); \
})
static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane, static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane,
const struct fb_plane_view_dims *dims, const struct fb_plane_view_dims *dims,
u32 obj_offset, u32 gtt_offset, int x, int y, u32 obj_offset, u32 gtt_offset, int x, int y,
...@@ -1304,12 +1335,26 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p ...@@ -1304,12 +1335,26 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
struct drm_rect r; struct drm_rect r;
u32 size = 0; u32 size = 0;
assign_chk_ovf(i915, remap_info->offset, obj_offset); assign_bfld_chk_ovf(i915, remap_info->offset, obj_offset);
assign_chk_ovf(i915, remap_info->src_stride, plane_view_src_stride_tiles(fb, color_plane, dims));
assign_chk_ovf(i915, remap_info->width, plane_view_width_tiles(fb, color_plane, dims, x)); if (intel_fb_is_gen12_ccs_aux_plane(&fb->base, color_plane)) {
assign_chk_ovf(i915, remap_info->height, plane_view_height_tiles(fb, color_plane, dims, y)); remap_info->linear = 1;
assign_chk_ovf(i915, remap_info->size,
plane_view_linear_tiles(fb, color_plane, dims, x, y));
} else {
remap_info->linear = 0;
assign_chk_ovf(i915, remap_info->src_stride,
plane_view_src_stride_tiles(fb, color_plane, dims));
assign_chk_ovf(i915, remap_info->width,
plane_view_width_tiles(fb, color_plane, dims, x));
assign_chk_ovf(i915, remap_info->height,
plane_view_height_tiles(fb, color_plane, dims, y));
}
if (view->gtt.type == I915_GGTT_VIEW_ROTATED) { if (view->gtt.type == I915_GGTT_VIEW_ROTATED) {
drm_WARN_ON(&i915->drm, remap_info->linear);
check_array_bounds(i915, view->gtt.rotated.plane, color_plane); check_array_bounds(i915, view->gtt.rotated.plane, color_plane);
assign_chk_ovf(i915, remap_info->dst_stride, assign_chk_ovf(i915, remap_info->dst_stride,
...@@ -1344,16 +1389,23 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p ...@@ -1344,16 +1389,23 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
gtt_offset = aligned_offset; gtt_offset = aligned_offset;
} }
assign_chk_ovf(i915, remap_info->dst_stride,
plane_view_dst_stride_tiles(fb, color_plane, remap_info->width));
color_plane_info->x = x; color_plane_info->x = x;
color_plane_info->y = y; color_plane_info->y = y;
color_plane_info->stride = remap_info->dst_stride * tile_width * if (remap_info->linear) {
fb->base.format->cpp[color_plane]; color_plane_info->stride = fb->base.pitches[color_plane];
size += remap_info->size;
} else {
unsigned int dst_stride = plane_view_dst_stride_tiles(fb, color_plane,
remap_info->width);
assign_chk_ovf(i915, remap_info->dst_stride, dst_stride);
color_plane_info->stride = dst_stride *
tile_width * fb->base.format->cpp[color_plane];
size += remap_info->dst_stride * remap_info->height; size += dst_stride * remap_info->height;
}
} }
/* /*
...@@ -1361,10 +1413,16 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p ...@@ -1361,10 +1413,16 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
* the x/y offsets. x,y will hold the first pixel of the framebuffer * the x/y offsets. x,y will hold the first pixel of the framebuffer
* plane from the start of the remapped/rotated gtt mapping. * plane from the start of the remapped/rotated gtt mapping.
*/ */
intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y, if (remap_info->linear)
tile_width, tile_height, intel_adjust_linear_offset(&color_plane_info->x, &color_plane_info->y,
tile_size, remap_info->dst_stride, fb->base.format->cpp[color_plane],
gtt_offset * tile_size, 0); color_plane_info->stride,
gtt_offset * tile_size, 0);
else
intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y,
tile_width, tile_height,
tile_size, remap_info->dst_stride,
gtt_offset * tile_size, 0);
return size; return size;
} }
...@@ -1377,15 +1435,10 @@ calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane, ...@@ -1377,15 +1435,10 @@ calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane,
const struct fb_plane_view_dims *dims, const struct fb_plane_view_dims *dims,
int x, int y) int x, int y)
{ {
struct drm_i915_private *i915 = to_i915(fb->base.dev);
unsigned int tiles; unsigned int tiles;
if (is_surface_linear(&fb->base, color_plane)) { if (is_surface_linear(&fb->base, color_plane)) {
unsigned int size; tiles = plane_view_linear_tiles(fb, color_plane, dims, x, y);
size = (y + dims->height) * fb->base.pitches[color_plane] +
x * fb->base.format->cpp[color_plane];
tiles = DIV_ROUND_UP(size, intel_tile_size(i915));
} else { } else {
tiles = plane_view_src_stride_tiles(fb, color_plane, dims) * tiles = plane_view_src_stride_tiles(fb, color_plane, dims) *
plane_view_height_tiles(fb, color_plane, dims, y); plane_view_height_tiles(fb, color_plane, dims, y);
......
...@@ -1407,11 +1407,12 @@ add_padding_pages(unsigned int count, ...@@ -1407,11 +1407,12 @@ add_padding_pages(unsigned int count,
} }
static struct scatterlist * static struct scatterlist *
remap_pages(struct drm_i915_gem_object *obj, remap_tiled_color_plane_pages(struct drm_i915_gem_object *obj,
unsigned int offset, unsigned int alignment_pad, unsigned int offset, unsigned int alignment_pad,
unsigned int width, unsigned int height, unsigned int width, unsigned int height,
unsigned int src_stride, unsigned int dst_stride, unsigned int src_stride, unsigned int dst_stride,
struct sg_table *st, struct scatterlist *sg) struct sg_table *st, struct scatterlist *sg,
unsigned int *gtt_offset)
{ {
unsigned int row; unsigned int row;
...@@ -1459,6 +1460,8 @@ remap_pages(struct drm_i915_gem_object *obj, ...@@ -1459,6 +1460,8 @@ remap_pages(struct drm_i915_gem_object *obj,
sg = add_padding_pages(left >> PAGE_SHIFT, st, sg); sg = add_padding_pages(left >> PAGE_SHIFT, st, sg);
} }
*gtt_offset += alignment_pad + dst_stride * height;
return sg; return sg;
} }
...@@ -1495,6 +1498,61 @@ remap_contiguous_pages(struct drm_i915_gem_object *obj, ...@@ -1495,6 +1498,61 @@ remap_contiguous_pages(struct drm_i915_gem_object *obj,
} while (1); } while (1);
} }
static struct scatterlist *
remap_linear_color_plane_pages(struct drm_i915_gem_object *obj,
unsigned int obj_offset, unsigned int alignment_pad,
unsigned int size,
struct sg_table *st, struct scatterlist *sg,
unsigned int *gtt_offset)
{
if (!size)
return sg;
if (alignment_pad)
sg = add_padding_pages(alignment_pad, st, sg);
sg = remap_contiguous_pages(obj, obj_offset, size, st, sg);
sg = sg_next(sg);
*gtt_offset += alignment_pad + size;
return sg;
}
static struct scatterlist *
remap_color_plane_pages(const struct intel_remapped_info *rem_info,
struct drm_i915_gem_object *obj,
int color_plane,
struct sg_table *st, struct scatterlist *sg,
unsigned int *gtt_offset)
{
unsigned int alignment_pad = 0;
if (rem_info->plane_alignment)
alignment_pad = ALIGN(*gtt_offset, rem_info->plane_alignment) - *gtt_offset;
if (rem_info->plane[color_plane].linear)
sg = remap_linear_color_plane_pages(obj,
rem_info->plane[color_plane].offset,
alignment_pad,
rem_info->plane[color_plane].size,
st, sg,
gtt_offset);
else
sg = remap_tiled_color_plane_pages(obj,
rem_info->plane[color_plane].offset,
alignment_pad,
rem_info->plane[color_plane].width,
rem_info->plane[color_plane].height,
rem_info->plane[color_plane].src_stride,
rem_info->plane[color_plane].dst_stride,
st, sg,
gtt_offset);
return sg;
}
static noinline struct sg_table * static noinline struct sg_table *
intel_remap_pages(struct intel_remapped_info *rem_info, intel_remap_pages(struct intel_remapped_info *rem_info,
struct drm_i915_gem_object *obj) struct drm_i915_gem_object *obj)
...@@ -1519,21 +1577,8 @@ intel_remap_pages(struct intel_remapped_info *rem_info, ...@@ -1519,21 +1577,8 @@ intel_remap_pages(struct intel_remapped_info *rem_info,
st->nents = 0; st->nents = 0;
sg = st->sgl; sg = st->sgl;
for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++)
unsigned int alignment_pad = 0; sg = remap_color_plane_pages(rem_info, obj, i, st, sg, &gtt_offset);
if (rem_info->plane_alignment)
alignment_pad = ALIGN(gtt_offset, rem_info->plane_alignment) - gtt_offset;
sg = remap_pages(obj,
rem_info->plane[i].offset, alignment_pad,
rem_info->plane[i].width, rem_info->plane[i].height,
rem_info->plane[i].src_stride, rem_info->plane[i].dst_stride,
st, sg);
gtt_offset += alignment_pad +
rem_info->plane[i].dst_stride * rem_info->plane[i].height;
}
i915_sg_trim(st); i915_sg_trim(st);
......
...@@ -97,11 +97,20 @@ enum i915_cache_level; ...@@ -97,11 +97,20 @@ enum i915_cache_level;
struct intel_remapped_plane_info { struct intel_remapped_plane_info {
/* in gtt pages */ /* in gtt pages */
u32 offset; u32 offset:31;
u16 width; u32 linear:1;
u16 height; union {
u16 src_stride; /* in gtt pages for !linear */
u16 dst_stride; struct {
u16 width;
u16 height;
u16 src_stride;
u16 dst_stride;
};
/* in gtt pages for linear */
u32 size;
};
} __packed; } __packed;
struct intel_remapped_info { struct intel_remapped_info {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment