Commit e87297fa authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'drm-fixes-2020-12-04' of git://anongit.freedesktop.org/drm/drm

Pull drm fixes from Dave Airlie:
 "This week's regular fixes.

  i915 has fixes for a few races, use-after-free, and gpu hangs. Tegra
  just has some minor fixes that I didn't see much point in hanging on
  to. The nouveau fix is for all pre-nv50 cards and was reported a few
  times. Otherwise it's just some amdgpu, and a few misc fixes.

  Summary:

  amdgpu:
   - SMU11 manual fan fix
   - Renoir display clock fix
   - VCN3 dynamic powergating fix

  i915:
   - Program mocs:63 for cache eviction on gen9 (Chris)
   - Protect context lifetime with RCU (Chris)
   - Split the breadcrumb spinlock between global and contexts (Chris)
   - Retain default context state across shrinking (Venkata)
   - Limit frequency drop to RPe on parking (Chris)
   - Return earlier from intel_modeset_init() without display (Jani)
   - Defer initial modeset until after GGTT is initialized (Chris)

  nouveau:
   - pre-nv50 regression fix

  rockchip:
   - uninitialised LVDS property fix

  omap:
   - bridge fix

  panel:
   - race fix

  mxsfb:
   - fence sync fix
   - modifiers fix

  tegra:
   - idr init fix
   - sor fixes
   - output/of cleanup fix"

* tag 'drm-fixes-2020-12-04' of git://anongit.freedesktop.org/drm/drm: (22 commits)
  drm/amdgpu/vcn3.0: remove old DPG workaround
  drm/amdgpu/vcn3.0: stall DPG when WPTR/RPTR reset
  drm/amd/display: Init clock value by current vbios CLKs
  drm/amdgpu/pm/smu11: Fix fan set speed bug
  drm/i915/display: Defer initial modeset until after GGTT is initialised
  drm/i915/display: return earlier from intel_modeset_init() without display
  drm/i915/gt: Limit frequency drop to RPe on parking
  drm/i915/gt: Retain default context state across shrinking
  drm/i915/gt: Split the breadcrumb spinlock between global and contexts
  drm/i915/gt: Protect context lifetime with RCU
  drm/i915/gt: Program mocs:63 for cache eviction on gen9
  drm/omap: sdi: fix bridge enable/disable
  drm/panel: sony-acx565akm: Fix race condition in probe
  drm/rockchip: Avoid uninitialized use of endpoint id in LVDS
  drm/tegra: sor: Disable clocks on error in tegra_sor_init()
  drm/nouveau: make sure ret is initialized in nouveau_ttm_io_mem_reserve
  drm: mxsfb: Implement .format_mod_supported
  drm: mxsfb: fix fence synchronization
  drm/tegra: output: Do not put OF node twice
  drm/tegra: replace idr_init() by idr_init_base()
  ...
parents bbe2ba04 de9b485d
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -1011,6 +1011,11 @@ static int vcn_v3_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
	WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_CNTL, tmp);

	/* Stall DPG before WPTR/RPTR reset */
	WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
		UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK,
		~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);

	/* set the write pointer delay */
	WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR_CNTL, 0);

@@ -1033,6 +1038,10 @@ static int vcn_v3_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
	WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR,
		lower_32_bits(ring->wptr));

	/* Unstall DPG */
	WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
		0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);

	return 0;
}

@@ -1556,8 +1565,14 @@ static int vcn_v3_0_pause_dpg_mode(struct amdgpu_device *adev,
					UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK,
					UVD_DPG_PAUSE__NJ_PAUSE_DPG_ACK_MASK);

				/* Stall DPG before WPTR/RPTR reset */
				WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
					UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK,
					~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);

				/* Restore */
				ring = &adev->vcn.inst[inst_idx].ring_enc[0];
				ring->wptr = 0;
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_BASE_LO, ring->gpu_addr);
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_SIZE, ring->ring_size / 4);
@@ -1565,14 +1580,16 @@ static int vcn_v3_0_pause_dpg_mode(struct amdgpu_device *adev,
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));

				ring = &adev->vcn.inst[inst_idx].ring_enc[1];
				ring->wptr = 0;
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_BASE_LO2, ring->gpu_addr);
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_SIZE2, ring->ring_size / 4);
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
				WREG32_SOC15(VCN, inst_idx, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));

				WREG32_SOC15(VCN, inst_idx, mmUVD_RBC_RB_WPTR,
					RREG32_SOC15(VCN, inst_idx, mmUVD_SCRATCH2) & 0x7FFFFFFF);
				/* Unstall DPG */
				WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
					0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);

				SOC15_WAIT_ON_RREG(VCN, inst_idx, mmUVD_POWER_STATUS,
					UVD_PGFSM_CONFIG__UVDM_UVDU_PWR_ON, UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
@@ -1630,10 +1647,6 @@ static void vcn_v3_0_dec_ring_set_wptr(struct amdgpu_ring *ring)
{
	struct amdgpu_device *adev = ring->adev;

	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
		WREG32_SOC15(VCN, ring->me, mmUVD_SCRATCH2,
			lower_32_bits(ring->wptr) | 0x80000000);

	if (ring->use_doorbell) {
		adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr);
		WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr));
