Skip to content

Commit

Permalink
drm/i915: Use atomics to manipulate obj->frontbuffer_bits
Browse files Browse the repository at this point in the history
The individual bits inside obj->frontbuffer_bits are protected by each
plane->mutex, but the whole bitfield may be accessed by multiple KMS
operations simultaneously and so the RMW need to be under atomics.
However, for updating the single field we do not need to mandate that it
be under the struct_mutex, one more step towards its removal as the de
facto BKL.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470324762-2545-21-git-send-email-chris@chris-wilson.co.uk
  • Loading branch information
Chris Wilson committed Aug 4, 2016
1 parent b5add95 commit faf5bf0
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 44 deletions.
6 changes: 4 additions & 2 deletions drivers/gpu/drm/i915/i915_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
struct intel_engine_cs *engine;
struct i915_vma *vma;
unsigned int frontbuffer_bits;
int pin_count = 0;
enum intel_engine_id id;

Expand Down Expand Up @@ -204,8 +205,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
if (engine)
seq_printf(m, " (%s)", engine->name);

if (obj->frontbuffer_bits)
seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits);
frontbuffer_bits = atomic_read(&obj->frontbuffer_bits);
if (frontbuffer_bits)
seq_printf(m, " (frontbuffer: 0x%03x)", frontbuffer_bits);
}

static int i915_gem_object_list_info(struct seq_file *m, void *data)
Expand Down
4 changes: 1 addition & 3 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2127,8 +2127,6 @@ struct drm_i915_gem_object_ops {
*/
#define INTEL_MAX_SPRITE_BITS_PER_PIPE 5
#define INTEL_FRONTBUFFER_BITS_PER_PIPE 8
#define INTEL_FRONTBUFFER_BITS \
(INTEL_FRONTBUFFER_BITS_PER_PIPE * I915_MAX_PIPES)
#define INTEL_FRONTBUFFER_PRIMARY(pipe) \
(1 << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
#define INTEL_FRONTBUFFER_CURSOR(pipe) \
Expand Down Expand Up @@ -2216,7 +2214,7 @@ struct drm_i915_gem_object {
unsigned int cache_level:3;
unsigned int cache_dirty:1;

unsigned int frontbuffer_bits:INTEL_FRONTBUFFER_BITS;
atomic_t frontbuffer_bits;

unsigned int has_wc_mmap;
/** Count of VMA actually bound by this object */
Expand Down
21 changes: 14 additions & 7 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -4040,7 +4040,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
if (obj->stolen)
i915_gem_object_unpin_pages(obj);

WARN_ON(obj->frontbuffer_bits);
WARN_ON(atomic_read(&obj->frontbuffer_bits));

if (obj->pages && obj->madv == I915_MADV_WILLNEED &&
dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES &&
Expand Down Expand Up @@ -4557,16 +4557,23 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
struct drm_i915_gem_object *new,
unsigned frontbuffer_bits)
{
/* Control of individual bits within the mask are guarded by
* the owning plane->mutex, i.e. we can never see concurrent
* manipulation of individual bits. But since the bitfield as a whole
* is updated using RMW, we need to use atomics in order to update
* the bits.
*/
BUILD_BUG_ON(INTEL_FRONTBUFFER_BITS_PER_PIPE * I915_MAX_PIPES >
sizeof(atomic_t) * BITS_PER_BYTE);

if (old) {
WARN_ON(!mutex_is_locked(&old->base.dev->struct_mutex));
WARN_ON(!(old->frontbuffer_bits & frontbuffer_bits));
old->frontbuffer_bits &= ~frontbuffer_bits;
WARN_ON(!(atomic_read(&old->frontbuffer_bits) & frontbuffer_bits));
atomic_andnot(frontbuffer_bits, &old->frontbuffer_bits);
}

if (new) {
WARN_ON(!mutex_is_locked(&new->base.dev->struct_mutex));
WARN_ON(new->frontbuffer_bits & frontbuffer_bits);
new->frontbuffer_bits |= frontbuffer_bits;
WARN_ON(atomic_read(&new->frontbuffer_bits) & frontbuffer_bits);
atomic_or(frontbuffer_bits, &new->frontbuffer_bits);
}
}

Expand Down
18 changes: 6 additions & 12 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -2601,7 +2601,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
primary->fb = primary->state->fb = fb;
primary->crtc = primary->state->crtc = &intel_crtc->base;
intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary));
obj->frontbuffer_bits |= to_intel_plane(primary)->frontbuffer_bit;
atomic_or(to_intel_plane(primary)->frontbuffer_bit,
&obj->frontbuffer_bits);
}

