Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 303ba695 authored by Ville Syrjälä's avatar Ville Syrjälä
Browse files

drm/i915: Treat fb->offsets[] as a raw byte offset instead of a linear offset

Userspace wants to treat fb->offsets[] as raw byte offsets into the gem
bo. Adjust the kernel code to match.

Cc: Ben Widawsky <ben@bwidawsk.net>
Cc: Jason Ekstrand <jason@jlekstrand.net>
Cc: Daniel Stone <daniels@collabora.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170824191100.10949-2-ville.syrjala@linux.intel.com


Acked-by: default avatarBen Widawsky <ben@bwidawsk.net>
Fixes: 2e2adb05 ("drm/i915: Add render decompression support")
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
parent b69a784f
Loading
Loading
Loading
Loading
+64 −44
Original line number Diff line number Diff line
@@ -2288,11 +2288,7 @@ void intel_add_fb_offsets(int *x, int *y,
	}
}

/*
 * Input tile dimensions and pitch must already be
 * rotated to match x and y, and in pixel units.
 */
static u32 _intel_adjust_tile_offset(int *x, int *y,
static u32 __intel_adjust_tile_offset(int *x, int *y,
				      unsigned int tile_width,
				      unsigned int tile_height,
				      unsigned int tile_size,
@@ -2319,18 +2315,13 @@ static u32 _intel_adjust_tile_offset(int *x, int *y,
	return new_offset;
}

/*
 * Adjust the tile offset by moving the difference into
 * the x/y offsets.
 */
static u32 intel_adjust_tile_offset(int *x, int *y,
				    const struct intel_plane_state *state, int plane,
static u32 _intel_adjust_tile_offset(int *x, int *y,
				     const struct drm_framebuffer *fb, int plane,
				     unsigned int rotation,
				     u32 old_offset, u32 new_offset)
{
	const struct drm_i915_private *dev_priv = to_i915(state->base.plane->dev);
	const struct drm_framebuffer *fb = state->base.fb;
	const struct drm_i915_private *dev_priv = to_i915(fb->dev);
	unsigned int cpp = fb->format->cpp[plane];
	unsigned int rotation = state->base.rotation;
	unsigned int pitch = intel_fb_pitch(fb, plane, rotation);

	WARN_ON(new_offset > old_offset);
@@ -2349,7 +2340,7 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
			pitch_tiles = pitch / (tile_width * cpp);
		}

		_intel_adjust_tile_offset(x, y, tile_width, tile_height,
		__intel_adjust_tile_offset(x, y, tile_width, tile_height,
					   tile_size, pitch_tiles,
					   old_offset, new_offset);
	} else {
@@ -2362,6 +2353,19 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
	return new_offset;
}

/*
 * Adjust the tile offset by moving the difference into
 * the x/y offsets.
 */
static u32 intel_adjust_tile_offset(int *x, int *y,
				    const struct intel_plane_state *state, int plane,
				    u32 old_offset, u32 new_offset)
{
	return _intel_adjust_tile_offset(x, y, state->base.fb, plane,
					 state->base.rotation,
					 old_offset, new_offset);
}

/*
 * Computes the linear offset to the base tile and adjusts
 * x, y. bytes per pixel is assumed to be a power-of-two.
@@ -2413,7 +2417,7 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
		offset = (tile_rows * pitch_tiles + tiles) * tile_size;
		offset_aligned = offset & ~alignment;

		_intel_adjust_tile_offset(x, y, tile_width, tile_height,
		__intel_adjust_tile_offset(x, y, tile_width, tile_height,
					   tile_size, pitch_tiles,
					   offset, offset_aligned);
	} else {
@@ -2447,16 +2451,24 @@ u32 intel_compute_tile_offset(int *x, int *y,
					  rotation, alignment);
}

/* Convert the fb->offset[] linear offset into x/y offsets */
static void intel_fb_offset_to_xy(int *x, int *y,
/* Convert the fb->offset[] into x/y offsets */
static int intel_fb_offset_to_xy(int *x, int *y,
				 const struct drm_framebuffer *fb, int plane)
{
	unsigned int cpp = fb->format->cpp[plane];
	unsigned int pitch = fb->pitches[plane];
	u32 linear_offset = fb->offsets[plane];
	struct drm_i915_private *dev_priv = to_i915(fb->dev);

	if (fb->modifier != DRM_FORMAT_MOD_LINEAR &&
	    fb->offsets[plane] % intel_tile_size(dev_priv))
		return -EINVAL;

	*y = linear_offset / pitch;
	*x = linear_offset % pitch / cpp;
	*x = 0;
	*y = 0;

	_intel_adjust_tile_offset(x, y,
				  fb, plane, DRM_MODE_ROTATE_0,
				  fb->offsets[plane], 0);

	return 0;
}

static unsigned int intel_fb_modifier_to_tiling(uint64_t fb_modifier)
@@ -2523,12 +2535,18 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
		unsigned int cpp, size;
		u32 offset;
		int x, y;
		int ret;

		cpp = fb->format->cpp[i];
		width = drm_framebuffer_plane_width(fb->width, fb, i);
		height = drm_framebuffer_plane_height(fb->height, fb, i);

		intel_fb_offset_to_xy(&x, &y, fb, i);
		ret = intel_fb_offset_to_xy(&x, &y, fb, i);
		if (ret) {
			DRM_DEBUG_KMS("bad fb plane %d offset: 0x%x\n",
				      i, fb->offsets[i]);
			return ret;
		}

		if ((fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
		     fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) && i == 1) {
@@ -2539,11 +2557,13 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
			int ccs_x, ccs_y;

			intel_tile_dims(fb, i, &tile_width, &tile_height);
			tile_width *= hsub;
			tile_height *= vsub;

			ccs_x = (x * hsub) % (tile_width * hsub);
			ccs_y = (y * vsub) % (tile_height * vsub);
			main_x = intel_fb->normal[0].x % (tile_width * hsub);
			main_y = intel_fb->normal[0].y % (tile_height * vsub);
			ccs_x = (x * hsub) % tile_width;
			ccs_y = (y * vsub) % tile_height;
			main_x = intel_fb->normal[0].x % tile_width;
			main_y = intel_fb->normal[0].y % tile_height;

			/*
			 * CCS doesn't have its own x/y offset register, so the intra CCS tile
@@ -2632,7 +2652,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv,
			 * We only keep the x/y offsets, so push all of the
			 * gtt offset into the x/y offsets.
			 */
			_intel_adjust_tile_offset(&x, &y,
			__intel_adjust_tile_offset(&x, &y,
						   tile_width, tile_height,
						   tile_size, pitch_tiles,
						   gtt_offset_rotated * tile_size, 0);