+11 −2
Original line number Diff line number Diff line
@@ -163,8 +163,17 @@ void rn_update_clocks(struct clk_mgr *clk_mgr_base,
			new_clocks->dppclk_khz = 100000;
	}

	if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
		if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
	/*
	 * Temporally ignore thew 0 cases for disp and dpp clks.
	 * We may have a new feature that requires 0 clks in the future.
	 */
	if (new_clocks->dppclk_khz == 0 || new_clocks->dispclk_khz == 0) {
		new_clocks->dppclk_khz = clk_mgr_base->clks.dppclk_khz;
		new_clocks->dispclk_khz = clk_mgr_base->clks.dispclk_khz;
	}

	if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) {
		if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz)
			dpp_clock_lowered = true;
		clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
		update_dppclk = true;
+6 −1
Original line number Diff line number Diff line
@@ -1164,7 +1164,12 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
	if (ret)
		return ret;

	crystal_clock_freq = amdgpu_asic_get_xclk(adev);
	/*
	 * crystal_clock_freq div by 4 is required since the fan control
	 * module refers to 25MHz
	 */

	crystal_clock_freq = amdgpu_asic_get_xclk(adev) / 4;
	tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
	WREG32_SOC15(THM, 0, mmCG_TACH_CTRL,
		     REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL),
+12 −12
Original line number Diff line number Diff line
@@ -18021,16 +18021,6 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
	if (!HAS_GMCH(i915))
		sanitize_watermarks(i915);
	/*
	 * Force all active planes to recompute their states. So that on
	 * mode_setcrtc after probe, all the intel_plane_state variables
	 * are already calculated and there is no assert_plane warnings
	 * during bootup.
	 */
	ret = intel_initial_commit(dev);
	if (ret)
		drm_dbg_kms(&i915->drm, "Initial commit in probe failed.\n");
	return 0;
}
@@ -18039,11 +18029,21 @@ int intel_modeset_init(struct drm_i915_private *i915)
{
	int ret;
	intel_overlay_setup(i915);
	if (!HAS_DISPLAY(i915))
		return 0;
	/*
	 * Force all active planes to recompute their states. So that on
	 * mode_setcrtc after probe, all the intel_plane_state variables
	 * are already calculated and there is no assert_plane warnings
	 * during bootup.
	 */
	ret = intel_initial_commit(&i915->drm);
	if (ret)
		return ret;
	intel_overlay_setup(i915);
	ret = intel_fbdev_init(&i915->drm);
	if (ret)
		return ret;
+74 −94
Original line number Diff line number Diff line
@@ -101,18 +101,37 @@ static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
	intel_gt_pm_put_async(b->irq_engine->gt);
}

static void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
{
	spin_lock(&b->irq_lock);
	if (b->irq_armed)
		__intel_breadcrumbs_disarm_irq(b);
	spin_unlock(&b->irq_lock);
}

static void add_signaling_context(struct intel_breadcrumbs *b,
				  struct intel_context *ce)
{
	intel_context_get(ce);
	list_add_tail(&ce->signal_link, &b->signalers);
	lockdep_assert_held(&ce->signal_lock);

	spin_lock(&b->signalers_lock);
	list_add_rcu(&ce->signal_link, &b->signalers);
	spin_unlock(&b->signalers_lock);
}

static void remove_signaling_context(struct intel_breadcrumbs *b,
static bool remove_signaling_context(struct intel_breadcrumbs *b,
				     struct intel_context *ce)
{
	list_del(&ce->signal_link);
	intel_context_put(ce);
	lockdep_assert_held(&ce->signal_lock);

	if (!list_empty(&ce->signals))
		return false;

	spin_lock(&b->signalers_lock);
	list_del_rcu(&ce->signal_link);
	spin_unlock(&b->signalers_lock);

	return true;
}

static inline bool __request_completed(const struct i915_request *rq)
@@ -175,6 +194,8 @@ static void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl)