static void i9xx_update_primary_plane(struct drm_plane *primary,
Expand Down Expand Up @@ -13810,19 +13811,12 @@ static void intel_atomic_track_fbs(struct drm_atomic_state *state)
{
struct drm_plane_state *old_plane_state;
struct drm_plane *plane;
struct drm_i915_gem_object *obj, *old_obj;
struct intel_plane *intel_plane;
int i;

mutex_lock(&state->dev->struct_mutex);
for_each_plane_in_state(state, plane, old_plane_state, i) {
obj = intel_fb_obj(plane->state->fb);
old_obj = intel_fb_obj(old_plane_state->fb);
intel_plane = to_intel_plane(plane);

i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
}
mutex_unlock(&state->dev->struct_mutex);
for_each_plane_in_state(state, plane, old_plane_state, i)
i915_gem_track_fb(intel_fb_obj(old_plane_state->fb),
intel_fb_obj(plane->state->fb),
to_intel_plane(plane)->frontbuffer_bit);
}

/**
Expand Down
23 changes: 9 additions & 14 deletions drivers/gpu/drm/i915/intel_frontbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,22 @@
#include "i915_drv.h"

void __intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
enum fb_op_origin origin)
enum fb_op_origin origin,
unsigned int frontbuffer_bits)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);

WARN_ON(!mutex_is_locked(&dev->struct_mutex));

if (origin == ORIGIN_CS) {
spin_lock(&dev_priv->fb_tracking.lock);
dev_priv->fb_tracking.busy_bits |= obj->frontbuffer_bits;
dev_priv->fb_tracking.flip_bits &= ~obj->frontbuffer_bits;
dev_priv->fb_tracking.busy_bits |= frontbuffer_bits;
dev_priv->fb_tracking.flip_bits &= ~frontbuffer_bits;
spin_unlock(&dev_priv->fb_tracking.lock);
}

intel_psr_invalidate(dev, obj->frontbuffer_bits);
intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits);
intel_fbc_invalidate(dev_priv, obj->frontbuffer_bits, origin);
intel_psr_invalidate(dev, frontbuffer_bits);
intel_edp_drrs_invalidate(dev, frontbuffer_bits);
intel_fbc_invalidate(dev_priv, frontbuffer_bits, origin);
}

/**
Expand Down Expand Up @@ -119,15 +118,11 @@ static void intel_frontbuffer_flush(struct drm_device *dev,

void __intel_fb_obj_flush(struct drm_i915_gem_object *obj,
bool retire,
enum fb_op_origin origin)
enum fb_op_origin origin,
unsigned int frontbuffer_bits)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
unsigned frontbuffer_bits;

WARN_ON(!mutex_is_locked(&dev->struct_mutex));

frontbuffer_bits = obj->frontbuffer_bits;

if (retire) {
spin_lock(&dev_priv->fb_tracking.lock);
Expand Down
20 changes: 14 additions & 6 deletions drivers/gpu/drm/i915/intel_frontbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ void intel_frontbuffer_flip(struct drm_device *dev,
unsigned frontbuffer_bits);

void __intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
enum fb_op_origin origin);
enum fb_op_origin origin,
unsigned int frontbuffer_bits);
void __intel_fb_obj_flush(struct drm_i915_gem_object *obj,
bool retire,
enum fb_op_origin origin);
enum fb_op_origin origin,
unsigned int frontbuffer_bits);

/**
* intel_fb_obj_invalidate - invalidate frontbuffer object
Expand All @@ -55,10 +57,13 @@ void __intel_fb_obj_flush(struct drm_i915_gem_object *obj,
static inline void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
enum fb_op_origin origin)
{
if (!obj->frontbuffer_bits)
unsigned int frontbuffer_bits;

frontbuffer_bits = atomic_read(&obj->frontbuffer_bits);
if (!frontbuffer_bits)
return;

__intel_fb_obj_invalidate(obj, origin);
__intel_fb_obj_invalidate(obj, origin, frontbuffer_bits);
}

/**
Expand All @@ -75,10 +80,13 @@ static inline void intel_fb_obj_flush(struct drm_i915_gem_object *obj,
bool retire,
enum fb_op_origin origin)
{
if (!obj->frontbuffer_bits)
unsigned int frontbuffer_bits;

frontbuffer_bits = atomic_read(&obj->frontbuffer_bits);
if (!frontbuffer_bits)
return;

__intel_fb_obj_flush(obj, retire, origin);
__intel_fb_obj_flush(obj, retire, origin, frontbuffer_bits);
}

#endif /* __INTEL_FRONTBUFFER_H__ */

0 comments on commit faf5bf0

Please sign in to comment.