[PATCH 3/3] drm: Track framebuffer references at the point of assignment

Daniel Vetter daniel at ffwll.ch
Mon Nov 28 07:48:34 UTC 2016


On Fri, Nov 25, 2016 at 03:32:31PM +0000, Chris Wilson wrote:
> We can simplify the code greatly if both legacy and atomic paths updated
> the references as they assigned the framebuffer to the planes. Long
> before framebuffer reference counting was added, the code had to keep
> the old_fb around until after the operation was completed - but now we
> can simply leave it to the reference handling to prevent invalid use.
> 
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_display.c |  2 +-
>  drivers/gpu/drm/armada/armada_crtc.c        |  9 +----
>  drivers/gpu/drm/bochs/bochs_kms.c           |  2 +-
>  drivers/gpu/drm/drm_atomic.c                | 44 +-------------------
>  drivers/gpu/drm/drm_atomic_helper.c         | 35 ++--------------
>  drivers/gpu/drm/drm_crtc.c                  | 18 +--------
>  drivers/gpu/drm/drm_crtc_helper.c           | 18 +++++----
>  drivers/gpu/drm/drm_fb_helper.c             | 23 +++++------
>  drivers/gpu/drm/drm_plane.c                 | 62 ++++++++++-------------------
>  drivers/gpu/drm/i915/intel_display.c        | 17 ++++----
>  drivers/gpu/drm/mgag200/mgag200_mode.c      |  2 +-
>  drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c   |  2 +-
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c   |  2 +-
>  drivers/gpu/drm/nouveau/nouveau_display.c   |  2 +-
>  drivers/gpu/drm/nouveau/nv50_display.c      |  7 ----
>  drivers/gpu/drm/qxl/qxl_display.c           |  4 +-
>  drivers/gpu/drm/radeon/radeon_display.c     |  3 +-
>  drivers/gpu/drm/shmobile/shmob_drm_crtc.c   |  2 +-
>  drivers/gpu/drm/tilcdc/tilcdc_crtc.c        |  4 +-
>  drivers/gpu/drm/udl/udl_modeset.c           |  2 +-
>  drivers/gpu/drm/vc4/vc4_crtc.c              |  2 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c         |  4 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c        | 10 ++---
>  drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c        |  4 +-
>  include/drm/drm_atomic.h                    |  3 --
>  include/drm/drm_plane.h                     | 27 ++++++++++---
>  26 files changed, 100 insertions(+), 210 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
> index 741144fcc7bc..2aa4e707be1b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
> @@ -225,7 +225,7 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
>  	DRM_DEBUG_DRIVER("crtc:%d[%p], pflip_stat:AMDGPU_FLIP_PENDING, work: %p,\n",
>  					 amdgpu_crtc->crtc_id, amdgpu_crtc, work);
>  	/* update crtc fb */
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
>  	amdgpu_flip_work_func(&work->flip_work.work);
>  	return 0;
> diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
> index 95cb3966b2ca..1b8cc4dbe5a5 100644
> --- a/drivers/gpu/drm/armada/armada_crtc.c
> +++ b/drivers/gpu/drm/armada/armada_crtc.c
> @@ -1065,13 +1065,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
>  		return ret;
>  	}
>  
> -	/*
> -	 * Don't take a reference on the new framebuffer;
> -	 * drm_mode_page_flip_ioctl() has already grabbed a reference and
> -	 * will _not_ drop that reference on successful return from this
> -	 * function.  Simply mark this new framebuffer as the current one.
> -	 */
> -	dcrtc->crtc.primary->fb = fb;
> +	drm_plane_set_fb(dcrtc->crtc.primary, fb);
>  
>  	/*
>  	 * Finally, if the display is blanked, we won't receive an
> @@ -1080,6 +1074,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
>  	if (dpms_blanked(dcrtc->dpms))
>  		armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary);
>  
> +	drm_framebuffer_unreference(fb);
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
> index 0b4e5d117043..afe3bd2cd79e 100644
> --- a/drivers/gpu/drm/bochs/bochs_kms.c
> +++ b/drivers/gpu/drm/bochs/bochs_kms.c
> @@ -103,7 +103,7 @@ static int bochs_crtc_page_flip(struct drm_crtc *crtc,
>  	struct drm_framebuffer *old_fb = crtc->primary->fb;
>  	unsigned long irqflags;
>  
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  	bochs_crtc_mode_set_base(crtc, 0, 0, old_fb);
>  	if (event) {
>  		spin_lock_irqsave(&bochs->dev->event_lock, irqflags);
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 19d7bcb88217..63dd5d5becdf 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1253,7 +1253,7 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
>  		DRM_DEBUG_ATOMIC("Set [NOFB] for plane state %p\n",
>  				 plane_state);
>  
> -	drm_framebuffer_assign(&plane_state->fb, fb);
> +	drm_framebuffer_assign(__mkwrite_drm_framebuffer(&plane_state->fb), fb);

Feels like const gone the wrong way round? Or I'm not entirely clear on
what this is supposed to achieve. Just dropping the const would still be a
nice improvement.
-Daniel

>  }
>  EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
>  
> @@ -1774,45 +1774,6 @@ static int atomic_set_prop(struct drm_atomic_state *state,
>  }
>  
>  /**
> - * drm_atomic_clean_old_fb -- Unset old_fb pointers and set plane->fb pointers.
> - *
> - * @dev: drm device to check.
> - * @plane_mask: plane mask for planes that were updated.
> - * @ret: return value, can be -EDEADLK for a retry.
> - *
> - * Before doing an update plane->old_fb is set to plane->fb,
> - * but before dropping the locks old_fb needs to be set to NULL
> - * and plane->fb updated. This is a common operation for each
> - * atomic update, so this call is split off as a helper.
> - */
> -void drm_atomic_clean_old_fb(struct drm_device *dev,
> -			     unsigned plane_mask,
> -			     int ret)
> -{
> -	struct drm_plane *plane;
> -
> -	/* if succeeded, fixup legacy plane crtc/fb ptrs before dropping
> -	 * locks (ie. while it is still safe to deref plane->state).  We
> -	 * need to do this here because the driver entry points cannot
> -	 * distinguish between legacy and atomic ioctls.
> -	 */
> -	drm_for_each_plane_mask(plane, dev, plane_mask) {
> -		if (ret == 0) {
> -			struct drm_framebuffer *new_fb = plane->state->fb;
> -			if (new_fb)
> -				drm_framebuffer_reference(new_fb);
> -			plane->fb = new_fb;
> -			plane->crtc = plane->state->crtc;
> -
> -			if (plane->old_fb)
> -				drm_framebuffer_unreference(plane->old_fb);
> -		}
> -		plane->old_fb = NULL;
> -	}
> -}
> -EXPORT_SYMBOL(drm_atomic_clean_old_fb);
> -
> -/**
>   * DOC: explicit fencing properties
>   *
>   * Explicit fencing allows userspace to control the buffer synchronization
> @@ -2148,7 +2109,6 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
>  		    !(arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
>  			plane = obj_to_plane(obj);
>  			plane_mask |= (1 << drm_plane_index(plane));
> -			plane->old_fb = plane->fb;
>  		}
>  		drm_mode_object_unreference(obj);
>  	}
> @@ -2174,8 +2134,6 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
>  	}
>  
>  out:
> -	drm_atomic_clean_old_fb(dev, plane_mask, ret);
> -
>  	complete_crtc_signaling(dev, state, fence_state, num_fences, !ret);
>  
>  	if (ret == -EDEADLK) {
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 494680c9056e..05c7bbf2745e 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -2052,6 +2052,9 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
>  	}
>  
>  	for_each_plane_in_state(state, plane, plane_state, i) {
> +		drm_plane_set_fb(plane, plane_state->fb);
> +		plane->crtc = plane_state->crtc;
> +
>  		plane->state->state = state;
>  		swap(state->planes[i].state, plane->state);
>  		plane->state->state = NULL;
> @@ -2129,14 +2132,6 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
>  backoff:
>  	drm_atomic_state_clear(state);
>  	drm_atomic_legacy_backoff(state);
> -
> -	/*
> -	 * Someone might have exchanged the framebuffer while we dropped locks
> -	 * in the backoff code. We need to fix up the fb refcount tracking the
> -	 * core does for us.
> -	 */
> -	plane->old_fb = plane->fb;
> -
>  	goto retry;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_update_plane);
> @@ -2197,14 +2192,6 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane)
>  backoff:
>  	drm_atomic_state_clear(state);
>  	drm_atomic_legacy_backoff(state);
> -
> -	/*
> -	 * Someone might have exchanged the framebuffer while we dropped locks
> -	 * in the backoff code. We need to fix up the fb refcount tracking the
> -	 * core does for us.
> -	 */
> -	plane->old_fb = plane->fb;
> -
>  	goto retry;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
> @@ -2332,14 +2319,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set)
>  backoff:
>  	drm_atomic_state_clear(state);
>  	drm_atomic_legacy_backoff(state);
> -
> -	/*
> -	 * Someone might have exchanged the framebuffer while we dropped locks
> -	 * in the backoff code. We need to fix up the fb refcount tracking the
> -	 * core does for us.
> -	 */
> -	crtc->primary->old_fb = crtc->primary->fb;
> -
>  	goto retry;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_set_config);
> @@ -2810,14 +2789,6 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
>  backoff:
>  	drm_atomic_state_clear(state);
>  	drm_atomic_legacy_backoff(state);
> -
> -	/*
> -	 * Someone might have exchanged the framebuffer while we dropped locks
> -	 * in the backoff code. We need to fix up the fb refcount tracking the
> -	 * core does for us.
> -	 */
> -	plane->old_fb = plane->fb;
> -
>  	goto retry;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_page_flip);
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 90931e039731..f94550a40ec9 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -385,8 +385,6 @@ int drm_mode_getcrtc(struct drm_device *dev,
>  int drm_mode_set_config_internal(struct drm_mode_set *set)
>  {
>  	struct drm_crtc *crtc = set->crtc;
> -	struct drm_framebuffer *fb;
> -	struct drm_crtc *tmp;
>  	int ret;
>  
>  	/*
> @@ -394,24 +392,10 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
>  	 * connectors from it), hence we need to refcount the fbs across all
>  	 * crtcs. Atomic modeset will have saner semantics ...
>  	 */
> -	drm_for_each_crtc(tmp, crtc->dev)
> -		tmp->primary->old_fb = tmp->primary->fb;
> -
> -	fb = set->fb;
>  
>  	ret = crtc->funcs->set_config(set);
> -	if (ret == 0) {
> +	if (ret == 0)
>  		crtc->primary->crtc = crtc;
> -		crtc->primary->fb = fb;
> -	}
> -
> -	drm_for_each_crtc(tmp, crtc->dev) {
> -		if (tmp->primary->fb)
> -			drm_framebuffer_reference(tmp->primary->fb);
> -		if (tmp->primary->old_fb)
> -			drm_framebuffer_unreference(tmp->primary->old_fb);
> -		tmp->primary->old_fb = NULL;
> -	}
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 5d2cb138eba6..9818fd8c5988 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -177,7 +177,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev)
>  				(*crtc_funcs->disable)(crtc);
>  			else
>  				(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
> -			crtc->primary->fb = NULL;
> +			drm_plane_set_fb(crtc->primary, NULL);
>  		}
>  	}
>  }
> @@ -579,7 +579,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
>  	save_set.mode = &set->crtc->mode;
>  	save_set.x = set->crtc->x;
>  	save_set.y = set->crtc->y;
> -	save_set.fb = set->crtc->primary->fb;
> +	save_set.fb = drm_plane_get_fb(set->crtc->primary);
>  
>  	/* We should be able to check here if the fb has the same properties
>  	 * and then just flip_or_move it */
> @@ -700,13 +700,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
>  			DRM_DEBUG_KMS("attempting to set mode from"
>  					" userspace\n");
>  			drm_mode_debug_printmodeline(set->mode);
> -			set->crtc->primary->fb = set->fb;
> +			drm_plane_set_fb(set->crtc->primary, set->fb);
>  			if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
>  						      set->x, set->y,
>  						      save_set.fb)) {
>  				DRM_ERROR("failed to set mode on [CRTC:%d:%s]\n",
>  					  set->crtc->base.id, set->crtc->name);
> -				set->crtc->primary->fb = save_set.fb;
> +				drm_plane_set_fb(set->crtc->primary,
> +						 save_set.fb);
>  				ret = -EINVAL;
>  				goto fail;
>  			}
> @@ -721,17 +722,18 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
>  	} else if (fb_changed) {
>  		set->crtc->x = set->x;
>  		set->crtc->y = set->y;
> -		set->crtc->primary->fb = set->fb;
> +		drm_plane_set_fb(set->crtc->primary, set->fb);
>  		ret = crtc_funcs->mode_set_base(set->crtc,
>  						set->x, set->y, save_set.fb);
>  		if (ret != 0) {
>  			set->crtc->x = save_set.x;
>  			set->crtc->y = save_set.y;
> -			set->crtc->primary->fb = save_set.fb;
> +			drm_plane_set_fb(set->crtc->primary, save_set.fb);
>  			goto fail;
>  		}
>  	}
>  
> +	drm_framebuffer_unreference(save_set.fb);
>  	kfree(save_connector_encoders);
>  	kfree(save_encoder_crtcs);
>  	return 0;
> @@ -763,6 +765,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
>  				      save_set.y, save_set.fb))
>  		DRM_ERROR("failed to restore config after modeset failure\n");
>  
> +	drm_framebuffer_unreference(save_set.fb);
>  	kfree(save_connector_encoders);
>  	kfree(save_encoder_crtcs);
>  	return ret;
> @@ -924,7 +927,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
>  			continue;
>  
>  		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
> -					       crtc->x, crtc->y, crtc->primary->fb);
> +					       crtc->x, crtc->y,
> +					       crtc->primary->fb);
>  
>  		/* Restoring the old config should never fail! */
>  		if (ret == false)
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 62641d59a2d7..851a7e30444b 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -285,7 +285,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
>  
>  	drm_for_each_crtc(c, dev) {
>  		if (crtc->base.id == c->base.id)
> -			return c->primary->fb;
> +			return drm_plane_get_fb(c->primary);
>  	}
>  
>  	return NULL;
> @@ -305,24 +305,27 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
>  
>  	for (i = 0; i < helper->crtc_count; i++) {
>  		struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
> -		crtc = mode_set->crtc;
> -		funcs = crtc->helper_private;
> -		fb = drm_mode_config_fb(crtc);
>  
> +		crtc = mode_set->crtc;
>  		if (!crtc->enabled)
>  			continue;
>  
> +		funcs = crtc->helper_private;
> +		if (funcs->mode_set_base_atomic == NULL)
> +			continue;
> +
> +		fb = drm_mode_config_fb(crtc);
>  		if (!fb) {
>  			DRM_ERROR("no fb to restore??\n");
>  			continue;
>  		}
>  
> -		if (funcs->mode_set_base_atomic == NULL)
> -			continue;
> -
>  		drm_fb_helper_restore_lut_atomic(mode_set->crtc);
> +
>  		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
>  					    crtc->y, LEAVE_ATOMIC_MODE_SET);
> +
> +		drm_framebuffer_unreference(fb);
>  	}
>  
>  	return 0;
> @@ -355,7 +358,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
>  
>  		plane_state->rotation = DRM_ROTATE_0;
>  
> -		plane->old_fb = plane->fb;
>  		plane_mask |= 1 << drm_plane_index(plane);
>  
>  		/* disable non-primary: */
> @@ -378,8 +380,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
>  	ret = drm_atomic_commit(state);
>  
>  fail:
> -	drm_atomic_clean_old_fb(dev, plane_mask, ret);
> -
>  	if (ret == -EDEADLK)
>  		goto backoff;
>  
> @@ -1391,7 +1391,6 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
>  
>  		plane = mode_set->crtc->primary;
>  		plane_mask |= (1 << drm_plane_index(plane));
> -		plane->old_fb = plane->fb;
>  	}
>  
>  	ret = drm_atomic_commit(state);
> @@ -1402,8 +1401,6 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
>  	info->var.yoffset = var->yoffset;
>  
>  fail:
> -	drm_atomic_clean_old_fb(dev, plane_mask, ret);
> -
>  	if (ret == -EDEADLK)
>  		goto backoff;
>  
> diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
> index 419ac313c36f..b424a5b40f5e 100644
> --- a/drivers/gpu/drm/drm_plane.c
> +++ b/drivers/gpu/drm/drm_plane.c
> @@ -285,17 +285,13 @@ void drm_plane_force_disable(struct drm_plane *plane)
>  	if (!plane->fb)
>  		return;
>  
> -	plane->old_fb = plane->fb;
>  	ret = plane->funcs->disable_plane(plane);
>  	if (ret) {
>  		DRM_ERROR("failed to disable plane with busy fb\n");
> -		plane->old_fb = NULL;
>  		return;
>  	}
>  	/* disconnect the plane from the fb and crtc: */
> -	drm_framebuffer_unreference(plane->old_fb);
> -	plane->old_fb = NULL;
> -	plane->fb = NULL;
> +	drm_plane_set_fb(plane, NULL);
>  	plane->crtc = NULL;
>  }
>  EXPORT_SYMBOL(drm_plane_force_disable);
> @@ -459,13 +455,10 @@ static int __setplane_internal(struct drm_plane *plane,
>  
>  	/* No fb means shut it down */
>  	if (!fb) {
> -		plane->old_fb = plane->fb;
>  		ret = plane->funcs->disable_plane(plane);
>  		if (!ret) {
> +			drm_plane_set_fb(plane, NULL);
>  			plane->crtc = NULL;
> -			plane->fb = NULL;
> -		} else {
> -			plane->old_fb = NULL;
>  		}
>  		goto out;
>  	}
> @@ -502,25 +495,15 @@ static int __setplane_internal(struct drm_plane *plane,
>  	if (ret)
>  		goto out;
>  
> -	plane->old_fb = plane->fb;
>  	ret = plane->funcs->update_plane(plane, crtc, fb,
>  					 crtc_x, crtc_y, crtc_w, crtc_h,
>  					 src_x, src_y, src_w, src_h);
>  	if (!ret) {
>  		plane->crtc = crtc;
> -		plane->fb = fb;
> -		fb = NULL;
> -	} else {
> -		plane->old_fb = NULL;
> +		drm_plane_set_fb(plane, fb);
>  	}
>  
>  out:
> -	if (fb)
> -		drm_framebuffer_unreference(fb);
> -	if (plane->old_fb)
> -		drm_framebuffer_unreference(plane->old_fb);
> -	plane->old_fb = NULL;
> -
>  	return ret;
>  }
>  
> @@ -551,6 +534,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
>  	struct drm_plane *plane;
>  	struct drm_crtc *crtc = NULL;
>  	struct drm_framebuffer *fb = NULL;
> +	int err;
>  
>  	if (!drm_core_check_feature(dev, DRIVER_MODESET))
>  		return -EINVAL;
> @@ -586,11 +570,16 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
>  	 * setplane_internal will take care of deref'ing either the old or new
>  	 * framebuffer depending on success.
>  	 */
> -	return setplane_internal(plane, crtc, fb,
> -				 plane_req->crtc_x, plane_req->crtc_y,
> -				 plane_req->crtc_w, plane_req->crtc_h,
> -				 plane_req->src_x, plane_req->src_y,
> -				 plane_req->src_w, plane_req->src_h);
> +	err = setplane_internal(plane, crtc, fb,
> +				plane_req->crtc_x, plane_req->crtc_y,
> +				plane_req->crtc_w, plane_req->crtc_h,
> +				plane_req->src_x, plane_req->src_y,
> +				plane_req->src_w, plane_req->src_h);
> +
> +	if (fb)
> +		drm_framebuffer_unreference(fb);
> +
> +	return err;
>  }
>  
>  static int drm_mode_cursor_universal(struct drm_crtc *crtc,
> @@ -852,19 +841,19 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  		ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
>  	}
>  	if (ret)
> -		goto out;
> +		goto out_fb;
>  
>  	if (crtc->primary->fb->pixel_format != fb->pixel_format) {
>  		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
>  		ret = -EINVAL;
> -		goto out;
> +		goto out_fb;
>  	}
>  
>  	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
>  		e = kzalloc(sizeof *e, GFP_KERNEL);
>  		if (!e) {
>  			ret = -ENOMEM;
> -			goto out;
> +			goto out_fb;
>  		}
>  		e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
>  		e->event.base.length = sizeof(e->event);
> @@ -872,11 +861,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  		ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
>  		if (ret) {
>  			kfree(e);
> -			goto out;
> +			goto out_fb;
>  		}
>  	}
>  
> -	crtc->primary->old_fb = crtc->primary->fb;
>  	if (crtc->funcs->page_flip_target)
>  		ret = crtc->funcs->page_flip_target(crtc, fb, e,
>  						    page_flip->flags,
> @@ -886,23 +874,13 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  	if (ret) {
>  		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
>  			drm_event_cancel_free(dev, &e->base);
> -		/* Keep the old fb, don't unref it. */
> -		crtc->primary->old_fb = NULL;
> -	} else {
> -		crtc->primary->fb = fb;
> -		/* Unref only the old framebuffer. */
> -		fb = NULL;
>  	}
>  
> +out_fb:
> +	drm_framebuffer_unreference(fb);
>  out:
>  	if (ret && crtc->funcs->page_flip_target)
>  		drm_crtc_vblank_put(crtc);
> -	if (fb)
> -		drm_framebuffer_unreference(fb);
> -	if (crtc->primary->old_fb)
> -		drm_framebuffer_unreference(crtc->primary->old_fb);
> -	crtc->primary->old_fb = NULL;
>  	drm_modeset_unlock_crtc(crtc);
> -
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 8630de472f9a..b887b7caf1d1 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -2818,12 +2818,15 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
>  	if (i915_gem_object_is_tiled(obj))
>  		dev_priv->preserve_bios_swizzle = true;
>  
> -	drm_framebuffer_reference(fb);
> -	primary->fb = primary->state->fb = fb;
> +	drm_plane_set_fb(primary, fb);
> +	update_state_fb(primary);
> +
>  	primary->crtc = primary->state->crtc = &intel_crtc->base;
>  	intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary));
>  	atomic_or(to_intel_plane(primary)->frontbuffer_bit,
>  		  &obj->frontbuffer_bits);
> +
> +	drm_framebuffer_unreference(fb);
>  }
>  
>  static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane,
> @@ -12191,7 +12194,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	/* Reference the objects for the scheduled work. */
>  	drm_framebuffer_reference(work->old_fb);
>  
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  	update_state_fb(crtc->primary);
>  
>  	work->pending_flip_obj = i915_gem_object_get(obj);
> @@ -12293,7 +12296,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	atomic_dec(&intel_crtc->unpin_work_count);
>  	mutex_unlock(&dev->struct_mutex);
>  cleanup:
> -	crtc->primary->fb = old_fb;
> +	drm_plane_set_fb(crtc->primary, old_fb);
>  	update_state_fb(crtc->primary);
>  
>  	i915_gem_object_put(obj);
> @@ -13080,7 +13083,6 @@ intel_modeset_update_crtc_state(struct drm_atomic_state *state)
>  		if (drm_atomic_get_existing_plane_state(state, crtc->primary)) {
>  			struct drm_plane_state *plane_state = crtc->primary->state;
>  
> -			crtc->primary->fb = plane_state->fb;
>  			crtc->x = plane_state->src_x >> 16;
>  			crtc->y = plane_state->src_y >> 16;
>  		}
> @@ -17093,10 +17095,9 @@ void intel_modeset_gem_init(struct drm_device *dev)
>  		if (IS_ERR(vma)) {
>  			DRM_ERROR("failed to pin boot fb on pipe %d\n",
>  				  to_intel_crtc(c)->pipe);
> -			drm_framebuffer_unreference(c->primary->fb);
> -			c->primary->fb = NULL;
> -			c->primary->crtc = c->primary->state->crtc = NULL;
> +			drm_plane_set_fb(c->primary, NULL);
>  			update_state_fb(c->primary);
> +			c->primary->crtc = c->primary->state->crtc = NULL;
>  			c->state->plane_mask &= ~(1 << drm_plane_index(c->primary));
>  		}
>  	}
> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> index 6b21cb27e1cc..a2d3ba237f45 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
> @@ -1392,7 +1392,7 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
>  		mgag200_bo_push_sysram(bo);
>  		mgag200_bo_unreserve(bo);
>  	}
> -	crtc->primary->fb = NULL;
> +	drm_plane_set_fb(crtc->primary, NULL);
>  }
>  
>  /* These provide the minimum set of functions required to handle a CRTC */
> diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
> index 911e4690d36a..5c902561c715 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
> @@ -180,7 +180,7 @@ static void mdp4_plane_set_scanout(struct drm_plane *plane,
>  	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe),
>  			msm_framebuffer_iova(fb, mdp4_kms->id, 3));
>  
> -	plane->fb = fb;
> +	drm_plane_set_fb(plane, fb);
>  }
>  
>  static void mdp4_write_csc_config(struct mdp4_kms *mdp4_kms,
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> index 81c0562ab489..0191ecbcae0b 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
> @@ -425,7 +425,7 @@ static void set_scanout_locked(struct drm_plane *plane,
>  	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
>  			msm_framebuffer_iova(fb, mdp5_kms->id, 3));
>  
> -	plane->fb = fb;
> +	drm_plane_set_fb(plane, fb);
>  }
>  
>  /* Note: mdp5_plane->pipe_lock must be locked */
> diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
> index bd37ae127582..7979617f5709 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_display.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_display.c
> @@ -977,7 +977,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  	mutex_unlock(&cli->mutex);
>  
>  	/* Update the crtc struct and cleanup */
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  
>  	nouveau_bo_fence(old_bo, fence, false);
>  	ttm_bo_unreserve(&old_bo->bo);
> diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
> index 22a8b70a4d1e..b098b6d04595 100644
> --- a/drivers/gpu/drm/nouveau/nv50_display.c
> +++ b/drivers/gpu/drm/nouveau/nv50_display.c
> @@ -2277,13 +2277,6 @@ nv50_head_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  	drm_atomic_state_clear(state);
>  	drm_atomic_legacy_backoff(state);
>  
> -	/*
> -	 * Someone might have exchanged the framebuffer while we dropped locks
> -	 * in the backoff code. We need to fix up the fb refcount tracking the
> -	 * core does for us.
> -	 */
> -	plane->old_fb = plane->fb;
> -
>  	goto retry;
>  }
>  
> diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
> index a61c0d460ec2..2e01c6e5d905 100644
> --- a/drivers/gpu/drm/qxl/qxl_display.c
> +++ b/drivers/gpu/drm/qxl/qxl_display.c
> @@ -237,7 +237,6 @@ static int qxl_crtc_page_flip(struct drm_crtc *crtc,
>  	int one_clip_rect = 1;
>  	int ret = 0;
>  
> -	crtc->primary->fb = fb;
>  	bo_old->is_primary = false;
>  	bo->is_primary = true;
>  
> @@ -249,6 +248,7 @@ static int qxl_crtc_page_flip(struct drm_crtc *crtc,
>  	if (ret)
>  		return ret;
>  
> +	drm_plane_set_fb(crtc->primary, fb);
>  	qxl_draw_dirty_fb(qdev, qfb_src, bo, 0, 0,
>  			  &norect, one_clip_rect, inc);
>  
> @@ -755,7 +755,7 @@ static void qxl_crtc_disable(struct drm_crtc *crtc)
>  		ret = qxl_bo_reserve(bo, false);
>  		qxl_bo_unpin(bo);
>  		qxl_bo_unreserve(bo);
> -		crtc->primary->fb = NULL;
> +		drm_plane_set_fb(crtc->primary, NULL);
>  	}
>  
>  	qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);
> diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> index e7409e8a9f87..1eb004dc4cd6 100644
> --- a/drivers/gpu/drm/radeon/radeon_display.c
> +++ b/drivers/gpu/drm/radeon/radeon_display.c
> @@ -598,8 +598,7 @@ static int radeon_crtc_page_flip_target(struct drm_crtc *crtc,
>  	radeon_crtc->flip_work = work;
>  
>  	/* update crtc fb */
> -	crtc->primary->fb = fb;
> -
> +	drm_plane_set_fb(crtc->primary, fb);
>  	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
>  
>  	queue_work(radeon_crtc->flip_queue, &work->flip_work);
> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> index 6547b1db460a..fc5df59976cd 100644
> --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
> @@ -462,7 +462,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
>  	}
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
>  
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  	shmob_drm_crtc_update_base(scrtc);
>  
>  	if (event) {
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> index 822531ebd4b0..f57154b69e9d 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
> @@ -260,9 +260,7 @@ int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
>  		return -EBUSY;
>  	}
>  
> -	drm_framebuffer_reference(fb);
> -
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  
>  	spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
>  
> diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
> index f2b2481cad52..05133ef8942c 100644
> --- a/drivers/gpu/drm/udl/udl_modeset.c
> +++ b/drivers/gpu/drm/udl/udl_modeset.c
> @@ -380,7 +380,7 @@ static int udl_crtc_page_flip(struct drm_crtc *crtc,
>  	if (event)
>  		drm_crtc_send_vblank_event(crtc, event);
>  	spin_unlock_irqrestore(&dev->event_lock, flags);
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
> index 7f08d681a74b..b13597b3f699 100644
> --- a/drivers/gpu/drm/vc4/vc4_crtc.c
> +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
> @@ -785,7 +785,7 @@ static int vc4_async_page_flip(struct drm_crtc *crtc,
>  	 * is released.
>  	 */
>  	drm_atomic_set_fb_for_plane(plane->state, fb);
> -	plane->fb = fb;
> +	drm_plane_set_fb(plane, fb);
>  
>  	vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno,
>  			   vc4_async_page_flip_complete);
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> index 23ec673d5e16..61a3cce08dfe 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> @@ -260,7 +260,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
>  
>  		connector->encoder = NULL;
>  		encoder->crtc = NULL;
> -		crtc->primary->fb = NULL;
> +		drm_plane_set_fb(crtc->primary, NULL);
>  		crtc->enabled = false;
>  
>  		vmw_ldu_del_active(dev_priv, ldu);
> @@ -281,7 +281,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
>  
>  	vmw_svga_enable(dev_priv);
>  
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  	encoder->crtc = crtc;
>  	connector->encoder = encoder;
>  	crtc->x = set->x;
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> index f42359084adc..573c7407c32c 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> @@ -310,7 +310,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
>  
>  		connector->encoder = NULL;
>  		encoder->crtc = NULL;
> -		crtc->primary->fb = NULL;
> +		drm_plane_set_fb(crtc->primary, NULL);
>  		crtc->x = 0;
>  		crtc->y = 0;
>  		crtc->enabled = false;
> @@ -371,7 +371,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
>  
>  		connector->encoder = NULL;
>  		encoder->crtc = NULL;
> -		crtc->primary->fb = NULL;
> +		drm_plane_set_fb(crtc->primary, NULL);
>  		crtc->x = 0;
>  		crtc->y = 0;
>  		crtc->enabled = false;
> @@ -384,7 +384,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
>  	connector->encoder = encoder;
>  	encoder->crtc = crtc;
>  	crtc->mode = *mode;
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  	crtc->x = set->x;
>  	crtc->y = set->y;
>  	crtc->enabled = true;
> @@ -407,7 +407,7 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc,
>  	if (!vmw_kms_crtc_flippable(dev_priv, crtc))
>  		return -EINVAL;
>  
> -	crtc->primary->fb = fb;
> +	drm_plane_set_fb(crtc->primary, fb);
>  
>  	/* do a full screen dirty update */
>  	vclips.x = crtc->x;
> @@ -454,7 +454,7 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc,
>  	return ret;
>  
>  out_no_fence:
> -	crtc->primary->fb = old_fb;
> +	drm_plane_set_fb(crtc->primary, old_fb);
>  	return ret;
>  }
>  
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
> index 94ad8d2acf9a..01c4d574fa78 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
> @@ -486,7 +486,7 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv,
>  		new_display_srf = NULL;
>  	}
>  
> -	crtc->primary->fb = new_fb;
> +	drm_plane_set_fb(crtc->primary, new_fb);
>  	stdu->content_fb_type = new_content_type;
>  	return 0;
>  
> @@ -580,7 +580,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set)
>  		if (ret)
>  			return ret;
>  
> -		crtc->primary->fb = NULL;
> +		drm_plane_set_fb(crtc->primary, NULL);
>  		crtc->enabled = false;
>  		encoder->crtc = NULL;
>  		connector->encoder = NULL;
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 5d5f85db43f0..fb616039a2bf 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -360,9 +360,6 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
>  
>  void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
>  
> -void
> -drm_atomic_clean_old_fb(struct drm_device *dev, unsigned plane_mask, int ret);
> -
>  int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
>  int __must_check drm_atomic_commit(struct drm_atomic_state *state);
>  int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state);
> diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
> index 5b38eb94783b..eacb1124616b 100644
> --- a/include/drm/drm_plane.h
> +++ b/include/drm/drm_plane.h
> @@ -72,7 +72,7 @@ struct drm_plane_state {
>  	 * Currently bound framebuffer. Do not write this directly, use
>  	 * drm_atomic_set_fb_for_plane()
>  	 */
> -	struct drm_framebuffer *fb;
> +	struct drm_framebuffer * const fb;
>  
>  	/**
>  	 * @fence:
> @@ -451,8 +451,6 @@ enum drm_plane_type {
>   * @format_default: driver hasn't supplied supported formats for the plane
>   * @crtc: currently bound CRTC
>   * @fb: currently bound fb
> - * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by
> - * 	drm_mode_set_config_internal() to implement correct refcounting.
>   * @funcs: helper functions
>   * @properties: property tracking for this plane
>   * @type: type of plane (overlay, primary, cursor)
> @@ -484,9 +482,7 @@ struct drm_plane {
>  	bool format_default;
>  
>  	struct drm_crtc *crtc;
> -	struct drm_framebuffer *fb;
> -
> -	struct drm_framebuffer *old_fb;
> +	struct drm_framebuffer * const fb;
>  
>  	const struct drm_plane_funcs *funcs;
>  
> @@ -596,5 +592,24 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
>  #define drm_for_each_plane(plane, dev) \
>  	list_for_each_entry(plane, &(dev)->mode_config.plane_list, head)
>  
> +#define __mkwrite_drm_framebuffer(fb__) (struct drm_framebuffer **)(fb__)
> +
> +static inline void drm_plane_set_fb(struct drm_plane *plane,
> +				    struct drm_framebuffer *fb)
> +{
> +	if (plane->fb == fb)
> +		return;
> +
> +	drm_framebuffer_assign(__mkwrite_drm_framebuffer(&plane->fb), fb);
> +}
> +
> +static inline struct drm_framebuffer *
> +drm_plane_get_fb(struct drm_plane *plane)
> +{
> +	struct drm_framebuffer *fb = plane->fb;
> +	if (fb)
> +		drm_framebuffer_reference(fb);
> +	return fb;
> +}
>  
>  #endif
> -- 
> 2.10.2
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the dri-devel mailing list