static bool __signal_request(struct i915_request *rq)
{
	GEM_BUG_ON(test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags));

	if (!__dma_fence_signal(&rq->fence)) {
		i915_request_put(rq);
		return false;
@@ -195,15 +216,12 @@ static void signal_irq_work(struct irq_work *work)
	struct intel_breadcrumbs *b = container_of(work, typeof(*b), irq_work);
	const ktime_t timestamp = ktime_get();
	struct llist_node *signal, *sn;
	struct intel_context *ce, *cn;
	struct list_head *pos, *next;
	struct intel_context *ce;

	signal = NULL;
	if (unlikely(!llist_empty(&b->signaled_requests)))
		signal = llist_del_all(&b->signaled_requests);

	spin_lock(&b->irq_lock);

	/*
	 * Keep the irq armed until the interrupt after all listeners are gone.
	 *
@@ -229,47 +247,44 @@ static void signal_irq_work(struct irq_work *work)
	 * interrupt draw less ire from other users of the system and tools
	 * like powertop.
	 */
	if (!signal && b->irq_armed && list_empty(&b->signalers))
		__intel_breadcrumbs_disarm_irq(b);
	if (!signal && READ_ONCE(b->irq_armed) && list_empty(&b->signalers))
		intel_breadcrumbs_disarm_irq(b);

	list_for_each_entry_safe(ce, cn, &b->signalers, signal_link) {
		GEM_BUG_ON(list_empty(&ce->signals));
	rcu_read_lock();
	list_for_each_entry_rcu(ce, &b->signalers, signal_link) {
		struct i915_request *rq;

		list_for_each_safe(pos, next, &ce->signals) {
			struct i915_request *rq =
				list_entry(pos, typeof(*rq), signal_link);
		list_for_each_entry_rcu(rq, &ce->signals, signal_link) {
			bool release;

			GEM_BUG_ON(!check_signal_order(ce, rq));
			if (!__request_completed(rq))
				break;

			if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL,
						&rq->fence.flags))
				break;

			/*
			 * Queue for execution after dropping the signaling
			 * spinlock as the callback chain may end up adding
			 * more signalers to the same context or engine.
			 */
			clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
			spin_lock(&ce->signal_lock);
			list_del_rcu(&rq->signal_link);
			release = remove_signaling_context(b, ce);
			spin_unlock(&ce->signal_lock);

			if (__signal_request(rq))
				/* We own signal_node now, xfer to local list */
				signal = slist_add(&rq->signal_node, signal);
		}

		/*
		 * We process the list deletion in bulk, only using a list_add
		 * (not list_move) above but keeping the status of
		 * rq->signal_link known with the I915_FENCE_FLAG_SIGNAL bit.
		 */
		if (!list_is_first(pos, &ce->signals)) {
			/* Advance the list to the first incomplete request */
			__list_del_many(&ce->signals, pos);
			if (&ce->signals == pos) { /* now empty */
			if (release) {
				add_retire(b, ce->timeline);
				remove_signaling_context(b, ce);
				intel_context_put(ce);
			}
		}
	}

	spin_unlock(&b->irq_lock);
	rcu_read_unlock();

	llist_for_each_safe(signal, sn, signal) {
		struct i915_request *rq =
@@ -298,14 +313,15 @@ intel_breadcrumbs_create(struct intel_engine_cs *irq_engine)
	if (!b)
		return NULL;

	spin_lock_init(&b->irq_lock);
	b->irq_engine = irq_engine;

	spin_lock_init(&b->signalers_lock);
	INIT_LIST_HEAD(&b->signalers);
	init_llist_head(&b->signaled_requests);

	spin_lock_init(&b->irq_lock);
	init_irq_work(&b->irq_work, signal_irq_work);

	b->irq_engine = irq_engine;

	return b;
}

@@ -347,9 +363,9 @@ void intel_breadcrumbs_free(struct intel_breadcrumbs *b)
	kfree(b);
}

static void insert_breadcrumb(struct i915_request *rq,
			      struct intel_breadcrumbs *b)
static void insert_breadcrumb(struct i915_request *rq)
{
	struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs;
	struct intel_context *ce = rq->context;
	struct list_head *pos;

@@ -371,6 +387,7 @@ static void insert_breadcrumb(struct i915_request *rq,
	}

	if (list_empty(&ce->signals)) {
		intel_context_get(ce);
		add_signaling_context(b, ce);
		pos = &ce->signals;
	} else {
@@ -396,8 +413,9 @@ static void insert_breadcrumb(struct i915_request *rq,
				break;
		}
	}
	list_add(&rq->signal_link, pos);
	list_add_rcu(&rq->signal_link, pos);
	GEM_BUG_ON(!check_signal_order(ce, rq));
	GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags));
	set_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);

	/*
@@ -410,7 +428,7 @@ static void insert_breadcrumb(struct i915_request *rq,

bool i915_request_enable_breadcrumb(struct i915_request *rq)
{
	struct intel_breadcrumbs *b;
	struct intel_context *ce = rq->context;

	/* Serialises with i915_request_retire() using rq->lock */
	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
@@ -425,68 +443,31 @@ bool i915_request_enable_breadcrumb(struct i915_request *rq)
	if (!test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
		return true;

	/*
	 * rq->engine is locked by rq->engine->active.lock. That however
	 * is not known until after rq->engine has been dereferenced and
	 * the lock acquired. Hence we acquire the lock and then validate
	 * that rq->engine still matches the lock we hold for it.
	 *
	 * Here, we are using the breadcrumb lock as a proxy for the
	 * rq->engine->active.lock, and we know that since the breadcrumb
	 * will be serialised within i915_request_submit/i915_request_unsubmit,
	 * the engine cannot change while active as long as we hold the
	 * breadcrumb lock on that engine.
	 *
	 * From the dma_fence_enable_signaling() path, we are outside of the
	 * request submit/unsubmit path, and so we must be more careful to
	 * acquire the right lock.
	 */
	b = READ_ONCE(rq->engine)->breadcrumbs;
	spin_lock(&b->irq_lock);
	while (unlikely(b != READ_ONCE(rq->engine)->breadcrumbs)) {
		spin_unlock(&b->irq_lock);
		b = READ_ONCE(rq->engine)->breadcrumbs;
		spin_lock(&b->irq_lock);
	}

	/*
	 * Now that we are finally serialised with request submit/unsubmit,
	 * [with b->irq_lock] and with i915_request_retire() [via checking
	 * SIGNALED with rq->lock] confirm the request is indeed active. If
	 * it is no longer active, the breadcrumb will be attached upon
	 * i915_request_submit().
	 */
	spin_lock(&ce->signal_lock);
	if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
		insert_breadcrumb(rq, b);

	spin_unlock(&b->irq_lock);
		insert_breadcrumb(rq);
	spin_unlock(&ce->signal_lock);

	return true;
}

void i915_request_cancel_breadcrumb(struct i915_request *rq)
{
	struct intel_breadcrumbs *b = rq->engine->breadcrumbs;

	/*
	 * We must wait for b->irq_lock so that we know the interrupt handler
	 * has released its reference to the intel_context and has completed
	 * the DMA_FENCE_FLAG_SIGNALED_BIT/I915_FENCE_FLAG_SIGNAL dance (if
	 * required).
	 */
	spin_lock(&b->irq_lock);
	if (test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags)) {
	struct intel_context *ce = rq->context;
	bool release;

	if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags))
		return;

		list_del(&rq->signal_link);
		if (list_empty(&ce->signals))
			remove_signaling_context(b, ce);
	spin_lock(&ce->signal_lock);
	list_del_rcu(&rq->signal_link);
	release = remove_signaling_context(rq->engine->breadcrumbs, ce);
	spin_unlock(&ce->signal_lock);
	if (release)
		intel_context_put(ce);

		clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
	i915_request_put(rq);
}
	spin_unlock(&b->irq_lock);
}

static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
{
@@ -495,9 +476,9 @@ static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)

	drm_printf(p, "Signals:\n");

	spin_lock_irq(&b->irq_lock);
	list_for_each_entry(ce, &b->signalers, signal_link) {
		list_for_each_entry(rq, &ce->signals, signal_link) {
	rcu_read_lock();
	list_for_each_entry_rcu(ce, &b->signalers, signal_link) {
		list_for_each_entry_rcu(rq, &ce->signals, signal_link)
			drm_printf(p, "\t[%llx:%llx%s] @ %dms\n",
				   rq->fence.context, rq->fence.seqno,
				   i915_request_completed(rq) ? "!" :
@@ -505,8 +486,7 @@ static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
				   "",
				   jiffies_to_msecs(jiffies - rq->emitted_jiffies));
	}
	}
	spin_unlock_irq(&b->irq_lock);
	rcu_read_unlock();
}

void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
Loading